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,310 @@
# 反馈与工单 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` 唯一拥有 `/genealogy/pc/feedback` 的 GET/POST 契约;新增 UMD 模块 `feedback-pages.js` 负责 DTO 构造、完整 VO 规范化、列表/详情渲染和四类页面初始化。“工单”只是反馈记录的帮助中心展示名称,详情通过 URL 中由列表响应产生的 `feedbackId` 在我的反馈列表中精确匹配。
**Tech Stack:** 静态 HTML、原生 JavaScript UMD、Axios、Node `node:test`
## Global Constraints
- 后端 `D:\WorkSpace\Java\Genealogy` 全程只读。
- 只调用 `POST /genealogy/pc/feedback``GET /genealogy/pc/feedback`
- 请求只发送 `feedbackType``feedbackContent``contactInfo`;不发送 `feedbackTitle`
- `feedbackType` 只允许后端已确认字典值 `advice/bug/complaint/other`;空值省略并由后端默认 `advice`
- `feedbackId` 只能来自提交或列表响应,不提供文本输入。
- 页面不展示 `appUserId``handlerId``appUserPhone`、原始 JSON。
- 所有提交防重复;提交成功后必须重读列表并匹配同一 `feedbackId`
---
### Task 1: ApiClient 反馈契约
**Files:**
- Modify: `utils/ApiClient.js`
- Modify: `tests/api-client-contract.test.js`
**Interfaces:**
- Produces: `submitFeedback(body)``myFeedback()`
- [ ] **Step 1: 写失败的契约测试**
增加测试,使用完整请求字面量断言:
```js
await client.submitFeedback({
feedbackType: 'bug',
feedbackContent: '页面按钮无响应',
contactInfo: '19181970173',
feedbackTitle: 'must-drop',
appUserId: 'must-drop'
});
await client.myFeedback();
assert.deepEqual(calls, [
{
method: 'POST',
url: '/genealogy/pc/feedback',
body: {
feedbackType: 'bug',
feedbackContent: '页面按钮无响应',
contactInfo: '19181970173'
}
},
{ method: 'GET', url: '/genealogy/pc/feedback' }
]);
```
- [ ] **Step 2: 运行 RED**
Run:
```powershell
node --test tests/api-client-contract.test.js
```
Expected: FAIL`submitFeedback``myFeedback` 不存在。
- [ ] **Step 3: 最小实现**
`createClient()` 返回对象中增加:
```js
submitFeedback: function (body) {
return request('POST', '/genealogy/pc/feedback', {
body: pickDefined(body, ['feedbackType', 'feedbackContent', 'contactInfo'])
});
},
myFeedback: function () {
return request('GET', '/genealogy/pc/feedback');
}
```
- [ ] **Step 4: 运行 GREEN**
Run:
```powershell
node --test tests/api-client-contract.test.js
```
Expected: PASS。
---
### Task 2: 反馈 DTO、VO、列表和详情边界
**Files:**
- Create: `public/js/feedback-pages.js`
- Create: `tests/feedback-pages.test.js`
**Interfaces:**
- Produces:
- `getFeedbackId(search)`
- `buildFeedbackBody(values)`
- `validateFeedbackBody(body)`
- `normalizeFeedback(item)`
- `normalizeFeedbackList(data)`
- `findFeedbackById(data, feedbackId)`
- `buildFeedbackDetailUrl(feedbackId)`
- `renderFeedbackList(data, options)`
- `renderFeedbackDetail(item)`
- [ ] **Step 1: 写失败的纯行为测试**
用完整 `FeedbackVo` 字面量验证:
```js
assert.deepEqual(FeedbackPages.buildFeedbackBody({
feedbackType: ' bug ',
feedbackContent: ' 页面按钮无响应 ',
contactInfo: ' 19181970173 ',
feedbackTitle: 'must-drop',
appUserId: 'must-drop'
}), {
feedbackType: 'bug',
feedbackContent: '页面按钮无响应',
contactInfo: '19181970173'
});
```
同时断言:
- `feedbackContent` 为空时报错;
- 类型只允许 `advice/bug/complaint/other`,空值省略;
- 不安全 number ID、空内容、`handleStatus``0/1/2/3``status``0/1` 的响应拒绝;
- 数组包含一个非法元素时整批返回空数组;
- 详情只精确匹配同一字符串 `feedbackId`,不存在时不回退第一条;
- 列表和详情转义可见文本,不出现内部用户/处理人 ID、账号手机号或原始 JSON;
- 详情 URL 使用 `ticket-detail.html?feedbackId=...`
- [ ] **Step 2: 运行 RED**
Run:
```powershell
node --test tests/feedback-pages.test.js
```
Expected: FAIL,模块不存在。
- [ ] **Step 3: 最小实现纯函数**
`normalizeFeedback()` 返回且只返回:
```js
{
feedbackId,
feedbackType,
feedbackContent,
contactInfo,
handleStatus,
handleResult,
handleTime,
status,
remark
}
```
状态展示固定为:
```js
{ '0': '待处理', '1': '处理中', '2': '已处理', '3': '已关闭' }
```
- [ ] **Step 4: 运行 GREEN**
Run:
```powershell
node --test tests/feedback-pages.test.js
node --check public/js/feedback-pages.js
```
Expected: PASS。
---
### Task 3: 四个页面的真实反馈闭环
**Files:**
- Modify: `profile-feedback.html`
- Modify: `submit-ticket.html`
- Modify: `my-tickets.html`
- Modify: `ticket-detail.html`
- Modify: `public/js/feedback-pages.js`
- Modify: `tests/feedback-pages.test.js`
- Modify: `tests/pending-pages.test.js`
- Modify: `tests/public-static-pages.test.js`
- Modify: `tests/pc-scope.test.js`
**Interfaces:**
- Produces: `initFeedbackFormPage()``initFeedbackListPage()``initFeedbackDetailPage()``init()`
- [ ] **Step 1: 写失败的页面行为测试**
断言四个页面:
- 不再包含 `data-feature-status="pending"``pending-pages.js`
- 均加载 `feedback-pages.js` 和 ApiClient 依赖;
- 两个提交页只提供 `feedbackType/feedbackContent/contactInfo`,不存在 `feedbackTitle` 或任意业务 ID 输入;
- 列表页有 `data-feedback-list` 和刷新按钮;
- 详情页只有 `data-feedback-detail`,不提供回复、追问、删除或关闭操作。
断言脚本提交后调用 `myFeedback()`,必须按提交响应的 `feedbackId` 重读匹配;详情按 URL `feedbackId` 精确匹配。
- [ ] **Step 2: 运行 RED**
Run:
```powershell
node --test tests/feedback-pages.test.js tests/pending-pages.test.js tests/public-static-pages.test.js tests/pc-scope.test.js
```
Expected: FAIL,四个页面仍为 pending。
- [ ] **Step 3: 实现页面初始化**
提交页:
1. 构造并校验请求;
2. `writePending` 锁和按钮禁用;
3. 调用 `submitFeedback(body)`
4. 规范化提交响应;
5. 重读 `myFeedback()`,精确找到同一 `feedbackId`
6. 个人反馈页刷新历史列表;工单页进入 `ticket-detail.html?feedbackId=...`
列表页读取 `myFeedback()` 并生成详情链接。详情页从 URL 读取 ID、重读列表并精确匹配;未匹配显示“反馈记录不存在或无权查看”。
- [ ] **Step 4: 运行 GREEN**
Run:
```powershell
node --test tests/feedback-pages.test.js tests/pending-pages.test.js tests/public-static-pages.test.js tests/pc-scope.test.js
node --check public/js/feedback-pages.js
```
Expected: PASS。
---
### Task 4: 导航、规划和收尾验证
**Files:**
- Modify: `help.html`
- Modify: `profile-services.html`
- Modify: `docs/PC接口对接规划.md`
- Modify: `tests/stage6-navigation.test.js`
- Modify: `docs/superpowers/plans/2026-07-29-feedback-tickets.md`
**Interfaces:**
- Consumes: Task 13 的真实反馈闭环。
- [ ] **Step 1: 写失败的导航测试**
断言:
- 帮助中心可直接进入提交工单和我的工单;
- 服务中心可进入意见反馈;
- 所有入口不再被 pending 状态拦截;
- 不存在独立 ticket API、反馈标题或手填 `feedbackId` 的入口。
- [ ] **Step 2: 运行 RED**
Run:
```powershell
node --test tests/stage6-navigation.test.js tests/public-static-pages.test.js
```
Expected: FAIL,帮助中心尚未开放我的工单入口或旧 pending 断言仍存在。
- [ ] **Step 3: 更新入口和规划**
规划记录:
- `AppFeedbackBody` 三个字段来源与提交时机;
- `FeedbackVo` 可见字段、内部隐藏字段和四种处理状态;
- 无独立工单 path,四个页面共用反馈记录;
- 提交后重读、详情精确匹配、401/403 和隐私边界;
- 后端没有用户侧回复、追问、关闭或删除接口,继续阻断。
- [ ] **Step 4: 聚焦和全量验证**
Run:
```powershell
node --test tests/feedback-pages.test.js tests/api-client-contract.test.js tests/pending-pages.test.js tests/public-static-pages.test.js tests/pc-scope.test.js tests/stage6-navigation.test.js
npm test
node --check public/js/feedback-pages.js
git -c safe.directory=D:/WorkSpace/Web/jiapu diff --check
```
Expected: 全部 PASS。
- [ ] **Step 5: 浏览器只读验证**
使用真实登录态验证四个页面、我的反馈列表、无记录详情、隐私和控制台错误。未经用户本轮明确授权,不提交真实反馈。