diff --git a/backend/internal/modules/adminfinance/dashboard.go b/backend/internal/modules/adminfinance/dashboard.go index 09b0834..2a92862 100644 --- a/backend/internal/modules/adminfinance/dashboard.go +++ b/backend/internal/modules/adminfinance/dashboard.go @@ -25,15 +25,22 @@ func (r *Repository) Dashboard(ctx context.Context, query DashboardQuery) (*Dash func (r *Repository) summary(ctx context.Context, query DashboardQuery) (*FinanceSummaryDTO, error) { db := r.db.WithContext(ctx) var payment paymentSummaryRow - if err := db.Table("payment_orders"). - Select(`COALESCE(SUM(CASE WHEN biz_type IN ('order_pay') AND status = 'paid' THEN amount_cent ELSE 0 END), 0) AS total_flow_amount_cent, - COALESCE(SUM(CASE WHEN biz_type IN ? AND status = 'refunded' THEN amount_cent ELSE 0 END), 0) AS total_refund_amount_cent, - COALESCE(SUM(CASE WHEN biz_type IN ? AND status = 'refunding' THEN amount_cent ELSE 0 END), 0) AS pending_refund_amount_cent, - COALESCE(SUM(CASE WHEN biz_type IN ('order_pay') AND status = 'paid' THEN 1 ELSE 0 END), 0) AS successful_pay_count, - COALESCE(SUM(CASE WHEN biz_type IN ? AND status = 'refunded' THEN 1 ELSE 0 END), 0) AS successful_refund_count, - COALESCE(SUM(CASE WHEN biz_type IN ? AND status = 'refunding' THEN 1 ELSE 0 END), 0) AS pending_refund_count`, - refundBizTypes(), refundBizTypes(), refundBizTypes(), refundBizTypes()). - Where("created_at >= ? AND created_at <= ?", query.StartDate, query.EndDate). + if err := db.Table("payment_orders AS po"). + Select(`COALESCE(SUM(CASE WHEN po.biz_type IN ('order_pay') AND po.status = 'paid' THEN po.amount_cent ELSE 0 END), 0) AS total_flow_amount_cent, + COALESCE(SUM(CASE WHEN po.biz_type IN ? AND po.status = 'refunded' THEN po.amount_cent ELSE 0 END), 0) AS total_refund_amount_cent, + COALESCE(SUM(CASE WHEN po.biz_type IN ? AND po.status = 'refunding' THEN po.amount_cent ELSE 0 END), 0) AS pending_refund_amount_cent, + COALESCE(SUM(CASE WHEN po.biz_type IN ('order_pay') AND po.status = 'paid' THEN 1 ELSE 0 END), 0) AS successful_pay_count, + COALESCE(SUM(CASE WHEN po.biz_type IN ? AND po.status = 'refunded' AND po.amount_cent >= COALESCE(orig.amount_cent, 0) THEN 1 ELSE 0 END), 0) AS full_refund_count, + COALESCE(SUM(CASE WHEN po.biz_type IN ? AND po.status = 'refunded' AND po.amount_cent < COALESCE(orig.amount_cent, 0) THEN 1 ELSE 0 END), 0) AS partial_refund_count, + COALESCE(SUM(CASE WHEN po.biz_type IN ? AND po.status = 'refunding' THEN 1 ELSE 0 END), 0) AS pending_refund_count`, + refundBizTypes(), refundBizTypes(), refundBizTypes(), refundBizTypes(), refundBizTypes()). + Joins(`LEFT JOIN ( + SELECT order_id, MAX(amount_cent) AS amount_cent + FROM payment_orders + WHERE biz_type = 'order_pay' AND status = 'paid' + GROUP BY order_id + ) AS orig ON orig.order_id = po.order_id`). + Where("po.created_at >= ? AND po.created_at <= ?", query.StartDate, query.EndDate). Scan(&payment).Error; err != nil { return nil, err } @@ -85,7 +92,9 @@ func (r *Repository) summary(ctx context.Context, query DashboardQuery) (*Financ SettlementDiffAmountCent: settlement.OwnerShouldIncomeAmountCent - settlement.OwnerWalletIncomeAmountCent, EstimatedIncomeAmountCent: estimated.EstimatedIncomeAmountCent, SuccessfulPayCount: payment.SuccessfulPayCount, - SuccessfulRefundCount: payment.SuccessfulRefundCount, + SuccessfulRefundCount: payment.FullRefundCount + payment.PartialRefundCount, + FullRefundCount: payment.FullRefundCount, + PartialRefundCount: payment.PartialRefundCount, PendingRefundCount: payment.PendingRefundCount, SettledOrderCount: settlement.SettledOrderCount, PendingSettleOrderCount: estimated.PendingSettleOrderCount, @@ -96,17 +105,24 @@ func (r *Repository) summary(ctx context.Context, query DashboardQuery) (*Financ func (r *Repository) dailyItems(ctx context.Context, query DashboardQuery) ([]FinanceDailyDTO, error) { db := r.db.WithContext(ctx) payments := make([]dailyPaymentRow, 0) - if err := db.Table("payment_orders"). - Select(`DATE(created_at) AS date, - COALESCE(SUM(CASE WHEN biz_type IN ('order_pay') AND status = 'paid' THEN amount_cent ELSE 0 END), 0) AS total_flow_amount_cent, - COALESCE(SUM(CASE WHEN biz_type IN ? AND status = 'refunded' THEN amount_cent ELSE 0 END), 0) AS total_refund_amount_cent, - COALESCE(SUM(CASE WHEN biz_type IN ? AND status = 'refunding' THEN amount_cent ELSE 0 END), 0) AS pending_refund_amount_cent, - COALESCE(SUM(CASE WHEN biz_type IN ('order_pay') AND status = 'paid' THEN 1 ELSE 0 END), 0) AS successful_pay_count, - COALESCE(SUM(CASE WHEN biz_type IN ? AND status = 'refunded' THEN 1 ELSE 0 END), 0) AS successful_refund_count, - COALESCE(SUM(CASE WHEN biz_type IN ? AND status = 'refunding' THEN 1 ELSE 0 END), 0) AS pending_refund_count`, - refundBizTypes(), refundBizTypes(), refundBizTypes(), refundBizTypes()). - Where("created_at >= ? AND created_at <= ?", query.StartDate, query.EndDate). - Group("DATE(created_at)"). + if err := db.Table("payment_orders AS po"). + Select(`DATE(po.created_at) AS date, + COALESCE(SUM(CASE WHEN po.biz_type IN ('order_pay') AND po.status = 'paid' THEN po.amount_cent ELSE 0 END), 0) AS total_flow_amount_cent, + COALESCE(SUM(CASE WHEN po.biz_type IN ? AND po.status = 'refunded' THEN po.amount_cent ELSE 0 END), 0) AS total_refund_amount_cent, + COALESCE(SUM(CASE WHEN po.biz_type IN ? AND po.status = 'refunding' THEN po.amount_cent ELSE 0 END), 0) AS pending_refund_amount_cent, + COALESCE(SUM(CASE WHEN po.biz_type IN ('order_pay') AND po.status = 'paid' THEN 1 ELSE 0 END), 0) AS successful_pay_count, + COALESCE(SUM(CASE WHEN po.biz_type IN ? AND po.status = 'refunded' AND po.amount_cent >= COALESCE(orig.amount_cent, 0) THEN 1 ELSE 0 END), 0) AS full_refund_count, + COALESCE(SUM(CASE WHEN po.biz_type IN ? AND po.status = 'refunded' AND po.amount_cent < COALESCE(orig.amount_cent, 0) THEN 1 ELSE 0 END), 0) AS partial_refund_count, + COALESCE(SUM(CASE WHEN po.biz_type IN ? AND po.status = 'refunding' THEN 1 ELSE 0 END), 0) AS pending_refund_count`, + refundBizTypes(), refundBizTypes(), refundBizTypes(), refundBizTypes(), refundBizTypes()). + Joins(`LEFT JOIN ( + SELECT order_id, MAX(amount_cent) AS amount_cent + FROM payment_orders + WHERE biz_type = 'order_pay' AND status = 'paid' + GROUP BY order_id + ) AS orig ON orig.order_id = po.order_id`). + Where("po.created_at >= ? AND po.created_at <= ?", query.StartDate, query.EndDate). + Group("DATE(po.created_at)"). Scan(&payments).Error; err != nil { return nil, err } @@ -153,7 +169,9 @@ func (r *Repository) dailyItems(ctx context.Context, query DashboardQuery) ([]Fi item.PendingRefundAmountCent = row.PendingRefundAmountCent item.ChannelNetAmountCent = row.TotalFlowAmountCent - row.TotalRefundAmountCent item.SuccessfulPayCount = row.SuccessfulPayCount - item.SuccessfulRefundCount = row.SuccessfulRefundCount + item.SuccessfulRefundCount = row.FullRefundCount + row.PartialRefundCount + item.FullRefundCount = row.FullRefundCount + item.PartialRefundCount = row.PartialRefundCount item.PendingRefundCount = row.PendingRefundCount itemsByDate[date] = item } @@ -188,7 +206,8 @@ type paymentSummaryRow struct { TotalRefundAmountCent int64 PendingRefundAmountCent int64 SuccessfulPayCount int64 - SuccessfulRefundCount int64 + FullRefundCount int64 + PartialRefundCount int64 PendingRefundCount int64 } @@ -210,7 +229,8 @@ type dailyPaymentRow struct { TotalRefundAmountCent int64 PendingRefundAmountCent int64 SuccessfulPayCount int64 - SuccessfulRefundCount int64 + FullRefundCount int64 + PartialRefundCount int64 PendingRefundCount int64 } diff --git a/backend/internal/modules/adminfinance/dto.go b/backend/internal/modules/adminfinance/dto.go index dee847d..51f2192 100644 --- a/backend/internal/modules/adminfinance/dto.go +++ b/backend/internal/modules/adminfinance/dto.go @@ -37,6 +37,8 @@ type FinanceSummaryDTO struct { EstimatedIncomeAmountCent int64 `json:"estimated_income_amount_cent"` SuccessfulPayCount int64 `json:"successful_pay_count"` SuccessfulRefundCount int64 `json:"successful_refund_count"` + FullRefundCount int64 `json:"full_refund_count"` + PartialRefundCount int64 `json:"partial_refund_count"` PendingRefundCount int64 `json:"pending_refund_count"` SettledOrderCount int64 `json:"settled_order_count"` PendingSettleOrderCount int64 `json:"pending_settle_order_count"` @@ -56,6 +58,8 @@ type FinanceDailyDTO struct { EstimatedIncomeAmountCent int64 `json:"estimated_income_amount_cent"` SuccessfulPayCount int64 `json:"successful_pay_count"` SuccessfulRefundCount int64 `json:"successful_refund_count"` + FullRefundCount int64 `json:"full_refund_count"` + PartialRefundCount int64 `json:"partial_refund_count"` PendingRefundCount int64 `json:"pending_refund_count"` SettledOrderCount int64 `json:"settled_order_count"` } diff --git a/frontend/src/features/admin/api/adminFinance.ts b/frontend/src/features/admin/api/adminFinance.ts index af189e5..1e06590 100644 --- a/frontend/src/features/admin/api/adminFinance.ts +++ b/frontend/src/features/admin/api/adminFinance.ts @@ -17,6 +17,8 @@ export interface FinanceSummary { estimated_income_amount_cent: number successful_pay_count: number successful_refund_count: number + full_refund_count: number + partial_refund_count: number pending_refund_count: number settled_order_count: number pending_settle_order_count: number @@ -36,6 +38,8 @@ export interface FinanceDailyItem { estimated_income_amount_cent: number successful_pay_count: number successful_refund_count: number + full_refund_count: number + partial_refund_count: number pending_refund_count: number settled_order_count: number } diff --git a/frontend/src/features/admin/views/AdminFinanceDashboardView.vue b/frontend/src/features/admin/views/AdminFinanceDashboardView.vue index 4193fdf..53be3e4 100644 --- a/frontend/src/features/admin/views/AdminFinanceDashboardView.vue +++ b/frontend/src/features/admin/views/AdminFinanceDashboardView.vue @@ -93,7 +93,10 @@ function rowDiffClass(row: FinanceDailyItem) {
总退款 {{ moneyCent(dashboard.summary.total_refund_amount_cent) }} - {{ dashboard.summary.successful_refund_count }} 笔成功退款 + {{ dashboard.summary.full_refund_count }} 笔全额 / + {{ dashboard.summary.partial_refund_count }} 笔部分
渠道净流入 @@ -167,8 +170,11 @@ function rowDiffClass(row: FinanceDailyItem) { - - + + + + +