diff --git a/backend/internal/modules/listing/receive_pricing.go b/backend/internal/modules/listing/receive_pricing.go
index 38ffd50..a920f6b 100644
--- a/backend/internal/modules/listing/receive_pricing.go
+++ b/backend/internal/modules/listing/receive_pricing.go
@@ -98,6 +98,28 @@ func applyMainSiteReceivePricing(req *CreateRequest, options systemconfig.Publis
buyerAnchorCoinBase = referenceSellerCoinBasePrice(coinWan, referenceRatio)
}
pricing := calculateExternalPlatformPricing(coinM, buyerAnchorRatio, buyerAnchorCoinBase, consumablePrice, config)
+ premiumRatioMarkup := 0.0
+ if req.IsPremium {
+ premiumRatioMarkup = NormalizePremiumReviewRatioMarkup(
+ options.RatioConfig.PremiumReviewRatioMarkup,
+ )
+ }
+ if premiumRatioMarkup > 0 && pricing.BuyerRatio > premiumRatioMarkup {
+ beforeRatio := pricing.BuyerRatio
+ afterRatio := roundRatio(beforeRatio - premiumRatioMarkup)
+ buyerCoinBasePrice := roundMoney(coinWan / afterRatio)
+ pricing = buildExternalPlatformPricing(
+ coinWan,
+ sellerTotalPrice,
+ consumablePrice,
+ buyerCoinBasePrice,
+ pricing.RuleType,
+ )
+ breakdown["premium_review_ratio_markup"] = premiumRatioMarkup
+ breakdown["premium_review_ratio_before"] = beforeRatio
+ breakdown["premium_review_ratio_after"] = pricing.BuyerRatio
+ breakdown["premium_review_ratio_markup_applied"] = true
+ }
breakdown["seller_reference_ratio"] = referenceRatio
breakdown["seller_ratio"] = sellerRatio
breakdown["seller_coin_base_price"] = sellerCoinBasePrice
@@ -170,6 +192,17 @@ func NormalizeQualityOwnerRatioDiscount(value float64) float64 {
return roundRatio(value)
}
+// NormalizePremiumReviewRatioMarkup 限制极品专区发布时额外增加的比例加价点数,最大 10。
+func NormalizePremiumReviewRatioMarkup(value float64) float64 {
+ if value < 0 || math.IsNaN(value) || math.IsInf(value, 0) {
+ return 0
+ }
+ if value > maxAcceleratedSaleRatioIncrement {
+ return maxAcceleratedSaleRatioIncrement
+ }
+ return roundRatio(value)
+}
+
// referenceSellerCoinBasePrice 计算主站参考比例下的号主基础价,用作买家定价锚点。
func referenceSellerCoinBasePrice(coinWan, referenceRatio float64) float64 {
if referenceRatio <= 0 {
diff --git a/backend/internal/modules/listing/receive_pricing_test.go b/backend/internal/modules/listing/receive_pricing_test.go
index b3c44c5..e2a3a34 100644
--- a/backend/internal/modules/listing/receive_pricing_test.go
+++ b/backend/internal/modules/listing/receive_pricing_test.go
@@ -82,6 +82,28 @@ func TestApplyMainSiteReceivePricingKeepsAcceleratedRatioWithinMainSiteRange(t *
}
}
+func TestApplyMainSiteReceivePricingIncludesPremiumReviewMarkup(t *testing.T) {
+ req := fullReceivePricingRequest(50)
+ req.IsPremium = true
+ applyMainSiteReceivePricing(&req, systemconfig.DefaultPublishOptions(), defaultSalePriceConfig(), 0, 0, false)
+ breakdown := ensurePriceBreakdown(req.AssetSummary)
+ if got := readSummaryNumber(breakdown["premium_review_ratio_markup"]); got != 1 {
+ t.Fatalf("premium review markup = %v, want 1", got)
+ }
+ if got := readSummaryNumber(breakdown["premium_review_ratio_before"]); got != 45 {
+ t.Fatalf("premium buyer ratio before = %v, want 45", got)
+ }
+ if got := readSummaryNumber(breakdown["premium_review_ratio_after"]); got != 44 {
+ t.Fatalf("premium buyer ratio after = %v, want 44", got)
+ }
+ if applied, _ := breakdown["premium_review_ratio_markup_applied"].(bool); !applied {
+ t.Fatal("premium review markup should be applied before review")
+ }
+ if req.PriceCent != 22730 {
+ t.Fatalf("premium PriceCent = %d, want final 22730", req.PriceCent)
+ }
+}
+
func TestApplyMainSiteReceivePricingAllowsQualityOwnerExclusiveRatio(t *testing.T) {
req := fullReceivePricingRequest(42)
req.OwnerIsQualityOwner = true
diff --git a/backend/internal/modules/systemconfig/dto.go b/backend/internal/modules/systemconfig/dto.go
index 7687a77..fbfb2b8 100644
--- a/backend/internal/modules/systemconfig/dto.go
+++ b/backend/internal/modules/systemconfig/dto.go
@@ -183,6 +183,7 @@ type PublishDepositSkinGroupRule struct {
type PublishRatioConfig struct {
QualityOwnerRatioDiscount float64 `json:"quality_owner_ratio_discount"`
+ PremiumReviewRatioMarkup float64 `json:"premium_review_ratio_markup"`
InsuranceBaseRatios []PublishInsuranceBaseRatio `json:"insurance_base_ratios"`
ConfigItems []PublishRatioConfigItem `json:"config_items"`
CoinCorrections []PublishCoinCorrection `json:"coin_corrections"`
diff --git a/backend/internal/modules/systemconfig/normalize.go b/backend/internal/modules/systemconfig/normalize.go
index 6dd3a3f..a5c6342 100644
--- a/backend/internal/modules/systemconfig/normalize.go
+++ b/backend/internal/modules/systemconfig/normalize.go
@@ -252,6 +252,19 @@ func normalizePublishOptions(options *PublishOptionsDTO) {
if len(options.RatioConfig.CoinCorrections) == 0 {
options.RatioConfig.CoinCorrections = defaults.RatioConfig.CoinCorrections
}
+ options.RatioConfig.PremiumReviewRatioMarkup = normalizePremiumReviewRatioMarkup(
+ options.RatioConfig.PremiumReviewRatioMarkup,
+ )
+}
+
+func normalizePremiumReviewRatioMarkup(value float64) float64 {
+ if value < 0 || math.IsNaN(value) || math.IsInf(value, 0) {
+ return 0
+ }
+ if value > 10 {
+ return 10
+ }
+ return math.Round(value*10) / 10
}
func normalizeSalePriceConfig(config *PublishSalePriceConfig) {
diff --git a/backend/internal/modules/systemconfig/publish_options.go b/backend/internal/modules/systemconfig/publish_options.go
index fa057db..33e51e2 100644
--- a/backend/internal/modules/systemconfig/publish_options.go
+++ b/backend/internal/modules/systemconfig/publish_options.go
@@ -106,6 +106,7 @@ func DefaultPublishOptions() PublishOptionsDTO {
},
RatioConfig: PublishRatioConfig{
QualityOwnerRatioDiscount: 1,
+ PremiumReviewRatioMarkup: 1,
InsuranceBaseRatios: []PublishInsuranceBaseRatio{
{Insurance: "3*3", Ratio: 40},
{Insurance: "2*3", Ratio: 42},
diff --git a/backend/internal/modules/systemconfig/publish_options_test.go b/backend/internal/modules/systemconfig/publish_options_test.go
index fcbb1aa..08b9175 100644
--- a/backend/internal/modules/systemconfig/publish_options_test.go
+++ b/backend/internal/modules/systemconfig/publish_options_test.go
@@ -128,6 +128,36 @@ func TestNormalizePublishOptionsValueDefaultsQualityOwnerRatioDiscount(t *testin
got.RatioConfig.QualityOwnerRatioDiscount,
)
}
+ if got.RatioConfig.PremiumReviewRatioMarkup != 1 {
+ t.Fatalf(
+ "premium_review_ratio_markup = %v, want 1",
+ got.RatioConfig.PremiumReviewRatioMarkup,
+ )
+ }
+}
+
+func TestNormalizePublishOptionsValuePreservesExplicitZeroPremiumReviewRatioMarkup(t *testing.T) {
+ options := DefaultPublishOptions()
+ options.RatioConfig.PremiumReviewRatioMarkup = 0
+ raw, err := json.Marshal(options)
+ if err != nil {
+ t.Fatalf("构造配置失败: %v", err)
+ }
+
+ normalized, err := normalizePublishOptionsValue(string(raw))
+ if err != nil {
+ t.Fatalf("规范化失败: %v", err)
+ }
+ var got PublishOptionsDTO
+ if err := json.Unmarshal([]byte(normalized), &got); err != nil {
+ t.Fatalf("解析规范化结果失败: %v", err)
+ }
+ if got.RatioConfig.PremiumReviewRatioMarkup != 0 {
+ t.Fatalf(
+ "premium_review_ratio_markup = %v, want explicit 0",
+ got.RatioConfig.PremiumReviewRatioMarkup,
+ )
+ }
}
func TestNormalizePublishOptionsValuePreservesExplicitZeroQualityOwnerDiscount(t *testing.T) {
diff --git a/backend/internal/modules/systemconfig/repository.go b/backend/internal/modules/systemconfig/repository.go
index 989ffad..37fc41a 100644
--- a/backend/internal/modules/systemconfig/repository.go
+++ b/backend/internal/modules/systemconfig/repository.go
@@ -337,6 +337,10 @@ func normalizePublishOptionsValue(value string) (string, error) {
options.RatioConfig.QualityOwnerRatioDiscount =
DefaultPublishOptions().RatioConfig.QualityOwnerRatioDiscount
}
+ if !hasNestedJSONField(fields, "ratio_config", "premium_review_ratio_markup") {
+ options.RatioConfig.PremiumReviewRatioMarkup =
+ DefaultPublishOptions().RatioConfig.PremiumReviewRatioMarkup
+ }
originalVersion := options.SchemaVersion
if options.SchemaVersion < publishOptionsSchemaVersion {
if hasLegacyPublishQuantityItem(options.QuantityItems) {
diff --git a/frontend/src/features/admin/components/PublishOptionsDialog.vue b/frontend/src/features/admin/components/PublishOptionsDialog.vue
index 26e4966..a38f30d 100644
--- a/frontend/src/features/admin/components/PublishOptionsDialog.vue
+++ b/frontend/src/features/admin/components/PublishOptionsDialog.vue
@@ -412,6 +412,17 @@ async function handleSave() {
默认 1,表示优质号主可在基础比例上降低 1;普通号主不能使用该区间。
+