From 54985b7c36181f4476c9fbbd0a7876d7f6052733 Mon Sep 17 00:00:00 2001 From: yml2213 Date: Thu, 17 Sep 2026 17:34:23 +0800 Subject: [PATCH] =?UTF-8?q?docs(distribution):=20=E6=94=B6=E5=BD=95?= =?UTF-8?q?=E5=88=86=E7=AB=99=E6=94=B6=E5=8F=B7=E5=AE=9A=E4=BB=B7=E5=88=86?= =?UTF-8?q?=E6=9E=90=E4=B8=8E=E6=94=B9=E9=80=A0=E6=96=B9=E6=A1=88=E5=B9=B6?= =?UTF-8?q?=E6=A0=87=E6=B3=A8=E6=96=B9=E6=A1=88=20B=20=E5=AE=9E=E6=96=BD?= =?UTF-8?q?=E6=83=85=E5=86=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增第 0 节「实施情况」:已落地口径、关键决策(压价上限 20 点、 新字段 receive_cost_delta、压价差进 35/40/25 分成池)、代码落点与回归锚点 - 状态行由「分析稿(未实施)」更新为「方案 B 已实施」,5.2 节与第 6、8 节同步标注 - 记录连带修正 a36332d:解耦仅作用于分站收号侧,主站加速出售买家价仍跟随卖家比例 - 第 2–4 节的改造前现状与问题定位原样保留,作为决策依据 --- docs/分站收号定价分析与改造方案.md | 486 +++++++++++++++++++++++++++++ 1 file changed, 486 insertions(+) create mode 100644 docs/分站收号定价分析与改造方案.md diff --git a/docs/分站收号定价分析与改造方案.md b/docs/分站收号定价分析与改造方案.md new file mode 100644 index 0000000..c19e6f5 --- /dev/null +++ b/docs/分站收号定价分析与改造方案.md @@ -0,0 +1,486 @@ +# 分站收号定价分析与改造方案 + +> 状态:**方案 B 已实施**(2026-09-17)。第 2–4 节记录改造前的现状口径与问题定位,保留为决策依据; +> 第 5 节起的候选方案中,**方案 B 已落地**,方案 C 未实施,方案 D 待办。实施口径见第 0 节。 +> 更新时间:2026-09-17 +> 适用范围:主站/分站的「收号(回收)比例」、号主底价、买家价、分销三方分账。 +> 关联文档:[分销网管理后台设计方案](分销网管理后台设计方案.md)、[出售加价规则](出售加价规则.md)、[发布比例计算](发布比例计算.md) + +--- + +## 0. 实施情况(方案 B,2026-09-17) + +### 0.1 已落地的口径 + +``` +分站收号比例 = 主站参考比例 R + receive_cost_delta (点数越大,收号价越低) +分站买家价 = 锚定主站参考比例 R 推导 (不随收号价联动 ← 解耦核心) +主站买家价 = 仍跟 seller_ratio 联动 (含加速出售,主站行为不变) +压价差 = 经结算层 profit 自动进入 35/40/25 三方分成池 +货架自主加价 = 100% 归分站 (原有逻辑,未改动) +``` + +两条死边界:分站收号价 ≤ 主站参考价(`receive_cost_delta ≥ 0` 保证);分站卖价 ≥ 主站挂牌价(原有 clamp 保证)。 + +### 0.2 关键决策 + +| 决策点 | 结论 | +|---|---| +| 压价点数上限 | 沿用 20 点 | +| 字段方案 | 新增 `receive_cost_delta`(迁移 000072),旧 `receive_ratio_delta` 保留只读 | +| 压价差归属 | 进入 35/40/25 分成池(非全归分站);仅货架自主加价 100% 归分站 | +| 主站是否受影响 | 否。主站加速出售买卖仍联动,仅分站走解耦锚点 | + +### 0.3 代码落点 + +| 位置 | 改动 | +|---|---| +| `backend/migrations/000072_distribution_site_receive_cost_delta.sql` | 新增 `receive_cost_delta` 列 | +| `backend/internal/modules/listing/receive_pricing.go` | 新增 `Normalize/ApplySiteReceiveCostDelta`;分站买家锚点改用 R;快照写 `site_receive_cost_delta` 与 `pricing_model` | +| `backend/internal/modules/listing/site_receive.go` | 新增 `ReceiveCostDeltaBySiteCode` / `resolveSiteReceiveCostDelta` | +| `backend/internal/modules/distribution/{dto,repository}.go` | 新字段读写与 `normalizeReceiveCostDelta` 校验 | +| `frontend/src/shared/utils/pricing.ts`、`usePricingCalculator.ts` | 买卖双轨试算(`calculatedRatio` 收号侧 / `anchorRatio` 买家侧) | +| 主站后台弹窗、分销后台 SiteSettings | 文案改为价格语义「收号价比主站低 X 点」 | + +### 0.4 连带修正 + +实现过程中发现并修正:主站加速出售的买家价一度被误锚到参考比例(`a36332d`)。 +解耦只应作用于分站收号侧,主站加速出售必须继续让买家价跟随卖家比例。 + +### 0.5 回归锚点 + +R=43、coinM=100 时:`receive_cost_delta=3` → 收号比例 46、号主收 **217.4**(低于主站 232.6)、 +买家价 **263.2 不变**、提价利润池 30.6 → **54.9**。已由 `receive_pricing_test.go` 固定。 + +--- + +## 1. 结论摘要(TL;DR) + +1. **当前分站收号不是「低价收号赚差价」,而是「加价收号抢货源、买家买单」。** + 分站唯一可调的是「相对主站下调 X 点」,数学上 `卖家比例 = 主站参考比例 R − X`,比例变小 → **号主底价变高**;平台把买家价一起抬高,从而使三方分账池变大。 +2. **用户直觉(分站能低价收号 → 各方都多赚)与代码方向相反。** + 因为买家价是从「卖家收货价」推导出来的(`买家比例 = 卖家比例 − 修正点数` 或 `买家价 = 卖家价 + 固定加价`),分站一旦压价收货,买家价同步下移,**绝对毛利反而缩小**,省下来的钱全被买家拿走。 +3. **「一会高一会低、一会大一会小」有三个来源:** + - 三套定价引擎在币量档位间硬切换,边界处毛利会「跳崖」甚至「币更多、利润更少」; + - **390M 以上三档是「待定」**(配置里 `RatioSubtract = 0`),买家价 = 号主价,**提价利润恒为 0**,分账池为 0,且 `X` 调多少都没用; + - 固定加价带(10–90M)里 `X` 只转移号主/买家的钱,**不改变分账池**,所以同一个 `X` 在不同档位效果完全不同。 +4. **根因:买价与卖价绑在同一个变量上,价差是公式给的固定比例差,不是市场差价。** 因此「分站的收货议价能力」无处体现。 +5. 建议分三阶段:**先做方案 D(补 390M+、抹平跳变,1–2 人天)止血 → 再做方案 B(解耦,5–8 人天,带影子计算开关)→ 最后做方案 C(分站自费让利,8–15 人天)**。 + +--- + +## 2. 术语与比例语义 + +所有比例统一为 **`1:X` = 1 元兑换 X 万哈夫币**,因此: + +``` +价格(元) = 万哈夫币 ÷ X +X 越小 → 价格越贵;X 越大 → 价格越便宜 +``` + +| 名称 | 代码字段 | 谁决定 | 取值 | +|---|---|---|---| +| 主站参考回收比例(上限) | `seller_reference_ratio` | 账号属性自动算 | 见 2.1 | +| 主站挂牌回收比例 | `seller_ratio` | 号主可调,服务端 clamp | `[R, R+10]`(只能调大=降价加速出售) | +| 分站收号比例 | 无独立字段,创建时实时算 | 分站 `receive_ratio_delta` | `max(0.01, R − delta)`,恒 ≤ R | +| 买家比例 | `buyer_ratio` | 由卖家比例推导 | 比例带:`卖家比例 − 修正点数`;固定带:由固定加价反推 | +| 分站货架加价 | `shelf_ratio_delta` / `shelf_markup_cent` | 分站自主 | 见 2.4,**与收号比例无关** | + +### 2.1 主站参考比例 R 的计算 + +代码:`backend/internal/modules/listing/receive_pricing.go`(`calculateSellerReferenceRatio`),默认参数见 `backend/internal/modules/systemconfig/publish_options.go`。 + +``` +R = 保险基准比例 (3*3=40, 2*3=42, 2*2=47, 2*1=48) + + 缺配惩罚 (红皮/刀皮/砖皮 各 +1;满体力/满负重 缺失各 +1) + + 币量修正 (>130M +1, >230M +2.5, >380M +4, >530M +5) + + 日均损耗修正 = clamp(floor((日均损耗-10)/10), 0, 4) +``` + +示例:1 亿哈夫币、3*3、满体力、满负重、无皮肤 → `R = 40 +(红皮1 + 刀皮1 + 砖皮1)= 43`。 +该用例已被单测固定:`backend/internal/modules/listing/receive_pricing_test.go`(期望号主基础价 232.6、买家比例 38、总价 263.20)。 + +### 2.2 主站与分站的规则差异 + +```go +// backend/internal/modules/listing/receive_pricing.go:73-77 +sellerRatio := clampSaleRatio(referenceRatio, requestedRatio) // 主站:[R, R+10] +if onDistributionSite { + sellerRatio = ApplySiteReceiveRatioDelta(referenceRatio, delta) // 分站:R - delta +} +``` + +- **主站**:号主填的比例会被 clamp 到 `[R, R+10]`;填小于 R 会被拉回 R,填大是「加速出售」(主动降价)。 +- **分站**:号主填的加速比例**被完全忽略**,强制为 `R − delta`。即使号主愿意更便宜卖(比例更大),系统也会强制把价格抬到 `R − delta`。 + +### 2.3 生效链路与快照 + +``` +号主在分站域名/带 X-Distribution-Site-Code 的商城上架 + → handler 取 header(handler_user.go) + → ResolveReceiveRatioDelta(listingID, siteCode)(listing/site_receive.go) + → applyMainSiteReceivePricing(...)(listing/receive_pricing.go) + → 结果写入 asset_summary.price_breakdown(seller_ratio / seller_total_price / buyer_ratio / site_receive_ratio_delta ...) + → 后续改 delta 不影响已发布商品;历史订单用下单时快照 +``` + +读侧:分站「收号管理」用 `ReceivePricingFromAssetSummary` 读快照(`distribution/repository.go` 约 2634 行)。 + +### 2.4 两套「分站加价」不要混淆 + +| 机制 | 适用对象 | 归属 | +|---|---|---| +| `receive_ratio_delta`(本文主题) | 号主在**分站上架**的账号(分站收号) | 影响号主底价与买家价,进 35/40/25 分账 | +| `shelf_ratio_delta` | 主站账号同步到**分站销售** | 分站自主加价,溢价 100% 归分站(`listing/shelf_ratio.go`) | + +### 2.5 从比例到价格、到分账 + +``` +万W = 哈夫币 / 10000 +号主基础价 seller_coin_base = round0.1( W / sellerRatio ) +号主总价 seller_total = 号主基础价 + 额外消耗品价 +买家价: + coinM < 10M → 买家价 = 号主价(无加价) + 10M ≤ coinM < 90M → 买家价 = 号主基础价 + 固定加价(28/31/34/38) + coinM ≥ 90M → 买家比例 = 卖家比例 − 修正点数(5/4/3.5/3/0),买家价 = round0.1(W / 买家比例) +平台提价利润 = 买家总价 − 号主总价 +``` + +分账(`backend/internal/modules/distribution/pricing.go`): + +- `CalculateSettlement`:`净支付 − 号主底价 − 有效分站加价 = 提价利润`;服务费按利润百分比单独计算; +- `SplitSettlement`:收号方 35% + 卖出方 40%,服务费 25% 记财务快照; +- 结算一律使用订单上的整数分快照,规则/站点后续变更不影响历史订单。 + +模式由买卖双方站点决定(`distribution/lifecycle.go` 的 `resolveDistributionMode`): + +| 场景 | 模式 | 分成 | +|---|---|---| +| 号主挂分站、主站买家买(本主题:分站收号) | `two_party_distributor_receive` | 分站 35% / 主站卖出 40% / 服务费 25% | +| 号主挂主站、分站买家买 | `two_party_platform_receive` | 主站收号 35% / 分站卖出 40% / 25% | +| 同一分站买卖 | `site_self_sell` | 分站 75% / 25% | +| 两个不同分站 | `three_party` | A 35% / B 40% / 25% | + +--- + +## 3. 验证示例 + +以下数字均按项目口径(比例 1 位小数、金额 0.1 元、结算按分)计算,可用于回归对照。 + +### 3.1 例 A:1 亿哈夫币(coinM=100,W=10000 万),R=43,比例修正带 −5 + +| 场景 | 收号比例 | 号主底价 | 买家比例 | 买家价 | 提价利润 | 分站 35% | 主站 40% | 服务费 25% | +|---|---|---|---|---|---|---|---|---| +| 主站默认 | 43.0 | 232.6 | 38.0 | 263.2 | 30.6 | 10.71 | 12.24 | 7.65 | +| 主站加速 +10 | 53.0 | 188.7 | 48.0 | 208.3 | 19.6 | 6.86 | 7.84 | 4.90 | +| 分站 delta=0 | 43.0 | 232.6 | 38.0 | 263.2 | 30.6 | 10.71 | 12.24 | 7.65 | +| 分站 delta=3 | 40.0 | 250.0 | 35.0 | 285.7 | 35.7 | 12.50 | 14.28 | 8.93 | +| 分站 delta=5 | 38.0 | 263.2 | 33.0 | 303.0 | 39.8 | 13.93 | 15.92 | 9.95 | +| 分站 delta=10 | 33.0 | 303.0 | 28.0 | 357.1 | 54.1 | 18.93 | 21.64 | 13.53 | +| 分站 delta=20 | 23.0 | 434.8 | 18.0 | 555.6 | 120.8 | 42.28 | 48.32 | 30.20 | + +> delta 每加 1 点,号主底价相对涨约 `delta / (R − delta)`;≥90M 时买家价涨得更快,分账池随之变大。 + +### 3.2 例 B:2000 万哈夫币(coinM=20,W=2000 万),R=43,固定加价带 +28 + +| 场景 | 收号比例 | 号主底价 | 买家价 | 提价利润 | 分站 35% | +|---|---|---|---|---|---| +| 主站默认 | 43.0 | 46.5 | 74.5 | 28.0 | 9.80 | +| 分站 delta=3 | 40.0 | 50.0 | 78.0 | 28.0 | 9.80 | +| 分站 delta=5 | 38.0 | 52.6 | 80.6 | 28.0 | 9.80 | +| 分站 delta=20 | 23.0 | 87.0 | 115.0 | 28.0 | 9.80 | + +> **固定加价带里 delta 不改变分账池**:只是把「号主多得 = 买家多付」同额搬运。 + +### 3.3 例 C:2 亿哈夫币(coinM=200,W=20000 万),R=44(>130M 修正 +1),修正带 −4 + +| 场景 | 收号比例 | 号主底价 | 买家比例 | 买家价 | 提价利润 | 分站 35% | +|---|---|---|---|---|---|---| +| 分站 delta=0 | 44.0 | 454.5 | 40.0 | 500.0 | 45.5 | 15.93 | +| 分站 delta=5 | 39.0 | 512.8 | 35.0 | 571.4 | 58.6 | 20.51 | +| 分站 delta=10 | 34.0 | 588.2 | 30.0 | 666.7 | 78.5 | 27.48 | + +--- + +## 4. 问题清单 + +### 4.1 问题一:方向反转——「低价收号」在当前引擎里反而缩小分账池 + +**证明(比例带)**:设卖家比例 `X`、修正点数 `s`、`W` 为万哈夫币: + +``` +号主价 S = W / X +买家价 B = W / (X − s) +毛利 M = B − S = W·s / (X(X − s)) +dM/dX < 0 → X 越大(收货越便宜),M 越小 +``` + +**用 1 亿号(R=43、s=5)验证**:假设放开 2.2 节的 `R` 上限,允许分站压价 5 点(比例 43→48): + +| 方案 | 号主收货价 | 买家价 | 毛利 | 分站 35% | +|---|---|---|---|---| +| 现状基准(delta=0) | 232.6 | 263.2 | 30.6 | 10.71 | +| 假设压价收货 δ=+5 | **208.3**(号主少拿 24.3) | **232.6**(买家也少付 30.6) | **24.3(池子反而变小 6.3)** | **8.51(少赚 2.20)** | +| 现行让利 δ=5 | 263.2(号主多拿) | 303.0(买家多付) | 39.8(池子变大 9.2) | 13.93 | + +结论:**分站压价省下的 24.3 元被买家全部拿走,分账池还缩水。** 现行的「让利」之所以能让三方多赚,是因为成本转嫁给了买家。用户期望的「低收号 → 每方多赚」在当前结构下无法实现。 + +### 4.2 问题二:三套引擎切换 + 档位边界跳变 + +以满配 9 格账号为例(基础 40 + 币量修正,日均损耗 10),`delta=0` 与 `delta=5`: + +| 币量 | R | 规则 | δ=0 利润 | δ=0 分站 35% | δ=5 利润 | δ=5 分站 35% | +|---|---|---|---|---|---|---| +| 89M | 40 | 固定 +38 | 38.0 | 13.30 | 38.0 | 13.30 | +| **91M** | 40 | 比例 −5 | **32.5**(比 89M 少) | 11.38 | 43.3 | 15.16 | +| 130M | 40 | 比例 −5 | 46.4 | 16.24 | 61.9 | 21.67 | +| **131M** | 41 | 比例 −5 | **44.4**(币更多、利润更少) | 15.54 | 58.7 | 20.55 | +| 230M | 41 | 比例 −4 | 52.3 | 18.31 | 68.8 | 24.08 | +| **231M** | 42.5 | 比例 −3.5 | **48.8**(又掉) | 17.08 | 63.4 | 22.19 | +| 309M | 42.5 | 比例 −3.5 | 65.2 | 22.82 | 84.8 | 29.68 | +| **310M** | 42.5 | 比例 −3 | **55.4**(掉 9.8) | 19.39 | 71.9 | 25.17 | +| 380M | 42.5 | 比例 −3 | 67.9 | 23.77 | 88.1 | 30.84 | +| **381M** | 44 | 比例 −3 | **63.4**(掉 4.5) | 22.19 | 81.4 | 28.49 | +| 389M | 44 | 比例 −3 | 64.7 | 22.65 | 83.2 | 29.12 | +| **390M** | 44 | 比例 −0 | **0.00** | **0.00** | **0.00** | **0.00** | +| 600M | 45 | 比例 −0 | 0.00 | 0.00 | 0.00 | 0.00 | + +跳变根因:固定加价档的边界(10/30/50/70/90)与比例修正档的边界(90/150/230/310/390/470/550)不同步;同时 `R` 的币量修正本身在 130/230/380/530M 处跳档,两者叠加造成非单调。 + +### 4.3 问题三:390M 以上「待定」档 → 0 利润、delta 完全失效 + +- 默认配置:`{390–470: 0}, {470–550: 0}, {550+: 0}`(`external_pricing.go` 与 `systemconfig/sale_price_config.go` 各一份)。 +- `买家比例 = 卖家比例 − 0`,即买家价 = 号主价,**提价利润恒为 0**;三方分账全为 0,服务费基数为 0 也为 0。 +- 此时 `delta` 无论调多少,卖家价与买家价同额上涨,利润仍是 0。 +- 文档 `docs/出售加价规则.md:17-19` 明确标注这三档为「待定」,属于未完成配置。 + +### 4.4 问题四:同一个 delta 在不同档位效果不同 + +| 档位 | delta 对分账池的影响 | +|---|---| +| 10M ≤ coinM < 90M(固定加价) | **无影响**(利润恒定 28/31/34/38) | +| 90M ≤ coinM < 390M(比例修正) | 正影响(delta 越大池子越大) | +| coinM ≥ 390M(修正 0) | **无影响**(恒为 0) | +| coinM < 10M(无规则) | 无影响(恒为 0) | + +运营视角即「调了这个数字,有时有用、有时没用、有时效果特别大」。 + +### 4.5 问题五:命名与文案反向误导 + +- 截图/主站后台文案:`相对主站下调 X 点`,字面像「把收货价往下调(更便宜)」; +- 代码:`sellerRatio = R − delta`,比例下降 → `价格 = W / X` 上升 → **收货价更高**。 +- 同一界面上会同时出现 4 个「比例」(主站上限、回收比例、买家比例、货架加价比例),且与金额反向,极易理解错。 + +### 4.6 问题六:工程重复实现风险 + +- 前端 `frontend/src/shared/utils/pricing.ts` 与后端 `external_pricing.go` 是两套同口径实现,容易漂移; +- 默认加价规则存在**三份副本**: + 1. `backend/internal/modules/listing/external_pricing.go:56` `defaultSalePriceConfig()` + 2. `backend/internal/modules/systemconfig/sale_price_config.go` `DefaultSalePriceConfig()` + 3. `frontend/src/features/listings/api/listingOptions.ts` `emptyListingSalePriceConfig` +- 线上已存在的 `system_configs.listing.sale_price_config` 是初始化播种的(`systemconfig/repository.go`),**改代码默认值不会更新老库**,必须迁移或后台手改。 + +--- + +## 5. 候选改造方案 + +### 5.1 方案 A:保持现状(基线) + +「分站加价收货抢货源,平台抬高买家价放大分账池」。不推荐作为长期方案,仅作为对照基线。 + +- 优点:抢货源有直接的价格武器;90–390M 区间三方分账随 delta 增长。 +- 缺点:买家承担全部成本;分站「低成本收货」能力无处体现;固定带与 ≥390M 时 delta 失效;价格随 delta 上涨可能流失买家。 + +### 5.2 方案 B:解耦(售价锚定主站,分站压价收货)— ✅ 已实施(2026-09-17) + +**目标口径** + +``` +收货价 P_buy = W / (R + δ) δ ≥ 0,分站靠议价压低收货价 +售价 P_sell = 主站售价(R) 不再与 P_buy 联动 +毛利 M = P_sell − P_buy → 35% 分站 / 40% 主站 / 25% 服务费 +``` + +**示例(1 亿号,R=43,主站售价锚定 263.2)** + +| 分站压价 δ | 收货比例 | 号主收到 | 售价 | 毛利 | 分站 35% | 主站 40% | 平台 25% | +|---|---|---|---|---|---|---|---| +| 0 | 43 | 232.6 | 263.2 | 30.6 | 10.71 | 12.24 | 7.65 | +| 2 | 45 | 222.2 | 263.2 | 41.0 | 14.35 | 16.40 | 10.25 | +| 5 | 48 | 208.3 | 263.2 | 54.9 | 19.21 | 21.96 | 13.73 | +| 10 | 53 | 188.7 | 263.2 | 74.5 | 26.08 | 29.80 | 18.63 | +| 20 | 63 | 158.7 | 263.2 | 104.5 | 36.57 | 41.80 | 26.13 | + +小号同样成立(coinM=20,售价锚定 74.5):δ=5 时号主 41.7,毛利 28.0 → 32.8,分站 9.80 → 11.48。 + +**要点**:此口径下「每方多赚」指分站/主站/平台,**号主是让利方**,必须设收货价下限保护。 + +### 5.3 方案 C:方案 B + 分站自费让利 + +在 B 的基础上保留「加价抢货」能力,但**让利部分从分站自己的 35% 扣除,绝不抬高买家价**。 + +``` +收货价 = W / (R + δ_buy − δ_subsidy) +分站净得 = 35% × 毛利 − 补贴(δ_subsidy 对应金额) +``` + +需要额外定义:补贴封顶、分站应得为负时的处理(挂应收 or 归零)、退款/部分退款时的补贴冲回规则。 + +### 5.4 方案 D:只修数据坑(模型不动) + +- 补齐 390M 以上三档的修正值; +- 抹平档位跳变(连续化或让档位只升不降); +- 统一/合并三份默认值,迁移线上 `system_configs`; +- 修正文案与命名(比例 ↔ 价格语义)。 + +保持「让利抢货」口径不变。 + +### 5.5 方案对比 + +| 维度 | B 解耦 | C = B + 自费让利 | D 只修数据坑 | +|---|---|---|---| +| 新增 DB 字段 | 1(或给旧字段加语义版本) | 2–3(站点 + 订单快照 + 财务) | 0 | +| 后端主要改动 | `receive_pricing.go`、配置默认值、站点字段 | 叠加 `distribution/pricing.go`、`lifecycle.go`、财务模型 | `systemconfig`、默认值、迁移更新配置行 | +| 前端主要改动 | 发布页定价、分销后台设置 | 叠加结算/账务展示 | 默认规则数组、文案 | +| 历史订单影响 | 无(快照) | 无,但新单财务字段增多 | 无 | +| 改造量(含测试) | 5–8 人天 | 8–15 人天 | 1–2 人天 | +| 主要风险 | 无下限压价伤号主、买家价基准变更 | 结算正确性、退款分摊、负余额、审计 | 老库配置不自动生效、三处默认值漏改 | +| 回滚方式 | 代码回退 | 代码回退 + 新字段保留只读 | 代码回退 + 恢复旧配置 JSON | + +--- + +## 6. 改造清单(方案 B 清单已实施,其余为计划项) + +### 6.1 方案 B 清单 + +| 文件 | 计划改动 | +|---|---| +| `backend/internal/modules/listing/receive_pricing.go` | `applyMainSiteReceivePricing`:分站分支拆成「卖家压价比例」与「买家定价基准 R」两条;`ApplySiteReceiveRatioDelta`(`:115`)方向反转或改名 `ApplySiteReceiveCostDelta`,加下限;`NormalizeSiteReceiveRatioDelta`(`:104`)范围重定;`ReceivePricingFromAssetSummary`(`:28`)输出金额字段 | +| `backend/internal/modules/listing/external_pricing.go` | `calculateExternalPlatformPricing`(`:118`)入参语义从「卖家比例」改为「基准 R」,明确区分,避免再次耦合 | +| `backend/internal/modules/listing/site_receive.go` | 读取新字段 / 新语义 + 兼容旧字段 | +| `backend/internal/model/distribution.go` | 新增 `receive_cost_delta`,保留旧 `receive_ratio_delta` 只读 | +| `backend/internal/modules/distribution/repository.go` | `normalizeReceiveRatioDelta`(`:69`)校验、`UpdateSite`(`:329`/`:381`)、DTO 映射、读侧快照(约 `:2634`) | +| `backend/migrations/`(新增 000072) | `ALTER TABLE distribution_sites ADD receive_cost_delta ...`;`price_breakdown` 增加 `pricing_model` 版本标记(仅代码写入,不改表也可) | +| `frontend/src/shared/utils/pricing.ts` | `applySiteReceiveRatioDelta`(`:162`)与 `calculatePlatformPricing`(`:175`)解绑;买家定价改用基准 R | +| `frontend/src/shared/composables/usePricingCalculator.ts` | 同步口径与展示 | +| `frontend/src/features/listings/api/listingOptions.ts` | 类型与默认值同步 | +| `frontend/src/stores/distributionSite.ts` | 读取新字段 | +| `frontend/src/features/seller/composables/usePublishForm.ts` | 传参同步 | +| `distribution-admin/src/pages/SiteSettings.tsx`、`distribution-admin/src/api.ts` | 输入改为「压价点数」,文案改为价格语义 | +| `frontend/src/features/admin/views/AdminDistributionSitesView.vue` | 主站侧弹窗/列同步 | + +### 6.2 方案 C 额外清单 + +| 文件 | 计划改动 | +|---|---| +| `backend/internal/model/distribution.go`、新迁移 | 站点加 `receive_subsidy_delta`;订单加补贴快照;`DistributionOrderFinancial`(`:89`)增列 | +| `backend/internal/modules/distribution/pricing.go` | `CalculateSettlement`(`:173`)、`SplitSettlement`(`:273`)引入补贴项与封顶规则 | +| `backend/internal/modules/distribution/lifecycle.go` | `SnapshotPaidOrderTx`(`:183`)、结算/释放/退款重算(`:300` 起)带补贴与按比例冲回 | +| `backend/internal/modules/distribution/repository.go` | 结算批次与分站余额负数处理 | +| `distribution-admin` 钱包/结算页、主站财务看板 | 补贴明细与净收益展示 | +| `docs/分销网管理后台设计方案.md` 7.5 / 7.8 | 同步口径 | + +### 6.3 方案 D 清单 + +| 文件 | 计划改动 | +|---|---| +| `backend/internal/modules/systemconfig/sale_price_config.go` | 补齐 390M+ 三档修正值 | +| `backend/internal/modules/listing/external_pricing.go:56` | 同步默认值,并考虑与 `systemconfig` 合并消除重复 | +| `backend/migrations/`(新增) | `UPDATE system_configs SET value=... WHERE key='listing.sale_price_config'`,且仅当当前值等于旧默认时更新,避免覆盖运营手改 | +| `frontend/src/features/listings/api/listingOptions.ts` | 前端默认值与归一化同步 | +| `docs/出售加价规则.md` | 「待定」改为确定值 | +| 跳变处理(可选,会扩大改动) | `external_pricing.go` 档位判定 + 前端同名逻辑连续化 | + +--- + +## 7. 风险与回滚 + +### 7.1 通用风险 + +1. **前后端双实现必须同步**:任何口径改动都要同时改 `pricing.ts` 与 `external_pricing.go`,否则发布页预览与实际扣款不一致。 +2. **三份默认值 + 线上配置行**:改默认只影响新库;老库需迁移或后台手改。 +3. **快照语义**:`seller_ratio` 在旧/新口径下含义不同,建议在 `asset_summary.price_breakdown` 写入 `pricing_model` 版本号,报表才能区分。 +4. **历史数据不可重算**:所有金额在支付时快照,改引擎只影响之后的新发布/编辑商品与订单;这也意味着回滚不需要动历史数据。 + +### 7.2 方案特有风险 + +- **方案 B**:分站可能无限压价 → 号主流失、跨站套利;必须设收货价下限(如不低于主站回收价的某个百分比)与 `δ` 上限。分站收号商品的买家价基准变化可能引起客诉。 +- **方案 C**:资金链路改动,补贴参与退款/部分退款/超时释放/税费基数;需处理分站应得为负;对账口径需同步更新。 +- **方案 D**:改档位值会让 ≥390M 大额号的买家价一次性变化,需运营知情;迁移需保护运营已手改的配置。 + +### 7.3 回滚 + +- B / C:回退代码即可;新增列保留(可空、默认 0),历史订单/快照不受影响。 +- D:回退代码;若已执行配置迁移,需保留旧 JSON 以便恢复(或在迁移中同时记录旧值)。 + +--- + +## 8. 建议实施顺序 + +1. **阶段 0:方案 D 止血** —— ⏳ 待办。补齐 390M+、消除「0 利润」与主要跳变。 + 注:方案 B 解耦后,分站侧毛利不再依赖买家价下移,390M+ 的「0 提价利润」对分站压价收益的影响已减弱,但主站自身挂牌价仍受影响,故此项仍需处理。 +2. **阶段 1:方案 B** —— ✅ 已实施(2026-09-17)。未采用影子计算开关:以新字段 + `receive_cost_delta` + 快照 `pricing_model = site_cost_decoupled_v1` 标记区分口径,存量商品靠快照天然隔离。 +3. **阶段 2:方案 C** —— ⏳ 未实施。需先定义补贴封顶与退款冲回规则。 + +文案修正已随阶段 1 一并完成:主站/分销后台均改为价格语义「收号价比主站低 X 点」。 + +--- + +## 9. 验收与回归用例 + +### 9.1 确定性回归表 + +构造 `(coinM, 账号属性, delta)` → `(号主底价, 买家价, 毛利, 三方分账)` 的固定表格,前后端分别执行并逐项比对。已有可对齐的基准点: + +- `R=43`、`coinM=100`:主站默认号主基础价 `232.6`、买家比例 `38`、买家总价 `263.20`(`receive_pricing_test.go` 已固定)。 + +### 9.2 属性断言 + +1. **单调性**:新口径下(方案 B/C)压价 δ 越大 → 毛利与三方分账单调不降。 +2. **无跳变**:相邻币量档位之间毛利变化有界,不出现「币更多、利润更少」。 +3. **非负**:任何档位、任何 δ 下毛利与分账 ≥ 0(除非产品明确允许负补贴)。 +4. **前后端一致**:同一输入下前端预览与后端快照金额完全一致。 +5. **边界**:coinM 在 10/30/50/70/90/130/230/310/380/390/470/530/550 各边界值前后各测一点。 + +### 9.3 回归范围 + +- 后端:`receive_pricing_test.go`、`external_adjustment_test.go`、`distribution/pricing_test.go`、`distribution/lifecycle_test.go`、`backend/internal/e2e`。 +- 前端:`usePricingCalculator` 相关单测(建议新增)、发布页 e2e。 +- 结算:结算批次、冷却释放、退款重算。 + +--- + +## 10. 附录 + +### 10.1 代码索引 + +| 主题 | 位置 | +|---|---| +| 收号定价主流程 | `backend/internal/modules/listing/receive_pricing.go:55` | +| 分站 delta 应用 | `backend/internal/modules/listing/receive_pricing.go:115` | +| 买家加价与档位规则 | `backend/internal/modules/listing/external_pricing.go:56`、`:118` | +| 分站 delta 读取 | `backend/internal/modules/listing/site_receive.go` | +| 分销分账 | `backend/internal/modules/distribution/pricing.go:173`、`:273` | +| 订单来源/模式判定 | `backend/internal/modules/distribution/lifecycle.go:38` | +| 支付快照 | `backend/internal/modules/distribution/lifecycle.go:183` | +| 站点字段与校验 | `backend/internal/model/distribution.go`、`backend/internal/modules/distribution/repository.go:69` | +| 收号比例迁移 | `backend/migrations/000070_distribution_site_receive_ratio.sql` | +| 加价默认规则(后端·listing) | `backend/internal/modules/listing/external_pricing.go:56` | +| 加价默认规则(后端·systemconfig) | `backend/internal/modules/systemconfig/sale_price_config.go` | +| 加价默认规则(前端) | `frontend/src/features/listings/api/listingOptions.ts` | +| 前端定价实现 | `frontend/src/shared/utils/pricing.ts:128/162/175`、`frontend/src/shared/composables/usePricingCalculator.ts` | +| 分销后台设置 UI | `distribution-admin/src/pages/SiteSettings.tsx` | +| 主站后台分站管理 UI | `frontend/src/features/admin/views/AdminDistributionSitesView.vue` | +| 加价规则文档 | `docs/出售加价规则.md`、`docs/发布比例计算.md` | + +### 10.2 术语表 + +| 术语 | 含义 | +|---|---| +| 主站参考比例 R | 按账号属性算出的回收比例基准,也是主站给号主的最高价(比例最小值) | +| 回收比例 / 收号比例 | 号主侧的兑换比例,越大表示收购价越低 | +| 买家比例 | 租客侧的兑换比例,由主站规则从卖家侧推导 | +| δ(delta) | 分站相对主站的比例调整点数 | +| 提价利润 | 买家价 − 号主价,进入 35/40/25 分账 | +| 分站自主加价 | 主站账号在分站销售时的加价,100% 归分站 |