package exporter import ( "context" "time" "gorm.io/gorm" "github.com/break/junhong_cmp_fiber/pkg/constants" ) // AgentRechargeDataSource 代理充值导出数据源。 type AgentRechargeDataSource struct { db *gorm.DB } // NewAgentRechargeDataSource 创建代理充值导出数据源。 func NewAgentRechargeDataSource(db *gorm.DB) *AgentRechargeDataSource { return &AgentRechargeDataSource{db: db} } // Scene 返回导出场景编码。 func (s *AgentRechargeDataSource) Scene() string { return constants.ExportTaskSceneAgentRecharge } // Count 统计代理充值导出行数。 func (s *AgentRechargeDataSource) Count(ctx context.Context, params ExportParams) (int, error) { var total int64 query := s.applyFilters(s.baseQuery(ctx), params) if err := query.Count(&total).Error; err != nil { return 0, err } return int(total), nil } // Headers 返回代理充值导出表头。 func (s *AgentRechargeDataSource) Headers(context.Context, ExportParams) ([]string, error) { return []string{ "充值单号", "店铺名称", "充值类型", "充值金额(元)", "实付金额(元)", "充值前余额(元)", "充值后余额(元)", "状态", "支付方式", "运营备注", "驳回原因", "创建时间", "支付时间", "完成时间", "提交人", "审批来源", "审批状态", "支付凭证", }, nil } // Fetch 按 offset/limit 查询代理充值导出数据。 func (s *AgentRechargeDataSource) Fetch(ctx context.Context, params ExportParams, offset, limit int) ([][]string, error) { if limit <= 0 { return [][]string{}, nil } var items []agentRechargeExportRow query := s.applyFilters(s.baseQuery(ctx), params). Select(` r.recharge_no, r.amount, r.payment_method, r.status, r.remark, COALESCE(r.rejection_reason, '') AS rejection_reason, r.created_at, r.paid_at, r.completed_at, COALESCE(sh.shop_name, '') AS shop_name, COALESCE(ac.username, '') AS submitter_name, ai.provider AS approval_provider, ai.status AS approval_status, wt.amount AS actual_amount, wt.balance_before, wt.balance_after, COALESCE((SELECT string_agg(voucher.value, ',' ORDER BY voucher.ordinality) FROM jsonb_array_elements_text(COALESCE(r.payment_voucher_key, '[]'::jsonb)) WITH ORDINALITY AS voucher(value, ordinality)), '') AS voucher_keys `). Joins("LEFT JOIN tb_shop AS sh ON sh.id = r.shop_id"). Joins("LEFT JOIN tb_account AS ac ON ac.id = r.user_id"). Joins("LEFT JOIN tb_approval_instance AS ai ON ai.id = r.approval_instance_id"). Joins(`LEFT JOIN LATERAL ( SELECT t.amount, t.balance_before, t.balance_after FROM tb_agent_wallet_transaction AS t WHERE t.reference_type = ? AND t.reference_id = r.id AND t.transaction_type = ? AND t.status = ? AND t.deleted_at IS NULL ORDER BY t.id ASC LIMIT 1 ) AS wt ON TRUE`, constants.ReferenceTypeTopup, constants.AgentTransactionTypeRecharge, constants.TransactionStatusSuccess). Order("r.id ASC"). Limit(limit). Offset(offset) if err := query.Scan(&items).Error; err != nil { return nil, err } rows := make([][]string, 0, len(items)) for _, item := range items { rows = append(rows, []string{ item.RechargeNo, item.ShopName, formatRechargeType(item.PaymentMethod), formatMoneyYuan(item.Amount), formatOptionalMoneyYuan(item.ActualAmount), formatOptionalMoneyYuan(item.BalanceBefore), formatOptionalMoneyYuan(item.BalanceAfter), constants.GetRechargeStatusName(item.Status), constants.GetBusinessPaymentMethodName(item.PaymentMethod), item.Remark, item.RejectionReason, item.CreatedAt.Format(exportTimeLayout), formatOptionalTime(item.PaidAt), formatOptionalTime(item.CompletedAt), item.SubmitterName, formatApprovalProvider(item.ApprovalProvider), formatOptionalApprovalStatus(item.ApprovalStatus), item.VoucherKeys, }) } return rows, nil } func (s *AgentRechargeDataSource) baseQuery(ctx context.Context) *gorm.DB { return s.db.WithContext(ctx).Table("tb_agent_recharge_record AS r").Where("r.deleted_at IS NULL") } func (s *AgentRechargeDataSource) applyFilters(query *gorm.DB, params ExportParams) *gorm.DB { query = applyExportShopScope(query, params, "r.shop_id") if shopID, ok := filterUint(params.Filters, "shop_id"); ok { query = query.Where("r.shop_id = ?", shopID) } if status, ok := filterInt(params.Filters, "status"); ok { query = query.Where("r.status = ?", status) } if start, ok := filterTime(params.Filters, "start_date"); ok { query = query.Where("r.created_at >= ?", start) } if end, ok := filterEndDate(params.Filters, "end_date"); ok { query = query.Where("r.created_at <= ?", end) } return query } type agentRechargeExportRow struct { RechargeNo string `gorm:"column:recharge_no"` ShopName string `gorm:"column:shop_name"` Amount int64 `gorm:"column:amount"` ActualAmount *int64 `gorm:"column:actual_amount"` BalanceBefore *int64 `gorm:"column:balance_before"` BalanceAfter *int64 `gorm:"column:balance_after"` PaymentMethod string `gorm:"column:payment_method"` Status int `gorm:"column:status"` Remark string `gorm:"column:remark"` RejectionReason string `gorm:"column:rejection_reason"` CreatedAt time.Time `gorm:"column:created_at"` PaidAt *time.Time `gorm:"column:paid_at"` CompletedAt *time.Time `gorm:"column:completed_at"` SubmitterName string `gorm:"column:submitter_name"` ApprovalProvider *string `gorm:"column:approval_provider"` ApprovalStatus *int `gorm:"column:approval_status"` VoucherKeys string `gorm:"column:voucher_keys"` } func formatRechargeType(paymentMethod string) string { if paymentMethod == constants.RechargeMethodOffline { return "员工线下代充值" } return "在线充值" } func formatOptionalMoneyYuan(value *int64) string { if value == nil { return "" } return formatMoneyYuan(*value) } func formatApprovalProvider(provider *string) string { if provider == nil || *provider == "" { return "" } if *provider == constants.IntegrationProviderWeCom { return "企业微信" } return *provider } func formatOptionalApprovalStatus(status *int) string { if status == nil { return "" } return constants.GetApprovalStatusName(*status) }