Files
jiapu/docs/superpowers/plans/2026-07-29-vip-packages-orders.md
T
fizzleaf 309598bfa6 feat(api): 添加帮助中心反馈系统和VIP服务功能
- 在ApiClient中新增submitFeedback、myFeedback、helpArticles、helpArticleDetail、
  siteArticles、promotions、vipPackages、createVipOrder、vipOrders等方法
- 添加帮助文章和站点资讯的参数验证逻辑
- 更新测试文件添加新的API方法测试用例
- 在HTML页面中添加反馈、帮助和VIP服务相关页面的脚本引用
- 更新加入家谱页面为完整的申请流程界面
- 修改资讯详情页面为站点资讯展示页面
- 更新AxiosRequestUtil中认证处理逻辑
- 添加世系树渲染的HTML生成函数用于页面复用
- 更新文档中的API契约说明和页面规划
2026-07-30 16:04:48 +08:00

7.8 KiB
Raw Blame History

VIP 套餐与订单 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: 在服务中心开放 VIP 套餐查看、响应选项创建订单和我的订单刷新闭环,不制造支付或取消能力。

Architecture: utils/ApiClient.js 唯一拥有 /genealogy/pc/vip/** 的三个接口;新增 vip-pages.js 规范化套餐、家谱选项和订单,使用响应中的字符串 ID 构造 AppVipOrderBodyprofile-services.html 作为唯一 VIP 页面,只提供套餐选择、可选家谱选择、创建订单和订单刷新。

Tech Stack: 静态 HTML、原生 JavaScript UMD、Axios、Node node:test

Global Constraints

  • 后端 D:\WorkSpace\Java\Genealogy 全程只读。
  • 只调用 GET /genealogy/pc/vip/packagesPOST /genealogy/pc/vip/ordersGET /genealogy/pc/vip/orders
  • packageId 只能来自套餐响应;genealogyId 只能来自 genealogiesMine() 响应,不提供文本输入。
  • 页面不提供未经确认的支付方式选择;请求省略 payType,由后端默认 wechat
  • 不显示立即支付、模拟支付成功、取消订单、退款或关闭订单操作。
  • 创建成功后重读订单列表并精确匹配同一 orderId
  • 不展示 appUserId、用户手机号、内部原始 JSON。

Task 1: ApiClient VIP 契约

Files:

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

Interfaces:

  • Produces: vipPackages()createVipOrder(body)vipOrders()

  • Step 1: 写失败契约测试

await client.vipPackages();
await client.createVipOrder({
  packageId: '2062179707935264769',
  genealogyId: '2062179707935264770',
  payType: 'wechat',
  appUserId: 'must-drop',
  payStatus: 'must-drop'
});
await client.vipOrders();

assert.deepEqual(calls.map((config) => [config.method, config.url, config.data]), [
  ['get', '/genealogy/pc/vip/packages', undefined],
  ['post', '/genealogy/pc/vip/orders', {
    packageId: '2062179707935264769',
    genealogyId: '2062179707935264770',
    payType: 'wechat'
  }],
  ['get', '/genealogy/pc/vip/orders', undefined]
]);
  • Step 2: 运行 RED

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

Expected: FAILVIP 方法不存在。

  • Step 3: 最小实现
vipPackages: function () {
  return request('GET', '/genealogy/pc/vip/packages');
},
createVipOrder: function (body) {
  return request('POST', '/genealogy/pc/vip/orders', {
    body: pickDefined(body, ['packageId', 'genealogyId', 'payType'])
  });
},
vipOrders: function () {
  return request('GET', '/genealogy/pc/vip/orders');
}
  • Step 4: 运行 GREEN

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

Expected: PASS。


Task 2: 套餐、家谱选项和订单数据边界

Files:

  • Create: public/js/vip-pages.js
  • Create: tests/vip-pages.test.js

Interfaces:

  • Produces:

    • normalizeVipPackage(item)
    • normalizeVipPackages(data)
    • normalizeGenealogyOption(item)
    • buildVipOrderBody(values)
    • validateVipOrderBody(body)
    • normalizeVipOrder(item)
    • normalizeVipOrders(data)
    • renderVipPackages(data, selectedPackageId)
    • renderGenealogyOptions(data)
    • renderVipOrders(data)
  • Step 1: 写失败纯行为测试

使用完整 VipPackageVoVipOrderVo 字面量断言:

  • 套餐要求稳定字符串 packageId、非空名称、packageType=vip/storagedurationUnit=permanent/day/month/year、非负价格、status=0

  • 停用套餐和不安全数字长 ID 不渲染;

  • 家谱选项要求稳定字符串 genealogyId 和非空 genealogyName

  • body 只保留 packageId/genealogyId/payType,页面默认构造不包含 payType

  • 必须选择有效套餐;可选家谱必须是安全字符串 ID;若显式提供 payType 只允许已确认 wechat

  • 订单要求稳定 orderId/packageId、订单号、套餐名、非负金额、payStatus=0/1/2/3status=0/1

  • 渲染不出现用户 ID、手机号、原始 JSON,不出现支付/取消/退款按钮。

  • Step 2: 运行 RED

Run: node --test tests/vip-pages.test.js

Expected: FAIL,模块不存在。

  • Step 3: 最小实现纯函数

支付状态:

{ '0': '待支付', '1': '已支付', '2': '已关闭', '3': '已退款' }

套餐类型:

{ vip: '会员套餐', storage: '存储扩容' }

套餐和订单金额保留后端字符串语义,不进行浮点运算。

  • Step 4: 运行 GREEN

Run:

node --test tests/vip-pages.test.js
node --check public/js/vip-pages.js

Expected: PASS。


Task 3: 服务中心真实 VIP 闭环

Files:

  • Modify: profile-services.html
  • Modify: public/js/vip-pages.js
  • Modify: tests/vip-pages.test.js
  • Modify: tests/pending-pages.test.js
  • Modify: tests/pc-scope.test.js

Interfaces:

  • Produces: initVipPage()init()

  • Step 1: 写失败页面行为测试

断言:

  • 服务中心不再 pending,加载 vip-pages.js

  • 有套餐列表、只读选中提示、可选家谱下拉、订单表单、刷新订单和订单列表;

  • 不存在 packageId/genealogyId/orderId 文本或数字输入;

  • 不存在 payType 选择器以及支付、取消、退款、模拟成功按钮;

  • 脚本并行读取套餐、我的家谱和订单;

  • 创建后重读订单并精确匹配提交响应 orderId

  • Step 2: 运行 RED

Run:

node --test tests/vip-pages.test.js tests/pending-pages.test.js tests/pc-scope.test.js

Expected: FAIL,服务中心仍为 pending 且允许手填 ID。

  • Step 3: 实现页面初始化
  1. 401 跳转登录,403 保留登录态;
  2. Promise.all([vipPackages(), genealogiesMine(), vipOrders()]) 读取页面数据;
  3. 点击套餐卡保存响应中的字符串 packageId
  4. 家谱下拉只使用 genealogiesMine() 选项,空值表示不关联家谱;
  5. 表单提交使用 writePending 锁;
  6. 创建响应必须规范化;
  7. 重读 vipOrders() 并找到同一 orderId
  8. 刷新订单列表并展示“订单已创建;当前 PC 暂未开放在线支付”。
  • Step 4: 运行 GREEN

Run:

node --test tests/vip-pages.test.js tests/pending-pages.test.js tests/pc-scope.test.js
node --check public/js/vip-pages.js

Expected: PASS。


Task 4: 导航、规划和收尾验证

Files:

  • Modify: profile.html
  • Modify: docs/PC接口对接规划.md
  • Modify: tests/stage6-navigation.test.js
  • Modify: docs/superpowers/plans/2026-07-29-vip-packages-orders.md

Interfaces:

  • Consumes: Task 13 的 VIP 套餐与订单闭环。

  • Step 1: 写失败导航测试

断言个人中心服务入口可进入 profile-services.html,服务页真实开放并且所有 VIP 业务都留在该唯一 owner 页面。

  • Step 2: 运行 RED

Run: node --test tests/stage6-navigation.test.js tests/pending-pages.test.js

Expected: FAIL,服务页仍 pending 或未加载真实脚本。

  • Step 3: 更新规划

记录 AppVipOrderBodyVipPackageVoVipOrderVo 的字段来源、枚举、隐藏字段、写后重读和支付能力阻断;阶段 7 标记 VIP 批次完成。

  • Step 4: 聚焦和全量验证

Run:

node --test tests/vip-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/vip-pages.js
git -c safe.directory=D:/WorkSpace/Web/jiapu diff --check

Expected: 全部 PASS。

  • Step 5: 浏览器只读验证

真实登录态验证套餐、家谱下拉、订单空/有数据态、无伪支付动作和控制台错误。未经用户本轮明确授权,不创建真实订单。