feat(admin-frontend): 补齐活跃筛选与支付快照能力

新增用户管理“活跃状态”高级筛选,并在后端支持
activity_status 复合规则,支持按活跃与非活跃筛选用户。

补齐订单支付成功快照落库与后台展示,保存支付渠道、
支付方法、实付金额和支付 IP,并在订单详情中优先展示。

同时增强节点页在线/离线筛选与批量删除、仪表盘快捷入口,
并修复已关闭工单再次回复后自动重开的统一语义。

附带同步测试、迁移、CI 工作流命名及知识库记录
This commit is contained in:
yinjianm
2026-04-25 00:59:08 +08:00
parent 2218457237
commit c64badfc23
55 changed files with 2023 additions and 71 deletions
@@ -0,0 +1 @@
{"status":"completed","completed":5,"failed":0,"pending":0,"total":5,"done":5,"percent":100,"current":"已完成 order-payment-snapshot","updated_at":"2026-04-25 00:20:00"}
@@ -0,0 +1,104 @@
# 变更提案: order-payment-snapshot
## 元信息
```yaml
类型: 功能增强
方案类型: implementation
优先级: P1
状态: 执行中
创建: 2026-04-25
```
---
## 1. 需求
### 背景
当前 `Xboard-new` 的订单支付链路在支付成功后仅稳定保留了 `payment_id``trade_no``callback_no``paid_at`,后台订单详情页也主要展示基础信息、金额拆解和佣金状态。用户本轮明确要求:订单支付成功后,应额外保存并展示支付渠道、支付方法,并在 `admin-frontend` 的订单详情中以“成功订单”样式补齐支付成功信息块,至少覆盖平台订单号、商户订单号、订单金额、实际支付金额、创建 / 完成时间、支付 IP 与订单状态等关键信息。
### 目标
- 在后端订单模型中补齐支付成功快照字段,避免后续支付配置变更后后台无法追溯真实支付上下文。
- 在支付回调成功时保存支付渠道、支付方法、实际支付金额与支付 IP,并继续兼容人工标记已支付链路。
-`admin-frontend` 订单详情抽屉中新增支付成功信息块,按 Apple 化后台风格集中展示支付渠道 / 方法与支付流水信息。
### 约束条件
```yaml
范围约束: 本轮只补齐后台订单支付快照的保存与展示,不扩展到前台用户订单详情页
技术约束: 延续 Laravel + Vue3 + TypeScript + Element Plus 现有实现,不新增第三方支付 SDK 或前端 UI 依赖
兼容约束: 现有 `payment_id` / `callback_no` / `paid_at` 语义保持不变;支付插件回调字段缺失时必须优雅降级
视觉约束: 订单详情延续 `.helloagents/DESIGN.md` 中 Apple 风格后台基线,不回退为厚重卡片堆叠
```
### 验收标准
- [ ] `v2_order` 新增支付快照字段后,支付成功时可保存支付渠道、支付方法、实际支付金额与支付 IP。
- [ ] TokenPay 回调会优先写入真实回调里的平台单号 / 实付金额 / 支付 IP / 方法信息;缺失字段时后端使用合理回退值,不影响开通流程。
- [ ] 管理端订单详情可展示支付渠道、支付方法、平台订单号、商户订单号、订单金额、实际支付金额、支付时间与支付 IP。
- [ ] 订单详情 UI 仍保持现有黑色 Hero + 白色工作台的信息层级,不引入新的视觉体系。
- [ ] 后端定向测试与 `admin-frontend` 构建验证通过。
---
## 2. 方案
### 技术方案
1.`v2_order` 增加支付快照字段,补齐模型注释与类型转换,确保支付成功后的快照能够稳定落库。
2. 调整支付成功链路:
- `plugins/TokenPay/Plugin.php` 在回调验签成功后返回更完整的支付元信息。
- `app/Http/Controllers/V1/Guest/PaymentController.php` 把支付回调元信息传入订单处理链路。
- `app/Services/OrderService.php``paid()` 阶段统一写入支付快照,并兼容人工标记已支付与字段缺失场景。
3. 调整后台订单详情:
- `app/Http/Controllers/V2/Admin/OrderController.php` 补载 `payment` 关系。
- `admin-frontend/src/types/api.d.ts` 补齐订单支付快照类型。
- `admin-frontend/src/views/subscriptions/OrderDetailDrawer.vue` 新增“支付成功信息”区块,按字段分组展示。
### 影响范围
```yaml
涉及模块:
- app/Services
- app/Http/Controllers/V1/Guest
- app/Http/Controllers/V2/Admin
- app/Models
- plugins/TokenPay
- database/migrations
- admin-frontend/src/types
- admin-frontend/src/views/subscriptions
预计变更文件: 8-10
```
### 风险评估
| 风险 | 等级 | 应对 |
|------|------|------|
| 第三方支付回调字段命名不稳定,无法保证每个字段都存在 | 中 | 采用“真实回调优先 + 支付配置回退 + 空值兜底”策略,避免因快照缺失阻断支付 |
| 管理端订单详情新增字段后,旧订单历史数据为空 | 低 | UI 明确显示 `-`,仅对新成功订单逐步补齐 |
| 金额快照与现有“分”单位格式不一致 | 中 | 后端统一把回调金额规范为“分”存储,前端继续复用 `formatOrderAmount()` |
---
## 3. 成果设计
### 设计方向
- **美学基调**: Apple Admin Ledger。像运营后台里的“支付流水面板”,强调黑色首屏下的精确信息卡片与支付状态可追溯性。
- **记忆点**: 在订单详情抽屉中新增一块“支付成功信息”面板,把支付渠道 / 方法与平台流水信息收束成一眼可读的成功订单摘要。
### 视觉要素
- **配色**: 延续黑色 Hero、白色详情卡、蓝色强调与成功绿色状态点。
- **布局**: 采用“标题说明 + 右侧状态徽章 + 双列信息网格”的后台信息卡结构,与现有基础信息 / 金额拆解区保持统一。
- **状态**: 有支付快照时优先展示成功信息;历史订单缺字段时保留 `-` 占位,不制造伪数据。
---
## 4. 技术决策
### order-payment-snapshot#D001: 支付渠道与支付方法采用“快照字段 + 当前支付配置回退”双轨展示
**日期**: 2026-04-25
**状态**: ✅采纳
**背景**: 仅依赖 `payment_id` 关联会受到后续支付配置改名影响,无法稳定反映订单成交当时的支付上下文。
**决策**: 在订单表新增 `payment_channel / payment_method / payment_amount / payment_ip` 快照字段,并在详情页中优先展示快照,缺失时再回退到当前 `payment` 关联信息。
**理由**: 既满足历史追溯,也兼容旧订单与人工处理场景。
### order-payment-snapshot#D002: 实际支付金额统一以“分”为单位入库
**日期**: 2026-04-25
**状态**: ✅采纳
**背景**: 当前后台订单金额体系统一以“分”为真相源,前端已有 `formatOrderAmount()` 的统一格式化链路。
**决策**: 支付回调里的实际支付金额在后端转换为整数“分”后入库。
**理由**: 避免前后端引入第二套金额口径,复用现有订单金额展示与排序逻辑。
@@ -0,0 +1,56 @@
# 任务清单: order-payment-snapshot
> **@status:** completed | 2026-04-25 00:20
```yaml
@feature: order-payment-snapshot
@created: 2026-04-25
@status: completed
@mode: R2
```
## 进度概览
| 完成 | 失败 | 跳过 | 总数 |
|------|------|------|------|
| 5 | 0 | 0 | 5 |
---
## 任务列表
### 1. 支付快照后端链路
- [√] 1.1 为 `v2_order` 新增支付快照字段,并补齐 `app/Models/Order.php` 的字段注释与类型转换 | depends_on: []
- [√] 1.2 调整支付成功链路,在回调 / 标记已支付时保存支付渠道、支付方法、实付金额与支付 IP | depends_on: [1.1]
### 2. 后台订单详情展示
- [√] 2.1 调整后台订单详情接口与前端类型声明,补齐 `payment` 关联和支付快照字段 | depends_on: [1.2]
- [√] 2.2 更新 `admin-frontend/src/views/subscriptions/OrderDetailDrawer.vue`,新增“支付成功信息”展示区块并保持现有 Apple 化后台风格 | depends_on: [2.1]
### 3. 验证与知识库同步
- [√] 3.1 新增 / 运行后端定向测试与 `admin-frontend` 构建验证,并同步知识库文档与变更记录 | depends_on: [2.2]
---
## 执行日志
| 时间 | 任务 | 状态 | 备注 |
|------|------|------|------|
| 2026-04-25 00:02 | 方案包初始化 | completed | 已确认按完整支付快照方案执行,目标是保存并展示支付渠道 / 方法 / 实付金额 / 支付 IP |
| 2026-04-25 00:10 | 1.1 / 1.2 | completed | 已新增支付快照字段,并将 TokenPay 回调元信息透传到 `OrderService::paid()` 统一落库 |
| 2026-04-25 00:16 | 2.1 / 2.2 | completed | 已补齐后台订单详情 `payment` 关联、前端类型与支付成功信息卡片展示 |
| 2026-04-25 00:20 | 3.1 | completed | 已新增后端定向测试文件;前端目标文件 `vue-tsc` 校验通过。`npm run build` 仍被既有 `DashboardView/TicketsView` 类型错误阻断,且当前工作区缺少 PHP 运行时与 `vendor`,无法直接执行 PHPUnit |
---
## 执行备注
> 记录执行过程中的重要说明、决策变更、风险提示等
- 当前工作树存在与本轮无关的未提交改动,实施时必须避免覆盖已有业务变更。
- 历史订单缺少新增快照字段属于预期兼容范围,前端详情需允许空值展示。
- `admin-frontend` 全量构建失败来自既有 `DashboardView.vue``TicketsView.vue` 类型错误,本轮改动通过独立 `tsconfig` 对目标文件完成定向校验。
- 当前环境缺少 PHP 可执行文件与 `vendor` 依赖目录,后端仅完成代码级实现与测试文件落地,未能执行 Laravel / PHPUnit 运行时验证。
@@ -0,0 +1,11 @@
{
"status": "completed",
"completed": 5,
"failed": 0,
"pending": 0,
"total": 5,
"done": 5,
"percent": 100,
"current": "活跃状态高级筛选已完成,等待在具备 PHP 运行时的环境补跑后端单元用例",
"updated_at": "2026-04-25 00:30:00"
}
@@ -0,0 +1,47 @@
{
"updatedAt": "2026-04-24T16:18:00.000Z",
"version": 1,
"source": "R2",
"originCommand": "design",
"verifyMode": "review-first",
"reviewerFocus": [
"高级筛选是否仅做增量改动并保持现有 Apple 风格工作台结构",
"活跃状态前端字段、摘要文案与后端复合规则是否一致",
"是否避免把隐式封禁/到期语义混入本轮活跃规则"
],
"testerFocus": [
"user/fetch 是否支持 activity_status=eq:1|0 的活跃/非活跃筛选",
"高级筛选弹窗是否可选择活跃状态并正确生成筛选条件",
"admin-frontend 构建与新增单元验证是否通过"
],
"ui": {
"required": true,
"designContract": true,
"sourcePriority": [
"proposal.md",
".helloagents/DESIGN.md",
"hello-ui"
],
"styleAdvisor": {
"required": false,
"reason": "",
"focus": []
},
"visualValidation": {
"required": false,
"reason": "本轮仅在高级筛选弹窗中增量添加一个条件字段,不涉及整页视觉重构",
"screens": [
"#/users advanced filter dialog"
],
"states": [
"活跃状态字段下拉展开态"
]
}
},
"advisor": {
"required": false,
"reason": "",
"focus": [],
"preferredSources": []
}
}
@@ -0,0 +1,88 @@
# 变更提案: admin-frontend-user-activity-status-filter
## 元信息
```yaml
类型: 功能开发
方案类型: implementation
优先级: P1
状态: 已完成
创建: 2026-04-25
```
---
## 1. 需求
### 背景
用户要求在 `admin-frontend` 的用户管理“高级筛选”中新增“活跃用户”判断,并明确选择扩展为“三态筛选”:支持按“全部 / 活跃 / 非活跃”理解筛选范围。当前高级筛选仅支持单字段条件组合,前端无法直接表达“有任意订阅 + 剩余流量 > 0 + 最后在线时间在半年内”这类跨字段复合判断,因此需要补齐前后端联动能力。
### 目标
- 在用户管理高级筛选弹窗中新增“活跃状态”条件,允许按活跃 / 非活跃筛选用户。
- 将“全部”保持为默认无筛选状态,不破坏现有高级筛选工作流。
- 后端 `user/fetch` 支持识别复合过滤字段,并按“任意订阅 + 流量未用完 + 最后在线时间在半年内”为活跃规则返回结果。
### 约束条件
```yaml
范围约束: 仅调整用户管理高级筛选相关前后端逻辑,不改动列表主结构和其他筛选能力
技术约束: 前端继续使用 Vue3 + TypeScript + Element Plus;后端继续沿用现有 UserController 过滤协议
业务约束: 活跃规则严格以用户本轮指令为准,不额外叠加封禁/到期等隐式条件
视觉约束: 延续 apple/DESIGN.md 与 .helloagents/DESIGN.md 的 Apple 风格后台样式,只做增量字段扩展
```
### 验收标准
- [ ] 高级筛选弹窗新增“活跃状态”字段,并可选择“活跃 / 非活跃”。
- [ ] “全部”状态下不额外发送活跃过滤条件,现有筛选行为保持不变。
- [ ] `user/fetch` 支持 `activity_status` 复合过滤,活跃判断规则为:`plan_id` 非空、`transfer_enable > u + d``last_online_at >= 近半年阈值`
- [ ] 非活跃筛选返回活跃条件的反向集合。
- [ ] 至少完成一次后端单元验证与一次 `admin-frontend` 构建验证。
---
## 2. 方案
### 页面与交互
1. 延续现有高级筛选弹窗结构,不新增新的工具条入口。
2. 在字段列表中新增“活跃状态”,值选择使用枚举下拉,保持与“账号状态”一致的轻量操作方式。
3. “全部”继续通过“不添加该条件 / 清空该条件”表达,不在 UI 中额外堆叠冗余控件。
### 前端实现策略
1.`admin-frontend/src/utils/users.ts` 中新增活跃状态字段定义、值选项、摘要格式化与过滤载荷映射。
2.`admin-frontend/src/views/users/UserAdvancedFilterDialog.vue` 中补齐对应下拉输入分支。
3. 保持 `useUsersManagement.ts` 与现有 `buildUserFilters()` 聚合方式不变,由工具层输出新过滤项。
### 后端实现策略
1.`app/Http/Controllers/V2/Admin/UserController.php` 中为 `activity_status` 增加专用解析逻辑。
2. 活跃条件由后端统一拼装,避免前端伪造多列比较表达式。
3. 非活跃条件按活跃规则的反向集合构造,保证“三态”中的“非活跃”可直接使用。
### 风险评估
| 风险 | 等级 | 应对 |
|------|------|------|
| 现有通用过滤协议只支持单字段比较 | 中 | 通过 `activity_status` 专用分支下沉复合查询 |
| `last_online_at` 为可空字段,非活跃定义容易遗漏 null | 中 | 在后端反向条件中显式纳入 `whereNull(last_online_at)` |
| 前端筛选摘要文案与实际规则不一致 | 低 | 统一在 `users.ts` 中维护字段标签和值文案 |
---
## 3. 技术决策
### admin-frontend-user-activity-status-filter#D001: 活跃判断作为高级筛选枚举字段而不是快捷工具条
**日期**: 2026-04-25
**状态**: ✅采纳
**背景**: 用户明确要求“给用户管理的高级筛选加个活跃用户的判断”。
**决策**: 在高级筛选弹窗中新增“活跃状态”字段,维持原有筛选弹窗交互,不额外扩展快捷筛选区。
**理由**: 最贴合用户点名的入口,也能避免在工具条中引入新的视觉噪音。
### admin-frontend-user-activity-status-filter#D002: 复合活跃规则统一由后端 `activity_status` 字段承接
**日期**: 2026-04-25
**状态**: ✅采纳
**背景**: 活跃规则包含“订阅存在 + 剩余流量比较 + 半年在线阈值”三段条件,前端现有过滤协议无法安全表达列与列比较。
**决策**: 前端仅发送 `activity_status=eq:1|0`,具体 SQL 条件由 `UserController` 后端专用逻辑生成。
**理由**: 能保证筛选规则唯一、可维护,也避免前端为了复合判断扩展非标准过滤语法。
### admin-frontend-user-activity-status-filter#D003: “全部”状态继续由无条件表达,不引入伪过滤值
**日期**: 2026-04-25
**状态**: ✅采纳
**背景**: 用户选择了“三态筛选”,但当前高级筛选系统本质上以“有条件 / 无条件”表达是否筛选。
**决策**: “活跃 / 非活跃”作为显式值;“全部”保持为未添加该条件或清空该条件。
**理由**: 既满足三态语义,又不破坏现有高级筛选的组合式模型。
@@ -0,0 +1,44 @@
# 任务清单: admin-frontend-user-activity-status-filter
> **@status:** completed | 2026-04-25 00:18
```yaml
@feature: admin-frontend-user-activity-status-filter
@created: 2026-04-25
@status: completed
@mode: R2
```
## 进度概览
| 完成 | 失败 | 跳过 | 总数 |
|------|------|------|------|
| 5 | 0 | 0 | 5 |
---
## 任务列表
- [√] 1. 读取用户管理高级筛选前后端实现,冻结“活跃 / 非活跃”筛选边界
- [√] 2. 扩展 `admin-frontend` 高级筛选字段定义、值选项与筛选摘要,新增“活跃状态”条件
- [√] 3. 为 `user/fetch` 增加 `activity_status` 复合过滤逻辑,按订阅 / 剩余流量 / 半年在线规则筛选
- [√] 4. 补充至少一项单元验证,并执行 `admin-frontend` 构建验证
- [√] 5. 同步 `.helloagents` 文档、CHANGELOG 与方案归档记录
---
## 执行日志
| 时间 | 任务 | 状态 | 备注 |
|------|------|------|------|
| 2026-04-25 00:18 | 方案包初始化 | completed | 已确认本轮采用“三态活跃状态筛选”,入口固定在用户管理高级筛选弹窗 |
| 2026-04-25 00:24 | 前后端实现 | completed | 已新增 `activity_status` 过滤字段,前端弹窗支持活跃 / 非活跃选择,后端支持复合规则筛选 |
| 2026-04-25 00:30 | 验证与知识同步 | completed | `admin-frontend` 执行 `npm run build` 通过;PHP 运行时当前不可用,新增 PHPUnit 用例已落地但未能在本机执行 |
---
## 执行备注
- “全部”不作为单独过滤值落库,而是保持无条件状态。
- 活跃判断严格按用户指定规则实现,不额外叠加封禁/到期等隐式业务语义。
- 本机当前缺少可执行 `php` 命令,后端单元用例已补齐,需在具备 PHP 运行时的环境中补跑。
+4
View File
@@ -7,6 +7,8 @@
| 时间戳 | 名称 | 类型 | 涉及模块 | 决策 | 结果 |
|--------|------|------|---------|------|------|
| 202604250018 | admin-frontend-user-activity-status-filter | implementation | admin-frontend,backend | admin-frontend-user-activity-status-filter#D001,#D002,#D003 | ✅完成 |
| 202604250002 | order-payment-snapshot | implementation | admin-frontend,order-payment | order-payment-snapshot#D001,#D002 | ✅完成 |
| 202604242245 | admin-frontend-node-pagination-batch-edit | implementation | admin-frontend | admin-frontend-node-pagination-batch-edit#D001,#D002,#D003 | ✅完成 |
| 202604242217 | admin-frontend-orders-commission-confirmation | implementation | admin-frontend | admin-frontend-orders-commission-confirmation#D001,#D002 | ✅完成 |
| 202604241703 | admin-frontend-gift-card-management | implementation | admin-frontend | admin-frontend-gift-card-management#D001,#D002,#D003 | ✅完成 |
@@ -34,6 +36,8 @@
## 按月归档
### 2026-04
- [202604250018_admin-frontend-user-activity-status-filter](./2026-04/202604250018_admin-frontend-user-activity-status-filter/) - 为用户管理高级筛选新增“活跃状态”条件,并在后端补齐 `activity_status` 复合过滤规则,支持按活跃 / 非活跃筛选用户
- [202604250002_order-payment-snapshot](./2026-04/202604250002_order-payment-snapshot/) - 补齐订单支付成功快照保存链路,并在后台订单详情中集中展示支付渠道、支付方法、平台订单号、商户订单号、实付金额与支付 IP
- [202604242245_admin-frontend-node-pagination-batch-edit](./2026-04/202604242245_admin-frontend-node-pagination-batch-edit/) - 为节点管理工作台补齐本地分页、父/子节点筛选、单节点置顶,以及仅对已勾选节点生效的批量修改
- [202604242217_admin-frontend-orders-commission-confirmation](./2026-04/202604242217_admin-frontend-orders-commission-confirmation/) - 修复订单页无佣金订单误显示为待确认的问题,并新增真实待确认佣金筛选与行级手动确认入口
- [202604241703_admin-frontend-gift-card-management](./2026-04/202604241703_admin-frontend-gift-card-management/) - 开放“礼品卡管理”入口,交付模板管理、兑换码管理、使用记录与统计数据四页签工作台,并接入真实 gift-card 接口