From 2389dbafc5b7f134f678c3120616ae1c76d1f490 Mon Sep 17 00:00:00 2001 From: "Apple\\Apple" Date: Tue, 7 Oct 2025 00:46:47 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat(topup):=20Admin-wide=20topup?= =?UTF-8?q?=20listing=20and=20route=20reorganization?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow administrators to view all platform topup orders and streamline admin-only routes. Frontend - TopupHistoryModal: dynamically switch endpoint by role - Admin → GET /api/user/topup (all orders) - Non-admin → GET /api/user/topup/self (own orders) - Use shared utils `isAdmin()`; keep logic centralized and DRY - Minor UI: set admin action button theme to outline for clarity Backend - model/topup.go: add GetAllTopUps(pageInfo) with pagination (ordered by id desc) - controller/topup.go: add GetAllTopUps handler returning PageInfo response - router/api-router.go: - Add admin route GET /api/user/topup (AdminAuth) - Move POST /api/user/topup/complete to adminRoute (keeps path stable, consolidates admin endpoints) Security/Behavior - Admin-only endpoints now reside under the admin route group with AdminAuth - No behavior change for regular users; no schema changes Affected files - model/topup.go - controller/topup.go - router/api-router.go - web/src/components/topup/modals/TopupHistoryModal.jsx --- controller/topup.go | 15 ++++++++++ model/topup.go | 29 +++++++++++++++++++ router/api-router.go | 3 +- .../topup/modals/TopupHistoryModal.jsx | 7 +++-- 4 files changed, 50 insertions(+), 4 deletions(-) diff --git a/controller/topup.go b/controller/topup.go index e6f6eef2d..8626695f3 100644 --- a/controller/topup.go +++ b/controller/topup.go @@ -330,6 +330,21 @@ func GetUserTopUps(c *gin.Context) { common.ApiSuccess(c, pageInfo) } +// GetAllTopUps 管理员获取全平台充值记录 +func GetAllTopUps(c *gin.Context) { + pageInfo := common.GetPageQuery(c) + + topups, total, err := model.GetAllTopUps(pageInfo) + if err != nil { + common.ApiError(c, err) + return + } + + pageInfo.SetTotal(int(total)) + pageInfo.SetItems(topups) + common.ApiSuccess(c, pageInfo) +} + type AdminCompleteTopupRequest struct { TradeNo string `json:"trade_no"` } diff --git a/model/topup.go b/model/topup.go index c280db430..e46a5a88f 100644 --- a/model/topup.go +++ b/model/topup.go @@ -136,6 +136,35 @@ func GetUserTopUps(userId int, pageInfo *common.PageInfo) (topups []*TopUp, tota return topups, total, nil } +// GetAllTopUps 获取全平台的充值记录(管理员使用) +func GetAllTopUps(pageInfo *common.PageInfo) (topups []*TopUp, total int64, err error) { + tx := DB.Begin() + if tx.Error != nil { + return nil, 0, tx.Error + } + defer func() { + if r := recover(); r != nil { + tx.Rollback() + } + }() + + if err = tx.Model(&TopUp{}).Count(&total).Error; err != nil { + tx.Rollback() + return nil, 0, err + } + + if err = tx.Order("id desc").Limit(pageInfo.GetPageSize()).Offset(pageInfo.GetStartIdx()).Find(&topups).Error; err != nil { + tx.Rollback() + return nil, 0, err + } + + if err = tx.Commit().Error; err != nil { + return nil, 0, err + } + + return topups, total, nil +} + // ManualCompleteTopUp 管理员手动完成订单并给用户充值 func ManualCompleteTopUp(tradeNo string) error { if tradeNo == "" { diff --git a/router/api-router.go b/router/api-router.go index 49a423602..963abd105 100644 --- a/router/api-router.go +++ b/router/api-router.go @@ -80,7 +80,6 @@ func SetApiRouter(router *gin.Engine) { selfRoute.POST("/stripe/pay", middleware.CriticalRateLimit(), controller.RequestStripePay) selfRoute.POST("/stripe/amount", controller.RequestStripeAmount) selfRoute.POST("/aff_transfer", controller.TransferAffQuota) - selfRoute.POST("/topup/complete", middleware.AdminAuth(), controller.AdminCompleteTopUp) selfRoute.PUT("/setting", controller.UpdateUserSetting) // 2FA routes @@ -95,6 +94,8 @@ func SetApiRouter(router *gin.Engine) { adminRoute.Use(middleware.AdminAuth()) { adminRoute.GET("/", controller.GetAllUsers) + adminRoute.GET("/topup", controller.GetAllTopUps) + adminRoute.POST("/topup/complete", controller.AdminCompleteTopUp) adminRoute.GET("/search", controller.SearchUsers) adminRoute.GET("/:id", controller.GetUser) adminRoute.POST("/", controller.CreateUser) diff --git a/web/src/components/topup/modals/TopupHistoryModal.jsx b/web/src/components/topup/modals/TopupHistoryModal.jsx index e2548f388..fe50c6864 100644 --- a/web/src/components/topup/modals/TopupHistoryModal.jsx +++ b/web/src/components/topup/modals/TopupHistoryModal.jsx @@ -63,9 +63,10 @@ const TopupHistoryModal = ({ visible, onCancel, t }) => { const loadTopups = async (currentPage, currentPageSize) => { setLoading(true); try { - const res = await API.get( - `/api/user/topup/self?p=${currentPage}&page_size=${currentPageSize}`, - ); + const endpoint = isAdmin() + ? `/api/user/topup?p=${currentPage}&page_size=${currentPageSize}` + : `/api/user/topup/self?p=${currentPage}&page_size=${currentPageSize}`; + const res = await API.get(endpoint); const { success, message, data } = res.data; if (success) { setTopups(data.items || []);