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,11 @@
{
"status": "in_progress",
"completed": 4,
"failed": 1,
"pending": 0,
"total": 5,
"done": 5,
"percent": 100,
"current": "代码修复与前端构建已完成,等待具备 PHP/Composer 的环境补跑后端验证",
"updated_at": "2026-04-25 00:15:50"
}
@@ -0,0 +1,43 @@
{
"updatedAt": "2026-04-24T16:06:00.000Z",
"version": 1,
"source": "R2",
"originCommand": "design",
"verifyMode": "review-first",
"reviewerFocus": [
"工单再次回复后的 reopen 语义是否统一落在 TicketService,不再依赖单端特判",
"管理端关闭态发送交互是否放开且未破坏现有 Apple 风格工单工作台结构",
"用户端是否通过既有 /user/ticket/reply 链路打通,而非引入新的接口分叉"
],
"testerFocus": [
"用户侧 closed ticket reply 后是否会自动变回开启状态",
"管理端 TicketWorkspaceDialog 在 closed ticket 下是否可发送并刷新状态",
"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": [],
"states": []
}
},
"advisor": {
"required": false,
"reason": "",
"focus": [],
"preferredSources": []
}
}
@@ -0,0 +1,86 @@
# 变更提案: ticket-closed-reply-reopen
## 元信息
```yaml
类型: 缺陷修复
方案类型: implementation
优先级: P1
状态: 进行中
创建: 2026-04-25
```
---
## 1. 需求
### 背景
用户要求在 `admin-frontend` 的工单工作台中允许“已关闭工单再次回复”,并明确选择“前后台统一”方案:无论管理员还是用户,只要对已关闭工单再次回复,就自动把该工单重新开启。当前代码中,`V1/User/TicketController::reply()` 会直接拒绝 closed ticket`TicketService::reply()` 也没有把工单状态改回开启;同时管理端 `TicketWorkspaceDialog.vue` 还会在 closed 状态禁用发送按钮。
### 目标
- 打通用户端与管理端的统一规则:已关闭工单再次回复后自动重开。
- 保持现有 `/ticket/reply``/ticket/close` 接口不变,只修正回复链路的业务语义。
- 管理端 `#/tickets` 保持现有 Apple 风格后台工作台,只做必要交互修复,不引入新的视觉系统分叉。
### 约束条件
```yaml
范围约束: 仅修复工单再次回复与自动重开链路,不扩展其他客服、通知或工单字段
技术约束: Laravel 后端继续复用现有 TicketService;管理端继续使用 Vue3 + TypeScript + Element Plus
兼容约束: 用户端主题源码不在仓内,仅有编译产物 bundle,因此优先通过后端语义修复保证用户侧链路可用
业务约束: 仍需保留 ticket_must_wait_reply 限制,避免同一角色连续刷消息破坏既有等待规则
视觉约束: 管理端交互保持 .helloagents/DESIGN.md 的 Apple 风格后台,不做大改版
```
### 验收标准
- [ ] 用户侧对已关闭工单调用回复接口时不再收到 “The ticket is closed and cannot be replied”,且回复后工单状态自动回到开启。
- [ ] 管理端 `#/tickets` 中已关闭工单仍可进入工作台发送回复,回复成功后状态刷新为开启中的工单。
- [ ] 回复后 `reply_status``last_reply_user_id` 仍保持当前系统既有语义,`ticket_must_wait_reply` 规则不回归。
- [ ] 至少补齐 1 个针对工单自动重开语义的自动化测试。
- [ ] `admin-frontend` 构建验证通过;后端目标测试通过。
---
## 2. 方案
### 技术方案
1.`TicketService::reply()` 为单一真相源补齐“回复即自动重开”的状态回写,确保用户端、管理端、Telegram 插件管理员回复等所有复用该服务的链路统一生效。
2. 移除 `V1/User/TicketController::reply()` 中“closed ticket 直接拒绝”的硬拦截,让用户端能走到统一服务逻辑;保留参数校验和 `ticket_must_wait_reply` 限制。
3. 调整管理端 `TicketWorkspaceDialog.vue` 的关闭态发送限制:closed ticket 允许继续输入并发送;关闭按钮仍只在开启态显示。
4. 基于当前仓内可维护代码补齐自动化测试,重点覆盖“回复 closed ticket 会自动 reopen”的核心业务语义;如果用户主题 bundle 不存在额外前端禁用,则不对 minified 用户端产物做无谓 patch。
### 影响范围
- 后端:`app/Services/TicketService.php``app/Http/Controllers/V1/User/TicketController.php`
- 管理端:`admin-frontend/src/views/tickets/TicketWorkspaceDialog.vue`
- 测试:`tests/Unit``tests/Feature`
- 文档:`.helloagents/context.md``.helloagents/modules/admin-frontend.md``.helloagents/CHANGELOG.md`
### 风险评估
| 风险 | 等级 | 应对 |
|------|------|------|
| 统一在服务层自动 reopen 可能影响管理员插件回复链路 | 中 | 只在“reply 成功后”把 status 设回开启,保持 reply_status/last_reply_user_id 语义不变,并补测试验证 |
| 用户主题只有编译 bundle,若前端本身禁用 closed reply,后端修复仍不足 | 中 | 已先排查 bundle,当前回复页未发现 closed 态本地禁用;若实施后验证发现仍受限,再最小化补丁 bundle |
| 管理端放开发送后,状态徽章与列表刷新可能不同步 | 低 | 回复成功后继续复用现有 `refreshWorkspace()``updated` 刷新链路 |
---
## 3. 技术决策
### ticket-closed-reply-reopen#D001: 自动重开规则下沉到 TicketService::reply()
**日期**: 2026-04-25
**状态**: ✅采纳
**背景**: 用户、管理员和插件管理员回复都复用工单服务,但当前 reopen 语义分散且缺失。
**决策**: 在 `TicketService::reply()` 内统一把成功回复后的工单状态改为 `STATUS_OPENING`
**理由**: 这是所有回复链路共享的唯一稳定汇合点,能避免只修某个 controller 导致语义不一致。
### ticket-closed-reply-reopen#D002: 用户端优先通过后端语义修复打通,不直接改 minified bundle
**日期**: 2026-04-25
**状态**: ✅采纳
**背景**: 仓内不存在用户主题源代码,只保留 `theme/Xboard/assets/umi.js` 编译产物。
**决策**: 先确认用户端详情页没有本地禁用 closed reply,再仅通过后端修复放开用户端;只有验证发现前端仍阻塞时才补 bundle。
**理由**: 降低对 minified 产物的高风险修改,优先用可维护的后端真相源完成统一业务规则。
### ticket-closed-reply-reopen#D003: 管理端仅修复交互门禁,不改变现有页面结构
**日期**: 2026-04-25
**状态**: ✅采纳
**背景**: 当前工单工作台已经符合项目既定 Apple 风格后台基线,本轮是行为修复不是页面重做。
**决策**: 放开发送按钮的 closed 态禁用,并继续保留现有 hero / 工作台 / 对话区布局。
**理由**: 最小化视觉影响,避免为了一个业务修复引入额外 UI 回归。
@@ -0,0 +1,45 @@
# 任务清单: ticket-closed-reply-reopen
> **@status:** in_progress | 2026-04-25 00:15
```yaml
@feature: ticket-closed-reply-reopen
@created: 2026-04-25
@status: in_progress
@mode: R2
```
## 进度概览
| 完成 | 失败 | 跳过 | 总数 |
|------|------|------|------|
| 4 | 1 | 0 | 5 |
---
## 任务列表
- [√] 1. 冻结工单回复/关闭链路的根因与实施边界,确认用户端由后端语义修复打通 | depends_on: []
- [√] 2. 修复后端工单回复逻辑:关闭态允许回复且回复成功后自动重开 | depends_on: [1]
- [√] 3. 修复管理端工单工作台:关闭态允许继续发送并复用现有刷新链路 | depends_on: [2]
- [√] 4. 补齐自动化测试,覆盖“closed ticket reply -> reopen”核心语义 | depends_on: [2]
- [X] 5. 运行后端/前端验证并同步知识库记录 | depends_on: [2, 3, 4]
---
## 执行日志
| 时间 | 任务 | 状态 | 备注 |
|------|------|------|------|
| 2026-04-25 00:06 | 方案包初始化 | completed | 已确认本轮采用“前后台统一”方案,根因定位到 V1 用户控制器拦截、TicketService 未自动 reopen、管理端发送按钮禁用 |
| 2026-04-25 00:10 | 实现完成 | completed | 已下沉 TicketService 自动重开语义,移除用户侧 closed reply 拦截,并放开管理端关闭态发送交互 |
| 2026-04-25 00:12 | 构建验证 | completed | `admin-frontend` 执行 `npm run build` 通过,最新产物已写入 `public/assets/admin` 子模块 |
| 2026-04-25 00:15 | 后端验证受阻 | failed | 当前终端无 `php` / `composer` / `docker`,无法继续执行 PHP 语法检查与新增单元测试,只能保留测试文件与代码级审查结果 |
---
## 执行备注
- 用户主题仓内仅保留 `theme/Xboard/assets/umi.js` 编译产物;当前已确认回复详情页没有明显的 closed 态本地禁用,优先通过后端语义修复打通用户侧。
- 本轮不改动工单关闭接口、工单自动关闭定时任务和流量日志对话框。
- 任务 5 标记失败仅因本机缺少 PHP / Composer / Docker 运行时;前端构建和知识库同步已完成,但后端自动验证仍待补跑。