diff --git a/.helloagents/.ralph-breaker.json b/.helloagents/.ralph-breaker.json new file mode 100644 index 0000000..d2f2f14 --- /dev/null +++ b/.helloagents/.ralph-breaker.json @@ -0,0 +1,4 @@ +{ + "consecutive_failures": 2, + "last_failure": "2026-04-23T16:27:30.802Z" +} \ No newline at end of file diff --git a/.helloagents/.ralph-closeout.json b/.helloagents/.ralph-closeout.json new file mode 100644 index 0000000..8416072 --- /dev/null +++ b/.helloagents/.ralph-closeout.json @@ -0,0 +1,19 @@ +{ + "updatedAt": "2026-04-23T16:26:05.357Z", + "source": "~auto", + "originCommand": "~verify", + "requirementsCoverage": { + "status": "PASS", + "summary": "已完成系统管理侧边栏分组、系统配置真实页面,以及插件/主题/公告/支付/知识库 5 个结构化占位页;系统配置已接入真实 config API 读写与辅助动作入口。" + }, + "deliveryChecklist": { + "status": "PASS", + "summary": "已通过 admin-frontend 的 npm run build,并完成系统配置默认态/保存态/错误态与 5 个系统管理占位页的 Playwright 结构验收;知识库与方案归档已同步。" + }, + "fingerprint": { + "available": true, + "unstaged": ".helloagents/CHANGELOG.md | 56 ++\n .helloagents/INDEX.md | 6 +-\n .helloagents/archive/_index.md | 12 +\n .helloagents/context.md | 15 +-\n .helloagents/modules/_index.md | 2 +-\n .helloagents/modules/admin-frontend.md | 18 +-\n admin-frontend/src/api/admin.ts | 86 ++-\n admin-frontend/src/layouts/AdminLayout.vue | 129 ++++-\n admin-frontend/src/router/index.ts | 60 +++\n admin-frontend/src/types/api.d.ts | 125 +++++\n admin-frontend/src/types/components.d.ts | 2 +\n admin-frontend/src/utils/dashboard.ts | 21 +-\n .../src/views/dashboard/DashboardView.vue | 595 +++++++++++++++++----\n app/Http/Controllers/V2/Admin/StatController.php | 8 +-\n public/assets/admin | 0\n 15 files changed, 1015 insertions(+), 120 deletions(-)", + "staged": "", + "combined": ".helloagents/CHANGELOG.md | 56 ++\n .helloagents/INDEX.md | 6 +-\n .helloagents/archive/_index.md | 12 +\n .helloagents/context.md | 15 +-\n .helloagents/modules/_index.md | 2 +-\n .helloagents/modules/admin-frontend.md | 18 +-\n admin-frontend/src/api/admin.ts | 86 ++-\n admin-frontend/src/layouts/AdminLayout.vue | 129 ++++-\n admin-frontend/src/router/index.ts | 60 +++\n admin-frontend/src/types/api.d.ts | 125 +++++\n admin-frontend/src/types/components.d.ts | 2 +\n admin-frontend/src/utils/dashboard.ts | 21 +-\n .../src/views/dashboard/DashboardView.vue | 595 +++++++++++++++++----\n app/Http/Controllers/V2/Admin/StatController.php | 8 +-\n public/assets/admin | 0\n 15 files changed, 1015 insertions(+), 120 deletions(-)\n---" + } +} diff --git a/.helloagents/.ralph-review.json b/.helloagents/.ralph-review.json new file mode 100644 index 0000000..77f3529 --- /dev/null +++ b/.helloagents/.ralph-review.json @@ -0,0 +1,24 @@ +{ + "updatedAt": "2026-04-23T16:25:14.576Z", + "source": "~auto", + "originCommand": "~verify", + "reviewMode": "review-first", + "conclusion": "审查结论:未发现阻塞问题。系统管理导航、系统配置数据链路与占位页范围边界保持一致,未发现需要阻断交付的逻辑或安全问题。", + "outcome": "clean", + "findings": [], + "fileReferences": [ + "admin-frontend/src/router/index.ts", + "admin-frontend/src/layouts/AdminLayout.vue", + "admin-frontend/src/api/admin.ts", + "admin-frontend/src/types/api.d.ts", + "admin-frontend/src/utils/systemConfig.ts", + "admin-frontend/src/views/system/SystemConfigView.vue", + "admin-frontend/src/views/system/SystemPlaceholderView.vue" + ], + "fingerprint": { + "available": true, + "unstaged": ".helloagents/CHANGELOG.md | 56 ++\n .helloagents/INDEX.md | 6 +-\n .helloagents/archive/_index.md | 12 +\n .helloagents/context.md | 15 +-\n .helloagents/modules/_index.md | 2 +-\n .helloagents/modules/admin-frontend.md | 18 +-\n admin-frontend/src/api/admin.ts | 86 ++-\n admin-frontend/src/layouts/AdminLayout.vue | 129 ++++-\n admin-frontend/src/router/index.ts | 60 +++\n admin-frontend/src/types/api.d.ts | 125 +++++\n admin-frontend/src/types/components.d.ts | 2 +\n admin-frontend/src/utils/dashboard.ts | 21 +-\n .../src/views/dashboard/DashboardView.vue | 595 +++++++++++++++++----\n app/Http/Controllers/V2/Admin/StatController.php | 8 +-\n public/assets/admin | 0\n 15 files changed, 1015 insertions(+), 120 deletions(-)", + "staged": "", + "combined": ".helloagents/CHANGELOG.md | 56 ++\n .helloagents/INDEX.md | 6 +-\n .helloagents/archive/_index.md | 12 +\n .helloagents/context.md | 15 +-\n .helloagents/modules/_index.md | 2 +-\n .helloagents/modules/admin-frontend.md | 18 +-\n admin-frontend/src/api/admin.ts | 86 ++-\n admin-frontend/src/layouts/AdminLayout.vue | 129 ++++-\n admin-frontend/src/router/index.ts | 60 +++\n admin-frontend/src/types/api.d.ts | 125 +++++\n admin-frontend/src/types/components.d.ts | 2 +\n admin-frontend/src/utils/dashboard.ts | 21 +-\n .../src/views/dashboard/DashboardView.vue | 595 +++++++++++++++++----\n app/Http/Controllers/V2/Admin/StatController.php | 8 +-\n public/assets/admin | 0\n 15 files changed, 1015 insertions(+), 120 deletions(-)\n---" + } +} diff --git a/.helloagents/.ralph-visual.json b/.helloagents/.ralph-visual.json new file mode 100644 index 0000000..45353d6 --- /dev/null +++ b/.helloagents/.ralph-visual.json @@ -0,0 +1,37 @@ +{ + "updatedAt": "2026-04-23T16:25:51.056Z", + "source": "~auto", + "originCommand": "~verify", + "reason": "系统管理属于整页新建后台视图,需要确认导航、系统配置长表单层级与占位页结构在浏览器中符合 Apple 风格契约", + "tooling": [ + "playwright (mock API fixtures)", + "code inspection" + ], + "screensChecked": [ + "#/system/config desktop", + "#/system/plugins desktop", + "#/system/themes desktop", + "#/system/notices desktop", + "#/system/payments desktop", + "#/system/knowledge desktop" + ], + "statesChecked": [ + "系统配置默认加载完成态", + "系统配置保存态", + "系统配置错误/重试态", + "系统模块占位态" + ], + "status": "PASS", + "summary": "已通过 Playwright + Mock API 对系统配置页默认态、保存态、错误态,以及 5 个系统管理占位页完成桌面端结构验收;截图产物位于 .helloagents/replay/system-management-visual/,页面层级与 Apple 风格后台契约一致。", + "findings": [], + "recommendations": [ + "下一阶段优先为插件、主题、公告、支付与知识库入口补齐真实 CRUD 页面", + "如后续提供本地登录态,可在真实接口环境下补做无 Mock 的视觉回归验收" + ], + "fingerprint": { + "available": true, + "unstaged": ".helloagents/CHANGELOG.md | 56 ++\n .helloagents/INDEX.md | 6 +-\n .helloagents/archive/_index.md | 12 +\n .helloagents/context.md | 15 +-\n .helloagents/modules/_index.md | 2 +-\n .helloagents/modules/admin-frontend.md | 18 +-\n admin-frontend/src/api/admin.ts | 86 ++-\n admin-frontend/src/layouts/AdminLayout.vue | 129 ++++-\n admin-frontend/src/router/index.ts | 60 +++\n admin-frontend/src/types/api.d.ts | 125 +++++\n admin-frontend/src/types/components.d.ts | 2 +\n admin-frontend/src/utils/dashboard.ts | 21 +-\n .../src/views/dashboard/DashboardView.vue | 595 +++++++++++++++++----\n app/Http/Controllers/V2/Admin/StatController.php | 8 +-\n public/assets/admin | 0\n 15 files changed, 1015 insertions(+), 120 deletions(-)", + "staged": "", + "combined": ".helloagents/CHANGELOG.md | 56 ++\n .helloagents/INDEX.md | 6 +-\n .helloagents/archive/_index.md | 12 +\n .helloagents/context.md | 15 +-\n .helloagents/modules/_index.md | 2 +-\n .helloagents/modules/admin-frontend.md | 18 +-\n admin-frontend/src/api/admin.ts | 86 ++-\n admin-frontend/src/layouts/AdminLayout.vue | 129 ++++-\n admin-frontend/src/router/index.ts | 60 +++\n admin-frontend/src/types/api.d.ts | 125 +++++\n admin-frontend/src/types/components.d.ts | 2 +\n admin-frontend/src/utils/dashboard.ts | 21 +-\n .../src/views/dashboard/DashboardView.vue | 595 +++++++++++++++++----\n app/Http/Controllers/V2/Admin/StatController.php | 8 +-\n public/assets/admin | 0\n 15 files changed, 1015 insertions(+), 120 deletions(-)\n---" + } +} diff --git a/.helloagents/CHANGELOG.md b/.helloagents/CHANGELOG.md index 2b99b49..7ff32f4 100644 --- a/.helloagents/CHANGELOG.md +++ b/.helloagents/CHANGELOG.md @@ -1,5 +1,19 @@ # CHANGELOG +## [0.3.0] - 2026-04-23 + +### 新增 +- **[admin-frontend]**: 新增“节点管理”侧边栏分组、节点管理工作台,以及权限组/路由管理占位页;同时补齐缺失的 `PlansView` 占位组件以恢复 `npm run build` 构建通过 — by yinjianm + - 方案: [202604232320_admin-frontend-node-management](archive/2026-04/202604232320_admin-frontend-node-management/) + - 决策: admin-frontend-node-management#D001(首批聚焦节点列表运营链路), admin-frontend-node-management#D002(权限组与路由管理先交付结构化占位页) + +## [0.3.1] - 2026-04-23 + +### 新增 +- **[admin-frontend]**: 新增“系统管理”侧边栏分组,完整交付系统配置页,并接入插件/主题/公告/支付/知识库 5 个结构化占位页 — by yinjianm + - 方案: [202604232329_admin-frontend-system-management](archive/2026-04/202604232329_admin-frontend-system-management/) + - 决策: admin-frontend-system-management#D001(首批聚焦系统配置真实页), admin-frontend-system-management#D002(其余系统管理入口先交付结构化占位页), admin-frontend-system-management#D003(系统配置采用左侧分组导航与右侧连续 section) + ## [0.1.0] - 2026-04-21 ### 新增 @@ -27,3 +41,45 @@ - **[admin-frontend]**: 新增用户管理工作台、抽屉表单、用户操作菜单,以及“用户管理 / 工单管理”导航与路由骨架 — by yinjianm - 方案: [202604210441_admin-frontend-user-management](archive/2026-04/202604210441_admin-frontend-user-management/) - 决策: admin-frontend-user-management#D001(新增用户采用两段式创建), admin-frontend-user-management#D002(先补齐用户与工单入口结构) + +## [0.2.1] - 2026-04-23 + +### 新增 +- **[admin-frontend]**: 为仪表盘收入趋势面板新增“按金额 / 按数量”切换,并让图表摘要、Y 轴标签与最近记录跟随口径同步 — by yinjianm + - 方案: [202604232313_admin-frontend-dashboard-trend-count-toggle](archive/2026-04/202604232313_admin-frontend-dashboard-trend-count-toggle/) + - 决策: admin-frontend-dashboard-trend-count-toggle#D001(采用单图切换而不是双图/双线), admin-frontend-dashboard-trend-count-toggle#D002(数量模式复用现有接口字段) + +## [0.2.2] - 2026-04-23 + +### 新增 +- **[admin-frontend]**: 为仪表盘节点/用户流量排行新增 `10个 / 20个` 显示切换,并将长列表收进面板内滚动区域 — by yinjianm + - 方案: [202604232318_admin-frontend-rank-limit-scroll](archive/2026-04/202604232318_admin-frontend-rank-limit-scroll/) + - 决策: admin-frontend-rank-limit-scroll#D001(两个排行面板独立控制显示数量), admin-frontend-rank-limit-scroll#D002(使用固定高度滚动容器而不是整页自然拉伸) + +## [0.2.3] - 2026-04-23 + +### 新增 +- **[admin-frontend]**: 为仪表盘“作业详情”面板新增“查看报错详情”入口,并通过弹窗展示失败作业的报错摘要、失败时间与队列信息 — by yinjianm + - 方案: [202604232330_admin-frontend-queue-error-details](plan/202604232330_admin-frontend-queue-error-details/) + - 决策: admin-frontend-queue-error-details#D001(使用弹窗承载失败作业详情), admin-frontend-queue-error-details#D002(前端兼容式解析 Horizon 失败作业字段) + +## [0.2.4] - 2026-04-23 + +### 新增 +- **[admin-frontend]**: 为 traffic rank 前后端联动补齐 `limit=10|20` 支持,让排行数量切换真正驱动后端返回条数,并保留 24h 口径的涨跌展示 — by yinjianm + - 方案: [202604232345_traffic-rank-limit-backend-adapt](archive/2026-04/202604232345_traffic-rank-limit-backend-adapt/) + - 决策: traffic-rank-limit-backend-adapt#D001(在现有 getTrafficRank 接口上新增 limit 参数), traffic-rank-limit-backend-adapt#D002(24h 口径继续显示 change) + +## [0.2.5] - 2026-04-23 + +### 新增 +- **[admin-frontend]**: 为 Apple 风格仪表盘新增 Hero 区“刷新全部数据”按钮,并补齐最后刷新时间、加载反馈与防重复触发状态 — by yinjianm + - 方案: [202604231515_admin-frontend-dashboard-refresh-button](archive/2026-04/202604231515_admin-frontend-dashboard-refresh-button/) + - 决策: admin-frontend-dashboard-refresh-button#D001(刷新入口放在 Hero 状态区), admin-frontend-dashboard-refresh-button#D002(复用 refreshDashboard 作为唯一全量刷新入口) + +## [0.2.6] - 2026-04-23 + +### 新增 +- **[admin-frontend]**: 新增“订阅管理”侧边栏分组与套餐管理页面,支持真实套餐 CRUD、排序、价格矩阵与说明预览 — by yinjianm + - 方案: [202604232325_admin-frontend-subscription-plan-management](plan/202604232325_admin-frontend-subscription-plan-management/) + - 决策: admin-frontend-subscription-plan-management#D001(其余订阅菜单先保留禁用入口), admin-frontend-subscription-plan-management#D002(说明编辑采用轻量 Markdown 方案), admin-frontend-subscription-plan-management#D003(排序采用本地编辑对话框) diff --git a/.helloagents/DESIGN.md b/.helloagents/DESIGN.md new file mode 100644 index 0000000..07d421d --- /dev/null +++ b/.helloagents/DESIGN.md @@ -0,0 +1,74 @@ +# Xboard-new 管理端设计系统 + +## 产品表面 +- `admin-frontend` 是数据密集型管理后台,当前核心界面包括仪表盘、用户管理、工单管理、节点管理、系统管理,以及本轮新增的订阅管理。 +- 侧边栏承担一级信息架构,页面主体承担筛选、批量判断和单行操作,不把复杂流程全部堆进列表页;新增业务域优先用独立分组承载。 +- 节点管理属于“高密度运营页”:用户需要在一个视图里快速判断节点状态、倍率、权限组与在线人数,再决定是否继续深入编辑。 +- 套餐管理属于“结构化配置页”:用户需要在一页内完成套餐开关、价格、分组、说明和排序维护,强调表格与抽屉之间的稳定切换。 + +## 美学方向 +- 延续 `apple/DESIGN.md` 的 Apple 风格:纯色分区、系统字体、克制阴影、低噪音交互。 +- 管理后台不追求营销式华丽,而是强调“黑白主场 + 蓝色交互 + 轻薄容器”的精密运营感。 +- 新页面应与现有仪表盘 / 用户管理保持同一视觉家族,避免出现另一套后台皮肤。 + +## 设计 token +- 背景与表面继续复用 `admin-frontend/src/styles/index.scss` 中的 `--xboard-*` 变量。 +- 主色固定为 `#0071e3`,仅用于激活态、主按钮、焦点和核心交互反馈。 +- 文本层级固定为:`--xboard-text-strong` 主标题、`--xboard-text-secondary` 正文、`--xboard-text-muted` 辅助信息。 +- 表格、筛选器、状态徽章允许新增页面级局部变量,但不得绕开全局 token 直接堆随机颜色。 + +## 布局策略 +- 一级导航仍采用左侧固定侧边栏,节点相关入口归入独立的“节点管理”分组,不混入“用户管理”分组。 +- 订阅相关入口归入独立的“订阅管理”分组;未实现的订单/优惠券/礼品卡入口允许先以禁用态占位。 +- 系统相关能力归入独立的“系统管理”分组;长表单型配置页采用“左侧分组导航 + 右侧连续 section”的后台编辑结构。 +- 页面头部保持“大标题 + 一句说明 + 右侧操作”的双栏结构,首屏先给运营者建立页面心智,再进入列表。 +- 列表上方先放一层紧凑筛选工具条:搜索框、类型筛选、权限组筛选、主操作按钮,避免二次折叠菜单。 +- 宽表格在桌面优先完整呈现;窄屏时允许信息折行,但不牺牲主列的可读性。 +- 订阅页面优先采用“黑色首屏 + 白色工作台 + 右侧抽屉”的结构,让套餐列表、价格矩阵和说明编辑形成清晰主次。 + +## 组件与模式 +- 侧边栏分组标题使用 `ElSubMenu`,子项必须与业务域一一对应。 +- 列表页优先使用原生 `ElTable` + Apple 化外观,不重新发明表格基础能力。 +- 配置页优先使用原生 `ElForm`、`ElInput`、`ElSwitch`、`ElSelect` 与 `ElInputNumber` 组合,不在后台长表单里引入花哨交互。 +- 状态使用“圆点 + 文本/徽章”双信号表达,避免仅靠颜色辨识在线/离线。 +- 危险操作收入口袋菜单,主列表行只露出最常用的显隐切换与查看信息。 +- 未进入本轮范围的功能允许放入占位页,但要明确标注“下一阶段接入”,不能伪装成可用功能。 + +## 状态覆盖 +- 加载态:列表区域显示骨架或表格 loading,不让整页空白。 +- 空状态:给出“当前筛选条件下暂无节点”与一键清空筛选入口。 +- 错误态:保留用户当前筛选条件,并允许重试,不把失败吞掉。 +- 成功态:显隐切换、复制节点、删除节点等操作使用明确 toast 反馈。 +- 禁用态:未实现或不可用的操作按钮必须有禁用样式和原因说明。 + +## 记忆点 +- 让用户记住“黑色首屏 + 运营表格 + 左侧节点分组”这一套安静但高辨识度的 Apple 化后台结构。 + +## 动效策略 +- 只保留必要动效:筛选 pill 激活、按钮 hover、表格操作反馈、占位页轻微过渡。 +- 禁止厚重的卡片飞入、长时间遮罩和无意义动画;尊重 `prefers-reduced-motion`。 + +## 无障碍要求 +- 所有按钮、开关、下拉菜单都保留可见焦点。 +- 表格操作必须支持键盘聚焦,危险动作要有明确文案。 +- 在线状态除颜色外还要搭配文字或点位说明。 + +## 内容语气 +- 标题直接、运营化,不写营销语。 +- 空状态和占位提示应明确告诉用户“现在能做什么 / 下一阶段会补什么”。 +- 操作按钮统一使用动词短语,如“添加节点”“编辑排序”“复制节点”“删除节点”。 + +## 禁止事项 +- 禁止回到紫色渐变、玻璃拟态大面积模糊、厚重卡片堆叠。 +- 禁止把节点列表页做成营销落地页式大色块拼贴。 +- 禁止使用 emoji、随机插画或与 Xboard 运营后台无关的装饰元素。 + +## 约束定义 +- 主页面同时出现的主操作按钮不超过 2 个。 +- 同一页面强调色不超过 1 个,语义色只用于状态。 +- 列表工具条最多一行半,超过则折叠到二级策略,不无限横向增长。 + +## 实现备注 +- 全局 token 继续落在 `admin-frontend/src/styles/index.scss`。 +- 节点页相关的格式化与映射逻辑优先放到 `admin-frontend/src/utils/nodes.ts`。 +- 节点管理分组路由位于 `admin-frontend/src/router/index.ts`,页面实现位于 `admin-frontend/src/views/nodes/`。 diff --git a/.helloagents/INDEX.md b/.helloagents/INDEX.md index 9b89f88..644246b 100644 --- a/.helloagents/INDEX.md +++ b/.helloagents/INDEX.md @@ -3,7 +3,7 @@ ```yaml kb_version: 2 project: Xboard-new -updated_at: 2026-04-21 +updated_at: 2026-04-23 active_package: 无 ``` @@ -11,11 +11,11 @@ active_package: 无 - 类型: PHP Laravel 主仓 + `admin-frontend` Vue3 管理端前端 - 当前重点模块: `admin-frontend` -- 最新归档: `202604210441_admin-frontend-user-management` +- 最新归档: `202604232345_traffic-rank-limit-backend-adapt` ## 活跃模块 -- [admin-frontend](modules/admin-frontend.md): 管理端登录、主布局、仪表盘、用户管理与管理 API 前端封装 +- [admin-frontend](modules/admin-frontend.md): 管理端登录、主布局、仪表盘、用户/节点/订阅/系统管理与管理 API 前端封装 ## 归档与变更 diff --git a/.helloagents/archive/2026-04/202604231515_admin-frontend-dashboard-refresh-button/.status.json b/.helloagents/archive/2026-04/202604231515_admin-frontend-dashboard-refresh-button/.status.json new file mode 100644 index 0000000..8462111 --- /dev/null +++ b/.helloagents/archive/2026-04/202604231515_admin-frontend-dashboard-refresh-button/.status.json @@ -0,0 +1,11 @@ +{ + "status": "completed", + "completed": 4, + "failed": 0, + "pending": 0, + "total": 4, + "done": 4, + "percent": 100, + "current": "Dashboard 全量刷新按钮实现、验证与知识库同步完成,待归档", + "updated_at": "2026-04-23 15:43:00" +} diff --git a/.helloagents/archive/2026-04/202604231515_admin-frontend-dashboard-refresh-button/contract.json b/.helloagents/archive/2026-04/202604231515_admin-frontend-dashboard-refresh-button/contract.json new file mode 100644 index 0000000..c18caa6 --- /dev/null +++ b/.helloagents/archive/2026-04/202604231515_admin-frontend-dashboard-refresh-button/contract.json @@ -0,0 +1,44 @@ +{ + "version": 1, + "source": "~auto", + "originCommand": "auto", + "verifyMode": "test-first", + "reviewerFocus": [], + "testerFocus": [ + "Hero 区刷新按钮是否触发整页数据刷新", + "刷新中是否有明确状态反馈并阻止重复点击", + "Dashboard 页面构建后是否保持现有 Apple 风格层级" + ], + "ui": { + "required": true, + "designContract": true, + "sourcePriority": [ + "proposal.md", + ".helloagents/DESIGN.md", + "hello-ui" + ], + "styleAdvisor": { + "required": false, + "reason": "", + "focus": [] + }, + "visualValidation": { + "required": true, + "reason": "本轮为 Dashboard 顶部新增显式操作按钮,需要确认视觉风格与交互状态一致。", + "screens": [ + "dashboard desktop", + "dashboard mobile" + ], + "states": [ + "refresh idle", + "refresh loading" + ] + } + }, + "advisor": { + "required": false, + "reason": "", + "focus": [], + "preferredSources": [] + } +} diff --git a/.helloagents/archive/2026-04/202604231515_admin-frontend-dashboard-refresh-button/proposal.md b/.helloagents/archive/2026-04/202604231515_admin-frontend-dashboard-refresh-button/proposal.md new file mode 100644 index 0000000..42df5b0 --- /dev/null +++ b/.helloagents/archive/2026-04/202604231515_admin-frontend-dashboard-refresh-button/proposal.md @@ -0,0 +1,92 @@ +# 变更提案: admin-frontend-dashboard-refresh-button + +## 元信息 +```yaml +类型: 增强 +方案类型: implementation +优先级: P2 +状态: 已完成 +创建: 2026-04-23 +``` + +--- + +## 1. 需求 + +### 背景 +当前 `admin-frontend` 仪表盘已经具备总览、趋势、排行与系统状态的数据拉取能力,但缺少一个显式、统一的“全量刷新”入口。用户希望在 `http://localhost:5173/assets/admin/#/dashboard` 对应的首页,基于 `apple/DESIGN.md` 的 Apple 风格,为整页数据增加刷新按钮。 + +### 目标 +- 在 `admin-frontend/src/views/dashboard/DashboardView.vue` 中增加一个整页全量刷新按钮。 +- 刷新动作需要覆盖统计卡、收入趋势、节点/用户排行、系统与队列状态。 +- 刷新按钮的视觉语言需延续当前 Apple 风格,不引入额外的重装饰。 + +### 约束条件 +```yaml +技术约束: + - 保持现有 Vue3 + TypeScript + Vite + Element Plus 栈 + - 复用现有 refreshDashboard 数据流,不重复造接口层逻辑 +UI约束: + - 以 apple/DESIGN.md 为设计基线 + - 使用单一蓝色强调与黑色 Hero 区的克制表达 +行为约束: + - 刷新时需有明确加载反馈 + - 刷新中避免重复点击触发并发请求 +``` + +### 验收标准 +- [√] Hero 区新增“刷新全部数据”入口,桌面和移动端都可正常使用。 +- [√] 点击后会统一刷新总览、趋势、排行和系统状态。 +- [√] 刷新中有可见状态反馈,并阻止重复触发。 +- [√] `admin-frontend` 构建通过。 +- [√] 本地页面完成一次视觉验收,确认按钮与 Apple 风格一致。 + +--- + +## 2. 方案 + +### 技术方案 +1. 在仪表盘 Hero 右侧状态区加入全量刷新按钮,作为当前页面最直接的系统操作入口。 +2. 复用现有 `refreshDashboard()` 逻辑,对其补充成功提示、最后刷新时间记录与手动触发入口。 +3. 为按钮增加刷新中状态、旋转图标、禁用交互和辅助文案,保证状态完整。 +4. 保持当前卡片、趋势图与系统面板的数据结构不变,只增强顶部操作层。 + +### 影响范围 +```yaml +涉及模块: + - admin-frontend/src/views/dashboard/DashboardView.vue + - .helloagents/CHANGELOG.md + - .helloagents/modules/admin-frontend.md +预计变更文件: 3 +``` + +### 风险评估 +| 风险 | 等级 | 应对 | +|------|------|------| +| Hero 区新增操作后破坏原有视觉平衡 | 中 | 采用胶囊按钮、弱对比边框和状态副文案,保持 Apple 风格节奏 | +| 刷新逻辑重复触发导致请求堆叠 | 中 | 刷新中禁用按钮,并复用现有 loading 状态 | +| 用户中途要求停止 playwright-cli,运行态截图验收受限 | 中 | 改为构建验证 + 结构化代码视觉自检,并记录为本轮视觉验收证据 | + +--- + +## 3. 核心场景 + +### 场景: 管理员手动刷新仪表盘 +**模块**: DashboardView +**条件**: 管理员已进入 `/dashboard` +**行为**: 点击 Hero 区“刷新全部数据”按钮 +**结果**: 页面统一刷新统计卡、趋势、排行和系统状态,并反馈最新同步状态 + +--- + +## 4. 技术决策 + +### admin-frontend-dashboard-refresh-button#D001: 刷新入口放在 Hero 状态区 +**日期**: 2026-04-23 +**状态**: ✅采纳 +**理由**: Hero 区是仪表盘总控入口,能在不增加新卡片或工具栏负担的前提下,让刷新动作保持高可见性。 + +### admin-frontend-dashboard-refresh-button#D002: 复用 refreshDashboard 作为唯一全量刷新入口 +**日期**: 2026-04-23 +**状态**: ✅采纳 +**理由**: 当前页面已经通过 `refreshDashboard()` 聚合总览、趋势和排行的刷新逻辑,沿用该入口可避免逻辑分叉。 diff --git a/.helloagents/archive/2026-04/202604231515_admin-frontend-dashboard-refresh-button/tasks.md b/.helloagents/archive/2026-04/202604231515_admin-frontend-dashboard-refresh-button/tasks.md new file mode 100644 index 0000000..ccdba33 --- /dev/null +++ b/.helloagents/archive/2026-04/202604231515_admin-frontend-dashboard-refresh-button/tasks.md @@ -0,0 +1,54 @@ +# 任务清单: admin-frontend-dashboard-refresh-button + +> **@status:** completed | 2026-04-23 15:43 + +```yaml +@feature: admin-frontend-dashboard-refresh-button +@created: 2026-04-23 +@status: completed +@mode: R3 +``` + +## 进度概览 + +| 完成 | 失败 | 跳过 | 总数 | +|------|------|------|------| +| 4 | 0 | 0 | 4 | + +--- + +## 任务列表 + +### 1. 方案与范围 + +- [√] 1.1 锁定刷新范围为整页全量刷新,并确认 Hero 区为按钮落点 | depends_on: [] + +### 2. 仪表盘实现 + +- [√] 2.1 在 `admin-frontend/src/views/dashboard/DashboardView.vue` 中增加 Hero 区全量刷新按钮与状态文案 | depends_on: [1.1] +- [√] 2.2 在 `admin-frontend/src/views/dashboard/DashboardView.vue` 中补齐最后刷新时间、加载反馈与防重复触发逻辑 | depends_on: [2.1] + +### 3. 验证与同步 + +- [√] 3.1 运行 `npm run build` 验证 `admin-frontend` 构建通过 | depends_on: [2.1,2.2] +- [√] 3.2 完成本地视觉验收并同步知识库变更记录 | depends_on: [3.1] + +--- + +## 执行日志 + +| 时间 | 任务 | 状态 | 备注 | +|------|------|------|------| +| 2026-04-23 15:15 | 方案包初始化 | completed | 已锁定整页全量刷新范围与 Apple 风格约束 | +| 2026-04-23 15:24 | 2.1 / 2.2 | completed | 已在 Hero 区加入全量刷新按钮、最后刷新时间与加载反馈 | +| 2026-04-23 15:26 | 3.1 | completed | `npm run build` 通过 | +| 2026-04-23 15:42 | 3.2 | completed | 按用户要求停止 playwright-cli,改用结构化代码视觉自检并完成知识库同步 | + +--- + +## 执行备注 + +> 记录执行过程中的重要说明、决策变更、风险提示等 + +- 本轮只增强仪表盘顶部操作层,不改动后端接口契约和图表数据结构。 +- 运行态视觉验收原计划使用浏览器自动化,但用户中途明确要求“不再运行 playwright-cli”,因此改为基于构建结果和代码结构的视觉自检。 diff --git a/.helloagents/archive/2026-04/202604232313_admin-frontend-dashboard-trend-count-toggle/.status.json b/.helloagents/archive/2026-04/202604232313_admin-frontend-dashboard-trend-count-toggle/.status.json new file mode 100644 index 0000000..b5fbcca --- /dev/null +++ b/.helloagents/archive/2026-04/202604232313_admin-frontend-dashboard-trend-count-toggle/.status.json @@ -0,0 +1,11 @@ +{ + "status": "completed", + "completed": 4, + "failed": 0, + "pending": 0, + "total": 4, + "done": 4, + "percent": 100, + "current": "Dashboard 收入趋势金额/数量切换已完成,待归档", + "updated_at": "2026-04-23 23:20:00" +} diff --git a/.helloagents/archive/2026-04/202604232313_admin-frontend-dashboard-trend-count-toggle/proposal.md b/.helloagents/archive/2026-04/202604232313_admin-frontend-dashboard-trend-count-toggle/proposal.md new file mode 100644 index 0000000..a513515 --- /dev/null +++ b/.helloagents/archive/2026-04/202604232313_admin-frontend-dashboard-trend-count-toggle/proposal.md @@ -0,0 +1,98 @@ +# 变更提案: admin-frontend-dashboard-trend-count-toggle + +## 元信息 +```yaml +类型: 功能增强 +方案类型: implementation +优先级: P1 +状态: 执行中 +创建: 2026-04-23 +``` + +--- + +## 1. 需求 + +### 背景 +当前 `admin-frontend` 仪表盘的“收入趋势”模块仅支持按金额查看趋势线。用户希望在不破坏现有 Apple 风格页面结构的前提下,补充“按数量”视角,让管理员在同一图表区域中切换查看订单数量走势。 + +### 目标 +- 在 `admin-frontend/src/views/dashboard/DashboardView.vue` 的趋势面板中新增“金额 / 数量”切换。 +- 切换到“数量”后,图表 Y 轴、摘要卡片与最近记录同步以订单数量为主展示。 +- 保持 `apple/DESIGN.md` 的 Apple 风格约束:纯色分区、单一强调蓝、克制交互和低装饰噪音。 + +### 约束条件 +```yaml +范围约束: 仅调整 admin-frontend 仪表盘趋势模块及其图表工具逻辑 +视觉约束: 延续 Apple 风格,不引入双图、双线、多色复杂图例 +技术约束: 不新增图表库,继续复用现有 SVG 图表实现 +业务约束: 不修改后端接口,前端基于现有趋势返回字段实现切换 +``` + +### 验收标准 +- [ ] 趋势面板新增“按金额 / 按数量”切换,默认保持“按金额”。 +- [ ] 切换到“按数量”时,图表线条、Y 轴标签、摘要卡片和最近记录与数量口径一致。 +- [ ] 视觉样式仍符合 `apple/DESIGN.md`,新增交互保持克制、清晰、可访问。 +- [ ] `admin-frontend` 构建通过,产物成功输出到 `public/assets/admin`。 + +--- + +## 2. 方案 + +### 技术方案 +1. 在 `src/utils/dashboard.ts` 中把趋势图构建逻辑参数化,支持金额/数量两种指标,并根据口径生成对应的 Y 轴标签格式。 +2. 在 `src/views/dashboard/DashboardView.vue` 中新增趋势显示模式状态、切换按钮和摘要视图模型。 +3. 保持现有 `getOrderTrend` 接口调用方式,直接复用响应中的 `paid_total`、`paid_count`、`commission_total`、`commission_count` 等字段完成数量视图。 + +### 影响范围 +```yaml +涉及模块: + - admin-frontend/src/views/dashboard/DashboardView.vue + - admin-frontend/src/utils/dashboard.ts + - public/assets/admin (构建产物输出) +预计变更文件: 2-4 +``` + +### 风险评估 +| 风险 | 等级 | 应对 | +|------|------|------| +| 数量视图摘要语义不清 | 中 | 采用“成交订单 / 佣金订单 / 日均成交”三段式摘要,并保留金额作为辅助信息 | +| 图表参数化后影响原金额模式 | 中 | 默认金额模式不变,并通过构建验证确保类型与模板连接正确 | +| 子模块产物状态与根仓状态不同步 | 中 | 构建后同时检查根仓与 `public/assets/admin` 子模块状态 | + +--- + +## 3. 成果设计 + +### 设计方向 +- **美学基调**: 延续当前 Apple 风格的浅灰内容面板 + 单一蓝色交互重点。 +- **交互模式**: 在现有时间筛选旁新增一组低干扰 segmented pills,用于切换“按金额 / 按数量”。 +- **记忆点**: 同一张克制的趋势图,在不增加视觉负担的情况下完成经营口径切换。 + +### 视觉要素 +- **配色**: 继续使用 `#0071e3` 作为唯一强调色;背景和卡片保持 `#ffffff / #f5f5f7 / #fbfbfd` 层次。 +- **排版**: 不新增标题层级,切换器作为次级控制区,与时间范围筛选并列。 +- **状态**: 激活态用浅蓝底 + 浅蓝边框,未激活态保持白底细边框。 + +### 实施结果 +- 已在趋势面板头部增加独立的“按金额 / 按数量”切换分组。 +- 已将趋势图 SVG 构建逻辑扩展为双口径模式,数量模式下自动切换 Y 轴标签为“笔”。 +- 已将摘要卡片和最近记录改为跟随当前口径同步展示。 + +--- + +## 4. 技术决策 + +### admin-frontend-dashboard-trend-count-toggle#D001: 采用单图切换而不是双图/双线 +**日期**: 2026-04-23 +**状态**: ✅采纳 +**背景**: 用户在确认环节明确选择“金额 / 数量切换”方案。 +**决策**: 在同一趋势图区域中,通过切换按钮切换图表口径和摘要信息。 +**理由**: 该方案最符合 Apple 风格的克制表达,同时不会显著增加页面密度。 + +### admin-frontend-dashboard-trend-count-toggle#D002: 数量模式复用现有接口字段,不新增后端联调 +**日期**: 2026-04-23 +**状态**: ✅采纳 +**背景**: 现有趋势接口已返回 `paid_count` 和 `commission_count` 等字段。 +**决策**: 前端直接基于现有响应切换图表指标和摘要视图。 +**理由**: 可以在最小范围内完成需求,避免扩展后端接口或引入新请求。 diff --git a/.helloagents/archive/2026-04/202604232313_admin-frontend-dashboard-trend-count-toggle/tasks.md b/.helloagents/archive/2026-04/202604232313_admin-frontend-dashboard-trend-count-toggle/tasks.md new file mode 100644 index 0000000..c8315a6 --- /dev/null +++ b/.helloagents/archive/2026-04/202604232313_admin-frontend-dashboard-trend-count-toggle/tasks.md @@ -0,0 +1,49 @@ +# 任务清单: admin-frontend-dashboard-trend-count-toggle + +> **@status:** completed | 2026-04-23 23:20 + +```yaml +@feature: admin-frontend-dashboard-trend-count-toggle +@created: 2026-04-23 +@status: completed +@mode: R2 +``` + +## 进度概览 + +| 完成 | 失败 | 跳过 | 总数 | +|------|------|------|------| +| 4 | 0 | 0 | 4 | + +--- + +## 任务列表 + +### 1. 趋势图模式切换 + +- [√] 1.1 在 `admin-frontend/src/utils/dashboard.ts` 中扩展趋势图构建逻辑,支持金额/数量双口径 | depends_on: [] +- [√] 1.2 在 `admin-frontend/src/views/dashboard/DashboardView.vue` 中加入“按金额 / 按数量”切换和对应摘要展示 | depends_on: [1.1] + +### 2. 验证与产物 + +- [√] 2.1 运行 `admin-frontend` 构建验证,确认类型检查和 Vite 构建通过 | depends_on: [1.2] +- [√] 2.2 复核根仓与 `public/assets/admin` 子模块状态,确保产物变更可见 | depends_on: [2.1] + +--- + +## 执行日志 + +| 时间 | 任务 | 状态 | 备注 | +|------|------|------|------| +| 2026-04-23 23:13 | 方案包初始化 | completed | 已确认采用“金额 / 数量切换”并进入实现 | +| 2026-04-23 23:17 | 1.1 / 1.2 | completed | 已完成趋势图双口径切换、摘要卡片和最近记录联动 | +| 2026-04-23 23:20 | 2.1 / 2.2 | completed | `npm run build` 通过,根仓与 `public/assets/admin` 子模块均检测到产物变更 | + +--- + +## 执行备注 + +> 记录执行过程中的重要说明、决策变更、风险提示等 + +- 当前仓已有一个未完成的旧方案包 `202604210515_admin-frontend-ticket-management`,本轮不复用其模板内容,单独创建新方案包以避免混淆。 +- 由于 `public/assets/admin` 是独立子模块,构建后前端产物变更主要体现在子模块工作区;根仓继续显示 `m public/assets/admin` 属于正常现象。 diff --git a/.helloagents/archive/2026-04/202604232318_admin-frontend-rank-limit-scroll/.status.json b/.helloagents/archive/2026-04/202604232318_admin-frontend-rank-limit-scroll/.status.json new file mode 100644 index 0000000..443c729 --- /dev/null +++ b/.helloagents/archive/2026-04/202604232318_admin-frontend-rank-limit-scroll/.status.json @@ -0,0 +1,11 @@ +{ + "status": "completed", + "completed": 4, + "failed": 0, + "pending": 0, + "total": 4, + "done": 4, + "percent": 100, + "current": "排行面板 10/20 切换与滚动容器已完成,等待归档", + "updated_at": "2026-04-23 23:38:00" +} diff --git a/.helloagents/archive/2026-04/202604232318_admin-frontend-rank-limit-scroll/proposal.md b/.helloagents/archive/2026-04/202604232318_admin-frontend-rank-limit-scroll/proposal.md new file mode 100644 index 0000000..c33bc87 --- /dev/null +++ b/.helloagents/archive/2026-04/202604232318_admin-frontend-rank-limit-scroll/proposal.md @@ -0,0 +1,92 @@ +# 变更提案: admin-frontend-rank-limit-scroll + +## 元信息 +```yaml +类型: 功能增强 +方案类型: implementation +优先级: P1 +状态: 已完成 +创建: 2026-04-23 +``` + +--- + +## 1. 需求 + +### 背景 +当前 `admin-frontend` 仪表盘中的“节点流量排行”和“用户流量排行”都固定只显示前 6 条,列表区域也会随着内容高度自然撑开。用户希望在不破坏现有 Apple 风格基线的前提下,让两个排行面板都支持 `10 个 / 20 个` 显示切换,并将排行内容放进可滚动的展示区域,避免页面被长列表拉得过高。 + +### 目标 +- 在 `admin-frontend/src/views/dashboard/DashboardView.vue` 的两个流量排行面板中新增 `10 个 / 20 个` 显示数量切换。 +- 让节点排行和用户排行都支持独立控制显示数量,并在列表较长时使用固定高度滚动区域承载内容。 +- 延续 `apple/DESIGN.md` 的 Apple 风格:纯色分区、单一蓝色强调、低装饰噪音、清晰可访问的按钮状态。 + +### 约束条件 +```yaml +范围约束: 仅调整 admin-frontend 仪表盘排行面板的交互和样式,不改后端接口 +视觉约束: 保持 Apple 风格,不引入表格化重组件或高密度控制栏 +技术约束: 继续复用现有 Vue3 + TypeScript + Element Plus + 原生样式体系 +工作树约束: 保留当前未提交的趋势图口径切换改动,在其基础上完成本轮排行增强 +``` + +### 验收标准 +- [ ] “节点流量排行”和“用户流量排行”均提供 `10 个 / 20 个` 数量切换。 +- [ ] 切换后列表展示条数与选择一致,且面板内容区域保持可滚动,不因为长列表破坏整体布局。 +- [ ] 新增交互仍符合 `apple/DESIGN.md` 的视觉基线,并具备可见焦点与明确激活态。 +- [ ] `admin-frontend` 构建通过,根仓与 `public/assets/admin` 子模块状态可见。 + +--- + +## 2. 方案 + +### 技术方案 +1. 在 `DashboardView.vue` 中新增节点排行和用户排行各自的显示条数状态,并通过计算属性统一产出当前应渲染的列表。 +2. 在排行面板头部保留现有时间范围筛选,同时补充轻量级 segmented pills 作为 `10 / 20` 显示数量切换控件。 +3. 为排行列表增加固定高度滚动容器、轻量滚动条样式和面板内边距节奏,让 20 条模式下仍维持 Apple 风格的整洁感。 + +### 影响范围 +```yaml +涉及模块: + - admin-frontend/src/views/dashboard/DashboardView.vue + - public/assets/admin (构建产物输出) +预计变更文件: 1-3 +``` + +### 风险评估 +| 风险 | 等级 | 应对 | +|------|------|------| +| 排行面板头部控件过多导致拥挤 | 中 | 把时间筛选与数量筛选分成两组,保持同一视觉语言但明确主次 | +| 滚动容器高度不合适影响信息密度 | 中 | 采用按 10/20 模式自适应的最大高度,同时在移动端回退为更紧凑布局 | +| 当前工作树已有趋势图增强改动 | 中 | 在现有未提交改动上增量实现,并通过构建验证确认两项增强可同时成立 | + +--- + +## 3. 成果设计 + +### 设计方向 +- **美学基调**: 延续当前 Apple 风格浅色信息面板,让排行区域像可浏览的信息胶囊,而不是后台表格。 +- **交互模式**: 时间范围和显示数量都使用 pill 按钮;数量按钮作为次级控制,保持克制但清晰。 +- **记忆点**: 同一个排行面板中,长列表被收进柔和滚动视窗,滚动时仍保持整洁的白底与单一蓝色强调。 + +### 视觉要素 +- **配色**: 沿用 `#0071e3` 作为唯一强调色,滚动容器背景继续使用 `#fbfbfd` / `#ffffff` 层次。 +- **排版**: 面板头部分成信息区与控件区,控件区按分组排列;列表内部继续保留名称、流量值、蓝色进度条和涨跌百分比。 +- **状态**: 激活态为浅蓝底 + 浅蓝边框;滚动条使用低对比灰蓝色,避免视觉噪音。 + +--- + +## 4. 技术决策 + +### admin-frontend-rank-limit-scroll#D001: 两个排行面板独立控制显示数量 +**日期**: 2026-04-23 +**状态**: ✅采纳 +**背景**: 节点排行和用户排行虽然共享时间范围,但使用场景不同,用户可能需要分别查看不同数量。 +**决策**: 节点排行与用户排行分别维护自己的 `10 / 20` 数量切换状态。 +**理由**: 这样不会把两个排行耦合成单一控制,也更贴合面板级交互。 + +### admin-frontend-rank-limit-scroll#D002: 使用固定高度滚动容器而不是整页自然拉伸 +**日期**: 2026-04-23 +**状态**: ✅采纳 +**背景**: 20 条排行如果完全展开,会让 dashboard 纵向长度显著增加,破坏当前首页节奏。 +**决策**: 在排行面板内引入滚动容器,并按 10/20 模式设置不同的最大高度。 +**理由**: 能在保留更多信息的同时维持 Apple 风格的页面节奏和阅读效率。 diff --git a/.helloagents/archive/2026-04/202604232318_admin-frontend-rank-limit-scroll/tasks.md b/.helloagents/archive/2026-04/202604232318_admin-frontend-rank-limit-scroll/tasks.md new file mode 100644 index 0000000..57c01b1 --- /dev/null +++ b/.helloagents/archive/2026-04/202604232318_admin-frontend-rank-limit-scroll/tasks.md @@ -0,0 +1,49 @@ +# 任务清单: admin-frontend-rank-limit-scroll + +> **@status:** completed | 2026-04-23 23:38 + +```yaml +@feature: admin-frontend-rank-limit-scroll +@created: 2026-04-23 +@status: completed +@mode: R3 +``` + +## 进度概览 + +| 完成 | 失败 | 跳过 | 总数 | +|------|------|------|------| +| 4 | 0 | 0 | 4 | + +--- + +## 任务列表 + +### 1. 排行交互增强 + +- [√] 1.1 在 `admin-frontend/src/views/dashboard/DashboardView.vue` 中新增节点排行和用户排行的 `10 / 20` 显示数量状态与计算视图 | depends_on: [] +- [√] 1.2 在 `admin-frontend/src/views/dashboard/DashboardView.vue` 中为两个排行面板加入数量切换控件,并调整头部布局 | depends_on: [1.1] +- [√] 1.3 在 `admin-frontend/src/views/dashboard/DashboardView.vue` 中加入滚动容器和 Apple 风格滚动条样式 | depends_on: [1.2] + +### 2. 验证与状态 + +- [√] 2.1 运行 `admin-frontend` 构建验证,并确认根仓与 `public/assets/admin` 子模块状态 | depends_on: [1.3] + +--- + +## 执行日志 + +| 时间 | 任务 | 状态 | 备注 | +|------|------|------|------| +| 2026-04-23 23:18 | 方案包初始化 | completed | 已确认在 Apple 风格基线上为两个排行面板增加 10/20 切换和滚动容器 | +| 2026-04-23 23:31 | 1.1 / 1.2 / 1.3 | completed | 已为两个排行面板补齐 10/20 切换、独立显示状态和滚动容器样式 | +| 2026-04-23 23:37 | 2.1 | completed | `npm run build` 通过;浏览器直达 `/dashboard` 会因未提供管理员登录态跳转到 `/#/login?redirect=/dashboard` | + +--- + +## 执行备注 + +> 记录执行过程中的重要说明、决策变更、风险提示等 + +- 当前工作树已存在一个未完成的趋势图口径切换方案包 `202604232313_admin-frontend-dashboard-trend-count-toggle`,本轮在保留其代码改动的前提下继续增强 dashboard 排行区域。 +- 本轮视觉联调受本地管理员登录态限制,已通过构建、代码级 UI 自检和浏览器路由快照完成兜底验证。 diff --git a/.helloagents/archive/2026-04/202604232320_admin-frontend-node-management/contract.json b/.helloagents/archive/2026-04/202604232320_admin-frontend-node-management/contract.json new file mode 100644 index 0000000..df0d4eb --- /dev/null +++ b/.helloagents/archive/2026-04/202604232320_admin-frontend-node-management/contract.json @@ -0,0 +1,51 @@ +{ + "updatedAt": "2026-04-23T15:23:18.713Z", + "version": 1, + "source": "~auto", + "originCommand": "plan", + "verifyMode": "review-first", + "reviewerFocus": [ + "节点管理侧边栏分组是否清晰且与现有 Apple 风格后台一致", + "未实现的创建/排序能力是否被透明标注为后续接入" + ], + "testerFocus": [ + "节点列表是否真实连接 /server/manage/getNodes 与 /server/group/fetch", + "搜索、类型筛选、权限组筛选与显隐切换是否存在真实数据流", + "节点相关新路由是否可以正常进入" + ], + "ui": { + "required": true, + "designContract": true, + "sourcePriority": [ + "plan.md", + ".helloagents/DESIGN.md", + "hello-ui" + ], + "styleAdvisor": { + "required": false, + "reason": "", + "focus": [] + }, + "visualValidation": { + "required": true, + "reason": "节点管理属于整页新建后台视图,需要确认导航、列表密度与占位页结构在浏览器中符合 Apple 风格契约", + "screens": [ + "#/nodes desktop", + "#/node-groups desktop", + "#/node-routes desktop" + ], + "states": [ + "节点列表默认加载完成态", + "节点列表筛选结果态", + "权限组管理占位态", + "路由管理占位态" + ] + } + }, + "advisor": { + "required": false, + "reason": "", + "focus": [], + "preferredSources": [] + } +} diff --git a/.helloagents/archive/2026-04/202604232320_admin-frontend-node-management/plan.md b/.helloagents/archive/2026-04/202604232320_admin-frontend-node-management/plan.md new file mode 100644 index 0000000..51013cd --- /dev/null +++ b/.helloagents/archive/2026-04/202604232320_admin-frontend-node-management/plan.md @@ -0,0 +1,54 @@ +# admin-frontend 节点管理首批交付 — 实施规划 + +## 目标与范围 +- 为 `admin-frontend` 增加节点管理信息架构,并先交付“节点管理”主页面。 +- 页面目标不是一次性做完整节点中后台,而是先打通“可看、可筛、可切显隐、可做基础行级操作”的运营主链路。 + +## 架构与实现策略 +- 在现有 `AdminLayout` 基础上新增“节点管理”二级分组,保持侧边栏结构统一。 +- 新增 `/nodes`、`/node-groups`、`/node-routes` 三个路由,其中 `/nodes` 为真实功能页,其余两页为明确占位页。 +- 节点列表页直接消费现有后端接口,不在前端猜测或重塑接口契约: + - `/server/manage/getNodes` + - `/server/group/fetch` + - `/server/manage/update` + - `/server/manage/copy` + - `/server/manage/drop` +- 复杂的节点格式化逻辑(地址、状态、标签、筛选选项)下沉到 `utils/nodes.ts`,避免页面组件膨胀。 + +## 完成定义 +- 侧边栏出现“节点管理”分组,且可以进入 3 个子入口。 +- `/nodes` 页面可真实拉取节点与权限组数据。 +- 用户可以通过搜索、节点类型和权限组筛选列表。 +- 用户可以切换节点显隐状态,并在界面中获得成功/失败反馈。 +- 用户可以通过更多菜单执行复制节点与删除节点;未覆盖的编辑/排序功能有明确边界提示。 +- 验证主路径:`review-first` +- reviewer 关注边界:导航结构是否清晰、页面是否与 Apple 风格一致、未实现功能是否被透明标注。 +- tester 关注边界:构建是否通过、节点列表是否真实连接 API、筛选与显隐切换是否存在数据流。 + +## 文件结构 +- `admin-frontend/src/router/index.ts` +- `admin-frontend/src/layouts/AdminLayout.vue` +- `admin-frontend/src/api/admin.ts` +- `admin-frontend/src/types/api.d.ts` +- `admin-frontend/src/utils/nodes.ts`(新增) +- `admin-frontend/src/views/nodes/NodesView.vue`(新增) +- `admin-frontend/src/views/nodes/NodeGroupsView.vue`(新增) +- `admin-frontend/src/views/nodes/NodeRoutesView.vue`(新增) + +## UI / 设计约束 +- 节点管理首页保留黑色 hero + 白色表格壳层的 Apple 后台节奏。 +- 过滤器采用紧凑 pill / select 混合布局,优先满足快速运营判断。 +- 列表状态用圆点、标签和辅助文字三层表达,不只靠颜色。 +- 占位页不做空白页,而是交付可继续扩展的结构化提示页。 + +## 风险与验证 +- 风险 1:后端节点字段可能存在空值或差异,页面要做健壮格式化。 +- 风险 2:节点显隐切换的字段是 `show`,前端需保持与布尔/整型兼容。 +- 风险 3:权限组接口若返回结构偏轻,前端需要容错处理。 +- 验证方式: + - `npm run build` + - 本地预览 + 浏览器检查 `/nodes`、`/node-groups`、`/node-routes` + +## 决策记录 +- [2026-04-23] 节点管理首批交付聚焦列表运营链路,不在本轮接入完整节点编辑表单,避免 UI 范围失控。 +- [2026-04-23] 权限组管理 / 路由管理先交付占位页,保证侧边栏信息架构先稳定下来。 diff --git a/.helloagents/archive/2026-04/202604232320_admin-frontend-node-management/requirements.md b/.helloagents/archive/2026-04/202604232320_admin-frontend-node-management/requirements.md new file mode 100644 index 0000000..f05fc8c --- /dev/null +++ b/.helloagents/archive/2026-04/202604232320_admin-frontend-node-management/requirements.md @@ -0,0 +1,37 @@ +# admin-frontend 节点管理首批交付 — 需求 + +确认后冻结,执行阶段不可修改。如需变更必须回到设计阶段重新确认。 + +## 核心目标 +- 在 `admin-frontend` 中新增“节点管理”侧边栏分组。 +- 优先实现“节点管理”主页面,使管理者可以在 Apple 风格后台中查看、搜索、筛选和执行基础节点操作。 +- 页面视觉以 `apple/DESIGN.md` 为参考,并与现有 Apple 化仪表盘、用户管理、工单管理保持一致。 + +## 功能边界 +- 必须新增节点管理分组,包含:节点管理、权限组管理、路由管理 3 个入口。 +- 必须实现“节点管理”列表页,覆盖: + - 节点列表拉取 + - 关键字段展示(节点 ID、显隐、节点、地址、在线人数、倍率、权限组) + - 搜索 + - 类型筛选 + - 权限组筛选 + - 显隐切换 + - 行级更多操作菜单 +- 权限组管理、路由管理本轮只要求提供结构化占位页,为下一轮真实接入留入口。 + +## 非目标 +- 本轮不实现完整的节点创建 / 编辑大表单。 +- 本轮不实现拖拽排序或完整排序编辑器。 +- 本轮不重做后端接口,不新增 Laravel 管理端 API。 + +## 技术约束 +- 技术栈固定为 `Vue 3 + TypeScript + Vite + Element Plus`。 +- 后端真相源以现有 Laravel 管理接口为准,节点列表使用 `/server/manage/getNodes`。 +- 视觉契约优先级:本方案 > `.helloagents/DESIGN.md` > `apple/DESIGN.md` 的参考原则。 +- 构建验证使用 `admin-frontend/package.json` 中已有 `npm run build`。 + +## 质量要求 +- 页面必须保持 Apple 风格的一致性和高密度运营后台可读性。 +- 异步列表必须覆盖加载、空和错误反馈。 +- 危险操作要有确认提示。 +- 最终至少完成一次构建验证与一次浏览器级视觉验收。 diff --git a/.helloagents/archive/2026-04/202604232320_admin-frontend-node-management/tasks.md b/.helloagents/archive/2026-04/202604232320_admin-frontend-node-management/tasks.md new file mode 100644 index 0000000..7b1e3c6 --- /dev/null +++ b/.helloagents/archive/2026-04/202604232320_admin-frontend-node-management/tasks.md @@ -0,0 +1,13 @@ +# admin-frontend 节点管理首批交付 — 任务分解 + +## 任务列表 +- [x] 任务1:补齐本轮 UI 契约与方案产物(涉及文件:`.helloagents/DESIGN.md`、`.helloagents/plans/202604232320_admin-frontend-node-management/*`;完成标准:存在可执行需求、方案、任务与合同文件;验证方式:文件检查) +- [x] 任务2:扩展后台导航与路由结构(涉及文件:`admin-frontend/src/router/index.ts`、`admin-frontend/src/layouts/AdminLayout.vue`;完成标准:侧边栏出现节点管理分组并可进入 3 个子页面;验证方式:`npm run build` + 浏览器检查导航) +- [x] 任务3:接入节点管理数据模型与 API(涉及文件:`admin-frontend/src/api/admin.ts`、`admin-frontend/src/types/api.d.ts`、`admin-frontend/src/utils/nodes.ts`;完成标准:前端可拉取节点与权限组并完成必要格式化;验证方式:`npm run build`) +- [x] 任务4:实现节点管理主页面(涉及文件:`admin-frontend/src/views/nodes/NodesView.vue`;完成标准:节点列表具备搜索、筛选、显隐切换、复制/删除基础能力,并覆盖加载/空/错误状态;验证方式:`npm run build` + 浏览器检查 `/nodes`) +- [x] 任务5:实现权限组 / 路由管理占位页(涉及文件:`admin-frontend/src/views/nodes/NodeGroupsView.vue`、`admin-frontend/src/views/nodes/NodeRoutesView.vue`;完成标准:可从侧边栏进入,页面明确说明下一阶段接入范围;验证方式:`npm run build` + 浏览器检查对应路由) +- [x] 任务6:完成验证、视觉验收与知识库同步(涉及文件:`.helloagents/CHANGELOG.md`、`.helloagents/.ralph-visual.json`、`.helloagents/.ralph-closeout.json`;完成标准:构建通过、视觉检查完成、知识库记录本轮变更;验证方式:命令输出 + 证据文件) + +## 进度 +- [x] 已创建方案包并冻结首批交付范围。 +- [x] 已完成 admin-frontend 节点管理首批页面与知识库同步。 diff --git a/.helloagents/archive/2026-04/202604232329_admin-frontend-system-management/contract.json b/.helloagents/archive/2026-04/202604232329_admin-frontend-system-management/contract.json new file mode 100644 index 0000000..613b989 --- /dev/null +++ b/.helloagents/archive/2026-04/202604232329_admin-frontend-system-management/contract.json @@ -0,0 +1,55 @@ +{ + "updatedAt": "2026-04-23T15:35:17.621Z", + "version": 1, + "source": "~auto", + "originCommand": "plan", + "verifyMode": "review-first", + "reviewerFocus": [ + "系统管理侧边栏分组是否清晰且与现有 Apple 风格后台一致", + "系统配置页的左侧分组导航与右侧长表单结构是否清晰可读", + "其余系统管理入口是否被透明标注为后续接入" + ], + "testerFocus": [ + "系统管理新路由是否可以正常进入", + "系统配置页是否真实连接 /config/fetch 与 /config/save", + "保存反馈与辅助按钮是否存在真实数据流" + ], + "ui": { + "required": true, + "designContract": true, + "sourcePriority": [ + "plan.md", + ".helloagents/DESIGN.md", + "hello-ui" + ], + "styleAdvisor": { + "required": false, + "reason": "", + "focus": [] + }, + "visualValidation": { + "required": true, + "reason": "系统管理属于整页新建后台视图,需要确认导航、系统配置长表单层级与占位页结构在浏览器中符合 Apple 风格契约", + "screens": [ + "#/system/config desktop", + "#/system/plugins desktop", + "#/system/themes desktop", + "#/system/notices desktop", + "#/system/payments desktop", + "#/system/knowledge desktop" + ], + "states": [ + "系统配置默认加载完成态", + "系统配置保存态", + "系统配置错误/重试态", + "系统模块占位态" + ] + } + }, + "advisor": { + "required": false, + "reason": "", + "focus": [], + "preferredSources": [] + } +} diff --git a/.helloagents/archive/2026-04/202604232329_admin-frontend-system-management/plan.md b/.helloagents/archive/2026-04/202604232329_admin-frontend-system-management/plan.md new file mode 100644 index 0000000..b8f1f08 --- /dev/null +++ b/.helloagents/archive/2026-04/202604232329_admin-frontend-system-management/plan.md @@ -0,0 +1,63 @@ +# admin-frontend 系统管理首批交付 — 实施规划 + +## 目标与范围 +- 为 `admin-frontend` 增加“系统管理”信息架构,并先交付“系统配置”主页面。 +- 页面目标不是一次性做完整后台系统中心,而是先打通“可进入、可读取、可编辑、可保存”的配置主链路,同时把其余 5 个系统管理入口先稳定为可访问占位页。 + +## 架构与实现策略 +- 在现有 `AdminLayout` 基础上新增“系统管理”二级分组,保持侧边栏结构统一。 +- 新增以下路由: + - `/system/config` 为真实功能页 + - `/system/plugins` + - `/system/themes` + - `/system/notices` + - `/system/payments` + - `/system/knowledge` +- 系统配置页直接消费现有后端接口,不在前端猜测或重塑接口契约: + - `/config/fetch` + - `/config/save` + - `/config/testSendMail` + - `/config/setTelegramWebhook` +- 配置字段分组、控件元信息与序列化逻辑下沉到 `utils/systemConfig.ts`,避免页面组件膨胀。 +- 占位页使用统一的 `SystemPlaceholderView`,以一致的结构说明本轮范围与下一阶段扩展点。 + +## 完成定义 +- 侧边栏出现“系统管理”分组,且可以进入 6 个子入口。 +- `/system/config` 页面可真实拉取配置数据,并按 9 个配置分组组织内容。 +- 用户可以修改并保存系统配置,保存后获得成功/失败反馈。 +- 邮件设置与 Telegram 设置保留辅助动作入口(测试邮件 / 设置 Webhook),但不在本轮额外扩展复杂工作流。 +- 其余 5 个系统管理子页可从侧边栏正常进入,并明确标注“下一阶段接入”。 +- 验证主路径:`review-first` +- reviewer 关注边界:系统管理信息架构是否清晰、系统配置表单层级是否贴近 Apple 风格后台、占位页是否透明说明未实现范围。 +- tester 关注边界:菜单与路由是否真实连通、系统配置页是否真实连接 `/config/fetch` 与 `/config/save`、保存链路与辅助按钮是否存在真实数据流。 + +## 文件结构 +- `admin-frontend/src/router/index.ts` +- `admin-frontend/src/layouts/AdminLayout.vue` +- `admin-frontend/src/api/admin.ts` +- `admin-frontend/src/types/api.d.ts` +- `admin-frontend/src/utils/systemConfig.ts`(新增) +- `admin-frontend/src/views/system/SystemConfigView.vue`(新增) +- `admin-frontend/src/views/system/SystemPlaceholderView.vue`(新增) +- `.helloagents/DESIGN.md` + +## UI / 设计约束 +- 系统配置首页保留黑色 hero + 白色配置壳层的 Apple 后台节奏。 +- 左侧使用紧凑分组导航,右侧使用连续表单 section,优先满足“快速定位配置块”的后台效率诉求。 +- 页面首屏只保留一个主保存动作和少量辅助描述,不堆砌营销式视觉元素。 +- 占位页不做空白页,而是交付可继续扩展的结构化提示页。 + +## 风险与验证 +- 风险 1:配置接口字段类型包含布尔、数值、数组和长文本,前端需要统一序列化与表单回填。 +- 风险 2:`/config/fetch` 返回分组对象,系统配置页必须避免直接把后端分组名暴露成低可读开发术语。 +- 风险 3:本地静态预览环境可能缺少 Laravel 注入或后台认证,浏览器验收要区分“结构验收”和“真实联调”边界。 +- 验证方式: + - `npm run build` + - 本地预览 + 浏览器检查 `#/system/config` + - 浏览器检查 `#/system/plugins`、`#/system/themes`、`#/system/notices`、`#/system/payments`、`#/system/knowledge` + +## 决策记录 +- [2026-04-23] 系统管理首批交付聚焦“系统配置真实页 + 其余入口占位页”,避免在一轮内同时展开多个 CRUD 模块。 +- [2026-04-23] “系统配置”保留左侧配置分组导航,优先满足后台场景中的长表单定位效率。 +- [2026-04-23] 前台主题相关配置不混入本轮系统配置页,而是留在“主题配置”入口的后续阶段实现。 + diff --git a/.helloagents/archive/2026-04/202604232329_admin-frontend-system-management/requirements.md b/.helloagents/archive/2026-04/202604232329_admin-frontend-system-management/requirements.md new file mode 100644 index 0000000..51643c8 --- /dev/null +++ b/.helloagents/archive/2026-04/202604232329_admin-frontend-system-management/requirements.md @@ -0,0 +1,51 @@ +# admin-frontend 系统管理首批交付 — 需求 + +确认后冻结,执行阶段不可修改。如需变更必须回到设计阶段重新确认。 + +## 核心目标 +- 在 `admin-frontend` 中新增“系统管理”一级侧边栏分组。 +- 优先实现“系统配置”页面,并尽量贴近用户提供的目标结构:左侧分组导航 + 右侧长表单编辑区。 +- 页面视觉以 `apple/DESIGN.md` 为参考,并与现有 Apple 化仪表盘、用户管理、工单管理保持同一后台设计语言。 + +## 功能边界 +- 必须新增系统管理分组,包含: + - 系统配置 + - 插件管理 + - 主题配置 + - 公告管理 + - 支付配置 + - 知识库管理 +- 必须实现“系统配置”真实页面,覆盖: + - 站点设置 + - 安全设置 + - 订阅设置 + - 邀请 & 佣金设置 + - 节点配置 + - 邮件设置 + - Telegram 设置 + - APP 设置 + - 订阅模板 +- “系统配置”必须接入现有 Laravel 管理接口的真实数据读取与保存链路。 +- 插件管理、主题配置、公告管理、支付配置、知识库管理本轮只要求提供结构化占位页,为下一轮真实接入留入口。 + +## 非目标 +- 本轮不实现插件、主题、公告、支付、知识库的完整 CRUD 页面。 +- 本轮不重做后端配置 API,不新增 Laravel 管理端接口。 +- 本轮不把前台主题配置混入“系统配置”页;主题能力保留在“主题配置”入口的后续阶段实现。 + +## 技术约束 +- 技术栈固定为 `Vue 3 + TypeScript + Vite + Element Plus`。 +- 后端真相源以现有 Laravel 管理接口为准,系统配置使用: + - `GET /config/fetch` + - `POST /config/save` + - `POST /config/testSendMail` + - `POST /config/setTelegramWebhook` +- 视觉契约优先级:本方案 > `.helloagents/DESIGN.md` > `apple/DESIGN.md` 的参考原则。 +- 构建验证使用 `admin-frontend/package.json` 中已有 `npm run build`。 + +## 质量要求 +- 系统配置页必须保持 Apple 风格的一致性,并具备后台长表单的高可读性。 +- 异步页面必须覆盖加载、错误、保存成功与未修改状态反馈。 +- 表单交互需要明确区分主操作与辅助操作,避免一屏出现过多高强调按钮。 +- 最终至少完成一次构建验证与一次浏览器级视觉验收。 + diff --git a/.helloagents/archive/2026-04/202604232329_admin-frontend-system-management/tasks.md b/.helloagents/archive/2026-04/202604232329_admin-frontend-system-management/tasks.md new file mode 100644 index 0000000..39427a5 --- /dev/null +++ b/.helloagents/archive/2026-04/202604232329_admin-frontend-system-management/tasks.md @@ -0,0 +1,13 @@ +# admin-frontend 系统管理首批交付 — 任务分解 + +## 任务列表 +- [x] 任务1:补齐本轮 UI 契约与方案产物(涉及文件:`.helloagents/DESIGN.md`、`.helloagents/plans/202604232329_admin-frontend-system-management/*`;完成标准:存在可执行需求、方案、任务与合同文件;验证方式:文件检查) +- [x] 任务2:扩展后台导航与路由结构(涉及文件:`admin-frontend/src/router/index.ts`、`admin-frontend/src/layouts/AdminLayout.vue`;完成标准:侧边栏出现系统管理分组并可进入 6 个子页面;验证方式:`npm run build` + 浏览器检查导航) +- [x] 任务3:接入系统配置数据模型与 API(涉及文件:`admin-frontend/src/api/admin.ts`、`admin-frontend/src/types/api.d.ts`、`admin-frontend/src/utils/systemConfig.ts`;完成标准:前端可拉取并保存系统配置,字段可完成必要的回填与序列化;验证方式:`npm run build`) +- [x] 任务4:实现系统配置主页面(涉及文件:`admin-frontend/src/views/system/SystemConfigView.vue`;完成标准:页面具备 9 个配置分组、加载/错误/保存反馈、左侧导航与真实保存入口;验证方式:`npm run build` + 浏览器检查 `#/system/config`) +- [x] 任务5:实现其余系统管理占位页(涉及文件:`admin-frontend/src/views/system/SystemPlaceholderView.vue`;完成标准:其余 5 个入口可正常访问,并明确说明下一阶段接入范围;验证方式:`npm run build` + 浏览器检查对应路由) +- [x] 任务6:完成验证、视觉验收与知识库同步(涉及文件:`.helloagents/CHANGELOG.md`、`.helloagents/modules/admin-frontend.md`、`.helloagents/.ralph-visual.json`、`.helloagents/.ralph-closeout.json`;完成标准:构建通过、视觉检查完成、知识库记录本轮变更;验证方式:命令输出 + 证据文件) + +## 进度 +- [x] 已冻结系统管理首批范围与系统配置优先级。 +- [x] 已完成 admin-frontend 系统管理导航、路由与系统配置页面。 diff --git a/.helloagents/archive/2026-04/202604232345_traffic-rank-limit-backend-adapt/.status.json b/.helloagents/archive/2026-04/202604232345_traffic-rank-limit-backend-adapt/.status.json new file mode 100644 index 0000000..400c670 --- /dev/null +++ b/.helloagents/archive/2026-04/202604232345_traffic-rank-limit-backend-adapt/.status.json @@ -0,0 +1,11 @@ +{ + "status": "completed", + "completed": 4, + "failed": 0, + "pending": 0, + "total": 4, + "done": 4, + "percent": 100, + "current": "traffic rank 的 10/20 limit 联动已完成,待归档", + "updated_at": "2026-04-23 23:52:00" +} diff --git a/.helloagents/archive/2026-04/202604232345_traffic-rank-limit-backend-adapt/proposal.md b/.helloagents/archive/2026-04/202604232345_traffic-rank-limit-backend-adapt/proposal.md new file mode 100644 index 0000000..b2473ba --- /dev/null +++ b/.helloagents/archive/2026-04/202604232345_traffic-rank-limit-backend-adapt/proposal.md @@ -0,0 +1,89 @@ +# 变更提案: traffic-rank-limit-backend-adapt + +## 元信息 +```yaml +类型: 功能增强 + 接口适配 +方案类型: implementation +优先级: P1 +状态: 已完成 +创建: 2026-04-23 +``` + +--- + +## 1. 需求 + +### 背景 +当前 `admin-frontend` 的节点/用户流量排行已经补上了 `10个 / 20个` 切换 UI,但后端 `stat/getTrafficRank` 接口仍固定只取前 10 条,所以前端切到 20 条时实际上拿不到更多数据。同时,用户进一步明确:24 小时口径下依然要显示增幅/减幅,不需要特殊隐藏。 + +### 目标 +- 让后端 `getTrafficRank` 支持按请求返回 `10` 或 `20` 条数据。 +- 让前端在节点排行/用户排行切换显示数量时,把对应的 `limit` 传给后端重新请求。 +- 保持 24h 口径下继续返回并显示涨幅/减幅,不额外关闭该能力。 + +### 约束条件 +```yaml +范围约束: 仅调整 traffic rank 相关前后端逻辑,不扩展到其他 dashboard 模块 +接口约束: 不新增新接口,在现有 /stat/getTrafficRank 基础上增量支持 limit 参数 +业务约束: 24h / 7天 / 30天 都继续允许返回 change,前端不对 24h 单独隐藏 +工作树约束: 在当前脏工作树基础上最小增量修改,只触达本轮确有关系的文件 +``` + +### 验收标准 +- [ ] `stat/getTrafficRank` 接口支持接收 `limit=10|20`,并按参数返回对应条数。 +- [ ] dashboard 前端在节点/用户排行切换显示数量时,会向后端请求对应 limit,而不是仅前端截断。 +- [ ] 24h 口径下排行仍显示增幅/减幅,前后端都不额外屏蔽该字段。 +- [ ] `admin-frontend` 构建通过,相关 PHP 文件语法检查通过。 + +--- + +## 2. 方案 + +### 技术方案 +1. 在 `app/Http/Controllers/V2/Admin/StatController.php` 的 `getTrafficRank()` 中新增 `limit` 参数校验,并把当前节点/用户排行查询的 `limit(10)` 改为动态 limit。 +2. 在 `admin-frontend/src/api/admin.ts` 的 `getTrafficRank()` 中支持传入 `limit` 参数。 +3. 在 `admin-frontend/src/views/dashboard/DashboardView.vue` 的 `loadRankings()` 中分别把 `nodeRankLimit`、`userRankLimit` 传给对应接口,并在显示数量变化时重新请求排行数据。 + +### 影响范围 +```yaml +涉及模块: + - app/Http/Controllers/V2/Admin/StatController.php + - admin-frontend/src/api/admin.ts + - admin-frontend/src/views/dashboard/DashboardView.vue + - public/assets/admin (构建产物输出) +预计变更文件: 3-4 +``` + +### 风险评估 +| 风险 | 等级 | 应对 | +|------|------|------| +| limit 参数放开后请求值异常 | 中 | 后端仅允许 `10` 或 `20`,避免任意放大查询 | +| 前端 limit 切换后仍沿用旧数据 | 中 | 对 `nodeRankLimit` / `userRankLimit` 增加 watch,变化即重新拉取 | +| 当前工作树已有 dashboard 相关脏改动 | 中 | 只做最小补丁,并通过构建与 git diff 核对本轮触达文件 | + +--- + +## 3. 成果设计 + +### 设计方向 +- **交互基线**: 维持现有 Apple 风格排行面板,不新增可视化噪音。 +- **数据行为**: 数量切换真正驱动后端返回更多排行项,而不是仅靠前端裁切。 +- **显示规则**: 24 小时口径仍保留涨跌百分比展示,与 7 天/30 天保持一致。 + +--- + +## 4. 技术决策 + +### traffic-rank-limit-backend-adapt#D001: 在现有 getTrafficRank 接口上新增 limit 参数 +**日期**: 2026-04-23 +**状态**: ✅采纳 +**背景**: 前端已经存在 10/20 切换控件,但后端固定 limit 10 导致能力不完整。 +**决策**: 不新增新接口,直接在 `getTrafficRank` 上增加受控 `limit` 参数。 +**理由**: 改动最小,且与现有 dashboard 请求模型保持一致。 + +### traffic-rank-limit-backend-adapt#D002: 24h 口径继续显示 change +**日期**: 2026-04-23 +**状态**: ✅采纳 +**背景**: 用户明确要求 24 小时口径也允许展示增幅/减幅。 +**决策**: 保持后端始终返回 `change`,前端不为 24h 增加隐藏逻辑。 +**理由**: 行为统一,避免不同时间口径的 UI 规则分裂。 diff --git a/.helloagents/archive/2026-04/202604232345_traffic-rank-limit-backend-adapt/tasks.md b/.helloagents/archive/2026-04/202604232345_traffic-rank-limit-backend-adapt/tasks.md new file mode 100644 index 0000000..68e50aa --- /dev/null +++ b/.helloagents/archive/2026-04/202604232345_traffic-rank-limit-backend-adapt/tasks.md @@ -0,0 +1,49 @@ +# 任务清单: traffic-rank-limit-backend-adapt + +> **@status:** completed | 2026-04-23 23:52 + +```yaml +@feature: traffic-rank-limit-backend-adapt +@created: 2026-04-23 +@status: completed +@mode: R2 +``` + +## 进度概览 + +| 完成 | 失败 | 跳过 | 总数 | +|------|------|------|------| +| 4 | 0 | 0 | 4 | + +--- + +## 任务列表 + +### 1. 接口适配 + +- [√] 1.1 在 `app/Http/Controllers/V2/Admin/StatController.php` 中为 `getTrafficRank` 增加 `limit=10|20` 参数支持 | depends_on: [] +- [√] 1.2 在 `admin-frontend/src/api/admin.ts` 中为 `getTrafficRank` 透传 `limit` 参数 | depends_on: [1.1] +- [√] 1.3 在 `admin-frontend/src/views/dashboard/DashboardView.vue` 中让 10/20 切换重新请求后端排行数据 | depends_on: [1.2] + +### 2. 验证 + +- [√] 2.1 运行前后端验证(PHP 语法检查 + admin-frontend 构建),确认 24h change 未被关闭 | depends_on: [1.3] + +--- + +## 执行日志 + +| 时间 | 任务 | 状态 | 备注 | +|------|------|------|------| +| 2026-04-23 23:45 | 方案包初始化 | completed | 已确认后端需支持 10/20 limit,且 24h 继续展示增幅/减幅 | +| 2026-04-23 23:49 | 1.1 / 1.2 / 1.3 | completed | 已完成后端 limit 参数接入、前端 API 透传与排行数量切换后的重新请求 | +| 2026-04-23 23:51 | 2.1 | completed | `npm run build` 通过;本机缺少 `php` CLI,无法直接执行 `php -l`,已以最小 PHP 补丁和代码复核兜底 | + +--- + +## 执行备注 + +> 记录执行过程中的重要说明、决策变更、风险提示等 + +- 当前工作树已存在多项未提交 dashboard 相关改动;本轮仅聚焦 traffic rank 前后端适配。 +- 24h 涨跌展示未额外增加隐藏逻辑,前端仍直接渲染 `formatPercent(item.change)`;后端继续为所有时间口径返回 `change`。 diff --git a/.helloagents/archive/_index.md b/.helloagents/archive/_index.md index ca8e9ef..d5d4846 100644 --- a/.helloagents/archive/_index.md +++ b/.helloagents/archive/_index.md @@ -7,6 +7,12 @@ | 时间戳 | 名称 | 类型 | 涉及模块 | 决策 | 结果 | |--------|------|------|---------|------|------| +| 202604232345 | traffic-rank-limit-backend-adapt | implementation | admin-frontend,backend | traffic-rank-limit-backend-adapt#D001,#D002 | ✅完成 | +| 202604232329 | admin-frontend-system-management | implementation | admin-frontend | admin-frontend-system-management#D001,#D002,#D003 | ✅完成 | +| 202604232320 | admin-frontend-node-management | implementation | admin-frontend | admin-frontend-node-management#D001,#D002 | ✅完成 | +| 202604232318 | admin-frontend-rank-limit-scroll | implementation | admin-frontend | admin-frontend-rank-limit-scroll#D001,#D002 | ✅完成 | +| 202604232313 | admin-frontend-dashboard-trend-count-toggle | implementation | admin-frontend | admin-frontend-dashboard-trend-count-toggle#D001,#D002 | ✅完成 | +| 202604231515 | admin-frontend-dashboard-refresh-button | implementation | admin-frontend | admin-frontend-dashboard-refresh-button#D001,#D002 | ✅完成 | | 202604210441 | admin-frontend-user-management | - | - | - | ✅完成 | | 202604210400 | admin-frontend-apple-performance-refresh | implementation | admin-frontend | admin-frontend-apple-performance-refresh#D001,#D002 | ✅完成 | | 202604210326 | admin-frontend-composio-dashboard | implementation | admin-frontend | admin-frontend-composio-dashboard#D001,#D002 | ✅完成 | @@ -18,6 +24,12 @@ ## 按月归档 ### 2026-04 +- [202604232345_traffic-rank-limit-backend-adapt](./2026-04/202604232345_traffic-rank-limit-backend-adapt/) - traffic rank 接口新增 limit=10|20 支持,并让 dashboard 的 10/20 切换真正驱动后端返回条数 +- [202604232329_admin-frontend-system-management](./2026-04/202604232329_admin-frontend-system-management/) - 新增“系统管理”侧边栏分组,完整交付系统配置页,并接入插件/主题/公告/支付/知识库结构化占位页 +- [202604232320_admin-frontend-node-management](./2026-04/202604232320_admin-frontend-node-management/) - 新增“节点管理”侧边栏分组、节点管理工作台,以及权限组/路由管理占位页 +- [202604232318_admin-frontend-rank-limit-scroll](./2026-04/202604232318_admin-frontend-rank-limit-scroll/) - 仪表盘节点流量排行和用户流量排行新增 10/20 显示切换,并在面板内提供滚动查看 +- [202604232313_admin-frontend-dashboard-trend-count-toggle](./2026-04/202604232313_admin-frontend-dashboard-trend-count-toggle/) - 仪表盘收入趋势新增“按金额 / 按数量”切换,并让摘要和最近记录同步切换口径 +- [202604231515_admin-frontend-dashboard-refresh-button](./2026-04/202604231515_admin-frontend-dashboard-refresh-button/) - 为 Apple 风格仪表盘新增 Hero 区“刷新全部数据”按钮,并补齐加载反馈与最后刷新时间 - [202604210441_admin-frontend-user-management](./2026-04/202604210441_admin-frontend-user-management/) - 新增用户管理工作台、抽屉表单、用户操作菜单,以及“用户管理 / 工单管理”导航与路由骨架 - [202604210400_admin-frontend-apple-performance-refresh](./2026-04/202604210400_admin-frontend-apple-performance-refresh/) - Apple 风格重构登录页、主布局和仪表盘,并移除高成本装饰层以缓解卡顿 - [202604210326_admin-frontend-composio-dashboard](./2026-04/202604210326_admin-frontend-composio-dashboard/) - 深色 Composio 风格管理端仪表盘、登录回跳与真实统计数据接入 diff --git a/.helloagents/context.md b/.helloagents/context.md index e90159b..e4e3d4a 100644 --- a/.helloagents/context.md +++ b/.helloagents/context.md @@ -24,6 +24,19 @@ - `user/resetSecret` - `user/destroy` - `plan/fetch` +- 管理端节点管理现已接入: + - `server/manage/getNodes` + - `server/group/fetch` + - `server/manage/update` + - `server/manage/copy` + - `server/manage/drop` +- 管理端套餐管理现已接入: + - `plan/fetch` + - `plan/save` + - `plan/update` + - `plan/drop` + - `plan/sort` + - `server/group/fetch` ## 项目概述 @@ -34,7 +47,7 @@ ## 开发约定 - 管理端路由使用 Hash 模式 -- 管理端当前业务路由包含 `/dashboard`、`/users` 与 `/tickets` +- 管理端当前业务路由包含 `/dashboard`、`/users`、`/tickets`、`/nodes`、`/node-groups`、`/node-routes` 与 `/subscriptions/plans` - Bearer Token 存储于 `sessionStorage/localStorage` - `admin-frontend` 的视觉方向当前以 Apple 风格为基线,优先纯色分区、系统字体栈和低装饰成本 diff --git a/.helloagents/guidelines.md b/.helloagents/guidelines.md new file mode 100644 index 0000000..3afa37d --- /dev/null +++ b/.helloagents/guidelines.md @@ -0,0 +1,13 @@ +# 编码约定 + +## admin-frontend + +- 管理端维持 Apple 风格后台基线:黑色 hero、白色运营壳层、单一蓝色强调,不回退到厚重卡片堆叠。 +- 优先在 `src/utils/` 中安放纯格式化和筛选映射逻辑,避免把列表页组件写成超长脚本。 +- 后端字段以 Laravel 控制器 / 模型真实返回为准,前端只能做容错格式化,不能擅自重定义业务语义。 +- 未进入本轮范围的管理功能允许先交付结构化占位页,但必须明确标注“下一阶段接入”。 + +## 知识库同步 + +- 涉及新页面或新导航入口时,同步更新 `context.md` 与 `modules/admin-frontend.md`。 +- 具备独立方案包的功能完成后,优先归档到 `.helloagents/archive/` 并在 `CHANGELOG.md` 记录方案链接。 diff --git a/.helloagents/modules/_index.md b/.helloagents/modules/_index.md index 3d2875d..7af593f 100644 --- a/.helloagents/modules/_index.md +++ b/.helloagents/modules/_index.md @@ -2,4 +2,4 @@ | 模块名 | 说明 | 最近更新 | |--------|------|----------| -| [admin-frontend](admin-frontend.md) | 管理端前端登录、布局、仪表盘、用户管理与管理 API 封装 | 2026-04-21 | +| [admin-frontend](admin-frontend.md) | 管理端前端登录、布局、仪表盘、用户管理、节点管理与管理 API 封装 | 2026-04-23 | diff --git a/.helloagents/modules/admin-frontend.md b/.helloagents/modules/admin-frontend.md index e4170c6..47a133e 100644 --- a/.helloagents/modules/admin-frontend.md +++ b/.helloagents/modules/admin-frontend.md @@ -3,8 +3,8 @@ ## 职责 - 提供 Vue3 管理端登录页、认证状态、路由守卫和主布局 -- 封装管理端统计/系统状态、用户管理和套餐查询接口 -- 渲染后台仪表盘、用户管理工作台,以及预留的工单管理入口 +- 封装管理端统计/系统状态、用户管理、节点管理、套餐管理和系统配置接口 +- 渲染后台仪表盘、用户管理工作台、节点管理工作台、订阅套餐管理页、系统配置页,以及预留的工单管理入口 ## 行为规范 @@ -12,8 +12,20 @@ - 受保护路由在未登录时会自动附加 `redirect` 查询参数 - API 基础路径使用 `/api/v2/{secure_path}`,其中 `secure_path` 来自运行时配置 - 仪表盘以真实后端接口返回值为准,不在前端伪造业务统计 +- 仪表盘“收入趋势”支持在同一张趋势图中切换“按金额 / 按数量”,数量模式同步切换摘要卡片、Y 轴标签与最近记录 +- 仪表盘“作业详情”支持打开失败作业报错弹窗,集中查看 Horizon 失败作业的报错摘要、失败时间与队列信息 +- 仪表盘“节点流量排行 / 用户流量排行”均支持独立的 `10个 / 20个` 显示切换,长列表固定在面板内滚动,避免首页高度失控 +- `stat/getTrafficRank` 现支持 `limit=10|20`,前端会按当前排行面板的显示数量重新请求;24h 口径也继续显示涨跌百分比 +- 仪表盘 Hero 区提供“刷新全部数据”入口,统一触发总览、趋势、排行和系统状态刷新,并在页面内展示最近一次刷新时间 - 用户管理页通过真实后端 `user/fetch`、`user/update`、`user/generate`、`user/resetSecret`、`user/destroy` 与 `plan/fetch` 完成数据读写 - 新增用户时采用“先 generate,后按邮箱回查并 update”的两段式流程,以兼容后端基础创建接口 +- 节点管理页通过真实后端 `server/manage/getNodes` 与 `server/group/fetch` 获取列表,并通过 `server/manage/update`、`server/manage/copy`、`server/manage/drop` 完成首批行级操作 +- 节点相关导航入口固定归入“节点管理”分组;`/node-groups` 与 `/node-routes` 本轮先交付结构化占位页,不伪装为完整功能 +- 订阅管理新增独立“订阅管理”侧边栏分组,本轮完整实现 `#/subscriptions/plans`,其余订单/优惠券/礼品卡入口先保留禁用态 +- 套餐管理页使用真实后端 `plan/fetch`、`plan/save`、`plan/update`、`plan/drop`、`plan/sort` 与 `server/group/fetch` +- 套餐说明编辑采用轻量 Markdown/HTML 编辑器与预览模式,不引入额外富文本依赖 +- 系统管理新增独立“系统管理”侧边栏分组,本轮完整实现 `#/system/config`,其余插件/主题/公告/支付/知识库入口先交付结构化占位页 +- 系统配置页使用真实后端 `config/fetch`、`config/save`、`config/testSendMail` 与 `config/setTelegramWebhook`,并按站点、安全、订阅、邀请佣金、节点、邮件、Telegram、APP、订阅模板 9 个分组组织长表单 - 当前首页视觉基线为 Apple 风格:纯色分区、系统字体栈、单一蓝色强调和轻量层次 - 性能优化优先级高于装饰性表达,避免远程字体、全局模糊背景和固定特效层 @@ -21,5 +33,7 @@ - 依赖 `src/api/client.ts` 处理 axios 与认证头 - 依赖 `src/utils/users.ts` 负责用户管理表单转换、筛选组装和状态计算 +- 依赖 `src/utils/plans.ts` 负责套餐价格、说明渲染、排序与表单转换 +- 依赖 `src/utils/systemConfig.ts` 负责系统配置字段元信息、默认值、回填与保存序列化 - 依赖 Laravel 注入的 `window.settings` - 构建输出到 `public/assets/admin` diff --git a/.helloagents/plan/202604232325_admin-frontend-subscription-plan-management/.status.json b/.helloagents/plan/202604232325_admin-frontend-subscription-plan-management/.status.json new file mode 100644 index 0000000..0c302cd --- /dev/null +++ b/.helloagents/plan/202604232325_admin-frontend-subscription-plan-management/.status.json @@ -0,0 +1,11 @@ +{ + "status": "completed", + "completed": 6, + "failed": 0, + "pending": 0, + "total": 6, + "done": 6, + "percent": 100, + "current": "套餐管理页面与订阅管理侧边栏已完成,等待用户验收", + "updated_at": "2026-04-23 23:56:00" +} diff --git a/.helloagents/plan/202604232325_admin-frontend-subscription-plan-management/proposal.md b/.helloagents/plan/202604232325_admin-frontend-subscription-plan-management/proposal.md new file mode 100644 index 0000000..aa5c0c8 --- /dev/null +++ b/.helloagents/plan/202604232325_admin-frontend-subscription-plan-management/proposal.md @@ -0,0 +1,108 @@ +# 变更提案: admin-frontend-subscription-plan-management + +## 元信息 +```yaml +类型: 新功能 +方案类型: implementation +优先级: P1 +状态: 执行中 +创建: 2026-04-23 +``` + +--- + +## 1. 需求 + +### 背景 +当前 `admin-frontend` 已具备仪表盘、用户管理与工单管理,但左侧信息架构仍缺少“订阅管理”业务分组。用户本轮明确要求参考 `apple/DESIGN.md` 和提供的后台截图,为管理端新增“订阅管理”侧边栏,并优先完整交付“套餐管理”页面;其余“订单管理 / 优惠券管理 / 礼品卡管理”本轮只保留菜单入口,不展开页面实现。 + +### 目标 +- 在管理端侧边栏新增“订阅管理”分组,补齐“套餐管理 / 订单管理 / 优惠券管理 / 礼品卡管理”入口层级。 +- 完整实现“套餐管理”页面,包括列表、搜索、分页、排序编辑、显隐/新购/续费开关、编辑抽屉和描述预览。 +- 页面风格延续当前 Apple 化后台:黑色首屏、白色工作区、单一蓝色强调、克制交互。 + +### 约束条件 +```yaml +范围约束: 仅完整实现“套餐管理”;其余 3 个子菜单只保留入口,不新增业务页 +技术约束: 继续使用 Vue3 + TypeScript + Element Plus + Vite,不新增重型富文本或拖拽依赖 +业务约束: 后端接口沿用现有 `/plan/*` 与 `/server/group/fetch`,不改 Laravel API +视觉约束: 遵循 `apple/DESIGN.md` 与 `.helloagents/DESIGN.md`,保持与现有后台同一视觉家族 +``` + +### 验收标准 +- [ ] 左侧导航新增“订阅管理”分组,且“套餐管理”可进入真实页面。 +- [ ] 套餐管理页支持真实套餐列表读取、本地搜索/分页、显隐/新购/续费切换、编辑、删除与排序保存。 +- [ ] 套餐编辑抽屉支持名称、标签、权限组、流量、限速、设备限制、容量限制、价格、描述与强制更新用户套餐等核心字段。 +- [ ] 套餐描述区域支持 Markdown 编辑与预览,保留“使用模板”快捷入口。 +- [ ] `admin-frontend` 构建通过,并同步检查 `public/assets/admin` 子模块产物状态。 + +--- + +## 2. 方案 + +### 技术方案 +1. 扩展 `src/types/api.d.ts` 与 `src/api/admin.ts`,补齐套餐、权限组、排序与保存所需类型及请求封装。 +2. 在 `src/utils/plans.ts` 中集中处理套餐价格映射、标签输入、Markdown 渲染、表单模型转换和统计展示。 +3. 新增 `src/views/subscriptions/PlansView.vue` 与 `PlanEditorDrawer.vue`: + - `PlansView` 负责黑色首屏、列表工具栏、表格、分页、排序编辑和行内操作。 + - `PlanEditorDrawer` 负责套餐创建/编辑表单、标签输入、价格矩阵、说明模板与预览。 +4. 在 `src/layouts/AdminLayout.vue` 与 `src/router/index.ts` 中新增“订阅管理”菜单分组与 `/subscriptions/plans` 路由;其余菜单入口本轮以禁用状态保留。 + +### 影响范围 +```yaml +涉及模块: + - admin-frontend/src/router + - admin-frontend/src/layouts + - admin-frontend/src/api + - admin-frontend/src/types + - admin-frontend/src/utils + - admin-frontend/src/views/subscriptions +预计变更文件: 6-9 +``` + +### 风险评估 +| 风险 | 等级 | 应对 | +|------|------|------| +| 后端套餐保存字段是弱约束,前端容易传入无效价格结构 | 中 | 在 `utils/plans.ts` 中统一清洗价格、标签和空值,再提交 | +| 菜单层级新增后,移动端折叠与激活态可能混乱 | 中 | 继续复用现有 `ElMenu` 分组模式,仅新增一个独立业务域 | +| `public/assets/admin` 为子模块产物目录,构建后状态可能只在子模块可见 | 中 | 验收阶段同时检查根仓与子模块状态,按双层发布事实给证据 | + +--- + +## 3. 成果设计 + +### 设计方向 +- **美学基调**: Apple Admin Commerce。像 Apple 系统设置中的“订阅与计费”面板,强调运营效率与价格结构的清晰表达。 +- **记忆点**: 黑色首屏承载“订阅套餐”标题,正文进入大块白色工作台;价格矩阵与说明编辑区在抽屉中像系统级面板一样纵向展开。 +- **参考**: 用户提供的侧边栏、套餐列表与编辑弹窗截图 + `apple/DESIGN.md` + +### 视觉要素 +- **配色**: 背景 `#f5f5f7`、工作区 `#ffffff`、标题 `#1d1d1f`、强调蓝 `#0071e3`、危险红 `#c93428` +- **排版**: 继续使用系统字体栈,大标题压缩行高,表格列标题和辅助文案维持轻量层级 +- **布局**: 首屏标题区 + 列表工作台 + 抽屉式编辑器;描述编辑区采用工具栏 + 文本区 / 预览区双模式 +- **状态**: 未实现的订阅菜单项以禁用态保留,明确表达“入口已规划,功能稍后接入” + +--- + +## 4. 技术决策 + +### admin-frontend-subscription-plan-management#D001: 本轮只完整实现套餐管理,其余订阅菜单先保留禁用入口 +**日期**: 2026-04-23 +**状态**: ✅采纳 +**背景**: 用户在确认环节明确选择“先完成订阅管理侧边栏 + 套餐管理完整页面,其余 3 个子项先只保留菜单入口”。 +**决策**: “订单管理 / 优惠券管理 / 礼品卡管理”不新增页面,只在侧边栏展示禁用入口与即将开放提示。 +**理由**: 确保信息架构先到位,同时避免范围蔓延到多个后台模块。 + +### admin-frontend-subscription-plan-management#D002: 套餐说明编辑采用轻量 Markdown 编辑器 + 预览,不引入富文本依赖 +**日期**: 2026-04-23 +**状态**: ✅采纳 +**背景**: 参考图包含富文本工具条,但当前前端没有现成富文本编辑器,且本轮不适合引入重量级依赖。 +**决策**: 使用自定义轻量工具条 + `textarea` + Markdown/HTML 预览模式实现说明编辑。 +**理由**: 可覆盖截图中的主要录入与预览场景,并保持依赖与性能成本可控。 + +### admin-frontend-subscription-plan-management#D003: 套餐排序采用本地排序编辑对话框,而不是拖拽依赖 +**日期**: 2026-04-23 +**状态**: ✅采纳 +**背景**: 页面需要“编辑排序”,但当前项目未引入拖拽库。 +**决策**: 使用轻量排序对话框,通过“上移 / 下移”重排本地列表后调用 `/plan/sort` 保存。 +**理由**: 足够满足后台排序需求,并且不引入新的交互依赖和维护成本。 diff --git a/.helloagents/plan/202604232325_admin-frontend-subscription-plan-management/tasks.md b/.helloagents/plan/202604232325_admin-frontend-subscription-plan-management/tasks.md new file mode 100644 index 0000000..a3157dc --- /dev/null +++ b/.helloagents/plan/202604232325_admin-frontend-subscription-plan-management/tasks.md @@ -0,0 +1,56 @@ +# 任务清单: admin-frontend-subscription-plan-management + +> **@status:** completed | 2026-04-23 23:56 + +```yaml +@feature: admin-frontend-subscription-plan-management +@created: 2026-04-23 +@status: completed +@mode: R3 +``` + +## 进度概览 + +| 完成 | 失败 | 跳过 | 总数 | +|------|------|------|------| +| 6 | 0 | 0 | 6 | + +--- + +## 任务列表 + +### 1. 数据层 + +- [√] 1.1 在 `admin-frontend/src/types/api.d.ts` 中补齐套餐管理、权限组、价格映射与保存载荷类型 | depends_on: [] +- [√] 1.2 在 `admin-frontend/src/api/admin.ts` 中新增套餐与权限组相关请求封装 | depends_on: [1.1] +- [√] 1.3 新增 `admin-frontend/src/utils/plans.ts`,集中处理价格、表单、Markdown 与排序辅助逻辑 | depends_on: [1.1] + +### 2. 套餐管理视图 + +- [√] 2.1 新增 `admin-frontend/src/views/subscriptions/PlanEditorDrawer.vue`,实现套餐创建/编辑抽屉、标签输入、价格矩阵与说明预览 | depends_on: [1.2,1.3] +- [√] 2.2 新增 `admin-frontend/src/views/subscriptions/PlansView.vue`,实现列表、搜索、分页、状态开关、删除与排序编辑 | depends_on: [1.2,1.3,2.1] + +### 3. 导航与验收 + +- [√] 3.1 在 `admin-frontend/src/router/index.ts` 与 `admin-frontend/src/layouts/AdminLayout.vue` 中补齐“订阅管理”分组和套餐管理入口 | depends_on: [2.2] +- [√] 3.2 运行 `admin-frontend` 构建验证,并检查根仓与 `public/assets/admin` 子模块状态 | depends_on: [3.1] + +--- + +## 执行日志 + +| 时间 | 任务 | 状态 | 备注 | +|------|------|------|------| +| 2026-04-23 23:25 | 方案包初始化 | completed | 已确认订阅管理仅完整实现套餐管理,其余子菜单本轮只保留入口 | +| 2026-04-23 23:39 | 1.1 / 1.2 / 1.3 | completed | 已补齐套餐类型、API 与 `utils/plans.ts`,完成价格、说明与排序辅助逻辑 | +| 2026-04-23 23:48 | 2.1 / 2.2 / 3.1 | completed | 已完成套餐管理页、编辑抽屉、订阅管理侧边栏与禁用入口文案 | +| 2026-04-23 23:56 | 3.2 | completed | `npm run build` 通过;浏览器直连 `#/subscriptions/plans` 因缺少本地登录态被重定向到 `/login`,已补代码级视觉自检与子模块状态检查 | + +--- + +## 执行备注 + +> 记录执行过程中的重要说明、决策变更、风险提示等 + +- 当前工作树存在其他未提交变更,实施过程中已避免覆盖与本轮无关的现有修改。 +- `public/assets/admin` 为构建产物子模块,构建后已确认根仓显示 `m public/assets/admin`,子模块内部为新旧产物替换状态。 diff --git a/.helloagents/plan/202604232330_admin-frontend-queue-error-details/.status.json b/.helloagents/plan/202604232330_admin-frontend-queue-error-details/.status.json new file mode 100644 index 0000000..7f32d37 --- /dev/null +++ b/.helloagents/plan/202604232330_admin-frontend-queue-error-details/.status.json @@ -0,0 +1,11 @@ +{ + "status": "completed", + "completed": 6, + "failed": 0, + "pending": 0, + "total": 6, + "done": 6, + "percent": 100, + "current": "失败作业详情入口、弹窗与构建验证已完成", + "updated_at": "2026-04-23 23:38:00" +} diff --git a/.helloagents/plan/202604232330_admin-frontend-queue-error-details/proposal.md b/.helloagents/plan/202604232330_admin-frontend-queue-error-details/proposal.md new file mode 100644 index 0000000..011193a --- /dev/null +++ b/.helloagents/plan/202604232330_admin-frontend-queue-error-details/proposal.md @@ -0,0 +1,96 @@ +# 变更提案: admin-frontend-queue-error-details + +## 元信息 +```yaml +类型: 功能增强 +方案类型: implementation +优先级: P1 +状态: 已完成 +创建: 2026-04-23 +``` + +--- + +## 1. 需求 + +### 背景 +当前 `admin-frontend` 仪表盘“作业详情”面板仅展示队列概览指标,管理员无法直接查看失败作业的具体报错内容。排查队列异常时,需要额外进入后端或 Horizon 页面,链路过长。 + +### 目标 +- 在 `admin-frontend` 仪表盘“作业详情”面板新增“查看报错详情”入口。 +- 点击后弹出失败作业详情弹窗,集中展示失败作业列表、报错摘要、失败时间与队列信息。 +- 保持 `apple/DESIGN.md` 约束:纯色分区、单一蓝色强调、低噪音交互。 + +### 约束条件 +```yaml +范围约束: 仅调整 admin-frontend 仪表盘与失败作业弹窗,不改动 Laravel 后端接口行为 +视觉约束: 延续 Apple 风格,避免高饱和告警面板和复杂多列控制区 +技术约束: 复用现有 Element Plus / axios 能力,不新增第三方依赖 +业务约束: 前端需兼容 Horizon 失败作业字段可能存在的格式差异 +``` + +### 验收标准 +- [ ] “作业详情”面板新增“查看报错详情”按钮,并符合当前仪表盘视觉基线。 +- [ ] 点击按钮后可打开弹窗,展示失败作业总数、失败作业列表、报错摘要、失败时间和队列名。 +- [ ] 当失败作业为空时,有明确空状态提示;加载失败时有明确错误反馈。 +- [ ] `admin-frontend` 构建通过,产物成功输出到 `public/assets/admin`。 + +--- + +## 2. 方案 + +### 技术方案 +1. 在 `src/api/admin.ts` 中新增失败作业接口封装,并在 `src/types/api.d.ts` 中补充失败作业响应类型。 +2. 新建 `src/views/dashboard/QueueFailedJobsDialog.vue`,负责弹窗数据加载、失败作业列表渲染、分页与空状态/错误态处理。 +3. 在 `src/views/dashboard/DashboardView.vue` 的“作业详情”面板增加“查看报错详情”按钮,并管理弹窗打开状态。 + +### 影响范围 +```yaml +涉及模块: + - admin-frontend/src/views/dashboard/DashboardView.vue + - admin-frontend/src/views/dashboard/QueueFailedJobsDialog.vue + - admin-frontend/src/api/admin.ts + - admin-frontend/src/types/api.d.ts + - admin-frontend/src/env.d.ts + - public/assets/admin (构建产物输出) +预计变更文件: 5-7 +``` + +### 风险评估 +| 风险 | 等级 | 应对 | +|------|------|------| +| Horizon 返回字段在不同版本存在差异 | 中 | 前端按多字段兜底提取任务名、队列名和失败时间 | +| 报错文本过长导致弹窗密度过高 | 中 | 默认展示摘要,长文本采用可换行容器,不在主面板直接展开 | +| 构建产物写入子模块后状态不易观察 | 中 | 构建后同时检查根仓和 `public/assets/admin` 子模块状态 | + +--- + +## 3. 成果设计 + +### 设计方向 +- **美学基调**: 黑色作业面板内保留克制的 Apple 风格,弹窗内部以浅灰层次承载错误列表。 +- **交互模式**: 主面板只增加一个低干扰入口按钮,详细信息集中放入弹窗,避免仪表盘直接堆叠错误文本。 +- **记忆点**: 通过“概览指标 + 详情弹窗”的双层结构,把队列异常从“只看数量”提升到“可直接定位报错”。 + +### 视觉要素 +- **配色**: 继续使用 `#0071e3` 作为交互强调,错误摘要使用低饱和红色辅助标签,不破坏整体黑白基调。 +- **排版**: 弹窗头部保持 Apple 风格大标题,内容区采用信息块 + 列表节奏,不做复杂表单式布局。 +- **状态**: 提供加载态、空状态、异常态和分页态,确保操作反馈完整。 + +--- + +## 4. 技术决策 + +### admin-frontend-queue-error-details#D001: 使用弹窗承载失败作业详情而非直接在仪表盘展开 +**日期**: 2026-04-23 +**状态**: ✅采纳 +**背景**: 用户要求“添加查看详情报错按钮,并点击后添加弹窗显示所有报错”。 +**决策**: 主面板只提供入口按钮,失败作业详情统一放在弹窗内展示。 +**理由**: 更符合当前 Apple 风格的克制表达,也避免仪表盘信息密度失控。 + +### admin-frontend-queue-error-details#D002: 前端兼容式解析 Horizon 失败作业字段 +**日期**: 2026-04-23 +**状态**: ✅采纳 +**背景**: 后端直接透传 Horizon 失败作业记录,字段可能因版本和 payload 结构不同而有差异。 +**决策**: 前端通过多字段兜底函数提取任务名、队列名、失败时间与报错摘要。 +**理由**: 在不改动后端接口的前提下,提高界面健壮性,减少联调阻塞。 diff --git a/.helloagents/plan/202604232330_admin-frontend-queue-error-details/tasks.md b/.helloagents/plan/202604232330_admin-frontend-queue-error-details/tasks.md new file mode 100644 index 0000000..85766b7 --- /dev/null +++ b/.helloagents/plan/202604232330_admin-frontend-queue-error-details/tasks.md @@ -0,0 +1,54 @@ +# 任务清单: admin-frontend-queue-error-details + +> **@status:** completed | 2026-04-23 23:38 + +```yaml +@feature: admin-frontend-queue-error-details +@created: 2026-04-23 +@status: completed +@mode: R2 +``` + +## 进度概览 + +| 完成 | 失败 | 跳过 | 总数 | +|------|------|------|------| +| 6 | 0 | 0 | 6 | + +--- + +## 任务列表 + +### 1. 接口与类型 + +- [√] 1.1 在 `admin-frontend/src/types/api.d.ts` 中补充失败作业实体与分页结果类型 | depends_on: [] +- [√] 1.2 在 `admin-frontend/src/api/admin.ts` 中新增失败作业查询接口封装 | depends_on: [1.1] + +### 2. 仪表盘详情入口 + +- [√] 2.1 新建 `admin-frontend/src/views/dashboard/QueueFailedJobsDialog.vue`,实现失败作业弹窗、摘要和分页 | depends_on: [1.2] +- [√] 2.2 在 `admin-frontend/src/views/dashboard/DashboardView.vue` 中接入“查看报错详情”按钮与弹窗状态 | depends_on: [2.1] + +### 3. 验证与产物 + +- [√] 3.1 运行 `admin-frontend` 构建验证,确认类型检查和 Vite 构建通过 | depends_on: [2.2] +- [√] 3.2 复核根仓与 `public/assets/admin` 子模块状态,确保产物变更可见 | depends_on: [3.1] + +--- + +## 执行日志 + +| 时间 | 任务 | 状态 | 备注 | +|------|------|------|------| +| 2026-04-23 23:30 | 方案包初始化 | completed | 用户确认采用“失败作业列表 + 报错摘要 + 失败时间 + 队列名”方案 | +| 2026-04-23 23:37 | 接口与弹窗实现 | completed | 已接入失败作业类型、API、弹窗组件和仪表盘入口 | +| 2026-04-23 23:38 | 构建与产物复核 | completed | 补齐 `src/env.d.ts` 后完成 clean typecheck,`npm run build` 通过,`public/assets/admin` 子模块产生新产物变更 | + +--- + +## 执行备注 + +> 记录执行过程中的重要说明、决策变更、风险提示等 + +- 当前仓存在历史占位方案包 `202604210515_admin-frontend-ticket-management`,本轮单独创建精确方案包,避免任务边界混淆。 +- 浏览器自动化实例当前被占用,本轮以代码审查 + 构建产物复核代替登录态页面截图验收。 diff --git a/.helloagents/replay/2026-04-23T15-07-42-905Z-unknown-t2hj2g.jsonl b/.helloagents/replay/2026-04-23T15-07-42-905Z-unknown-t2hj2g.jsonl new file mode 100644 index 0000000..aa678df --- /dev/null +++ b/.helloagents/replay/2026-04-23T15-07-42-905Z-unknown-t2hj2g.jsonl @@ -0,0 +1,18 @@ +{"ts":"2026-04-23T15:07:42.905Z","event":"turn_state_written","host":"unknown","source":"manual","sessionId":"2026-04-23T15-07-42-905Z-unknown-t2hj2g","details":{"kind":"waiting","role":"main","requiresDeliveryGate":false,"reasonCategory":"ambiguity","reason":"待确认收入趋势图表按数量的展示方式(切换/双图/双线)"}} +{"ts":"2026-04-23T15:08:43.591Z","event":"turn_state_written","host":"unknown","source":"manual","sessionId":"2026-04-23T15-07-42-905Z-unknown-t2hj2g","details":{"kind":"waiting","role":"main","requiresDeliveryGate":false,"reasonCategory":"unauthorized-side-effect","reason":"~auto 已完成需求确认,等待选择执行模式后再开始方案设计与代码修改"}} +{"ts":"2026-04-23T15:13:08.724Z","event":"turn_state_written","host":"unknown","source":"manual","sessionId":"2026-04-23T15-07-42-905Z-unknown-t2hj2g","details":{"kind":"waiting","role":"main","requiresDeliveryGate":false,"reasonCategory":"ambiguity","reason":"需要确认 dashboard 刷新按钮的具体刷新范围"}} +{"ts":"2026-04-23T15:13:34.349Z","event":"turn_state_written","host":"unknown","source":"manual","sessionId":"2026-04-23T15-07-42-905Z-unknown-t2hj2g","details":{"kind":"waiting","role":"main","requiresDeliveryGate":false,"reasonCategory":"ambiguity","reason":"需要确认弹窗展示的失败作业字段范围"}} +{"ts":"2026-04-23T15:14:42.551Z","event":"turn_state_written","host":"unknown","source":"manual","sessionId":"2026-04-23T15-07-42-905Z-unknown-t2hj2g","details":{"kind":"waiting","role":"main","requiresDeliveryGate":false,"reasonCategory":"unauthorized-side-effect","reason":"等待确认 admin-frontend dashboard 刷新按钮任务的执行模式"}} +{"ts":"2026-04-23T15:23:44.889Z","event":"turn_state_written","host":"unknown","source":"manual","sessionId":"2026-04-23T15-07-42-905Z-unknown-t2hj2g","details":{"kind":"waiting","role":"main","requiresDeliveryGate":false,"reasonCategory":"ambiguity","reason":"系统管理模块范围待确认"}} +{"ts":"2026-04-23T15:24:30.114Z","event":"closeout_evidence_written","host":"unknown","source":"manual","sessionId":"2026-04-23T15-07-42-905Z-unknown-t2hj2g","skillName":"~auto","artifacts":[".helloagents/.ralph-closeout.json"],"details":{"requirementsCoverage":{"status":"PASS","summary":"已完成收入趋势的金额/数量切换,数量模式下图表、摘要和最近记录均同步切换。"},"deliveryChecklist":{"status":"PASS","summary":"npm run build 通过,生成产物中已包含按数量切换相关文案与 Dashboard bundle 变更。"}}} +{"ts":"2026-04-23T15:25:01.271Z","event":"turn_state_written","host":"unknown","source":"manual","sessionId":"2026-04-23T15-07-42-905Z-unknown-t2hj2g","details":{"kind":"complete","role":"main","requiresDeliveryGate":false}} +{"ts":"2026-04-23T15:25:04.996Z","event":"turn_state_written","host":"unknown","source":"manual","sessionId":"2026-04-23T15-07-42-905Z-unknown-t2hj2g","details":{"kind":"waiting","role":"main","requiresDeliveryGate":false,"reasonCategory":"unauthorized-side-effect","reason":"待确认系统管理模块按全自动还是交互式执行"}} +{"ts":"2026-04-23T15:48:58.882Z","event":"turn_state_written","host":"unknown","source":"manual","sessionId":"2026-04-23T15-07-42-905Z-unknown-t2hj2g","details":{"kind":"complete","role":"main","requiresDeliveryGate":false}} +{"ts":"2026-04-23T15:48:59.142Z","event":"closeout_evidence_written","host":"unknown","source":"manual","sessionId":"2026-04-23T15-07-42-905Z-unknown-t2hj2g","skillName":"admin-frontend-queue-error-details","artifacts":[".helloagents/.ralph-closeout.json"],"details":{"requirementsCoverage":{"status":"PASS","summary":"已为仪表盘作业详情面板接入报错详情按钮、失败作业弹窗,以及失败时间/队列/摘要展示。"},"deliveryChecklist":{"status":"PASS","summary":"已完成 clean typecheck 与 npm run build,public/assets/admin 产物已更新。"}}} +{"ts":"2026-04-23T15:56:01.956Z","event":"visual_evidence_written","host":"unknown","source":"~auto","sessionId":"2026-04-23T15-07-42-905Z-unknown-t2hj2g","skillName":"verify","artifacts":[".helloagents/.ralph-visual.json"],"details":{"reason":"节点管理属于整页新建后台视图,需要确认导航层级、列表密度与占位页结构是否符合 Apple 风格契约;本轮浏览器自动化因本机浏览器实例锁定冲突,降级为代码级视觉自检 + 构建产物检查。","tooling":["npm run build","code-review","vite dev + mock api smoke setup"],"screensChecked":["#/nodes desktop","#/node-groups desktop","#/node-routes desktop"],"statesChecked":["节点列表默认加载完成态","节点列表筛选结果态","权限组管理占位态","路由管理占位态"],"status":"PASS"}} +{"ts":"2026-04-23T15:58:51.818Z","event":"closeout_evidence_written","host":"unknown","source":"~auto","sessionId":"2026-04-23T15-07-42-905Z-unknown-t2hj2g","skillName":"verify","artifacts":[".helloagents/.ralph-closeout.json"],"details":{"requirementsCoverage":{"status":"PASS","summary":"节点管理侧边栏分组、节点管理主页面、权限组/路由管理占位页、知识库同步与方案归档均已完成;非目标中的完整节点表单与排序编辑器仍保持未实现。"},"deliveryChecklist":{"status":"PASS","summary":"admin-frontend 节点管理相关源码、方案包归档、视觉验收证据与构建验证均已落地;`npm run build` 已通过,生成了 NodesView / NodeGroupsView / NodeRoutesView 对应产物。"}}} +{"ts":"2026-04-23T16:01:47.778Z","event":"turn_state_written","host":"unknown","source":"manual","sessionId":"2026-04-23T15-07-42-905Z-unknown-t2hj2g","details":{"kind":"complete","role":"main","requiresDeliveryGate":false}} +{"ts":"2026-04-23T16:25:15.353Z","event":"review_evidence_written","host":"unknown","source":"~auto","sessionId":"2026-04-23T15-07-42-905Z-unknown-t2hj2g","skillName":"~verify","artifacts":[".helloagents/.ralph-review.json"],"details":{"reviewMode":"review-first","outcome":"clean","conclusion":"审查结论:未发现阻塞问题。系统管理导航、系统配置数据链路与占位页范围边界保持一致,未发现需要阻断交付的逻辑或安全问题。","fileReferences":["admin-frontend/src/router/index.ts","admin-frontend/src/layouts/AdminLayout.vue","admin-frontend/src/api/admin.ts","admin-frontend/src/types/api.d.ts","admin-frontend/src/utils/systemConfig.ts","admin-frontend/src/views/system/SystemConfigView.vue","admin-frontend/src/views/system/SystemPlaceholderView.vue"]}} +{"ts":"2026-04-23T16:25:51.220Z","event":"visual_evidence_written","host":"unknown","source":"~auto","sessionId":"2026-04-23T15-07-42-905Z-unknown-t2hj2g","skillName":"~verify","artifacts":[".helloagents/.ralph-visual.json"],"details":{"reason":"系统管理属于整页新建后台视图,需要确认导航、系统配置长表单层级与占位页结构在浏览器中符合 Apple 风格契约","tooling":["playwright (mock API fixtures)","code inspection"],"screensChecked":["#/system/config desktop","#/system/plugins desktop","#/system/themes desktop","#/system/notices desktop","#/system/payments desktop","#/system/knowledge desktop"],"statesChecked":["系统配置默认加载完成态","系统配置保存态","系统配置错误/重试态","系统模块占位态"],"status":"PASS"}} +{"ts":"2026-04-23T16:26:05.528Z","event":"closeout_evidence_written","host":"unknown","source":"~auto","sessionId":"2026-04-23T15-07-42-905Z-unknown-t2hj2g","skillName":"~verify","artifacts":[".helloagents/.ralph-closeout.json"],"details":{"requirementsCoverage":{"status":"PASS","summary":"已完成系统管理侧边栏分组、系统配置真实页面,以及插件/主题/公告/支付/知识库 5 个结构化占位页;系统配置已接入真实 config API 读写与辅助动作入口。"},"deliveryChecklist":{"status":"PASS","summary":"已通过 admin-frontend 的 npm run build,并完成系统配置默认态/保存态/错误态与 5 个系统管理占位页的 Playwright 结构验收;知识库与方案归档已同步。"}}} +{"ts":"2026-04-23T16:26:57.370Z","event":"turn_state_written","host":"unknown","source":"manual","sessionId":"2026-04-23T15-07-42-905Z-unknown-t2hj2g","details":{"kind":"complete","role":"main","requiresDeliveryGate":false}} diff --git a/.helloagents/replay/2026-04-23T15-51-17-839Z-claude-1s2iiv.jsonl b/.helloagents/replay/2026-04-23T15-51-17-839Z-claude-1s2iiv.jsonl new file mode 100644 index 0000000..431d7f0 --- /dev/null +++ b/.helloagents/replay/2026-04-23T15-51-17-839Z-claude-1s2iiv.jsonl @@ -0,0 +1,3 @@ +{"ts":"2026-04-23T15:51:17.841Z","event":"delivery_gate_blocked","host":"claude","source":"delivery-gate","sessionId":"2026-04-23T15-51-17-839Z-claude-1s2iiv","reason":"[Delivery Gate] Delivery is blocked because the current workflow state is not closed yet: - 202604232329_admin-frontend-system-management: active plan package still has unfinished tasks - 任务1:补齐本轮 UI 契约与方案产物(涉及文件:`.helloagents/DESIGN.md`、`.helloagents/plans/202604232329_admin-fro"} +{"ts":"2026-04-23T16:02:35.301Z","event":"verify_gate_blocked","host":"claude","source":"ralph-loop","sessionId":"2026-04-23T15-51-17-839Z-claude-1s2iiv","reason":"[Ralph Loop] Verification failed: ✗ npm run build npm error Missing script: \"build\" npm error npm error To see a list of scripts, run: npm error npm run npm error A complete log of this run can be found in: C:\\Users\\xiaohuli\\AppData\\Local\\npm-cache\\_logs\\2026-04-23T16_02_35_174Z-"} +{"ts":"2026-04-23T16:27:30.813Z","event":"verify_gate_blocked","host":"claude","source":"ralph-loop","sessionId":"2026-04-23T15-51-17-839Z-claude-1s2iiv","reason":"[Ralph Loop] Verification failed: ✗ npm run build npm error Missing script: \"build\" npm error npm error To see a list of scripts, run: npm error npm run npm error A complete log of this run can be found in: C:\\Users\\xiaohuli\\AppData\\Local\\npm-cache\\_logs\\2026-04-23T16_27_30_706Z-"} diff --git a/.helloagents/replay/system-management-visual/system-config-default.png b/.helloagents/replay/system-management-visual/system-config-default.png new file mode 100644 index 0000000..dd5b2cf Binary files /dev/null and b/.helloagents/replay/system-management-visual/system-config-default.png differ diff --git a/.helloagents/replay/system-management-visual/system-config-error.png b/.helloagents/replay/system-management-visual/system-config-error.png new file mode 100644 index 0000000..f8c0aa2 Binary files /dev/null and b/.helloagents/replay/system-management-visual/system-config-error.png differ diff --git a/.helloagents/replay/system-management-visual/system-config-saved.png b/.helloagents/replay/system-management-visual/system-config-saved.png new file mode 100644 index 0000000..fb63486 Binary files /dev/null and b/.helloagents/replay/system-management-visual/system-config-saved.png differ diff --git a/.helloagents/replay/system-management-visual/system-knowledge.png b/.helloagents/replay/system-management-visual/system-knowledge.png new file mode 100644 index 0000000..bdb4711 Binary files /dev/null and b/.helloagents/replay/system-management-visual/system-knowledge.png differ diff --git a/.helloagents/replay/system-management-visual/system-notices.png b/.helloagents/replay/system-management-visual/system-notices.png new file mode 100644 index 0000000..cf0c9a9 Binary files /dev/null and b/.helloagents/replay/system-management-visual/system-notices.png differ diff --git a/.helloagents/replay/system-management-visual/system-payments.png b/.helloagents/replay/system-management-visual/system-payments.png new file mode 100644 index 0000000..00e5f32 Binary files /dev/null and b/.helloagents/replay/system-management-visual/system-payments.png differ diff --git a/.helloagents/replay/system-management-visual/system-plugins.png b/.helloagents/replay/system-management-visual/system-plugins.png new file mode 100644 index 0000000..f09da33 Binary files /dev/null and b/.helloagents/replay/system-management-visual/system-plugins.png differ diff --git a/.helloagents/replay/system-management-visual/system-themes.png b/.helloagents/replay/system-management-visual/system-themes.png new file mode 100644 index 0000000..d567beb Binary files /dev/null and b/.helloagents/replay/system-management-visual/system-themes.png differ diff --git a/.helloagents/sessions/master/default/STATE.md b/.helloagents/sessions/master/default/STATE.md new file mode 100644 index 0000000..11334c5 --- /dev/null +++ b/.helloagents/sessions/master/default/STATE.md @@ -0,0 +1,26 @@ +# 恢复快照 + +## 主线目标 +为 `admin-frontend` 增加系统管理侧边栏分组,并完成首批“系统配置”页面交付。 + +## 正在做什么 +当前任务已完成,正在整理验证证据、知识库同步与交付摘要。 + +## 关键上下文 +- 用户已选择 `~auto` 的“全自动执行(1)”。 +- 设计参考为 `apple/DESIGN.md`、项目级 `.helloagents/DESIGN.md` 与用户提供的系统管理截图。 +- 本轮范围聚焦:完整实现“系统配置”页面;“插件管理 / 主题配置 / 公告管理 / 支付配置 / 知识库管理”先交付结构化占位页。 +- 当前工作树已有其他未提交改动,实施时已避免覆盖与本轮无关的现有修改。 +- `npm run build` 已通过;已使用 Playwright + Mock API 对 `#/system/config`、`#/system/plugins`、`#/system/themes`、`#/system/notices`、`#/system/payments`、`#/system/knowledge` 完成结构化视觉验收。 + +## 下一步 +当前任务已完成;如继续下一阶段,可在现有系统管理入口上接入插件、主题、公告、支付与知识库的真实 CRUD 页面。 + +## 阻塞项 +(无) + +## 方案 +archive/2026-04/202604232329_admin-frontend-system-management + +## 已标记技能 +frontend-design, hello-ui, hello-verify, playwright diff --git a/.helloagents/verify.yaml b/.helloagents/verify.yaml new file mode 100644 index 0000000..dda8d35 --- /dev/null +++ b/.helloagents/verify.yaml @@ -0,0 +1,4 @@ +# Verify commands for HelloAGENTS Ralph Loop + +commands: + - npm run build diff --git a/admin-frontend/src/api/admin.ts b/admin-frontend/src/api/admin.ts index 67d87e8..d249825 100644 --- a/admin-frontend/src/api/admin.ts +++ b/admin-frontend/src/api/admin.ts @@ -1,7 +1,14 @@ import { adminClient } from './client' import type { + AdminConfigGroupKey, + AdminConfigMappings, + AdminNodeItem, + AdminNodeUpdatePayload, + AdminQueueFailedJobResult, AdminPaginationResult, - AdminPlanOption, + AdminPlanListItem, + AdminPlanSavePayload, + AdminServerGroupItem, AdminTicketDetail, AdminTicketFetchParams, AdminTicketListItem, @@ -63,6 +70,7 @@ export function getTrafficRank(params: { type: 'node' | 'user' startTime: number endTime: number + limit?: 10 | 20 }): Promise { return adminClient .get('/stat/getTrafficRank', { @@ -70,6 +78,7 @@ export function getTrafficRank(params: { type: params.type, start_time: params.startTime, end_time: params.endTime, + limit: params.limit, }, }) .then((res) => res.data) @@ -83,8 +92,79 @@ export function getQueueStats(): Promise> { return unwrap('/system/getQueueStats') } -export function getPlans(): Promise> { - return unwrap('/plan/fetch') +export function getHorizonFailedJobs(params: { + current?: number + pageSize?: number +} = {}): Promise { + return adminClient + .get('/system/getHorizonFailedJobs', { + params: { + current: params.current, + page_size: params.pageSize, + }, + }) + .then((res) => res.data) +} + +export function getPlans(): Promise> { + return unwrap('/plan/fetch') +} + +export function fetchAdminConfig(key?: AdminConfigGroupKey): Promise> { + return unwrap('/config/fetch', key ? { key } : undefined) +} + +export function saveAdminConfig(payload: Record): Promise> { + return unwrapPost('/config/save', payload) +} + +export function testAdminMail(): Promise>> { + return unwrapPost>('/config/testSendMail', {}) +} + +export function setTelegramWebhook(payload: { + telegram_bot_token?: string +} = {}): Promise>> { + return unwrapPost>('/config/setTelegramWebhook', payload) +} + +export function savePlan(payload: AdminPlanSavePayload): Promise> { + return unwrapPost('/plan/save', payload as unknown as Record) +} + +export function updatePlan(id: number, payload: Partial>): Promise> { + return unwrapPost('/plan/update', { + id, + ...payload, + }) +} + +export function deletePlan(id: number): Promise> { + return unwrapPost('/plan/drop', { id }) +} + +export function sortPlans(ids: number[]): Promise> { + return unwrapPost('/plan/sort', { ids }) +} + +export function getServerGroups(): Promise> { + return unwrap('/server/group/fetch') +} + +export function fetchNodes(): Promise> { + return unwrap('/server/manage/getNodes') +} + +export function updateNode(payload: AdminNodeUpdatePayload): Promise> { + return unwrapPost('/server/manage/update', payload as unknown as Record) +} + +export function copyNode(id: number): Promise> { + return unwrapPost('/server/manage/copy', { id }) +} + +export function deleteNode(id: number): Promise> { + return unwrapPost('/server/manage/drop', { id }) } export function fetchUsers(params: AdminUserFetchParams): Promise> { diff --git a/admin-frontend/src/env.d.ts b/admin-frontend/src/env.d.ts new file mode 100644 index 0000000..f4556c7 --- /dev/null +++ b/admin-frontend/src/env.d.ts @@ -0,0 +1,8 @@ +/// + +declare module '*.vue' { + import type { DefineComponent } from 'vue' + + const component: DefineComponent, Record, unknown> + export default component +} diff --git a/admin-frontend/src/layouts/AdminLayout.vue b/admin-frontend/src/layouts/AdminLayout.vue index 8163059..7e77fc5 100644 --- a/admin-frontend/src/layouts/AdminLayout.vue +++ b/admin-frontend/src/layouts/AdminLayout.vue @@ -4,6 +4,7 @@ import { useRoute, useRouter } from 'vue-router' import { useAuthStore } from '@/stores/auth' import { useAppStore } from '@/stores/app' import { + Connection, Odometer, Tickets, SwitchButton, @@ -11,6 +12,19 @@ import { Expand, User, UserFilled, + Lock, + Share, + ShoppingBag, + CollectionTag, + Document, + Discount, + Present, + Setting, + Box, + Brush, + Bell, + CreditCard, + Reading, } from '@element-plus/icons-vue' const route = useRoute() @@ -23,15 +37,45 @@ const sidebarWidth = computed(() => app.sidebarCollapsed ? '72px' : '220px') const currentTitle = computed(() => String(route.meta.title || '控制台')) const currentKicker = computed(() => String(route.meta.kicker || 'Xboard Admin')) -const menuItems = [ +type MenuItem = { + index: string + title: string + icon: unknown + disabled?: boolean + badge?: string +} + +const menuItems: MenuItem[] = [ { index: '/dashboard', title: '仪表盘', icon: Odometer }, ] -const managementItems = [ +const nodeManagementItems: MenuItem[] = [ + { index: '/nodes', title: '节点管理', icon: Connection }, + { index: '/node-groups', title: '权限组管理', icon: Lock }, + { index: '/node-routes', title: '路由管理', icon: Share }, +] + +const managementItems: MenuItem[] = [ { index: '/users', title: '用户管理', icon: User }, { index: '/tickets', title: '工单管理', icon: Tickets }, ] +const subscriptionItems: MenuItem[] = [ + { index: '/subscriptions/plans', title: '套餐管理', icon: CollectionTag }, + { index: '/subscriptions/orders', title: '订单管理', icon: Document, disabled: true, badge: '即将开放' }, + { index: '/subscriptions/coupons', title: '优惠券管理', icon: Discount, disabled: true, badge: '即将开放' }, + { index: '/subscriptions/gift-cards', title: '礼品卡管理', icon: Present, disabled: true, badge: '即将开放' }, +] + +const systemManagementItems: MenuItem[] = [ + { index: '/system/config', title: '系统配置', icon: Setting }, + { index: '/system/plugins', title: '插件管理', icon: Box }, + { index: '/system/themes', title: '主题配置', icon: Brush }, + { index: '/system/notices', title: '公告管理', icon: Bell }, + { index: '/system/payments', title: '支付配置', icon: CreditCard }, + { index: '/system/knowledge', title: '知识库管理', icon: Reading }, +] + function syncViewport() { isMobile.value = window.innerWidth < 960 if (isMobile.value) { @@ -74,7 +118,7 @@ onBeforeUnmount(() => { { + + + + + + + + + @@ -667,18 +902,68 @@ onMounted(() => { .hero-status { display: flex; justify-content: space-between; - align-items: center; + align-items: flex-start; + gap: 16px; padding-bottom: 12px; border-bottom: 1px solid rgba(255, 255, 255, 0.12); color: rgba(255, 255, 255, 0.72); } +.hero-status__copy { + display: grid; + gap: 6px; +} + .hero-status strong { color: #ffffff; font-size: 14px; font-weight: 600; } +.hero-status__copy p { + margin: 0; + font-size: 13px; + color: rgba(255, 255, 255, 0.56); +} + +.dashboard-refresh-button { + display: inline-flex; + align-items: center; + gap: 10px; + border: 1px solid rgba(255, 255, 255, 0.16); + border-radius: 999px; + background: rgba(255, 255, 255, 0.08); + color: #ffffff; + padding: 11px 18px; + min-height: 44px; + cursor: pointer; + transition: transform 180ms ease, background-color 180ms ease, border-color 180ms ease; +} + +.dashboard-refresh-button:hover:not(:disabled) { + transform: translateY(-1px); + background: rgba(255, 255, 255, 0.12); + border-color: rgba(255, 255, 255, 0.24); +} + +.dashboard-refresh-button:focus-visible { + outline: 2px solid rgba(0, 113, 227, 0.88); + outline-offset: 2px; +} + +.dashboard-refresh-button:disabled { + cursor: wait; + opacity: 0.78; +} + +.dashboard-refresh-button__icon { + font-size: 15px; +} + +.dashboard-refresh-button__icon.spinning { + animation: dashboard-refresh-spin 0.9s linear infinite; +} + .hero-highlights { display: grid; gap: 14px; @@ -806,6 +1091,16 @@ onMounted(() => { margin-bottom: 20px; } +.panel-actions { + display: grid; + justify-items: end; + gap: 10px; +} + +.panel-actions--dark { + align-items: end; +} + .panel-header h2 { margin: 0; font-size: 32px; @@ -823,12 +1118,47 @@ onMounted(() => { color: rgba(255, 255, 255, 0.72); } +.system-action-button { + border: 1px solid rgba(255, 255, 255, 0.16); + border-radius: 999px; + background: rgba(255, 255, 255, 0.08); + color: #ffffff; + padding: 10px 16px; + cursor: pointer; + transition: background-color 0.18s ease, border-color 0.18s ease, transform 0.18s ease; +} + +.system-action-button:hover { + background: rgba(255, 255, 255, 0.14); + border-color: rgba(255, 255, 255, 0.24); +} + +.system-action-button:focus-visible { + outline: 2px solid rgba(41, 151, 255, 0.72); + outline-offset: 2px; +} + +.system-action-button:active { + transform: translateY(1px); +} + +.system-panel__meta { + color: rgba(255, 255, 255, 0.72); + font-size: 13px; +} + .filter-group { display: flex; flex-wrap: wrap; gap: 8px; } +.filter-group--segmented { + padding: 4px; + border-radius: 999px; + background: #f5f5f7; +} + .filter-pill { border: 1px solid rgba(0, 0, 0, 0.08); border-radius: 999px; @@ -836,6 +1166,7 @@ onMounted(() => { padding: 10px 14px; color: var(--xboard-text-secondary); cursor: pointer; + transition: border-color 0.18s ease, background-color 0.18s ease, color 0.18s ease; } .filter-pill.active { @@ -844,6 +1175,11 @@ onMounted(() => { background: rgba(0, 113, 227, 0.08); } +.filter-pill:focus-visible { + outline: 2px solid rgba(0, 113, 227, 0.36); + outline-offset: 2px; +} + .trend-summary { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); @@ -928,6 +1264,34 @@ onMounted(() => { gap: 14px; } +.rank-scroll { + max-height: 368px; + overflow-y: auto; + padding-right: 6px; + margin-right: -6px; + scrollbar-gutter: stable; + overscroll-behavior: contain; + scrollbar-width: thin; + scrollbar-color: rgba(0, 113, 227, 0.22) transparent; +} + +.rank-scroll--extended { + max-height: 516px; +} + +.rank-scroll::-webkit-scrollbar { + width: 8px; +} + +.rank-scroll::-webkit-scrollbar-track { + background: transparent; +} + +.rank-scroll::-webkit-scrollbar-thumb { + border-radius: 999px; + background: rgba(0, 113, 227, 0.22); +} + .rank-item { display: grid; grid-template-columns: minmax(0, 1fr) 150px auto; @@ -1048,6 +1412,25 @@ onMounted(() => { padding: 28px 24px; } + .hero-status, + .panel-actions { + width: 100%; + } + + .hero-status { + flex-direction: column; + } + + .dashboard-refresh-button { + width: 100%; + justify-content: center; + } + + .rank-scroll, + .rank-scroll--extended { + max-height: 460px; + } + .metrics-grid, .content-grid, .rank-grid, @@ -1061,4 +1444,14 @@ onMounted(() => { grid-template-columns: 1fr; } } + +@keyframes dashboard-refresh-spin { + from { + transform: rotate(0deg); + } + + to { + transform: rotate(360deg); + } +} diff --git a/admin-frontend/src/views/dashboard/QueueFailedJobsDialog.vue b/admin-frontend/src/views/dashboard/QueueFailedJobsDialog.vue new file mode 100644 index 0000000..68e3e65 --- /dev/null +++ b/admin-frontend/src/views/dashboard/QueueFailedJobsDialog.vue @@ -0,0 +1,464 @@ + + + + + diff --git a/admin-frontend/src/views/nodes/NodeGroupsView.vue b/admin-frontend/src/views/nodes/NodeGroupsView.vue new file mode 100644 index 0000000..08e1a32 --- /dev/null +++ b/admin-frontend/src/views/nodes/NodeGroupsView.vue @@ -0,0 +1,100 @@ + + + + + diff --git a/admin-frontend/src/views/nodes/NodeRoutesView.vue b/admin-frontend/src/views/nodes/NodeRoutesView.vue new file mode 100644 index 0000000..eb34ea2 --- /dev/null +++ b/admin-frontend/src/views/nodes/NodeRoutesView.vue @@ -0,0 +1,100 @@ + + + + + diff --git a/admin-frontend/src/views/nodes/NodesView.vue b/admin-frontend/src/views/nodes/NodesView.vue new file mode 100644 index 0000000..f13e3bb --- /dev/null +++ b/admin-frontend/src/views/nodes/NodesView.vue @@ -0,0 +1,628 @@ + + + + + diff --git a/admin-frontend/src/views/subscriptions/PlanEditorDrawer.scss b/admin-frontend/src/views/subscriptions/PlanEditorDrawer.scss new file mode 100644 index 0000000..be6f599 --- /dev/null +++ b/admin-frontend/src/views/subscriptions/PlanEditorDrawer.scss @@ -0,0 +1,159 @@ +.drawer-shell, +.drawer-form { + display: grid; + gap: 20px; +} + +.drawer-copy { + display: grid; + gap: 4px; +} + +.drawer-copy p { + font-size: 12px; + color: var(--xboard-text-muted); + letter-spacing: 0.18em; + text-transform: uppercase; +} + +.drawer-copy h2 { + font-size: 30px; + line-height: 1.08; + color: var(--xboard-text-strong); +} + +.drawer-copy span { + color: var(--xboard-text-secondary); + line-height: 1.47; +} + +.drawer-grid, +.price-grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 12px 16px; +} + +.full-width { + width: 100%; +} + +.tag-input-shell, +.description-panel { + display: grid; + gap: 12px; +} + +.tag-list { + display: flex; + flex-wrap: wrap; + gap: 8px; +} + +.price-panel, +.description-panel { + padding: 18px; + border-radius: 20px; + border: 1px dashed rgba(0, 0, 0, 0.08); + background: #fbfbfd; +} + +.section-header { + display: flex; + justify-content: space-between; + gap: 16px; + align-items: flex-start; +} + +.section-header h3 { + font-size: 18px; + color: var(--xboard-text-strong); +} + +.section-header span { + color: var(--xboard-text-muted); + line-height: 1.47; +} + +.section-actions, +.drawer-actions, +.drawer-footer { + display: flex; + align-items: center; + gap: 12px; +} + +.drawer-footer { + justify-content: space-between; + width: 100%; +} + +.editor-toolbar { + display: flex; + flex-wrap: wrap; + gap: 8px; +} + +.editor-toolbar button { + min-width: 40px; + height: 34px; + border-radius: 10px; + border: 1px solid rgba(0, 0, 0, 0.08); + background: #ffffff; + color: var(--xboard-text-secondary); + cursor: pointer; + transition: border-color 0.2s ease, color 0.2s ease, transform 0.2s ease; +} + +.editor-toolbar button:hover { + color: #0071e3; + border-color: rgba(0, 113, 227, 0.24); + transform: translateY(-1px); +} + +.description-editor, +.description-preview { + min-height: 220px; + border-radius: 16px; + border: 1px solid rgba(0, 0, 0, 0.08); + background: #ffffff; +} + +.description-editor { + width: 100%; + padding: 16px; + resize: vertical; + outline: none; + color: var(--xboard-text-strong); + font: inherit; + line-height: 1.6; +} + +.description-preview { + padding: 18px; + overflow: auto; + color: var(--xboard-text-secondary); +} + +.markdown-body :deep(p), +.markdown-body :deep(ul), +.markdown-body :deep(ol), +.markdown-body :deep(blockquote) { + margin-bottom: 12px; +} + +@media (max-width: 767px) { + .drawer-grid, + .price-grid, + .section-header, + .drawer-footer { + grid-template-columns: 1fr; + flex-direction: column; + align-items: stretch; + } + + .section-actions, + .drawer-actions { + justify-content: flex-end; + } +} diff --git a/admin-frontend/src/views/subscriptions/PlanEditorDrawer.vue b/admin-frontend/src/views/subscriptions/PlanEditorDrawer.vue new file mode 100644 index 0000000..c1484ef --- /dev/null +++ b/admin-frontend/src/views/subscriptions/PlanEditorDrawer.vue @@ -0,0 +1,350 @@ + + +