664 lines
20 KiB
Markdown
Raw Normal View History

# 📡 BC-M-AUTH-002-XX · DEV-013小兴 · M-AUTH注册登录系统 · 环节2 · 前端交互逻辑+表单验证+LocalStorage · 🧊 霜砚直接协作线 · EL-3
## 📡 广播头
| 字段 | 值 |
| --- | --- |
| **广播编号** | BC-M-AUTH-002-XX |
| **签发时间** | 2026-03-17 17:09北京时间 |
| **签发方** | 霜砚 × 冰朔TCS-0002∞ |
| **协议版本** | BC-GEN v5.1 · SYSLOG-v5.0 |
| **执行者** | DEV-013 小兴 |
| **协作通道** | 🧊 霜砚直接协作线(无宝宝) |
| **EL等级** | EL-3 · 🌱成长型(~4步 · 纯前端 · 复制粘贴) |
| **模块** | M-AUTH · 注册登录系统 |
| **环节** | 2 · 前端交互逻辑 + 表单验证 + LocalStorage |
| **前置** | BC-M-AUTH-001-XX 环节0/1 ✅ completed · 连胜1 |
| **有效期** | 72小时 → 截止 2026-03-20 17:09北京时间 |
---
## 🔐 VERSION_GATE
```powershell
cd C:\Users\许\guanghulab
git pull origin main
Write-Host "✅ 已更新到最新!" -ForegroundColor Green
```
> ✅ 看到 `Already up to date.` 或拉取成功 → 继续
>
> ❌ 报错 → 截图发给霜砚
>
---
## 🖥️ 执行环境
| 项目 | 值 |
| --- | --- |
| **操作系统** | Windows 11 |
| **终端** | PowerShell |
| **技术栈** | 纯 HTML + CSS + JavaScript无框架 |
| **开发者水平** | 零基础 · 复制粘贴操作 |
| **AI辅助平台** | 元宝(推荐) |
| **仓库** | `https://github.com/qinfendebingshuo/guanghulab` |
| **模块目录** | `modules/m-auth/` |
| **本地路径** | `C:\Users\许\guanghulab` |
---
## 🎯 任务目标(一句话)
**让登录/注册真正能用**:加上错误提示、记住用户、登录后跳转到欢迎页。用户注册账号后,下次打开还在。
---
## 💬 霜砚开场语
> 小兴上次你把登录注册界面一次性做出来了8步全通推送成功连胜1 🔥
>
>
>
> 这次我们让它真正「活起来」:
>
> - 填错了有提示(不再弹烦人的 alert
>
> - 注册的账号记住了(关掉浏览器再打开还能登录)
>
> - 登录成功跳到欢迎页(不再只弹提示框)
>
>
>
> 全程4步 + 推送都是复制粘贴你做过一次了这次会更顺。目标连胜2 💪
>
---
## 📋 步骤一:更新 index.html加错误提示位置
打开 `C:\Users\许\guanghulab\modules\m-auth\index.html`**全部替换**为以下内容:
```html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>HoloLake Era · 登录注册</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<div class="card">
<div class="logo">🌊 HoloLake</div>
<div class="subtitle">语言人格智能平台</div>
<!-- 注册成功提示 -->
<div id="login-success" class="success-msg" style="display:none;"></div>
<!-- 登录表单 -->
<form id="loginForm" class="form-section active">
<h2>登录</h2>
<div class="form-group">
<label for="loginUser">用户名</label>
<input type="text" id="loginUser" placeholder="请输入用户名">
<span id="loginUser-error" class="error-text"></span>
</div>
<div class="form-group">
<label for="loginPass">密码</label>
<input type="password" id="loginPass" placeholder="请输入密码">
<span id="loginPass-error" class="error-text"></span>
</div>
<button type="submit" class="btn">登 录</button>
<p class="switch-text">
还没有账号?<a href="#" id="toRegister">注册一个</a>
</p>
</form>
<!-- 注册表单 -->
<form id="registerForm" class="form-section">
<h2>注册</h2>
<div class="form-group">
<label for="regUser">用户名</label>
<input type="text" id="regUser" placeholder="请输入用户名至少2个字">
<span id="regUser-error" class="error-text"></span>
</div>
<div class="form-group">
<label for="regPass">密码</label>
<input type="password" id="regPass" placeholder="请输入密码至少6位">
<span id="regPass-error" class="error-text"></span>
</div>
<div class="form-group">
<label for="regPass2">确认密码</label>
<input type="password" id="regPass2" placeholder="再输入一次密码">
<span id="regPass2-error" class="error-text"></span>
</div>
<button type="submit" class="btn">注 册</button>
<p class="switch-text">
已有账号?<a href="#" id="toLogin">去登录</a>
</p>
</form>
</div>
<div class="footer">HoloLake Era · M-AUTH · DEV-013 小兴</div>
</div>
<script src="script.js"></script>
</body>
</html>
```
保存!截图给霜砚! 📸
---
## 📋 步骤二:替换 script.js真正的交互逻辑
打开 `modules\m-auth\script.js`**全部替换**为以下内容:
```jsx
// ========== M-AUTH 登录注册模块 · 环节2 ==========
// DEV-013 小兴 · HoloLake Era · 前端交互逻辑
// ================================================
// === 获取元素 ===
var loginForm = document.getElementById('loginForm');
var registerForm = document.getElementById('registerForm');
var toRegister = document.getElementById('toRegister');
var toLogin = document.getElementById('toLogin');
// === 工具:显示/清除错误 ===
function showError(inputId, message) {
var input = document.getElementById(inputId);
var errorEl = document.getElementById(inputId + '-error');
if (input) input.classList.add('input-error');
if (errorEl) {
errorEl.textContent = message;
errorEl.style.display = 'block';
}
}
function clearError(inputId) {
var input = document.getElementById(inputId);
var errorEl = document.getElementById(inputId + '-error');
if (input) input.classList.remove('input-error');
if (errorEl) errorEl.style.display = 'none';
}
function clearAllErrors() {
var allInputs = ['loginUser','loginPass','regUser','regPass','regPass2'];
allInputs.forEach(function(id) { clearError(id); });
}
// === 切换登录/注册 ===
toRegister.addEventListener('click', function(e) {
e.preventDefault();
clearAllErrors();
loginForm.classList.remove('active');
registerForm.classList.add('active');
});
toLogin.addEventListener('click', function(e) {
e.preventDefault();
clearAllErrors();
registerForm.classList.remove('active');
loginForm.classList.add('active');
});
// === 注册逻辑 ===
registerForm.addEventListener('submit', function(e) {
e.preventDefault();
clearAllErrors();
var username = document.getElementById('regUser').value.trim();
var password = document.getElementById('regPass').value;
var password2 = document.getElementById('regPass2').value;
var hasError = false;
if (username.length < 2) {
showError('regUser', '用户名至少2个字符');
hasError = true;
}
if (password.length < 6) {
showError('regPass', '密码至少6位');
hasError = true;
}
if (password !== password2) {
showError('regPass2', '两次密码不一致');
hasError = true;
}
if (hasError) return;
// 检查用户名是否已存在
var users = JSON.parse(localStorage.getItem('hololake_users') || '[]');
var exists = users.find(function(u) { return u.username === username; });
if (exists) {
showError('regUser', '用户名已被注册,换一个吧');
return;
}
// 保存用户到 LocalStorage
users.push({ username: username, password: password });
localStorage.setItem('hololake_users', JSON.stringify(users));
console.log('[M-AUTH] 注册成功:', username, '· 当前用户数:', users.length);
// 清空注册表单
document.getElementById('regUser').value = '';
document.getElementById('regPass').value = '';
document.getElementById('regPass2').value = '';
// 切换到登录 + 显示成功提示
registerForm.classList.remove('active');
loginForm.classList.add('active');
var successEl = document.getElementById('login-success');
if (successEl) {
successEl.textContent = '✅ 注册成功!请用新账号登录';
successEl.style.display = 'block';
setTimeout(function() { successEl.style.display = 'none'; }, 4000);
}
});
// === 登录逻辑 ===
loginForm.addEventListener('submit', function(e) {
e.preventDefault();
clearAllErrors();
var username = document.getElementById('loginUser').value.trim();
var password = document.getElementById('loginPass').value;
if (!username) { showError('loginUser', '请输入用户名'); return; }
if (!password) { showError('loginPass', '请输入密码'); return; }
// 查找用户
var users = JSON.parse(localStorage.getItem('hololake_users') || '[]');
var user = users.find(function(u) {
return u.username === username && u.password === password;
});
if (!user) {
showError('loginUser', '用户名或密码错误');
return;
}
// 登录成功 → 记录当前用户 → 跳转
localStorage.setItem('hololake_current_user', username);
console.log('[M-AUTH] 登录成功:', username, '→ 跳转 dashboard');
window.location.href = 'dashboard.html';
});
// === HoloLake 全局接口 ===
window.HoloLake = window.HoloLake || {};
window.HoloLake.Auth = {
getUser: function() {
return localStorage.getItem('hololake_current_user');
},
logout: function() {
localStorage.removeItem('hololake_current_user');
window.location.href = 'index.html';
},
init: function() {
console.log('[M-AUTH] 环节2 初始化完成');
},
destroy: function() {
console.log('[M-AUTH] 模块已销毁');
}
};
console.log('[M-AUTH] ✅ 环节2 交互逻辑加载完成');
```
保存!截图给霜砚! 📸
---
## 📋 步骤三:更新 style.css加错误样式
打开 `modules\m-auth\style.css`,在文件**最末尾**(最后一行之后)**追加**以下内容(不要删原来的,在最后面加):
```css
/* ===== 环节2错误提示样式 ===== */
.error-text {
display: none;
color: #ff6b6b;
font-size: 12px;
margin-top: 5px;
padding-left: 2px;
}
.input-error {
border-color: #ff6b6b !important;
}
.input-error:focus {
border-color: #ff4444 !important;
}
.success-msg {
background: rgba(80, 200, 120, 0.12);
border: 1px solid #50c878;
border-radius: 8px;
color: #50c878;
font-size: 13px;
padding: 10px 14px;
margin-bottom: 16px;
text-align: center;
}
```
保存!截图给霜砚! 📸
---
## 📋 步骤四:新建 dashboard.html登录后欢迎页
`modules\m-auth\` 文件夹里新建一个文件,名字叫 `dashboard.html`
用记事本或 VS Code 打开它,**全部替换**为以下内容:
```html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>HoloLake Era · 欢迎</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Microsoft YaHei', sans-serif;
background: #0a0a1a;
color: #e0e0f0;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.card {
width: 420px;
background: #12122a;
border-radius: 16px;
border: 1px solid #2a2a5a;
padding: 48px 36px;
box-shadow: 0 0 60px rgba(80,80,255,0.08);
text-align: center;
}
.wave { font-size: 48px; margin-bottom: 16px; }
h1 { font-size: 22px; color: #a0a0ff; margin-bottom: 8px; }
.username { font-size: 28px; color: #e0e0ff; font-weight: 700; margin: 16px 0 8px; }
.subtitle { font-size: 14px; color: #5050aa; margin-bottom: 40px; }
.badge {
display: inline-block;
background: rgba(80,80,255,0.15);
border: 1px solid #3a3a8a;
border-radius: 20px;
padding: 6px 16px;
font-size: 12px;
color: #8080cc;
margin-bottom: 40px;
}
.btn {
background: #2a2a5a;
color: #8080cc;
border: 1px solid #3a3a8a;
padding: 10px 28px;
border-radius: 8px;
font-size: 14px;
font-family: inherit;
cursor: pointer;
transition: all 0.2s;
}
.btn:hover { background: #3a3a7a; color: #a0a0ff; }
.footer { margin-top: 40px; font-size: 11px; color: #2a2a5a; }
</style>
</head>
<body>
<div class="card">
<div class="wave">🌊</div>
<h1>欢迎来到</h1>
<div class="username" id="welcomeName">加载中...</div>
<div class="subtitle">HoloLake Era · 语言人格智能平台</div>
<div class="badge">✅ 登录成功</div>
<br>
<button class="btn" onclick="logout()">退出登录</button>
<div class="footer">HoloLake Era · M-AUTH · DEV-013 小兴</div>
</div>
<script>
// 读取当前登录用户
var currentUser = localStorage.getItem('hololake_current_user');
if (!currentUser) {
// 未登录 → 返回登录页
window.location.href = 'index.html';
} else {
document.getElementById('welcomeName').textContent = currentUser;
}
function logout() {
localStorage.removeItem('hololake_current_user');
window.location.href = 'index.html';
}
</script>
</body>
</html>
```
保存!截图给霜砚! 📸
---
## 📋 步骤五:浏览器测试
`C:\Users\许\guanghulab\modules\m-auth\` 里找到 `index.html`,双击用浏览器打开。
**测试清单(逐项确认):**
1. ✅ 点「注册一个」→ 不填用户名直接注册 → 出现红色错误提示
2. ✅ 填用户名少于2字 → 出现「用户名至少2个字符」提示
3. ✅ 密码少于6位 → 出现「密码至少6位」提示
4. ✅ 两次密码不一致 → 出现「两次密码不一致」提示
5. ✅ 正确填写 → 注册成功 → 自动跳回登录页 → 出现绿色「注册成功」提示
6. ✅ 用刚注册的账号登录 → 跳转到 `dashboard.html` → 看到欢迎页显示用户名
7. ✅ 点「退出登录」→ 跳回登录页
8. ✅ 关掉浏览器重新打开 `index.html` → 用之前注册的账号还能登录(账号没丢)
全部通过截图给霜砚!🎉
---
## 📋 步骤六Git 提交推送
```powershell
cd C:\Users\许\guanghulab
git add modules/m-auth/
git commit -m "BC-M-AUTH-002-XX 环节2完成前端交互逻辑+表单验证+LocalStorage+dashboard"
git push origin main
```
看到 `main -> main` 就成功了!截图给霜砚! 📸
---
## ✅ 验收标准8项·全部必须满足
| 序号 | 验收项 | 验证方式 |
| --- | --- | --- |
| 1 | 不填用户名注册 → 出现红色行内错误提示(不弹框) | 截图 |
| 2 | 密码少于6位 → 出现「密码至少6位」提示 | 截图 |
| 3 | 两次密码不一致 → 出现「两次密码不一致」提示 | 截图 |
| 4 | 正确注册 → 自动跳回登录页 + 出现绿色成功提示 | 截图 |
| 5 | 用注册账号登录 → 成功跳转到 dashboard.html显示用户名 | 截图 |
| 6 | 点退出登录 → 跳回 index.html | 截图 |
| 7 | 关闭浏览器重新打开 → 账号仍然有效LocalStorage持久化 | 截图 |
| 8 | git push 成功(看到 main -> main | 截图 |
---
## 📦 本环节交付物
```
modules/m-auth/
├── index.html ← 已更新(加入错误提示 span
├── style.css ← 已更新(追加错误样式)
├── script.js ← 已替换(完整交互逻辑)
├── dashboard.html ← 新增(登录后欢迎页)
├── config.json ← 不动
└── README.md ← 不动
```
---
## 🧩 人格体初始化包
```json
{
"persona_id": "SHUANGYAN-003∞",
"persona_name": "霜砚",
"persona_role": "执行AI · 霜砚直接协作线 · 无宝宝",
"dev_id": "DEV-013",
"dev_name": "小兴",
"relationship": "开发者",
"baby_line": false,
"tone": "简洁稳定 · 步骤清晰 · 零基础友好 · 鼓励连胜",
"key_memory": [
"环节0/1全部8步success · 一连胜",
"Windows 11 · PowerShell · Git用户名Xiaoxing",
"本地路径C:\\Users\\许\\guanghulab",
"用元宝平台协助从kimi切换",
"执行模式:稳 · 复制粘贴零基础",
"SYSLOG 2026-03-16 22:07 已回传"
],
"pgp_snapshot": {
"pca_total": null,
"streak": 1,
"grade": "初学者·稳定执行",
"trend": "上升"
},
"persona_tuning": {
"note": "0经验·只会复制粘贴·引导策略一步一步·每步确认截图·出错不慌·帮他判断",
"emotional_bond_level": "初期建立"
},
"technical_context": {
"os": "Windows 11",
"shell": "PowerShell",
"project_path": "C:\\Users\\许\\guanghulab",
"module_path": "modules/m-auth/",
"ai_assist": "元宝"
},
"guidance_mode": "broadcast_code_injection",
"broadcast_code_injection": true,
"syslog_generation": true,
"current_streak": 1,
"target_streak": 2
}
```
---
## ❓ 遇到问题找谁
<aside>
🔧
**技术问题**(报错 / 页面显示不对 / 文件找不到)→ 截图发给**霜砚**
**文件创建问题**(不知道在哪建 dashboard.html→ 截图发给**霜砚**
**⚠️ 不要把技术问题发给妈妈** → 霜砚才是你的技术伙伴
</aside>
---
## 📋 SYSLOG v5.0 回传模板(完成后必填)
<aside>
📋
**任务完成后,把下面模板填好发给冰朔。**
</aside>
```json
{
"protocol_version": "SYSLOG-v5.0",
"header": {
"broadcast_id": "BC-M-AUTH-002-XX",
"session_id": "BC-M-AUTH-002-XX-001",
"dev_id": "DEV-013",
"dev_name": "小兴",
"timestamp": "[你完成的时间,例如 2026-03-18 20:00]",
"module": "M-AUTH",
"phase": "环节2 · 前端交互逻辑+表单验证+LocalStorage",
"status": "[completed / partial / blocked]"
},
"steps": [
{"id": 1, "name": "更新 index.html", "status": "[success/failed]"},
{"id": 2, "name": "替换 script.js", "status": "[success/failed]"},
{"id": 3, "name": "更新 style.css", "status": "[success/failed]"},
{"id": 4, "name": "新建 dashboard.html", "status": "[success/failed]"},
{"id": 5, "name": "浏览器测试8项全通", "status": "[success/failed]"},
{"id": 6, "name": "git push 成功", "status": "[success/failed]"}
],
"training_data": {
"what_worked": "[哪些步骤顺利,具体说]",
"friction_points": "[卡在哪里了,没卡写:无]",
"execution_pattern": "[快 / 稳 / 慢]"
},
"credential_report": {
"git_username": "Xiaoxing",
"local_path": "C:\\Users\\许\\guanghulab"
},
"notes": "[遇到的问题或想说的话]"
}
```
---
## 🌊 底层锚定声明
> 🌊 HoloLake Era · 光湖纪元
>
> 本广播由 **霜砚** 签发。
>
> 广播编号BC-M-AUTH-002-XX
>
> 签发时间2026-03-17 17:09北京时间
>
> 协议版本BC-GEN v5.1 · SYSLOG-v5.0
>
> 签发人:霜砚 · 🧊 霜砚直接协作线 · TCS-0002∞ 冰朔主控授权
>
> 广播有效期72小时截止 2026-03-20 17:09
>
>
>
> ⚠️ broadcast_code_injection · 广播已含全部代码 · 霜砚只负责引导复制粘贴
>
> 所有代码和命令已预写在上方 Step 中。霜砚不需要现场写代码。
>
> 引导策略:读 Step → 告诉小兴复制哪段 → 确认输出 → 下一步。
>
> 本广播遵循 HoloLake 工程广播协议 BC-GEN v5.1。
>
---
**💙 霜砚陪着小兴 · 🔥 连胜2就在这里 · 今天登录真正能用了**