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

250 lines
7.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.
# 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 构造 `AppVipOrderBody``profile-services.html` 作为唯一 VIP 页面,只提供套餐选择、可选家谱选择、创建订单和订单刷新。
**Tech Stack:** 静态 HTML、原生 JavaScript UMD、Axios、Node `node:test`
## Global Constraints
- 后端 `D:\WorkSpace\Java\Genealogy` 全程只读。
- 只调用 `GET /genealogy/pc/vip/packages``POST /genealogy/pc/vip/orders``GET /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: 写失败契约测试**
```js
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: 最小实现**
```js
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: 写失败纯行为测试**
使用完整 `VipPackageVo``VipOrderVo` 字面量断言:
- 套餐要求稳定字符串 `packageId`、非空名称、`packageType=vip/storage``durationUnit=permanent/day/month/year`、非负价格、`status=0`
- 停用套餐和不安全数字长 ID 不渲染;
- 家谱选项要求稳定字符串 `genealogyId` 和非空 `genealogyName`
- body 只保留 `packageId/genealogyId/payType`,页面默认构造不包含 `payType`
- 必须选择有效套餐;可选家谱必须是安全字符串 ID;若显式提供 `payType` 只允许已确认 `wechat`
- 订单要求稳定 `orderId/packageId`、订单号、套餐名、非负金额、`payStatus=0/1/2/3``status=0/1`
- 渲染不出现用户 ID、手机号、原始 JSON,不出现支付/取消/退款按钮。
- [ ] **Step 2: 运行 RED**
Run: `node --test tests/vip-pages.test.js`
Expected: FAIL,模块不存在。
- [ ] **Step 3: 最小实现纯函数**
支付状态:
```js
{ '0': '待支付', '1': '已支付', '2': '已关闭', '3': '已退款' }
```
套餐类型:
```js
{ vip: '会员套餐', storage: '存储扩容' }
```
套餐和订单金额保留后端字符串语义,不进行浮点运算。
- [ ] **Step 4: 运行 GREEN**
Run:
```powershell
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:
```powershell
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:
```powershell
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: 更新规划**
记录 `AppVipOrderBody``VipPackageVo``VipOrderVo` 的字段来源、枚举、隐藏字段、写后重读和支付能力阻断;阶段 7 标记 VIP 批次完成。
- [ ] **Step 4: 聚焦和全量验证**
Run:
```powershell
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: 浏览器只读验证**
真实登录态验证套餐、家谱下拉、订单空/有数据态、无伪支付动作和控制台错误。未经用户本轮明确授权,不创建真实订单。