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_plansviaGetAllUserPlans(0, 100, 0, -1), joins each with the source order'splan_id/type, and embeds a user brief. - Response includes
total_user_plans(rows scanned),missing_plan_id(rows withplan_id<=0), androws(per-row details:user_plan+order_no+order_plan_id+order_type+user). - User data is fetched via
GetUsersBriefByIdswith a singleWHERE INquery — no N+1. router/api.goregisters/api/diag/subscriptionsbehind the AdminAuth middleware.
- Pulls up to 100 rows from
model/useraddsUserBriefand batch lookup (model/user.go):- New
UserBriefstruct (id/username/display_name) for list-embedding scenarios. - New
GetUsersBriefByIds(ids []int) (map[int]*UserBrief, error): short-circuits on emptyids; otherwise runs a singleWHERE INquery and tolerates missing ids.
- New
- Order-management endpoints gain multi-dimensional filters + user embedding (
controller/order+model/order):- New
model.OrderAdminFilterstruct +applyTohelper;GetAllOrders/SearchOrdersnow take*OrderAdminFilter. model.Ordergains a transientUser *UserBrieffield (gorm:"-") that admin list responses serialize asuser.controlleraddsparseOrderAdminFilter, readingtype/status/source/user_id/plan_id/keywordfrom query params.- Empty
statusmeans "all", avoiding theOrderStatusPending(0)value clash. - New
enrichOrdersWithUserBriefhelper batches user embedding via a singleWHERE IN.
- New
UserPlan.Insertdefensively rejectsplan_id<=0(model/user_plan.go):Insertnow refuses to write whenPlanId<=0, returning the erroruser_plan.plan_id 不能为空.- Companion test
model/subscription_defense_test.gocovers bothInsertandActivatePackageByOrderdefensive 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 whenstatus≠1). - Detail modal shows full fields and lazily fetches the latest user info; mark-paid modal picks
pay_methodand optionalpay_trade_no. <a-spin>carriesstyle="width:100%"per AGENTS.md §10.4 to avoid layout collapse.
- Register
/admin/ordersroute and sidebar menu:router/index.js: registers/admin/orders;isAdminRouteincludesAdminOrders.layouts/AdminLayout.vue: inserts the "订单" menu item (iconicon-storage) between Channels and Redemption.api/order.jsextension:orderApi.list(params)accepts paging + multi-filter params;searchextends withstatus/source/user_id/plan_id.- New
buildAdminParamshelper only forwards truthy fields, keeping query strings clean.
🐛 Bug Fixes
- Fixed dirty
plan_id=0writes causing empty plan columns in the admin list: now blocked at theUserPlan.Insertboundary (see above), with the source flowActivatePackageByOrderalso 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/subscriptionsendpoint provides a single, visual place to inspect orders and diagnose subscriptions.
🧪 Tests
- New
model/order_admin_filter_test.go(theorder_admin_filter_testsuite):setupOrderAdminTestDBspins upglebarez/sqlitein-memory +gorm.AutoMigrateforusersandorders.seedUsersAndOrdersshared fixture helper; every user must setAccessToken/AffCodeto satisfy unique indexes.TestOrderAdminFilter_ApplyTo: verifies zero-value filter is a no-op.TestGetAllOrders_FilterMatrix: 9 subtests coveringtype/status/source/user_id/plan_id/keywordand combinations.TestSearchOrders_StatusFilter: verifies the search path also honoursstatus.TestGetUsersBriefByIds_EmptyAndIn: short-circuit on empty ids +WHERE INquery + missing-id tolerance.
- New
model/subscription_defense_test.go: covers both theUserPlan.InsertandActivatePackageByOrderdefensive paths.
📚 Documentation
README.mdadds QQ group info (979158b add qq group).
⚠️ Upgrade Notes
- Zero database migration:
UserBriefis a new type,Order.Useris agorm:"-"transient field, andOrderAdminFilteris 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/searchnow accept optional query paramsstatus/source/user_id/plan_id/keyword. Fully backward-compatible — absent params are ignored.
- Defensive change:
UserPlan.InsertandActivatePackageByOrdernow refuseplan_id<=0. If any legacy code path relied on this tolerance, the upstream caller must be fixed (none should). - Frontend: new
views/admin/AdminOrders.vueplus a sidebar entry;api/order.jsextended, no breaking changes. - Backend build:
go build ./...; tests viago test ./model/ ./controller/ ./middleware/.