Files
jiapu/docs/superpowers/plans/2026-07-29-feedback-tickets.md
T
2026-08-03 16:49:38 +08:00

311 lines
8.8 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` 唯一拥有 `/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: '<测试联系电话>',
feedbackTitle: 'must-drop',
appUserId: 'must-drop'
});
await client.myFeedback();
assert.deepEqual(calls, [
{
method: 'POST',
url: '/genealogy/pc/feedback',
body: {
feedbackType: 'bug',
feedbackContent: '页面按钮无响应',
contactInfo: '<测试联系电话>'
}
},
{ 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: ' <测试联系电话> ',
feedbackTitle: 'must-drop',
appUserId: 'must-drop'
}), {
feedbackType: 'bug',
feedbackContent: '页面按钮无响应',
contactInfo: '<测试联系电话>'
});
```
同时断言:
- `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: 浏览器只读验证**
使用真实登录态验证四个页面、我的反馈列表、无记录详情、隐私和控制台错误。未经用户本轮明确授权,不提交真实反馈。