Files
jiapu/docs/superpowers/plans/2026-07-29-genealogy-join-review.md
T
fizzleaf 309598bfa6 feat(api): 添加帮助中心反馈系统和VIP服务功能
- 在ApiClient中新增submitFeedback、myFeedback、helpArticles、helpArticleDetail、
  siteArticles、promotions、vipPackages、createVipOrder、vipOrders等方法
- 添加帮助文章和站点资讯的参数验证逻辑
- 更新测试文件添加新的API方法测试用例
- 在HTML页面中添加反馈、帮助和VIP服务相关页面的脚本引用
- 更新加入家谱页面为完整的申请流程界面
- 修改资讯详情页面为站点资讯展示页面
- 更新AxiosRequestUtil中认证处理逻辑
- 添加世系树渲染的HTML生成函数用于页面复用
- 更新文档中的API契约说明和页面规划
2026-07-30 16:04:48 +08:00

267 lines
8.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 家谱加入申请与审核 Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** 开放家谱申请加入、我的申请、撤销待审核申请,以及家谱管理员审核申请的完整 PC 页面闭环。
**Architecture:** `utils/ApiClient.js` 已拥有本批全部 PC path/body。新增 `join-pages.js` 负责可申请家谱选择、申请表单、我的申请和撤销;新增 `join-review-pages.js` 负责当前家谱待审核列表和通过/拒绝。两个 UMD 模块只使用响应中的字符串 ID,写入后重读对应列表。
**Tech Stack:** 静态 HTML、原生 JavaScript UMD、Axios、Node `node:test`
## Global Constraints
- 后端 `D:\WorkSpace\Java\Genealogy` 全程只读。
- 只调用 `/genealogy/pc/**`
- 家谱 ID 和申请 ID 必须来自 PC 响应或当前家谱上下文,不能手填。
- `inviterUserId` 没有安全 PC 来源,不展示、不发送。
- 所有写操作防重复,401 清登录态,403 保留登录态。
- 每项生产行为先运行失败测试,再最小实现。
---
### Task 1: 申请数据边界
**Files:**
- Create: `tests/join-pages.test.js`
- Create: `public/js/join-pages.js`
**Interfaces:**
- Consumes: `genealogyOptions(query)``applyToGenealogy(genealogyId, body)``myGenealogyJoinApplies()``cancelGenealogyJoinApply(applyId)`
- Produces:
- `normalizeJoinGenealogy(item)`
- `buildJoinApplyBody(values)`
- `validateJoinApplyBody(body)`
- `normalizeJoinApply(item)`
- `normalizeJoinApplies(data)`
- `renderJoinGenealogyOptions(data)`
- `renderMyJoinApplies(data)`
- [ ] **Step 1: 写失败的纯行为测试**
用完整 `AppGenealogyVo``GenealogyJoinApplyVo` 字面量验证:
```js
assert.deepEqual(JoinPages.buildJoinApplyBody({
applicantName: ' 叶子 ',
phone: ' 19181970173 ',
relationDesc: ' 族亲 ',
applyReason: ' 申请加入 ',
inviterUserId: 'must-drop'
}), {
applicantName: '叶子',
phone: '19181970173',
relationDesc: '族亲',
applyReason: '申请加入'
});
```
断言:
- `applicantName <= 50``phone <= 30``relationDesc <= 100``applyReason <= 500`
- 可申请家谱必须有稳定 `genealogyId/genealogyName/surname`,停用家谱拒绝。
- 申请必须有稳定 `applyId/genealogyId``status`;状态只允许 `0/1/2/3`
- 安全数字长 ID 只接受字符串;不安全 number 拒绝。
- 普通用户列表不展示内部用户 ID、邀请人 ID、审核人 ID或原始 JSON。
- 只有 `status=0` 渲染撤销按钮。
- [ ] **Step 2: 运行 RED**
Run:
```powershell
node --test tests/join-pages.test.js
```
Expected: FAIL,模块不存在。
- [ ] **Step 3: 最小实现纯函数**
所有可见文本使用 `escapeHtml`;响应任一必需字段无效时拒绝该条,数组包含非法元素时整批返回空数组。
- [ ] **Step 4: 运行 GREEN**
Run:
```powershell
node --test tests/join-pages.test.js
node --check public/js/join-pages.js
```
Expected: PASS。
---
### Task 2: 申请页面与我的申请
**Files:**
- Modify: `join-genealogy.html`
- Modify: `profile-join-family.html`
- Modify: `public/js/join-pages.js`
- Modify: `tests/join-pages.test.js`
- Modify: `tests/pending-pages.test.js`
- Modify: `tests/pc-scope.test.js`
**Interfaces:**
- Produces: `initJoinApplyPage()``initMyJoinAppliesPage()`
- [ ] **Step 1: 写失败的页面行为测试**
断言:
- 两页均不再 pending,并加载 `join-pages.js`
- `join-genealogy.html` 有关键词搜索、后端家谱选项、申请资料表单;不存在 `genealogyId/inviterUserId/applyId` 文本输入。
- `profile-join-family.html` 有我的申请列表和刷新入口;申请 ID 只存在于响应渲染按钮属性。
- 页面没有邀请码输入或“分享码”伪语义。
- [ ] **Step 2: 运行 RED**
Run:
```powershell
node --test tests/join-pages.test.js tests/pending-pages.test.js tests/pc-scope.test.js
```
Expected: FAIL,页面仍 pending/缺少真实行为。
- [ ] **Step 3: 实现申请和撤销**
`join-genealogy.html`
1. 读取 `genealogyOptions({keyword})`
2. 用户只能点击响应卡片选择家谱,内部保存字符串 `genealogyId`
3. 构造并校验申请 body。
4. 提交后重读 `myGenealogyJoinApplies()`,必须找到同一响应 `applyId`
5. 跳转 `profile-join-family.html`
`profile-join-family.html`
1. 读取并渲染我的申请。
2. 只有待审核申请显示撤销。
3. 二次确认后调用撤销接口并重读列表,确保该申请不再为待审核。
- [ ] **Step 4: 运行 GREEN**
Run:
```powershell
node --test tests/join-pages.test.js tests/pending-pages.test.js tests/pc-scope.test.js
node --check public/js/join-pages.js
```
Expected: PASS。
---
### Task 3: 管理员审核
**Files:**
- Create: `tests/join-review-pages.test.js`
- Create: `public/js/join-review-pages.js`
- Modify: `profile-join-review.html`
- Modify: `tests/pending-pages.test.js`
- Modify: `tests/pc-scope.test.js`
**Interfaces:**
- Consumes: `genealogyDetail(genealogyId)``pendingGenealogyJoinApplies(genealogyId)``auditGenealogyJoinApply(genealogyId, applyId, body)`
- Produces:
- `getCurrentGenealogyId(search)`
- `buildJoinAuditBody(values)`
- `validateJoinAuditBody(body)`
- `renderPendingJoinApplies(data, canManage)`
- `initJoinReviewPage()`
- [ ] **Step 1: 写失败的审核行为测试**
```js
assert.deepEqual(JoinReviewPages.buildJoinAuditBody({
status: '2',
auditRemark: ' 资料不一致 ',
applyId: 'must-drop'
}), {
status: '2',
auditRemark: '资料不一致'
});
```
断言:
- `status` 只允许 `1/2``auditRemark <= 500`
- 页面只从 URL/`ProfileUI` 读取家谱 ID。
- 只有 `genealogyDetail.canManage=true` 显示审核动作。
- 待审核列表显示申请人名称、申请手机号、关系和原因,但隐藏内部用户 ID、邀请人/审核人 ID。
- 通过和拒绝按钮使用响应中的稳定 `applyId`
- [ ] **Step 2: 运行 RED**
Run:
```powershell
node --test tests/join-review-pages.test.js
```
Expected: FAIL,模块不存在且页面仍 pending。
- [ ] **Step 3: 实现审核页面**
加载当前家谱详情和待审核列表;没有上下文时阻止请求并返回家谱选择入口。点击通过使用 `{status:'1'}`;拒绝要求输入可选审核说明并使用 `{status:'2', auditRemark}`。审核成功后重读待审核列表,确保同一 `applyId` 不再存在。
- [ ] **Step 4: 运行 GREEN**
Run:
```powershell
node --test tests/join-review-pages.test.js tests/pending-pages.test.js tests/pc-scope.test.js
node --check public/js/join-review-pages.js
```
Expected: PASS。
---
### Task 4: 导航、规划与验证
**Files:**
- Modify: `profile-families.html`
- Modify: `profile-family-admin.html`
- Modify: `profile.html`
- Modify: `tests/stage6-navigation.test.js`
- Modify: `docs/PC接口对接规划.md`
- Modify: `docs/superpowers/plans/2026-07-29-genealogy-join-review.md`
- [ ] **Step 1: 写失败的导航测试**
断言我的家谱入口可达申请页,家谱管理入口携带上下文进入审核页;不存在指向手填家谱 ID 或邀请码页面的入口。
- [ ] **Step 2: 运行 RED**
Run:
```powershell
node --test tests/stage6-navigation.test.js tests/pending-pages.test.js
```
Expected: FAIL,审核导航尚未稳定携带家谱上下文。
- [ ] **Step 3: 开放导航并更新规划**
记录申请/审核 DTO、VO、权限、状态、字段来源、写后重读和 `inviterUserId` 阻断。
- [ ] **Step 4: 聚焦和全量验证**
Run:
```powershell
node --test tests/join-pages.test.js tests/join-review-pages.test.js tests/api-client-contract.test.js tests/pending-pages.test.js tests/pc-scope.test.js tests/stage6-navigation.test.js
npm test
node --check public/js/join-pages.js
node --check public/js/join-review-pages.js
git -c safe.directory=D:/WorkSpace/Web/jiapu diff --check
```
Expected: 全部 PASS。
- [ ] **Step 5: 浏览器验证并报告**
真实账号验证可申请家谱列表、我的申请空状态、无家谱上下文审核分支、隐私和控制台错误。未经用户明确授权,不提交或审核真实申请。