Files
hfb_sys/backend/internal/modules/distribution/dto.go
T
yml2213 22fcaa5945 feat(distribution): 分站收号压价解耦买家价(方案 B 新口径)
核心语义反转:receive_cost_delta 为压价点数,收号比例 = 主站参考比例 R + 点数,
点数越大号主收号价越低;买家售价锚定主站参考比例推导,不再随收号价联动。

- 迁移 000072:distribution_sites 新增 receive_cost_delta(旧 receive_ratio_delta 保留只读)
- receive_pricing:新增 Normalize/ApplySiteReceiveCostDelta;分站定价买家侧改用
  R 锚点(referenceSellerCoinBasePrice),快照写入 site_receive_cost_delta 与 pricing_model 标记
- site_receive:新增 resolveSiteReceiveCostDelta 读取链路,旧 ResolveReceiveRatioDelta 保留
- 分成不变:压价差经结算层 profit 自动进入 35/40/25 三方分成池;
  货架自主加价仍 100% 归分站,两条边界均以主站为锚
- 权限对齐旧字段:主站全局管理员与分站操作员均可设置
- 前端三端同步:主站 pricing.ts/usePricingCalculator 买卖解耦试算、
  主站后台弹窗改「收号压价」价格语义文案、分销后台 SiteSettings 同步
- 测试:单测锚定 R=43 时 cost_delta=3 → 收号 217.4 / 卖价 263.2 不变 / markup 池 30.6→54.9
2026-09-17 15:54:56 +08:00

559 lines
24 KiB
Go

package distribution
import "time"
type SiteDTO struct {
ID uint64 `json:"id"`
SiteCode string `json:"site_code"`
SiteName string `json:"site_name"`
Domain string `json:"domain"`
Status string `json:"status"`
DisplayAccountEnabled bool `json:"display_account_enabled"`
LogoURL string `json:"logo_url"`
FaviconURL string `json:"favicon_url"`
BannersJSON string `json:"banners_json"`
AnnouncementsJSON string `json:"announcements_json"`
FooterInfoJSON string `json:"footer_info_json"`
DefaultSupportGroupID *uint64 `json:"default_support_group_id,omitempty"`
ListingQrcodeURL string `json:"listing_qrcode_url"`
ReceiveRatioDelta float64 `json:"receive_ratio_delta"`
ReceiveCostDelta float64 `json:"receive_cost_delta"`
TaxEnabled bool `json:"tax_enabled"`
TaxRateBPS int64 `json:"tax_rate_bps"`
SettlementHoldDays int `json:"settlement_hold_days"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
type CreateSiteRequest struct {
SiteCode string `json:"site_code" binding:"required,max=64"`
SiteName string `json:"site_name" binding:"required,max=128"`
Domain string `json:"domain" binding:"required,max=255"`
DisplayAccountEnabled *bool `json:"display_account_enabled"`
DefaultSupportGroupID *uint64 `json:"default_support_group_id"`
ListingQrcodeURL *string `json:"listing_qrcode_url"`
ReceiveRatioDelta *float64 `json:"receive_ratio_delta"`
ReceiveCostDelta *float64 `json:"receive_cost_delta"`
TaxEnabled *bool `json:"tax_enabled"`
TaxRateBPS *int64 `json:"tax_rate_bps"`
SettlementHoldDays *int `json:"settlement_hold_days"`
}
type UpdateSiteRequest struct {
SiteName *string `json:"site_name"`
Domain *string `json:"domain"`
Status *string `json:"status"`
DisplayAccountEnabled *bool `json:"display_account_enabled"`
DefaultSupportGroupID *uint64 `json:"default_support_group_id"`
ListingQrcodeURL *string `json:"listing_qrcode_url"`
ReceiveRatioDelta *float64 `json:"receive_ratio_delta"`
ReceiveCostDelta *float64 `json:"receive_cost_delta"`
TaxEnabled *bool `json:"tax_enabled"`
TaxRateBPS *int64 `json:"tax_rate_bps"`
SettlementHoldDays *int `json:"settlement_hold_days"`
LogoURL *string `json:"logo_url"`
FaviconURL *string `json:"favicon_url"`
BannersJSON *string `json:"banners_json"`
AnnouncementsJSON *string `json:"announcements_json"`
FooterInfoJSON *string `json:"footer_info_json"`
}
type RuleDTO struct {
ID uint64 `json:"id"`
SiteID *uint64 `json:"site_id,omitempty"`
Mode string `json:"mode"`
Version int `json:"version"`
Status string `json:"status"`
PlatformReceiveRatio float64 `json:"platform_receive_ratio"`
PlatformSellRatio float64 `json:"platform_sell_ratio"`
DistributorReceiveRatio float64 `json:"distributor_receive_ratio"`
DistributorSellRatio float64 `json:"distributor_sell_ratio"`
DistributorARatio float64 `json:"distributor_a_ratio"`
DistributorBRatio float64 `json:"distributor_b_ratio"`
ServiceFeeValue float64 `json:"service_fee_value"`
ServiceFeeUnit string `json:"service_fee_unit"`
PaymentFeeBPS int64 `json:"payment_fee_bps"`
TaxEnabled bool `json:"tax_enabled"`
TaxRateBPS int64 `json:"tax_rate_bps"`
EffectiveFrom time.Time `json:"effective_from"`
EffectiveTo *time.Time `json:"effective_to,omitempty"`
CreatedBy *uint64 `json:"created_by,omitempty"`
CreatedAt time.Time `json:"created_at"`
}
type CreateRuleRequest struct {
SiteID *uint64 `json:"site_id"`
Mode string `json:"mode" binding:"required"`
PlatformReceiveRatio float64 `json:"platform_receive_ratio"`
PlatformSellRatio float64 `json:"platform_sell_ratio"`
DistributorReceiveRatio float64 `json:"distributor_receive_ratio"`
DistributorSellRatio float64 `json:"distributor_sell_ratio"`
DistributorARatio float64 `json:"distributor_a_ratio"`
DistributorBRatio float64 `json:"distributor_b_ratio"`
ServiceFeeValue float64 `json:"service_fee_value"`
ServiceFeeUnit string `json:"service_fee_unit" binding:"required"`
PaymentFeeBPS int64 `json:"payment_fee_bps"`
TaxEnabled bool `json:"tax_enabled"`
TaxRateBPS int64 `json:"tax_rate_bps"`
EffectiveFrom time.Time `json:"effective_from"`
}
type UpdateRuleStatusRequest struct {
Status string `json:"status" binding:"required,oneof=draft active disabled"`
}
type DistributionOrderDTO struct {
OrderID uint64 `json:"order_id"`
OrderNo string `json:"order_no"`
SiteID uint64 `json:"site_id"`
ListingID uint64 `json:"listing_id"`
AccountID uint64 `json:"account_id"`
OwnerID uint64 `json:"owner_id"`
RenterID uint64 `json:"renter_id"`
Status string `json:"status"`
HandoffStatus string `json:"handoff_status"`
RefundStatus string `json:"refund_status"`
SettlementStatus string `json:"settlement_status"`
// 分销快照释放状态:pending=待释放,settled=已释放入账;release_at 为预计释放时间。
DistributorSettlementStatus string `json:"distributor_settlement_status"`
ReleaseAt *time.Time `json:"release_at,omitempty"`
DistributionMode string `json:"distribution_mode"`
GrossPaidAmountCent int64 `json:"gross_paid_amount_cent"`
RefundAmountCent int64 `json:"refund_amount_cent"`
NetPaidAmountCent int64 `json:"net_paid_amount_cent"`
PaymentFeeCent int64 `json:"payment_fee_cent"`
ServiceFeeCent int64 `json:"service_fee_cent"`
MarkupAmountCent int64 `json:"markup_amount_cent"`
TaxAmountCent int64 `json:"tax_amount_cent"`
SplitBaseAmountCent int64 `json:"split_base_amount_cent"`
RoundingAdjustmentCent int64 `json:"rounding_adjustment_cent"`
CreatedAt time.Time `json:"created_at"`
// 关联业务与分销商收益透传字段
ListingNo string `json:"listing_no,omitempty"`
Title string `json:"title,omitempty"`
GameName string `json:"game_name,omitempty"`
ServerRegion string `json:"server_region,omitempty"`
LoginPlatform string `json:"login_platform,omitempty"`
RentDurationHours int `json:"rent_duration_hours,omitempty"`
RentedAt *time.Time `json:"rented_at,omitempty"`
RenterPhone string `json:"renter_phone,omitempty"`
RenterNickname string `json:"renter_nickname,omitempty"`
OwnerRentAmountCent int64 `json:"owner_rent_amount_cent,omitempty"`
BasePriceCent int64 `json:"base_price_cent,omitempty"`
ShelfMarkupCent int64 `json:"shelf_markup_cent,omitempty"`
DepositAmountCent int64 `json:"deposit_amount_cent,omitempty"`
// 当前分销商在该订单中的收益拆解
DistributorEarningCent int64 `json:"distributor_earning_cent"`
DistributorRole string `json:"distributor_role,omitempty"`
DistributorMarkupCent int64 `json:"distributor_markup_cent"`
DistributorSplitCent int64 `json:"distributor_split_cent"`
}
type DistributionOrderListQuery struct {
SiteID uint64
Kind string
Role string
Status string
Mode string
FinancialStatus string
Keyword string
Page int
Size int
}
type DistributionOrderPage struct {
Items []DistributionOrderDTO `json:"items"`
Total int64 `json:"total"`
Page int `json:"page"`
PageSize int `json:"page_size"`
}
type AccountDisplayDTO struct {
ID uint64 `json:"id"`
SiteID uint64 `json:"site_id"`
AccountID uint64 `json:"account_id"`
ListingID uint64 `json:"listing_id"`
DisplayStatus string `json:"display_status"`
MarkupAmountCent int64 `json:"markup_amount_cent"`
ShelfRatioDelta float64 `json:"shelf_ratio_delta"`
BaseRatio float64 `json:"base_ratio,omitempty"`
SiteRatio float64 `json:"site_ratio,omitempty"`
ListingNo string `json:"listing_no,omitempty"`
Title string `json:"title,omitempty"`
GameName string `json:"game_name,omitempty"`
ServerRegion string `json:"server_region,omitempty"`
LoginPlatform string `json:"login_platform,omitempty"`
RankLevel string `json:"rank_level,omitempty"`
HafCoinAmount int64 `json:"haf_coin_amount,omitempty"`
PriceCent int64 `json:"price_cent,omitempty"`
SitePriceCent int64 `json:"site_price_cent,omitempty"`
DepositAmountCent int64 `json:"deposit_amount_cent,omitempty"`
ListingStatus string `json:"listing_status,omitempty"`
InTransaction bool `json:"in_transaction,omitempty"`
ListingSiteID *uint64 `json:"listing_site_id,omitempty"`
SourceChannel string `json:"source_channel,omitempty"`
}
type SyncSiteAccountsRequest struct {
ListingIDs []uint64 `json:"listing_ids"`
CleanStaleListings bool `json:"clean_stale_listings"`
DefaultShelfRatioDelta float64 `json:"default_shelf_ratio_delta"`
}
type SyncSiteAccountsResult struct {
SyncedCount int64 `json:"synced_count"`
SkippedCount int64 `json:"skipped_count"`
UpdatedCount int64 `json:"updated_count"`
DisabledStaleCount int64 `json:"disabled_stale_count"`
TotalActive int64 `json:"total_active"`
}
type PublicDistributionListingDTO struct {
ListingID uint64 `json:"listing_id"`
ListingNo string `json:"listing_no"`
AccountID uint64 `json:"account_id"`
Title string `json:"title"`
GameName string `json:"game_name"`
ServerRegion string `json:"server_region"`
LoginPlatform string `json:"login_platform"`
RankLevel string `json:"rank_level"`
HafCoinAmount int64 `json:"haf_coin_amount"`
PriceCent int64 `json:"price_cent"`
DepositAmountCent int64 `json:"deposit_amount_cent"`
MarkupAmountCent int64 `json:"markup_amount_cent"`
ShelfRatioDelta float64 `json:"shelf_ratio_delta"`
InTransaction bool `json:"in_transaction"`
SiteCode string `json:"site_code"`
SiteName string `json:"site_name"`
}
type PublicDistributionListingsResult struct {
Items []PublicDistributionListingDTO `json:"items"`
Total int64 `json:"total"`
Page int `json:"page"`
PageSize int `json:"page_size"`
}
type PublicSiteInfoDTO struct {
SiteCode string `json:"site_code"`
SiteName string `json:"site_name"`
Domain string `json:"domain"`
Status string `json:"status"`
DisplayAccountEnabled bool `json:"display_account_enabled"`
LogoURL string `json:"logo_url"`
FaviconURL string `json:"favicon_url"`
BannersJSON string `json:"banners_json"`
AnnouncementsJSON string `json:"announcements_json"`
FooterInfoJSON string `json:"footer_info_json"`
DefaultSupportGroupID *uint64 `json:"default_support_group_id,omitempty"`
ReceiveRatioDelta float64 `json:"receive_ratio_delta"`
ReceiveCostDelta float64 `json:"receive_cost_delta"`
}
type UpdateAccountDisplayRequest struct {
DisplayStatus string `json:"display_status" binding:"required,oneof=enabled disabled sold offline"`
}
type PaymentChannelDTO struct {
ID uint64 `json:"id"`
SiteID uint64 `json:"site_id"`
ConfigID uint64 `json:"config_id"`
Priority int `json:"priority"`
Status string `json:"status"`
}
type BindPaymentChannelRequest struct {
ConfigID uint64 `json:"config_id" binding:"required"`
Priority int `json:"priority"`
}
type SettlementBatchDTO struct {
ID uint64 `json:"id"`
SiteID uint64 `json:"site_id"`
BatchNo string `json:"batch_no"`
PeriodStart time.Time `json:"period_start"`
PeriodEnd time.Time `json:"period_end"`
TotalAmountCent int64 `json:"total_amount_cent"`
Status string `json:"status"`
}
type CreateSettlementBatchRequest struct {
SiteID uint64 `json:"site_id" binding:"required"`
PeriodStart time.Time `json:"period_start" binding:"required"`
PeriodEnd time.Time `json:"period_end" binding:"required"`
}
type SnapshotPartyRequest struct {
PartyRole string `json:"party_role" binding:"required"`
PartyType string `json:"party_type" binding:"required"`
PartyID uint64 `json:"party_id"`
Ratio float64 `json:"ratio"`
IncomeAmountCent int64 `json:"income_amount_cent"`
CostAmountCent int64 `json:"cost_amount_cent"`
}
type CreateFinancialSnapshotRequest struct {
SiteID uint64 `json:"site_id" binding:"required"`
RuleVersionID uint64 `json:"rule_version_id" binding:"required"`
GrossPaidAmountCent int64 `json:"gross_paid_amount_cent"`
RefundAmountCent int64 `json:"refund_amount_cent"`
MarkupAmountCent int64 `json:"markup_amount_cent"`
Parties []SnapshotPartyRequest `json:"parties"`
}
type SettlementItemDTO struct {
ID uint64 `json:"id"`
OrderID uint64 `json:"order_id"`
PartyRole string `json:"party_role"`
AmountCent int64 `json:"amount_cent"`
Status string `json:"status"`
}
type DistributionLoginRequest struct {
Username string `json:"username" binding:"required"`
Password string `json:"password" binding:"required"`
}
type DistributionLoginResponse struct {
Token string `json:"token"`
RefreshToken string `json:"refresh_token"`
Member DistributionCurrentMemberDTO `json:"member"`
}
type DistributionCurrentMemberDTO struct {
AdminID uint64 `json:"admin_id"`
Username string `json:"username"`
Nickname string `json:"nickname"`
IsSuperadmin bool `json:"is_superadmin"`
SiteID *uint64 `json:"site_id,omitempty"`
SiteCode string `json:"site_code,omitempty"`
SiteName string `json:"site_name,omitempty"`
Domain string `json:"domain,omitempty"`
MemberType string `json:"member_type,omitempty"`
}
type OnboardSiteRequest struct {
SiteCode string `json:"site_code" binding:"required,max=64"`
SiteName string `json:"site_name" binding:"required,max=128"`
Domain string `json:"domain" binding:"required,max=255"`
DisplayAccountEnabled *bool `json:"display_account_enabled"`
TaxEnabled *bool `json:"tax_enabled"`
TaxRateBPS *int64 `json:"tax_rate_bps"`
SettlementHoldDays *int `json:"settlement_hold_days"`
AdminUsername string `json:"admin_username" binding:"required,min=3,max=64"`
AdminPassword string `json:"admin_password" binding:"required,min=6,max=64"`
AdminNickname string `json:"admin_nickname"`
MemberType string `json:"member_type" binding:"omitempty,oneof=operator finance customer_service"`
DistributorReceiveRatio float64 `json:"distributor_receive_ratio"` // 兼容旧入参,开通时忽略,四种模式一律走默认分成
PlatformSellRatio float64 `json:"platform_sell_ratio"`
ServiceFeeValue float64 `json:"service_fee_value"`
}
type OnboardSiteResponse struct {
Site SiteDTO `json:"site"`
Rule RuleDTO `json:"rule"`
Member DistributionCurrentMemberDTO `json:"member"`
}
// ReceivedListingDTO 是分销站点收到的账号资产信息
type ReceivedListingDTO struct {
ListingID uint64 `json:"listing_id"`
ListingNo string `json:"listing_no"`
SiteID uint64 `json:"site_id"`
AccountID uint64 `json:"account_id"`
OwnerID uint64 `json:"owner_id"`
OwnerPhone string `json:"owner_phone"`
OwnerNickname string `json:"owner_nickname"`
Title string `json:"title"`
GameName string `json:"game_name"`
ServerRegion string `json:"server_region"`
LoginPlatform string `json:"login_platform"`
RankLevel string `json:"rank_level"`
HafCoinAmount int64 `json:"haf_coin_amount"`
SellerRatio float64 `json:"seller_ratio"`
SellerTotalPriceCent int64 `json:"seller_total_price_cent"`
BuyerRatio float64 `json:"buyer_ratio"`
PriceCent int64 `json:"price_cent"`
DepositAmountCent int64 `json:"deposit_amount_cent"`
Status string `json:"status"`
ReviewStatus string `json:"review_status"`
ReviewReason string `json:"review_reason"`
PublishedAt *time.Time `json:"published_at,omitempty"`
CreatedAt time.Time `json:"created_at"`
}
type ReceivedListingQuery struct {
SiteID uint64
Status string
ReviewStatus string
GameName string
Keyword string
Page int
PageSize int
Size int
}
type ReceivedListingPage struct {
Items []ReceivedListingDTO `json:"items"`
Total int64 `json:"total"`
Page int `json:"page"`
PageSize int `json:"page_size"`
}
type UpdateReceivedListingStatusRequest struct {
Status string `json:"status" binding:"required,oneof=published offline"`
}
// 站点品牌与装修 DTO。指针字段未传则保持原值,避免空字符串把装修清掉。
type UpdateSiteBrandingRequest struct {
LogoURL *string `json:"logo_url"`
FaviconURL *string `json:"favicon_url"`
BannersJSON *string `json:"banners_json"`
AnnouncementsJSON *string `json:"announcements_json"`
FooterInfoJSON *string `json:"footer_info_json"`
}
// 自主加价 DTO:增加该站「1 元兑换哈夫币」比例,不是人民币。
type UpdateAccountMarkupRequest struct {
ShelfRatioDelta float64 `json:"shelf_ratio_delta"`
}
type AccountMarkupItem struct {
ID uint64 `json:"id,omitempty"`
ListingID uint64 `json:"listing_id,omitempty"`
ShelfRatioDelta float64 `json:"shelf_ratio_delta"`
}
type BatchUpdateAccountMarkupRequest struct {
ListingIDs []uint64 `json:"listing_ids"`
DisplayIDs []uint64 `json:"display_ids"`
ShelfRatioDelta float64 `json:"shelf_ratio_delta"`
Items []AccountMarkupItem `json:"items"`
}
type BatchUpdateAccountDisplayRequest struct {
DisplayIDs []uint64 `json:"display_ids"`
ListingIDs []uint64 `json:"listing_ids"`
TargetStatus string `json:"target_status" binding:"required,oneof=enabled disabled"`
}
type AccountDisplayQuery struct {
Page int `form:"page" json:"page"`
PageSize int `form:"page_size" json:"page_size"`
Status string `form:"status" json:"status"`
Keyword string `form:"keyword" json:"keyword"`
}
type AccountDisplayPageDTO struct {
Items []AccountDisplayDTO `json:"items"`
Total int64 `json:"total"`
Page int `json:"page"`
PageSize int `json:"page_size"`
}
// 商户钱包与提现 DTO
type SiteWalletDTO struct {
SiteID uint64 `json:"site_id"`
AvailableBalanceCent int64 `json:"available_balance_cent"`
FrozenBalanceCent int64 `json:"frozen_balance_cent"`
PendingReleaseCent int64 `json:"pending_release_cent"`
TotalSettledCent int64 `json:"total_settled_cent"`
TotalWithdrawnCent int64 `json:"total_withdrawn_cent"`
SettlementHoldDays int `json:"settlement_hold_days"`
}
type ApplySiteWithdrawalRequest struct {
SiteID uint64 `json:"site_id"`
AmountCent int64 `json:"amount_cent" binding:"required,gt=0"`
AccountType string `json:"account_type" binding:"required,oneof=alipay bank"`
AccountName string `json:"account_name" binding:"required"`
AccountNo string `json:"account_no" binding:"required"`
BankName string `json:"bank_name"`
BankBranch string `json:"bank_branch"`
}
type SiteWithdrawalDTO struct {
ID uint64 `json:"id"`
WithdrawNo string `json:"withdraw_no"`
SiteID uint64 `json:"site_id"`
AmountCent int64 `json:"amount_cent"`
FeeCent int64 `json:"fee_cent"`
ActualAmountCent int64 `json:"actual_amount_cent"`
AccountType string `json:"account_type"`
AccountName string `json:"account_name"`
AccountNo string `json:"account_no"`
BankName string `json:"bank_name"`
BankBranch string `json:"bank_branch"`
Status string `json:"status"`
ReviewRemark string `json:"review_remark"`
PaymentProofURL string `json:"payment_proof_url"`
PaymentRemark string `json:"payment_remark"`
PaidAt *time.Time `json:"paid_at,omitempty"`
CreatedAt time.Time `json:"created_at"`
}
type SiteWithdrawalPage struct {
Items []SiteWithdrawalDTO `json:"items"`
Total int64 `json:"total"`
Page int `json:"page"`
PageSize int `json:"page_size"`
}
// 运营大盘统计 DTO
type DistributionAnalyticsDTO struct {
TodayReceivedCount int64 `json:"today_received_count"`
TotalReceivedCount int64 `json:"total_received_count"`
ActiveListingCount int64 `json:"active_listing_count"`
TodayOrderCount int64 `json:"today_order_count"`
TodayGMVCent int64 `json:"today_gmv_cent"`
TodayProfitCent int64 `json:"today_profit_cent"`
MonthProfitCent int64 `json:"month_profit_cent"`
AvailableBalanceCent int64 `json:"available_balance_cent"`
TrendDays []DistributionTrendPoint `json:"trend_days"`
}
type DistributionTrendPoint struct {
Date string `json:"date"`
ReceivedCount int64 `json:"received_count"`
OrderCount int64 `json:"order_count"`
GMVCent int64 `json:"gmv_cent"`
ProfitCent int64 `json:"profit_cent"`
}
// 分销站点独立短信配置结构体
type SiteSMSConfigDTO struct {
Enabled bool `json:"enabled"`
Provider string `json:"provider"`
AccessKeyID string `json:"access_key_id"`
MaskedSecret string `json:"masked_secret"`
HasSecret bool `json:"has_secret"`
Endpoint string `json:"endpoint"`
SignName string `json:"sign_name"`
LoginTemplateCode string `json:"login_template_code"`
}
type UpdateSiteSMSConfigRequest struct {
Enabled *bool `json:"enabled"`
Provider *string `json:"provider"`
AccessKeyID *string `json:"access_key_id"`
AccessKeySecret *string `json:"access_key_secret"`
Endpoint *string `json:"endpoint"`
SignName *string `json:"sign_name"`
LoginTemplateCode *string `json:"login_template_code"`
}
type TestSiteSMSConfigRequest struct {
Phone string `json:"phone" binding:"required"`
Enabled *bool `json:"enabled"`
Provider *string `json:"provider"`
AccessKeyID *string `json:"access_key_id"`
AccessKeySecret *string `json:"access_key_secret"`
Endpoint *string `json:"endpoint"`
SignName *string `json:"sign_name"`
LoginTemplateCode *string `json:"login_template_code"`
}