feat(api): 添加帮助中心反馈系统和VIP服务功能

- 在ApiClient中新增submitFeedback、myFeedback、helpArticles、helpArticleDetail、
  siteArticles、promotions、vipPackages、createVipOrder、vipOrders等方法
- 添加帮助文章和站点资讯的参数验证逻辑
- 更新测试文件添加新的API方法测试用例
- 在HTML页面中添加反馈、帮助和VIP服务相关页面的脚本引用
- 更新加入家谱页面为完整的申请流程界面
- 修改资讯详情页面为站点资讯展示页面
- 更新AxiosRequestUtil中认证处理逻辑
- 添加世系树渲染的HTML生成函数用于页面复用
- 更新文档中的API契约说明和页面规划
This commit is contained in:
fizzleaf
2026-07-30 16:04:48 +08:00
parent fb1743aa2a
commit 309598bfa6
53 changed files with 6740 additions and 282 deletions
@@ -0,0 +1,266 @@
# 家谱加入申请与审核 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: 浏览器验证并报告**
真实账号验证可申请家谱列表、我的申请空状态、无家谱上下文审核分支、隐私和控制台错误。未经用户明确授权,不提交或审核真实申请。