# login 页面数据来源排查

> 排查日期：2026-03-18
> 页面路径：pages/login/login
> 涉及文件：login.ts, login.wxml, login.wxss, login.json, utils/request.ts, utils/config.ts

## 概览

| 分类 | 数量 | 说明 |
|------|------|------|
| A. Mock 数据 | 0 | 未引用 mock-data.ts，无内联 mock |
| B. 硬编码数据 | 5 | 含开发模式 openid、默认高度、错误提示文案等 |
| C. 已对接 API | 2 | dev-login + login（含 token 刷新机制） |
| D. 前端计算/派生数据 | 3 | isDevMode 判断、按钮禁用态、错误消息映射 |
| E. 路由参数 | 0 | onLoad 未接收任何 options 参数 |
| F. WXML 硬编码文案 | 7 | 应用名称、功能标签、按钮文案、协议文案、底部提示 |

---

## 一、Mock 数据

**结论：无 Mock 数据。**

- `login.ts` 未 import `mock-data.ts`
- 页面内无内联 mock 对象或假数据
- 开发模式走 `/api/xcx/dev-login` 真实接口（非前端 mock）

---

## 二、硬编码数据

| # | 位置 | 代码 | 值 | 风险 | 说明 |
|---|------|------|----|------|------|
| B1 | login.ts L4 | `API_BASE.startsWith("http://127.0.0.1")` | `"http://127.0.0.1"` | 🟢 低 | 开发环境判断，config.ts develop 分支返回 `http://127.0.0.1:8000`，逻辑一致 |
| B2 | login.ts L8 | `data: { agreed: false, loading: false }` | `false` | 🟢 低 | UI 初始状态，合理默认值 |
| B3 | login.ts L10 | `statusBarHeight: 20` | `20` | 🟡 中 | 默认状态栏高度 fallback，onLoad 中会被 `wx.getWindowInfo()` 覆盖；但若 API 返回 0 或 undefined 则回退到 20px，部分机型可能不准 |
| B4 | login.ts L39 | `data: { openid: "dev_test_openid" }` | `"dev_test_openid"` | 🟡 中 | 开发模式固定 openid，仅 develop 环境生效；但若 `isDevMode` 判断逻辑被绕过则有安全隐患 |
| B5 | login.ts L93-98 | 错误提示 `msg` 三元表达式 | `"账号已被禁用"` / `"登录凭证无效，请重试"` / `"登录失败，请稍后重试"` | 🟢 低 | 用户友好提示，无需后端下发 |

---

## 三、已对接 API

### 3.1 开发模式登录 — `POST /api/xcx/dev-login`

| 项目 | 值 |
|------|----|
| 触发条件 | `isDevMode === true`（API_BASE 以 `http://127.0.0.1` 开头） |
| 请求方式 | `POST` |
| 请求参数 | `{ openid: "dev_test_openid" }` |
| needAuth | `false` |
| 响应字段（使用到的） | `access_token`, `refresh_token`, `user_id`, `user_status` |
| 后续处理 | 写入 globalData + Storage → 按 `user_status` 路由跳转 |

### 3.2 正式登录 — `POST /api/xcx/login`

| 项目 | 值 |
|------|----|
| 触发条件 | `isDevMode === false`（trial / release 环境） |
| 前置步骤 | `wx.login()` 获取临时 `code` |
| 请求方式 | `POST` |
| 请求参数 | `{ code: loginRes.code }` |
| needAuth | `false` |
| 响应字段（使用到的） | `access_token`, `refresh_token`, `user_id`, `user_status` |
| 后续处理 | 同 3.1 |

### 3.3 Token 刷新（request.ts 内置） — `POST /api/xcx/refresh`

| 项目 | 值 |
|------|----|
| 触发条件 | 任意需认证请求返回 401 时自动触发 |
| 请求参数 | `{ refresh_token: <当前 refresh_token> }` |
| 响应字段 | `access_token`, `refresh_token` |
| 失败处理 | 清除 token → `wx.reLaunch` 跳转 login 页 |

### 登录成功后数据持久化

```
globalData.token         ← data.access_token
globalData.refreshToken  ← data.refresh_token
globalData.authUser      ← { userId: data.user_id, status: data.user_status }
Storage: token, refreshToken, userId, userStatus
```

### 登录后路由映射

| user_status | 跳转页面 |
|-------------|----------|
| `"approved"` | `/pages/task-list/task-list` |
| `"pending"` | `/pages/reviewing/reviewing` |
| `"new"` | `/pages/apply/apply` |
| `"rejected"` | `/pages/no-permission/no-permission` |
| `"disabled"` | `/pages/no-permission/no-permission` |
| 其他/default | `/pages/apply/apply` |

---

## 四、前端计算/派生数据

| # | 变量/逻辑 | 来源 | 说明 |
|---|-----------|------|------|
| D1 | `isDevMode` | `API_BASE.startsWith("http://127.0.0.1")` | 模块顶层常量，决定走 dev-login 还是 wx.login 流程 |
| D2 | 按钮禁用态 | WXML: `(!agreed \|\| loading) ? 'login-btn--disabled' : 'login-btn--active'` | 由 `agreed` 和 `loading` 两个 data 字段派生 |
| D3 | 错误消息 `msg` | `err.statusCode` 三元映射 | 403→"账号已被禁用"，401→"登录凭证无效"，其他→"登录失败" |

---

## 五、路由参数

**结论：无路由参数。**

- `onLoad()` 未声明 `options` 参数
- 页面作为小程序首页（入口页），不接收外部传参

---

## 六、WXML 硬编码文案

| # | 元素 | 文案 | 建议 |
|---|------|------|------|
| F1 | `<text class="app-name">` | `球房运营助手` | 应用名称，可考虑从配置读取 |
| F2 | `<text class="app-desc">` | `为台球厅提升运营效率的内部管理工具` | 应用描述 |
| F3 | `<text class="feature-text">` ×3 | `任务管理` / `数据看板` / `智能助手` | 功能亮点标签 |
| F4 | `<text class="login-btn-text">` | `使用微信登录` | 按钮文案 |
| F5 | `<text class="agreement-text">` | `我已阅读并同意` | 协议前缀 |
| F6 | `<text class="link">` ×2 | `《用户协议》` / `《隐私政策》` | 协议链接文案（当前无跳转） |
| F7 | `<text class="footer-tip">` | `仅限球房内部员工使用` | 底部提示 |

> 注：login.json 中 `"navigationBarTitleText": "登录"` 也是硬编码，但因使用 `"navigationStyle": "custom"` 自定义导航栏，系统标题栏不显示，实际无影响。

---

## 七、联调 TODO

| 优先级 | 项目 | 当前状态 | 待办 |
|--------|------|----------|------|
| ✅ 已完成 | 登录接口对接 | dev-login + login 均已对接 | — |
| ✅ 已完成 | Token 持久化 | globalData + Storage 双写 | — |
| ✅ 已完成 | 401 自动刷新 | request.ts 内置 refresh 机制 | — |
| ✅ 已完成 | 状态路由 | 5 种 user_status 均有对应页面 | — |
| 🟡 待确认 | 协议链接跳转 | `《用户协议》`和`《隐私政策》`仅为文案，无 `bindtap` 跳转 | 需补充协议页面或 webview 跳转 |
| 🟡 待确认 | dev_test_openid 安全性 | 硬编码在前端代码中 | 确认后端 dev-login 仅在开发环境可用，生产环境应禁用该端点 |
| 🟢 可优化 | statusBarHeight fallback | 默认 20px | 可改为 `wx.getSystemInfoSync().statusBarHeight` 更精确的 fallback |
| 🟢 可优化 | 错误提示国际化 | 硬编码中文 | 当前仅面向内部员工，优先级低 |
