From f3b9feca6a03410a464c585f1374f40867b82658 Mon Sep 17 00:00:00 2001 From: admin Date: Sun, 10 May 2026 08:41:49 +0800 Subject: [PATCH] =?UTF-8?q?agent=E5=90=8E=E5=8F=B0finance=E5=92=8Cusers?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=9C=8D=E5=8A=A1=E7=AB=AF=E5=88=86=E9=A1=B5?= =?UTF-8?q?=E5=92=8C=E7=BB=9F=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/internal/router/agent/agent.go | 122 +++++++++++++++++- .../agent/finance/components/data-table.vue | 4 +- frontend/src/pages/agent/finance/index.vue | 79 +++++++----- .../agent/users/components/data-table.vue | 4 +- frontend/src/pages/agent/users/index.vue | 63 +++++---- 5 files changed, 203 insertions(+), 69 deletions(-) diff --git a/backend/internal/router/agent/agent.go b/backend/internal/router/agent/agent.go index f762b0c..1cf3b14 100644 --- a/backend/internal/router/agent/agent.go +++ b/backend/internal/router/agent/agent.go @@ -3,6 +3,7 @@ package agent import ( "fmt" "math/rand" + "sort" "strconv" "strings" "time" @@ -432,6 +433,11 @@ func handleGetUsers(c *gin.Context) { var total int64 database.DB.Model(&model.AppUser{}).Where("application_id IN ?", appIDs).Count(&total) + var activeCount, disabledCount, bannedCount int64 + database.DB.Model(&model.AppUser{}).Where("application_id IN ? AND status = ?", appIDs, "active").Count(&activeCount) + database.DB.Model(&model.AppUser{}).Where("application_id IN ? AND status = ?", appIDs, "disabled").Count(&disabledCount) + database.DB.Model(&model.AppUser{}).Where("application_id IN ? AND status = ?", appIDs, "banned").Count(&bannedCount) + var users []model.AppUser offset := 0 if pageInt, err := strconv.Atoi(page); err == nil && pageInt > 1 { @@ -446,8 +452,11 @@ func handleGetUsers(c *gin.Context) { database.DB.Where("application_id IN ?", appIDs).Order("created_at DESC").Limit(limit).Offset(offset).Find(&users) response.Success(c, gin.H{ - "users": users, - "total": total, + "users": users, + "total": total, + "active_count": activeCount, + "disabled_count": disabledCount, + "banned_count": bannedCount, }) } @@ -460,12 +469,113 @@ func handleGetFinance(c *gin.Context) { return } - var records []model.RechargeRecord - database.DB.Where("user_id = ?", userID).Order("created_at DESC").Limit(20).Find(&records) + typeFilter := c.Query("type") + page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) + pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20")) + + type TransactionItem struct { + ID uint `json:"id"` + Type string `json:"type"` + Amount float64 `json:"amount"` + Description string `json:"description"` + Balance float64 `json:"balance"` + CreatedAt string `json:"created_at"` + } + + var allTransactions []TransactionItem + + var rechargeRecords []model.RechargeRecord + database.DB.Where("user_id = ? AND status = ?", userID, "success").Order("created_at DESC").Find(&rechargeRecords) + for _, r := range rechargeRecords { + txType := "recharge" + if r.PaymentType == "refund" || r.Remark != "" && strings.Contains(strings.ToLower(r.Remark), "refund") { + txType = "refund" + } + desc := r.Remark + if desc == "" { + desc = "充值" + } + allTransactions = append(allTransactions, TransactionItem{ + ID: r.ID, + Type: txType, + Amount: r.Amount, + Description: desc, + Balance: user.Balance, + CreatedAt: r.CreatedAt.Format("2006-01-02T15:04:05Z07:00"), + }) + } + + var consumptionRecords []model.ConsumptionRecord + database.DB.Where("user_id = ?", userID).Order("created_at DESC").Find(&consumptionRecords) + for _, r := range consumptionRecords { + desc := r.Description + if desc == "" { + desc = r.Content + } + if desc == "" { + desc = "消费" + } + allTransactions = append(allTransactions, TransactionItem{ + ID: r.ID, + Type: "consume", + Amount: r.Amount, + Description: desc, + Balance: r.BalanceAfter, + CreatedAt: r.CreatedAt.Format("2006-01-02T15:04:05Z07:00"), + }) + } + + sort.Slice(allTransactions, func(i, j int) bool { + return allTransactions[i].CreatedAt > allTransactions[j].CreatedAt + }) + + var filtered []TransactionItem + if typeFilter != "" { + for _, tx := range allTransactions { + if tx.Type == typeFilter { + filtered = append(filtered, tx) + } + } + } else { + filtered = allTransactions + } + + total := len(filtered) + + rechargeCount := 0 + consumeCount := 0 + var totalRecharge, totalConsume float64 + for _, tx := range allTransactions { + if tx.Type == "recharge" || tx.Type == "refund" { + rechargeCount++ + totalRecharge += tx.Amount + } else if tx.Type == "consume" { + consumeCount++ + totalConsume += tx.Amount + } + } + + offset := (page - 1) * pageSize + end := offset + pageSize + if offset > total { + offset = total + } + if end > total { + end = total + } + + paginated := filtered[offset:end] response.Success(c, gin.H{ - "balance": user.Balance, - "records": records, + "balance": user.Balance, + "transactions": paginated, + "total": total, + "page": page, + "page_size": pageSize, + "recharge_count": rechargeCount, + "consume_count": consumeCount, + "total_recharge": totalRecharge, + "total_consume": totalConsume, }) } diff --git a/frontend/src/pages/agent/finance/components/data-table.vue b/frontend/src/pages/agent/finance/components/data-table.vue index 1f8dcc7..6a6621f 100644 --- a/frontend/src/pages/agent/finance/components/data-table.vue +++ b/frontend/src/pages/agent/finance/components/data-table.vue @@ -16,6 +16,7 @@ import DataTableToolbar from '@/pages/agent/finance/components/data-table-toolba const props = defineProps, 'columns'> & { typeFilter?: string + serverPagination?: DataTableProps['serverPagination'] }>() const emit = defineEmits<{ @@ -34,6 +35,7 @@ const table = generateVueTable({ get data() { return props.data }, get loading() { return props.loading }, columns: columns.value, + serverPagination: props.serverPagination, }) const columnLabels: Record = { @@ -51,7 +53,7 @@ defineExpose({