v0.0.15 — 管理员订单管理后台与订阅诊断端点
管理员可在后台「订单」页面集中管理全部用户订单(套餐订阅 + 充值),支持多维筛选、状态流转(标记已付 / 退款 / 删除)与详情查看;同步新增
/api/diag/subscriptions诊断端点,配套UserPlan.Insert防御性校验,方便排查plan_id异常问题。
中文
✨ 新增功能
后端(Go)
- 新增管理员诊断端点
GET /api/diag/subscriptions(controller/diag.go,AdminAuth):- 拉取
user_plans表前 100 行(GetAllUserPlans(0, 100, 0, -1)),逐行对比orders表中对应订单的plan_id/type,并嵌入用户摘要。 - 返回体含
total_user_plans(扫描行数)、missing_plan_id(plan_id<=0的疑似脏数据行数)、rows(逐行明细:user_plan+order_no+order_plan_id+order_type+user)。 - 用户信息复用
GetUsersBriefByIds单次WHERE IN查询,无 N+1。 router/api.go注册/api/diag/subscriptions路由(AdminAuth 中间件兜底)。
- 拉取
model/user增加UserBrief与批量查询(model/user.go):- 新增
UserBrief结构体(id/username/display_name三个字段),用于列表嵌入场景。 - 新增
GetUsersBriefByIds(ids []int) (map[int]*UserBrief, error):空ids短路不查 DB,否则单条WHERE IN查询,并对缺失 id 容错。
- 新增
- 订单管理接口支持多维过滤 + 用户嵌入(
controller/order+model/order):- 新增
model.OrderAdminFilter结构体与applyTohelper;GetAllOrders/SearchOrders改用*OrderAdminFilter参数。 model.Order新增User *UserBrief(gorm:"-")瞬时字段,admin 列表响应中作为user字段返回。controller新增parseOrderAdminFilter:从 query 解析type/status/source/user_id/plan_id/keyword六个过滤维度。status空字符串表示「全部」,避免与OrderStatusPending(0)值重叠。- 新增
enrichOrdersWithUserBrief批量补全User字段:单次WHERE IN查询全部目标 user id,无 N+1。
- 新增
UserPlan.Insert防御性校验拒绝plan_id<=0(model/user_plan.go):Insert入口新增前置校验:PlanId <= 0时直接返回错误user_plan.plan_id 不能为空,杜绝脏数据写入。- 配套新增
model/subscription_defense_test.go,覆盖Insert与ActivatePackageByOrder两处防御路径。
前端(web/default-pro/)
- 新增管理员订单列表页
views/admin/AdminOrders.vue:- 顶部欢迎条显示总条数 meta-chip。
- 独立搜索卡:订单号 / 支付流水号搜索 + 类型(套餐 / 充值)/ 状态(待支付 / 已支付 / 已取消 / 已退款)/ 来源(用户自助 / 管理员)三个
<a-select>下拉筛选 + 重置 / 刷新按钮。 - 11 列 grid 行展示:ID / 订单号 / 类型 / 用户 / 套餐 / 金额 / 支付方式 / 状态 / 来源 / 创建时间 / 操作,用户列渲染嵌入的
user.display_name。 - 操作列支持:查看详情 / 标记已付(
status=0→1)/ 退款(status=1→3)/ 删除(root 限定,仅status≠1可删)。 - 详情弹窗展示完整字段,并异步拉取最新 user 信息;标记已付弹窗选择
pay_method+ 可选pay_trade_no。 <a-spin>设置style="width:100%"避免布局塌陷(AGENTS.md §10.4)。
- 注册
/admin/orders路由与侧边栏菜单:router/index.js:注册/admin/orders路由;isAdminRoute加入AdminOrders判断。layouts/AdminLayout.vue:在渠道与兑换码之间插入「订单」菜单项(iconicon-storage)。api/order.js扩展:orderApi.list(params)接受分页与多过滤参数;search扩展支持status/source/user_id/plan_id。- 新增
buildAdminParamshelper,仅透传非零 / 非空字段,避免污染 query。
🐛 问题修复
- 修复
UserPlan.Insert写入plan_id=0导致 admin 列表套餐列空白的脏数据问题:通过新增PlanId<=0前置校验防御(见上),异常来源追溯到ActivatePackageByOrder流程同样增加防御。 - 修复 dashboard 与 admin 之间因缺乏统一订单管理入口导致的运维盲区:通过新增 AdminOrders 页面 +
/api/diag/subscriptions端点,提供集中可视化的订单与订阅诊断能力。
🧪 测试
- 新增
model/order_admin_filter_test.go(order_admin_filter_test测试集):setupOrderAdminTestDB用glebarez/sqlite内存库 +gorm.AutoMigrate建users+orders表。seedUsersAndOrders通用夹具 helper:每个 user 必须设AccessToken/AffCode以满足 unique 索引。TestOrderAdminFilter_ApplyTo:验证零值全字段为 no-op。TestGetAllOrders_FilterMatrix:9 个 subtest 覆盖type/status/source/user_id/plan_id/keyword五个过滤维度及组合。TestSearchOrders_StatusFilter:验证搜索结果也按status过滤。TestGetUsersBriefByIds_EmptyAndIn:验证空 ids 短路 +WHERE IN查询 + 缺失 id 容错。
- 新增
model/subscription_defense_test.go:覆盖UserPlan.Insert与ActivatePackageByOrder两处防御性校验路径。
📚 文档
README.md新增 QQ 群信息(979158b add qq group)。
⚠️ 升级注意事项
- 零数据库迁移:
UserBrief是新类型、Order.User是gorm:"-"瞬时字段、OrderAdminFilter仅是 controller 层的解析结构;不涉及表结构变更。 - 新增 admin 路由:
GET /api/diag/subscriptions(AdminAuth):诊断端点,生产环境视情况可关闭或仅暴露给 root。- admin 订单接口
/api/order/与/api/order/search新增可选 query 参数status/source/user_id/plan_id/keyword,向后兼容(不传则忽略)。
- 防御性变更:
UserPlan.Insert与ActivatePackageByOrder在plan_id<=0时会直接拒绝;若有历史代码路径依赖此容错行为,需同步修复上游调用方(理论上不应有此类调用)。 - 前端:新增
views/admin/AdminOrders.vue与侧边栏菜单项;api/order.js扩展,无破坏性变更。 - 后端构建:
go build ./...;测试运行go test ./model/ ./controller/ ./middleware/。