- 后端 internal/service 按职责拆分: fulfillment.go(1397→527)拆出 wallet/timeout/data/order/query/dashboard/shipnotify delivery.go(1124→801)拆出 upstream/link/state/helpers merchant.go(855→251)拆出 member/product/api_client/catalog/helpers - 前端 MerchantCenter.tsx(1327→606)拆出 merchantCenterTabs/merchantCenterUtils - docker-compose backend 透传 CORS_ALLOWED_ORIGINS - CORS 白名单实现(config/router/README/.env.example 配套) - 修复 gofmt 与文件尾部多余空行
196 lines
7.1 KiB
Go
196 lines
7.1 KiB
Go
package service
|
|
|
|
import (
|
|
"time"
|
|
|
|
"affiliate_dash/internal/model"
|
|
"affiliate_dash/internal/pkg/timeutil"
|
|
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
type DashboardStats struct {
|
|
Scope string `json:"scope"`
|
|
CatalogProductCount int64 `json:"catalog_product_count"`
|
|
ProductCount int64 `json:"product_count"`
|
|
ActiveProductCount int64 `json:"active_product_count"`
|
|
MerchantCount int64 `json:"merchant_count"`
|
|
ActiveMerchantCount int64 `json:"active_merchant_count"`
|
|
UserCount int64 `json:"user_count"`
|
|
OrderCount int64 `json:"order_count"`
|
|
TodayOrderCount int64 `json:"today_order_count"`
|
|
TotalSales int64 `json:"total_sales"`
|
|
TodaySales int64 `json:"today_sales"`
|
|
TotalFees int64 `json:"total_fees"`
|
|
TodayFees int64 `json:"today_fees"`
|
|
PaidOrderCount int64 `json:"paid_order_count"`
|
|
DeliveringOrderCount int64 `json:"delivering_order_count"`
|
|
DeliveredOrderCount int64 `json:"delivered_order_count"`
|
|
ShipFailedOrderCount int64 `json:"ship_failed_order_count"`
|
|
CancelledOrderCount int64 `json:"cancelled_order_count"`
|
|
WalletAvailableBalance int64 `json:"wallet_available_balance"`
|
|
WalletFrozenBalance int64 `json:"wallet_frozen_balance"`
|
|
APIClientCount int64 `json:"api_client_count"`
|
|
ActiveAPIClientCount int64 `json:"active_api_client_count"`
|
|
CallbackSubscriptionCount int64 `json:"callback_subscription_count"`
|
|
PendingCallbackCount int64 `json:"pending_callback_count"`
|
|
FailedCallbackCount int64 `json:"failed_callback_count"`
|
|
}
|
|
|
|
type dashboardStatusCount struct {
|
|
Status string
|
|
Count int64
|
|
}
|
|
|
|
// Dashboard 按角色汇总运营指标:平台管理员看全平台,商户账号看当前商户。
|
|
func (s *FulfillmentService) Dashboard(merchantID uint, isPlatformAdmin bool) (*DashboardStats, error) {
|
|
stats := &DashboardStats{Scope: "merchant"}
|
|
if isPlatformAdmin {
|
|
stats.Scope = "platform"
|
|
}
|
|
todayStart := timeutil.StartOfDay(time.Now())
|
|
|
|
productScope := func() *gorm.DB {
|
|
tx := s.db.Model(&model.MerchantProduct{})
|
|
if !isPlatformAdmin {
|
|
tx = tx.Where("merchant_id = ?", merchantID)
|
|
}
|
|
return tx
|
|
}
|
|
orderScope := func() *gorm.DB {
|
|
tx := s.db.Model(&model.FulfillmentOrder{})
|
|
if !isPlatformAdmin {
|
|
tx = tx.Where("merchant_id = ?", merchantID)
|
|
}
|
|
return tx
|
|
}
|
|
walletScope := func() *gorm.DB {
|
|
tx := s.db.Model(&model.WalletAccount{})
|
|
if !isPlatformAdmin {
|
|
tx = tx.Where("merchant_id = ?", merchantID)
|
|
}
|
|
return tx
|
|
}
|
|
apiClientScope := func() *gorm.DB {
|
|
tx := s.db.Model(&model.APIClient{})
|
|
if !isPlatformAdmin {
|
|
tx = tx.Where("merchant_id = ?", merchantID)
|
|
}
|
|
return tx
|
|
}
|
|
callbackScope := func() *gorm.DB {
|
|
tx := s.db.Model(&model.CallbackSubscription{})
|
|
if !isPlatformAdmin {
|
|
tx = tx.Where("merchant_id = ?", merchantID)
|
|
}
|
|
return tx
|
|
}
|
|
callbackDeliveryScope := func() *gorm.DB {
|
|
tx := s.db.Model(&model.CallbackDelivery{})
|
|
if !isPlatformAdmin {
|
|
tx = tx.Where("merchant_id = ?", merchantID)
|
|
}
|
|
return tx
|
|
}
|
|
|
|
if err := s.db.Model(&model.Product{}).Count(&stats.CatalogProductCount).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
if err := productScope().Count(&stats.ProductCount).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
if err := productScope().Where("status = ?", model.ProductStatusActive).Count(&stats.ActiveProductCount).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
if isPlatformAdmin {
|
|
if err := s.db.Model(&model.Merchant{}).Count(&stats.MerchantCount).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
if err := s.db.Model(&model.Merchant{}).Where("status = ?", model.MerchantStatusActive).Count(&stats.ActiveMerchantCount).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
if err := s.db.Model(&model.User{}).Count(&stats.UserCount).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
} else {
|
|
if err := s.db.Model(&model.Merchant{}).Where("id = ?", merchantID).Count(&stats.MerchantCount).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
if err := s.db.Model(&model.Merchant{}).Where("id = ? AND status = ?", merchantID, model.MerchantStatusActive).Count(&stats.ActiveMerchantCount).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
if err := s.db.Model(&model.User{}).
|
|
Joins("JOIN merchant_members ON merchant_members.user_id = users.id").
|
|
Where("merchant_members.merchant_id = ?", merchantID).
|
|
Count(&stats.UserCount).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
stats.CatalogProductCount = stats.ProductCount
|
|
}
|
|
if err := orderScope().Count(&stats.OrderCount).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
if err := orderScope().Where("created_at >= ?", todayStart).Count(&stats.TodayOrderCount).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
if err := orderScope().Where("order_status <> ?", model.OrderStatusCancelled).
|
|
Select("COALESCE(SUM(amount),0)").Scan(&stats.TotalSales).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
if err := orderScope().Where("order_status <> ?", model.OrderStatusCancelled).
|
|
Where("created_at >= ?", todayStart).
|
|
Select("COALESCE(SUM(amount),0)").Scan(&stats.TodaySales).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
if err := orderScope().Where("order_status <> ?", model.OrderStatusCancelled).
|
|
Select("COALESCE(SUM(service_fee_amount),0)").Scan(&stats.TotalFees).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
if err := orderScope().Where("order_status <> ?", model.OrderStatusCancelled).
|
|
Where("created_at >= ?", todayStart).
|
|
Select("COALESCE(SUM(service_fee_amount),0)").Scan(&stats.TodayFees).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
var orderStatusCounts []dashboardStatusCount
|
|
if err := orderScope().Select("order_status AS status, COUNT(*) AS count").
|
|
Group("order_status").Scan(&orderStatusCounts).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
for _, item := range orderStatusCounts {
|
|
switch item.Status {
|
|
case model.OrderStatusPaid:
|
|
stats.PaidOrderCount = item.Count
|
|
case model.OrderStatusDelivering:
|
|
stats.DeliveringOrderCount = item.Count
|
|
case model.OrderStatusDelivered:
|
|
stats.DeliveredOrderCount = item.Count
|
|
case model.OrderStatusShipFailed:
|
|
stats.ShipFailedOrderCount = item.Count
|
|
case model.OrderStatusCancelled:
|
|
stats.CancelledOrderCount = item.Count
|
|
}
|
|
}
|
|
if err := walletScope().Select("COALESCE(SUM(available_balance),0)").Scan(&stats.WalletAvailableBalance).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
if err := walletScope().Select("COALESCE(SUM(frozen_balance),0)").Scan(&stats.WalletFrozenBalance).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
if err := apiClientScope().Count(&stats.APIClientCount).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
if err := apiClientScope().Where("status = ?", model.APIClientStatusActive).Count(&stats.ActiveAPIClientCount).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
if err := callbackScope().Count(&stats.CallbackSubscriptionCount).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
if err := callbackDeliveryScope().Where("status = ?", model.CallbackDeliveryPending).Count(&stats.PendingCallbackCount).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
if err := callbackDeliveryScope().Where("status = ?", model.CallbackDeliveryFailed).Count(&stats.FailedCallbackCount).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
return stats, nil
|
|
}
|