Skip to content

v0.0.15 ​

✨ New Features ​

Go backend ​

  • New admin diagnostic endpoint GET /api/diag/subscriptions (controller/diag.go, AdminAuth):
    • Pulls up to 100 rows from user_plans via GetAllUserPlans(0, 100, 0, -1), joins each with the source order's plan_id / type, and embeds a user brief.
    • Response includes total_user_plans (rows scanned), missing_plan_id (rows with plan_id<=0), and rows (per-row details: user_plan + order_no + order_plan_id + order_type + user).
    • User data is fetched via GetUsersBriefByIds with a single WHERE IN query — no N+1.
    • router/api.go registers /api/diag/subscriptions behind the AdminAuth middleware.
  • model/user adds UserBrief and batch lookup (model/user.go):
    • New UserBrief struct (id / username / display_name) for list-embedding scenarios.
    • New GetUsersBriefByIds(ids []int) (map[int]*UserBrief, error): short-circuits on empty ids; otherwise runs a single WHERE IN query and tolerates missing ids.
  • Order-management endpoints gain multi-dimensional filters + user embedding (controller/order + model/order):
    • New model.OrderAdminFilter struct + applyTo helper; GetAllOrders / SearchOrders now take *OrderAdminFilter.
    • model.Order gains a transient User *UserBrief field (gorm:"-") that admin list responses serialize as user.
    • controller adds parseOrderAdminFilter, reading type / status / source / user_id / plan_id / keyword from query params.
    • Empty status means "all", avoiding the OrderStatusPending(0) value clash.
    • New enrichOrdersWithUserBrief helper batches user embedding via a single WHERE IN.
  • UserPlan.Insert defensively rejects plan_id<=0 (model/user_plan.go):
    • Insert now refuses to write when PlanId<=0, returning the error user_plan.plan_id 不能为空.
    • Companion test model/subscription_defense_test.go covers both Insert and ActivatePackageByOrder defensive paths.

Frontend (web/default-pro/) ​

  • New admin order-list page views/admin/AdminOrders.vue:
    • Welcome bar with total-count meta-chip.
    • Standalone search card: order-no / pay-trade-no search + three <a-select> filters (type: plan / recharge, status: pending / paid / cancelled / refunded, source: user / admin) + reset / refresh buttons.
    • 11-column grid row: ID / order-no / type / user / plan / amount / pay-method / status / source / created-at / actions; user column renders embedded user.display_name.
    • Actions: view details / mark-paid (status=0→1) / refund (status=1→3) / delete (root-only, only when status≠1).
    • Detail modal shows full fields and lazily fetches the latest user info; mark-paid modal picks pay_method and optional pay_trade_no.
    • <a-spin> carries style="width:100%" per AGENTS.md §10.4 to avoid layout collapse.
  • Register /admin/orders route and sidebar menu:
    • router/index.js: registers /admin/orders; isAdminRoute includes AdminOrders.
    • layouts/AdminLayout.vue: inserts the "订单" menu item (icon icon-storage) between Channels and Redemption.
    • api/order.js extension: orderApi.list(params) accepts paging + multi-filter params; search extends with status / source / user_id / plan_id.
    • New buildAdminParams helper only forwards truthy fields, keeping query strings clean.

🐛 Bug Fixes ​

  • Fixed dirty plan_id=0 writes causing empty plan columns in the admin list: now blocked at the UserPlan.Insert boundary (see above), with the source flow ActivatePackageByOrder also defensively guarded.
  • Closed the operations blind-spot between the dashboard and admin by adding a unified order-management entry point: the new AdminOrders page plus /api/diag/subscriptions endpoint provides a single, visual place to inspect orders and diagnose subscriptions.

🧪 Tests ​

  • New model/order_admin_filter_test.go (the order_admin_filter_test suite):
    • setupOrderAdminTestDB spins up glebarez/sqlite in-memory + gorm.AutoMigrate for users and orders.
    • seedUsersAndOrders shared fixture helper; every user must set AccessToken / AffCode to satisfy unique indexes.
    • TestOrderAdminFilter_ApplyTo: verifies zero-value filter is a no-op.
    • TestGetAllOrders_FilterMatrix: 9 subtests covering type / status / source / user_id / plan_id / keyword and combinations.
    • TestSearchOrders_StatusFilter: verifies the search path also honours status.
    • TestGetUsersBriefByIds_EmptyAndIn: short-circuit on empty ids + WHERE IN query + missing-id tolerance.
  • New model/subscription_defense_test.go: covers both the UserPlan.Insert and ActivatePackageByOrder defensive paths.

📚 Documentation ​

  • README.md adds QQ group info (979158b add qq group).

⚠️ Upgrade Notes ​

  • Zero database migration: UserBrief is a new type, Order.User is a gorm:"-" transient field, and OrderAdminFilter is a controller-layer parsing struct — no schema changes.
  • New admin routes:
    • GET /api/diag/subscriptions (AdminAuth): diagnostic endpoint; consider restricting or root-onlying it in production as needed.
    • Admin order endpoints /api/order/ and /api/order/search now accept optional query params status / source / user_id / plan_id / keyword. Fully backward-compatible — absent params are ignored.
  • Defensive change: UserPlan.Insert and ActivatePackageByOrder now refuse plan_id<=0. If any legacy code path relied on this tolerance, the upstream caller must be fixed (none should).
  • Frontend: new views/admin/AdminOrders.vue plus a sidebar entry; api/order.js extended, no breaking changes.
  • Backend build: go build ./...; tests via go test ./model/ ./controller/ ./middleware/.