package developer import ( "fmt" "verification-platform-backend/internal/database" "verification-platform-backend/internal/model" "verification-platform-backend/internal/service" "verification-platform-backend/pkg/response" "github.com/gin-gonic/gin" ) type FinanceRecordResponse struct { ID uint `json:"id"` OrderNo string `json:"order_no"` Type string `json:"type"` UserID uint `json:"user_id"` AppID uint `json:"app_id"` Amount float64 `json:"amount"` Detail string `json:"detail"` Status string `json:"status"` PaymentType string `json:"payment_type"` Remark string `json:"remark"` CreatedAt string `json:"created_at"` User *struct { ID uint `json:"id"` Username string `json:"username"` Email string `json:"email"` } `json:"user,omitempty"` } func SetupFinanceRoutes(r *gin.RouterGroup) { finance := r.Group("/finance") { finance.GET("/stats", handleGetFinanceStatistics) finance.GET("/statistics", handleGetFinanceStatistics) finance.GET("/recharge-records", handleGetRechargeRecords) finance.GET("/consumption-records", handleGetConsumptionRecords) finance.GET("/records", handleGetFinanceRecords) finance.DELETE("/records/:id", handleDeleteFinanceRecord) finance.POST("/records/batch-delete", handleBatchDeleteFinanceRecords) } } func handleGetFinanceStatistics(c *gin.Context) { userID, exists := c.Get("user_id") if !exists { response.Error(c, 401, "未授权") return } var appIDs []uint database.DB.Model(&model.Application{}).Where("user_id = ?", userID).Pluck("id", &appIDs) if len(appIDs) == 0 { response.Success(c, gin.H{ "total_income": 0, "total_expense": 0, "net_profit": 0, "monthly_transactions": 0, }) return } var appUserIDs []uint database.DB.Model(&model.AppUser{}).Where("application_id IN ?", appIDs).Pluck("id", &appUserIDs) if len(appUserIDs) == 0 { response.Success(c, gin.H{ "total_income": 0, "total_expense": 0, "net_profit": 0, "monthly_transactions": 0, }) return } var totalIncome float64 var totalExpense float64 database.DB.Model(&model.RechargeRecord{}). Where("user_id IN ? AND status = ?", appUserIDs, "success"). Select("COALESCE(SUM(amount), 0)"). Scan(&totalIncome) database.DB.Model(&model.ConsumptionRecord{}). Where("user_id IN ? AND status = ?", appUserIDs, "success"). Select("COALESCE(SUM(amount), 0)"). Scan(&totalExpense) response.Success(c, gin.H{ "total_income": totalIncome, "total_expense": totalExpense, "net_profit": totalIncome - totalExpense, }) } func handleGetRechargeRecords(c *gin.Context) { userID, exists := c.Get("user_id") if !exists { response.Error(c, 401, "未授权") return } var appIDs []uint database.DB.Model(&model.Application{}).Where("user_id = ?", userID).Pluck("id", &appIDs) if len(appIDs) == 0 { response.Success(c, gin.H{ "records": []model.RechargeRecord{}, "total": 0, }) return } var appUserIDs []uint database.DB.Model(&model.AppUser{}).Where("application_id IN ?", appIDs).Pluck("id", &appUserIDs) if len(appUserIDs) == 0 { response.Success(c, gin.H{ "records": []model.RechargeRecord{}, "total": 0, }) return } var records []model.RechargeRecord query := database.DB.Model(&model.RechargeRecord{}).Preload("AppUser").Where("user_id IN ?", appUserIDs) search := c.Query("search") status := c.Query("status") startDate := c.Query("start_date") endDate := c.Query("end_date") if search != "" { query = query.Where("order_no LIKE ? OR card_code LIKE ?", "%"+search+"%", "%"+search+"%") } if status != "" && status != "all" { query = query.Where("status = ?", status) } if startDate != "" { query = query.Where("created_at >= ?", startDate) } if endDate != "" { query = query.Where("created_at <= ?", endDate+" 23:59:59") } if err := query.Order("created_at DESC").Find(&records).Error; err != nil { response.Error(c, 500, "获取充值记录失败") return } response.Success(c, gin.H{ "records": records, "total": len(records), }) } func handleGetConsumptionRecords(c *gin.Context) { userID, exists := c.Get("user_id") if !exists { response.Error(c, 401, "未授权") return } var appIDs []uint database.DB.Model(&model.Application{}).Where("user_id = ?", userID).Pluck("id", &appIDs) if len(appIDs) == 0 { response.Success(c, gin.H{ "records": []model.ConsumptionRecord{}, "total": 0, }) return } var appUserIDs []uint database.DB.Model(&model.AppUser{}).Where("application_id IN ?", appIDs).Pluck("id", &appUserIDs) if len(appUserIDs) == 0 { response.Success(c, gin.H{ "records": []model.ConsumptionRecord{}, "total": 0, }) return } var records []model.ConsumptionRecord query := database.DB.Model(&model.ConsumptionRecord{}).Preload("AppUser").Where("user_id IN ?", appUserIDs) search := c.Query("search") recordType := c.Query("type") status := c.Query("status") startDate := c.Query("start_date") endDate := c.Query("end_date") if search != "" { query = query.Where("order_no LIKE ? OR content LIKE ?", "%"+search+"%", "%"+search+"%") } if recordType != "" && recordType != "all" { query = query.Where("type = ?", recordType) } if status != "" && status != "all" { query = query.Where("status = ?", status) } if startDate != "" { query = query.Where("created_at >= ?", startDate) } if endDate != "" { query = query.Where("created_at <= ?", endDate+" 23:59:59") } if err := query.Order("created_at DESC").Find(&records).Error; err != nil { response.Error(c, 500, "获取消费记录失败") return } response.Success(c, gin.H{ "records": records, "total": len(records), }) } func handleGetFinanceRecords(c *gin.Context) { userID, exists := c.Get("user_id") if !exists { response.Error(c, 401, "未授权") return } var appIDs []uint database.DB.Model(&model.Application{}).Where("user_id = ?", userID).Pluck("id", &appIDs) if len(appIDs) == 0 { response.Success(c, gin.H{ "recharge_records": []FinanceRecordResponse{}, "consumption_records": []FinanceRecordResponse{}, "total": 0, }) return } var appUserIDs []uint database.DB.Model(&model.AppUser{}).Where("application_id IN ?", appIDs).Pluck("id", &appUserIDs) if len(appUserIDs) == 0 { response.Success(c, gin.H{ "recharge_records": []FinanceRecordResponse{}, "consumption_records": []FinanceRecordResponse{}, "total": 0, }) return } page := c.DefaultQuery("page", "1") pageSize := c.DefaultQuery("page_size", "10") search := c.Query("search") recordType := c.Query("type") status := c.Query("status") startDate := c.Query("start_date") endDate := c.Query("end_date") var rechargeRecords []model.RechargeRecord rechargeQuery := database.DB.Model(&model.RechargeRecord{}).Preload("AppUser").Where("user_id IN ?", appUserIDs) if search != "" { rechargeQuery = rechargeQuery.Where("order_no LIKE ? OR card_code LIKE ?", "%"+search+"%", "%"+search+"%") } if recordType == "recharge" || recordType == "" || recordType == "all" { if status != "" && status != "all" { rechargeQuery = rechargeQuery.Where("status = ?", status) } if startDate != "" { rechargeQuery = rechargeQuery.Where("created_at >= ?", startDate) } if endDate != "" { rechargeQuery = rechargeQuery.Where("created_at <= ?", endDate+" 23:59:59") } if err := rechargeQuery.Order("created_at DESC").Find(&rechargeRecords).Error; err != nil { response.Error(c, 500, "获取充值记录失败") return } } var consumptionRecords []model.ConsumptionRecord consumptionQuery := database.DB.Model(&model.ConsumptionRecord{}).Preload("AppUser").Where("user_id IN ?", appUserIDs) if search != "" { consumptionQuery = consumptionQuery.Where("order_no LIKE ? OR content LIKE ?", "%"+search+"%", "%"+search+"%") } if recordType == "consumption" || recordType == "" || recordType == "all" { if status != "" && status != "all" { consumptionQuery = consumptionQuery.Where("status = ?", status) } if startDate != "" { consumptionQuery = consumptionQuery.Where("created_at >= ?", startDate) } if endDate != "" { consumptionQuery = consumptionQuery.Where("created_at <= ?", endDate+" 23:59:59") } if err := consumptionQuery.Order("created_at DESC").Find(&consumptionRecords).Error; err != nil { response.Error(c, 500, "获取消费记录失败") return } } var allRecords []FinanceRecordResponse for _, r := range rechargeRecords { var user *struct { ID uint `json:"id"` Username string `json:"username"` Email string `json:"email"` } if r.AppUser != nil && r.AppUser.ID != 0 { user = &struct { ID uint `json:"id"` Username string `json:"username"` Email string `json:"email"` }{ ID: r.AppUser.ID, Username: r.AppUser.Username, Email: r.AppUser.Email, } } allRecords = append(allRecords, FinanceRecordResponse{ ID: r.ID, OrderNo: r.OrderNo, Type: "recharge", UserID: r.UserID, AppID: r.AppUser.ApplicationID, Amount: r.Amount, Detail: r.CardCode, Status: r.Status, PaymentType: r.PaymentType, Remark: r.Remark, CreatedAt: r.CreatedAt.Format("2006-01-02 15:04:05"), User: user, }) } for _, r := range consumptionRecords { var user *struct { ID uint `json:"id"` Username string `json:"username"` Email string `json:"email"` } if r.AppUser != nil && r.AppUser.ID != 0 { user = &struct { ID uint `json:"id"` Username string `json:"username"` Email string `json:"email"` }{ ID: r.AppUser.ID, Username: r.AppUser.Username, Email: r.AppUser.Email, } } allRecords = append(allRecords, FinanceRecordResponse{ ID: r.ID, OrderNo: r.OrderNo, Type: "consumption", UserID: r.UserID, AppID: r.AppUser.ApplicationID, Amount: r.Amount, Detail: r.Content, Status: r.Status, PaymentType: r.PaymentType, Remark: r.Remark, CreatedAt: r.CreatedAt.Format("2006-01-02 15:04:05"), User: user, }) } total := len(allRecords) start := 0 end := total if p, err := parseInt(page); err == nil && p > 0 { if ps, err := parseInt(pageSize); err == nil && ps > 0 { start = (p - 1) * ps end = start + ps if start > total { start = total } if end > total { end = total } } } if start > end { start = end } response.Success(c, gin.H{ "records": allRecords[start:end], "total": total, }) } func parseInt(s string) (int, error) { var result int _, err := fmt.Sscanf(s, "%d", &result) return result, err } func handleDeleteFinanceRecord(c *gin.Context) { userID, exists := c.Get("user_id") if !exists { response.Error(c, 401, "未授权") return } recordID := c.Param("id") recordType := c.Query("type") var appIDs []uint database.DB.Model(&model.Application{}).Where("user_id = ?", userID).Pluck("id", &appIDs) if len(appIDs) == 0 { response.Error(c, 404, "记录不存在") return } var appUserIDs []uint database.DB.Model(&model.AppUser{}).Where("application_id IN ?", appIDs).Pluck("id", &appUserIDs) if len(appUserIDs) == 0 { response.Error(c, 404, "记录不存在") return } var deletedType string var deletedAmount float64 if recordType == "recharge" { var record model.RechargeRecord if err := database.DB.Where("id = ? AND user_id IN ?", recordID, appUserIDs).First(&record).Error; err != nil { response.Error(c, 404, "记录不存在") return } if err := database.DB.Delete(&record).Error; err != nil { response.Error(c, 500, "删除失败") return } deletedType = "充值记录" deletedAmount = record.Amount } else if recordType == "consumption" { var record model.ConsumptionRecord if err := database.DB.Where("id = ? AND user_id IN ?", recordID, appUserIDs).First(&record).Error; err != nil { response.Error(c, 404, "记录不存在") return } if err := database.DB.Delete(&record).Error; err != nil { response.Error(c, 500, "删除失败") return } deletedType = "消费记录" deletedAmount = record.Amount } else { var rechargeRecord model.RechargeRecord var consumptionRecord model.ConsumptionRecord if err := database.DB.Where("id = ? AND user_id IN ?", recordID, appUserIDs).First(&rechargeRecord).Error; err == nil { database.DB.Delete(&rechargeRecord) deletedType = "充值记录" deletedAmount = rechargeRecord.Amount service.LogOperation(c, "delete", "finance_record", nil, fmt.Sprintf("删除%s: %.2f", deletedType, deletedAmount), nil) response.Success(c, nil) return } if err := database.DB.Where("id = ? AND user_id IN ?", recordID, appUserIDs).First(&consumptionRecord).Error; err == nil { database.DB.Delete(&consumptionRecord) deletedType = "消费记录" deletedAmount = consumptionRecord.Amount service.LogOperation(c, "delete", "finance_record", nil, fmt.Sprintf("删除%s: %.2f", deletedType, deletedAmount), nil) response.Success(c, nil) return } response.Error(c, 404, "记录不存在") return } service.LogOperation(c, "delete", "finance_record", nil, fmt.Sprintf("删除%s: %.2f", deletedType, deletedAmount), nil) response.Success(c, nil) } func handleBatchDeleteFinanceRecords(c *gin.Context) { userID, exists := c.Get("user_id") if !exists { response.Error(c, 401, "未授权") return } var req struct { IDs []uint `json:"ids"` } if err := c.ShouldBindJSON(&req); err != nil { response.Error(c, 400, "参数错误") return } if len(req.IDs) == 0 { response.Error(c, 400, "请选择要删除的记录") return } var appIDs []uint database.DB.Model(&model.Application{}).Where("user_id = ?", userID).Pluck("id", &appIDs) if len(appIDs) == 0 { response.Error(c, 404, "记录不存在") return } var appUserIDs []uint database.DB.Model(&model.AppUser{}).Where("application_id IN ?", appIDs).Pluck("id", &appUserIDs) if len(appUserIDs) == 0 { response.Error(c, 404, "记录不存在") return } database.DB.Where("id IN ? AND user_id IN ?", req.IDs, appUserIDs).Delete(&model.RechargeRecord{}) database.DB.Where("id IN ? AND user_id IN ?", req.IDs, appUserIDs).Delete(&model.ConsumptionRecord{}) service.LogOperation(c, "batch_delete", "finance_record", nil, fmt.Sprintf("批量删除财务记录: %d条", len(req.IDs)), nil) response.Success(c, gin.H{"deleted": len(req.IDs)}) }