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

8.8 KiB
Raw Blame History

反馈与工单 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/feedbackGET /genealogy/pc/feedback
  • 请求只发送 feedbackTypefeedbackContentcontactInfo;不发送 feedbackTitle
  • feedbackType 只允许后端已确认字典值 advice/bug/complaint/other;空值省略并由后端默认 advice
  • feedbackId 只能来自提交或列表响应,不提供文本输入。
  • 页面不展示 appUserIdhandlerIdappUserPhone、原始 JSON。
  • 所有提交防重复;提交成功后必须重读列表并匹配同一 feedbackId

Task 1: ApiClient 反馈契约

Files:

  • Modify: utils/ApiClient.js
  • Modify: tests/api-client-contract.test.js

Interfaces:

  • Produces: submitFeedback(body)myFeedback()

  • Step 1: 写失败的契约测试

增加测试,使用完整请求字面量断言:

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:

node --test tests/api-client-contract.test.js

Expected: FAILsubmitFeedbackmyFeedback 不存在。

  • Step 3: 最小实现

createClient() 返回对象中增加:

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:

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 字面量验证:

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、空内容、handleStatus0/1/2/3status0/1 的响应拒绝;

  • 数组包含一个非法元素时整批返回空数组;

  • 详情只精确匹配同一字符串 feedbackId,不存在时不回退第一条;

  • 列表和详情转义可见文本,不出现内部用户/处理人 ID、账号手机号或原始 JSON;

  • 详情 URL 使用 ticket-detail.html?feedbackId=...

  • Step 2: 运行 RED

Run:

node --test tests/feedback-pages.test.js

Expected: FAIL,模块不存在。

  • Step 3: 最小实现纯函数

normalizeFeedback() 返回且只返回:

{
  feedbackId,
  feedbackType,
  feedbackContent,
  contactInfo,
  handleStatus,
  handleResult,
  handleTime,
  status,
  remark
}

状态展示固定为:

{ '0': '待处理', '1': '处理中', '2': '已处理', '3': '已关闭' }
  • Step 4: 运行 GREEN

Run:

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:

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:

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:

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:

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: 浏览器只读验证

使用真实登录态验证四个页面、我的反馈列表、无记录详情、隐私和控制台错误。未经用户本轮明确授权,不提交真实反馈。