feat: batch update - gift card breakdown spec, backend APIs, miniprogram pages, ETL finance recharge, docs & migrations

This commit is contained in:
Neo
2026-03-20 01:43:48 +08:00
parent 075caf067f
commit 79f9a0e1da
437 changed files with 118603 additions and 976 deletions

View File

@@ -0,0 +1,144 @@
# 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` | 🟡 中 | 默认状态栏高度 fallbackonLoad 中会被 `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 |
| 🟢 可优化 | 错误提示国际化 | 硬编码中文 | 当前仅面向内部员工,优先级低 |