feat(api): 添加帮助中心反馈系统和VIP服务功能
- 在ApiClient中新增submitFeedback、myFeedback、helpArticles、helpArticleDetail、 siteArticles、promotions、vipPackages、createVipOrder、vipOrders等方法 - 添加帮助文章和站点资讯的参数验证逻辑 - 更新测试文件添加新的API方法测试用例 - 在HTML页面中添加反馈、帮助和VIP服务相关页面的脚本引用 - 更新加入家谱页面为完整的申请流程界面 - 修改资讯详情页面为站点资讯展示页面 - 更新AxiosRequestUtil中认证处理逻辑 - 添加世系树渲染的HTML生成函数用于页面复用 - 更新文档中的API契约说明和页面规划
This commit is contained in:
@@ -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: 浏览器验证并报告**
|
||||
|
||||
真实账号验证可申请家谱列表、我的申请空状态、无家谱上下文审核分支、隐私和控制台错误。未经用户明确授权,不提交或审核真实申请。
|
||||
|
||||
Reference in New Issue
Block a user