约稿画师端费用明细 (2026-09-23)

需求背景

  • 来源:2026-09-23 音画会议(画师端费用明细弹窗计算异常)+ 任务 09-23-artist-fee-breakdown-refinement(费用明细契约细化:弹窗改后端供数)。
  • 动机:画师端「费用明细」弹窗此前由前端写死费率(平台服务费 10%、支付手续费 3.9%~5%)本地计算,与画师数据库实际配置不符;计算基数也不随退款后的已支付金额变化。需要后端按画师实际配置、以「已支付金额」为费基统一供数。
  • 范围:画师端新增只读试算接口 POST /api/artist_center/work_tasks/fee_estimate(费用明细唯一出口)。本次不改用户端、不改列表、不改结算服务与模拟器本体、无迁移、无新增错误码。
  • 面向读者:前端(画师端)、联调、测试。
  • 术语对照:commission = WorkTask(委托);净额 net_paid_amount(= 弹窗「已支付金额」)口径见《约稿详情净已支付金额》(2026-09-22)。

更新记录

  • 2026-09-23 首次发布:新增画师端费用试算接口 fee_estimate——费用明细唯一出口,按入参金额估算平台服务费 / 支付手续费 / 预计收入(开发阶段契约,后端未发版)。
  • 2026-09-24 Q2 口径迭代(就地更新):请求体移除 amount,费基改服务端派生(= net_paid_amount,不接受任意金额试算);payment_fee 由费率估算改为结算扣减口径逐单实际网关手续费(canceled 时为 0,语义=本次无需额外扣除、费基已内扣,非「实际手续费为 0」);新增 payment_fee_issues(原语 issues 原样透出,非空=金额信息不完整);fee_rates 移除 pay_fee_ratio;补充全退场景合法输出与前端标注义务(后端未发版,开发阶段契约就地更新,无兼容负担)。
  • 2026-09-24 钱包抵扣迭代(就地更新):新增 plat_fee_wallet_offset(手续费抵扣钱包 WalletUsage::PlatFee 预计抵扣,单列、不折进 platform_fee);estimated_income 公式加入 + plat_fee_wallet_offset;tips 改为显式抵扣数字口径(替代旧「实际收入可能会因手续费抵扣等发生微调」被动文案);弹窗绑定表新增「手续费抵扣钱包抵扣」行(> 0 时展示);钱包余额本身不进弹窗,仅输出预计抵扣金额(后端未发版,开发阶段契约就地更新)。
  • 2026-09-24 费基取数修正(就地更新):弹窗「已支付金额(费基行)」由详情 data.net_paid_amount 改绑试算响应 data.fee_base——费基与全部费用行同一次请求取数(一次请求内自洽);同源计算不代表跨请求恒等,详情与试算两次请求之间发生付款 / 退款 / 改价会错配新旧口径,禁止混读(纯前端绑定口径修正,接口契约不变)。
  • 2026-09-28 错误契约实测核对与排查补充(就地更新):422 示例对齐 Laravel 实际输出(含 errors 对象);补两类 404 排查区分(路径拼错 vs 业务不存在/非本人,按 message 区分);注明测试环境 APP_DEBUG=true 会附带 exception trace、生产仅 message。经测试库复现确认接口契约无缺口,2026-09-28 会议中的 422/404 为前端调用路径错误,接口无改动。

建议阅读顺序:第 1 章(一分钟上手)→ 第 2 章(接口变更)→ 第 3 章(接口示例)→ 第 4 章(字段与弹窗绑定)→ 第 5 章(兼容性)。

目录

章内容什么时候看
1. 一分钟上手取数流程 + 取值来源 + 对接要点刚拿到文档
2. 接口变更试算接口变更摘要找接口
3. 接口示例请求参数、响应示例、响应字段说明、错误语义对接具体接口
4. 字段与弹窗绑定弹窗行项 ↔ 字段绑定与前端对接说明联调对接
5. 兼容性说明兼容项与发布协同发布前确认

1. 一分钟上手

状态与口径:开发阶段契约、后端未发版;纯新增试算接口,无破坏性变更、无错误码变化。 费用明细是画师端专属概念,用户端详情与两端列表不输出任何费用明细字段。 面向前端(画师端)、联调、测试。

1.1 取数流程

1.2 取值来源

平台服务费率取画师数据库实际配置(响应 fee_rates.platform_fee_ratio 同步返回);支付手续费不是费率估算,而是结算扣减口径的逐单实际网关手续费(缺费时以 payment_fee_issues 标注不完整);手续费抵扣钱包仅输出预计抵扣金额(plat_fee_wallet_offset,余额不展示)。前端不做本地费率与取整计算。

1.3 对接要点

  1. 费基 = 已支付金额(服务端派生):请求体只传 id,不传金额;响应 fee_base 由服务端派生(口径同详情 net_paid_amount,合同覆盖口径),弹窗「已支付金额」行直接读该响应字段。不支持任意金额试算。
  2. 单一取数路径:平台服务费、支付手续费、手续费抵扣钱包预计抵扣、预计收入各行只取试算响应,前端不再本地写死费率或取整;费基行与全部费用行同读本次试算响应,稿酬参考行取详情字段(仅参考,不与费用行混源解读)。
  3. 守恒关系有条件成立:仅当 fee_base ≥ platform_fee + payment_fee − plat_fee_wallet_offset 时「费用行净额」等于费基;费用净合计超过费基时 estimated_income 截为 0(超支差额不向画师追收,也不折入其他字段),此时加和不等于费基——不要用加和反推费基,以 fee_base 为准。estimated_income 恒为 max(0, fee_base − platform_fee − payment_fee + plat_fee_wallet_offset)(与结算公式 income = total − payFee − feeAfterWaiver + platFeeRefund 逐项同构)。全退场景是合法输出:fee_base = 0 而 payment_fee > 0(手续费是已发生的常驻事实,退款后仍可能保留)时,费用净合计必然大于费基、estimated_income 为 0——这不是错误,不表示向画师追收。
  4. 手续费抵扣钱包预计抵扣(plat_fee_wallet_offset):单列字段,与 Open Call 减免同构展示;platform_fee 语义不变(减免后金额),抵扣不折进 platform_fee。上限 = platform_fee;无钱包 / 零余额 / platform_fee = 0 时为 0;canceled 态照常模拟(取消结算同走抵扣)。余额本身不展示(会议拍板),只展示预计抵扣金额;tips 口径见第 4.2 节。
  5. 费率读 fee_rates:响应自带 platform_fee_ratio 实际配置值(pay_fee_ratio 已移除,支付手续费不再按费率计算),展示平台费率时读它,不本地写死。
  6. payment_fee_issues 非空 ⟹ 金额信息不完整:此时 payment_fee 为部分和(缺费订单按 0 计入合计),金额是下界估计而非精准值——前端必须标注提示,不得宣称精准。issues 原样透出共享原语的 code / message / order_id,不重定义错误码;canceled 且 payment_fee = 0 时照常输出,不因本次不扣费而隐藏。
  7. canceled 语义:payment_fee = 0 表示本次计算无需额外扣除支付手续费(费基已内扣同源手续费),不表示实际手续费为 0;实际手续费真实值见详情净额字段组 non_refundable_fee。
  8. is_estimate: true 标注:恒为估算结果;对外展示建议保留「估算」语义提示。
  9. 错误分支:404(commission 不存在或非当前画师)、422(id 校验失败);无业务错误码分支。

2. 接口变更

artist_center

  • POST /api/artist_center/work_tasks/fee_estimate
    • 功能:画师侧费用试算(平台服务费 / 支付手续费 / 手续费抵扣钱包预计抵扣 / 预计收入,费基服务端派生)
    • 变更:✨ 新增接口;费用明细的唯一出口

费用明细是画师端专属:用户端详情与两端列表不输出任何费用明细字段。


3. 接口示例

artist_center

POST /api/artist_center/work_tasks/fee_estimate

  • 功能说明:按服务端派生的费基(net_paid_amount)与逐单实际网关手续费,估算当前画师一笔 commission 的平台服务费 / 支付手续费 / 手续费抵扣钱包预计抵扣 / 预计收入。只读、无状态、不写库。
  • 变更说明:✨ 新增接口。

请求参数

字段类型必填说明
idinteger是commission id(work_tasks.id),必须属于当前画师

其他校验规则

  • id >= 1,整数。
  • 不接受金额入参:费基由服务端派生(= 详情 net_paid_amount),历史字段 amount 已移除,传入会被忽略且不参与计算。

请求示例

{
  "id": 1001
}

响应示例

{
  "data": {
    "fee_base": 8000,
    "currency": { "id": 31, "code": "CNY", "symbol": "CN¥", "is_zero_decimal": false },
    "platform_fee_gross": 400,
    "platform_fee_waiver": 0,
    "platform_fee": 400,
    "payment_fee": 300,
    "payment_fee_issues": [],
    "plat_fee_wallet_offset": 100,
    "estimated_income": 7400,
    "fee_rates": { "platform_fee_ratio": 0.05 },
    "policy_code": null,
    "is_estimate": true
  }
}

缺费时 payment_fee 为部分和并透出 issues(前端据此标注「金额信息不完整」):

{
  "payment_fee": 197,
  "payment_fee_issues": [
    {
      "code": "business_gateway_fee_missing",
      "order_id": 2002,
      "message": "缺少业务币种的实际支付手续费"
    }
  ]
}

响应字段说明

字段类型说明
fee_baseinteger服务端派生费基 = 详情 net_paid_amount(working = min(retained, price),canceled = max(0, retained − nonRefundableFee),业务币种最小单位);展示以「已支付金额」为准
currencyobject / nullcommission 业务币种:id / code / symbol / is_zero_decimal
platform_fee_grossinteger减免前平台服务费 = ceil(round(fee_base × worktask_plat_fee_ratio, 2))
platform_fee_waiverintegerOpen Call 减免金额;无减免为 0
platform_feeinteger减免后平台服务费 = platform_fee_gross − platform_fee_waiver
payment_feeinteger本次计算需额外扣除的支付手续费:working 态 = 结算扣减口径 Σ 逐单实际网关手续费(共享原语派生);canceled = 0(费基已内扣同源手续费,非「实际手续费为 0」;实际手续费见详情净额字段组 non_refundable_fee)
payment_fee_issuesarray逐单手续费完整性问题,原语 issues 原样透出(code / message / order_id),不重定义错误码;canceled 且 payment_fee = 0 时照常输出。非空 ⟹ payment_fee 为部分和、金额信息不完整,前端须标注、不得宣称精准
plat_fee_wallet_offsetinteger本次预计用手续费抵扣钱包(WalletUsage::PlatFee)抵扣的平台费(业务币种最小单位);上限 = platform_fee;无钱包 / 零余额 / platform_fee = 0 时为 0;canceled 态照常模拟(取消结算同走抵扣);取数复用结算侧同一换算/取整口径(余额折算 floor)。单列字段、不折进 platform_fee;只输出预计抵扣金额,钱包余额本身不输出
estimated_incomeinteger预计收入 = max(0, fee_base − platform_fee − payment_fee + plat_fee_wallet_offset)(与结算公式逐项同构);费用净合计超费基时为 0(见第 1 章对接要点 3,全退场景 fee_base = 0 / payment_fee > 0 / income = 0 是合法输出)
fee_ratesobject画师 DB 实际费率,仅 platform_fee_ratio(pay_fee_ratio 已移除:支付手续费按实际费计算,不按费率估算),展示平台费率用
policy_codestring / nullOpen Call 减免政策标识;无减免为 null(此时 platform_fee_waiver 为 0)
is_estimateboolean恒为 true,估算语义标注

错误响应

以下 JSON 均为测试库实测输出(生产 APP_DEBUG=false 形态;测试环境 APP_DEBUG=true 时 404 会额外附带 exception / file / line / trace 调试字段,属框架行为,不要据此误判)。

  • 422:id 缺失或校验失败(框架级字段校验)。实测输出:
{
  "message": "The id field is required.",
  "errors": {
    "id": ["The id field is required."]
  }
}

id 非整数时:"message": "The id field must be an integer."(errors 结构同上,Laravel 实际校验文案为准)。

  • 404:两类来源需区分排查:
触发原因实测 message排查方向
请求路径拼错(如 fees_estimate)The route api/artist_center/work_tasks/fees_estimate could not be found.(直接点名拼错的路径)前端调用路径写错,改用 POST /api/artist_center/work_tasks/fee_estimate;接口本身无故障
commission 不存在或不属于当前画师Work task not found检查 id 是否真实存在、是否属于当前登录画师
{
  "message": "Work task not found"
}

无新增 ErrorCode:本接口无业务失败分支,以上均为 HTTP 级错误语义。


4. 字段与弹窗绑定

4.1 弹窗行项 ↔ 字段绑定

收入详情弹窗(预计收入弹窗)与顶部卡片的逐行取值;行名统一用「已支付金额」(不叫「净已支付金额」):

弹窗行项 / 元素取值字段
稿酬(参考行)详情 data.price(仅参考,不得与费用行混源解读)
已支付金额(费基行)响应 data.fee_base(与全部费用行同一次请求取数;费基由服务端派生、无入参)
平台服务费响应 data.platform_fee
平台服务费费率 tooltip响应 data.fee_rates.platform_fee_ratio
平台服务费减免提示响应 data.platform_fee_waiver(> 0 时附「已减免 X」)
手续费抵扣钱包抵扣响应 data.plat_fee_wallet_offset(> 0 时展示;钱包余额不展示,仅展示预计抵扣金额)
支付手续费响应 data.payment_fee(实际手续费口径;canceled=0 表示本次无需额外扣除)
支付手续费说明 tooltip「按实际支付手续费计算」(不展示固定费率,见第 4.2 节 tips 口径)
金额完整性标注响应 data.payment_fee_issues(非空时标注「金额信息不完整」)
预计收入(高亮行 + 顶部卡片)响应 data.estimated_income
估算标注响应 data.is_estimate

「详情」= 画师端约稿详情接口字段;「响应」= fee_estimate 试算响应 data。

费基与全部费用行同读本次试算响应(一次请求内自洽),详情字段仅用于稿酬参考行。同源计算不代表跨请求恒等:详情与试算两次请求之间发生付款 / 退款 / 改价,会「旧费基配新费用」错配新旧口径,禁止混读(不得用详情 data.net_paid_amount 充当费基与试算费用行拼表)。行名仍统一叫「已支付金额」。

平台服务费展示链:platform_fee_gross → platform_fee_waiver(Open Call 减免)→ plat_fee_wallet_offset(手续费抵扣钱包,> 0 时展示)→ 画师实际承担的平台费(= platform_fee − plat_fee_wallet_offset);钱包抵扣单列,不改写 platform_fee 行数值。

4.2 前端对接说明(pipipen-front 负责人实施)

  1. 删除本地计算:收入详情弹窗与顶部「预计收入」数字不再用前端本地计算(priceCalcData),改读试算响应。
  2. 新增「已支付金额」行:绑定响应 data.fee_base(与费用行同一次请求取数;费基服务端派生、无入参),位置在稿酬行之后(作为费基)。不要绑定详情 data.net_paid_amount——它与试算响应是两次请求,期间发生付款 / 退款 / 改价会错配新旧口径。
  3. 平台费率 tooltip 读 fee_rates.platform_fee_ratio:删除前端兜底写死费率(0.04 / 0.05)。支付手续费行不展示固定费率:tooltip 文案用「按实际支付手续费计算」;演示/联调用指定样本的实际手续费数值,不把通道费率(alipay-CNY 为 0、Stripe 约 3.x%)写成普遍保证。
  4. tips 文案口径:
    • 全退 / 手续费说明:「手续费已发生、退款后仍可能保留,预计收入最低为 0,不表示向画师追收」;
    • 手续费抵扣钱包:plat_fee_wallet_offset > 0 时 tips 用「预计收入已含手续费抵扣钱包预计抵扣 X;余额与汇率到结算时可能变化,以最终结算为准」,替代旧「实际收入可能会因手续费抵扣等发生微调,以最终结算为准」被动口径;抵扣为 0 时不追加该句;钱包余额本身不展示(会议拍板),只展示预计抵扣金额;
    • payment_fee_issues 非空 ⟹ 金额信息不完整(payment_fee 为部分和),前端须标注提示、不得宣称精准;
    • 现有文案「预计收入是基于当前稿酬以及服务费用计算出的预估值……」→「基于已支付金额以及服务费用计算出的预估值……」(i18n key ac.worktask_info.total_income_tips,前端仓库维护)。
  5. canceled 提示:payment_fee = 0 时如需说明,措辞为「本次无需额外扣除支付手续费」(费基已内扣);实际手续费引导用户查看详情净额字段组 non_refundable_fee,不要写「无手续费」。
  6. 估算语义标注:is_estimate 恒为 true,弹窗保留「估算」提示。
  7. 边界行为:
    • payment_fee_issues 非空 → 金额完整性标注(必做,见 tips 口径);
    • 费用净合计(platform_fee + payment_fee − plat_fee_wallet_offset)> 费基 → estimated_income 截 0,加和 ≠ 费基,禁止用加和反推费基,以 fee_base 为准;全退场景 fee_base = 0 / payment_fee > 0 / income = 0 是合法输出,不按异常处理;
    • 响应不含结算模拟层(方案 B 后契约无 settlement_preview 字段)。
  8. 取数路径(已拍板 B:统一走接口):弹窗打开时调 POST /work_tasks/fee_estimate { id }(只传 id,金额由服务端派生),渲染函数入参为响应估算对象;详情不再内嵌 fee_breakdown,单一取数路径无双源漂移。
  9. 数值差异预期:改造后数值与旧前端不一致是预期修正——费基(稿酬 → 已支付金额,部分支付/含退款场景差异最大)、费率(写死 4%/5% → 画师 DB 实际配置)、支付手续费(费率估算 → 逐单实际手续费,数值随样本订单变化)。

5. 兼容性说明

  • 纯新增接口,无破坏性变更:fee_estimate 只读、无状态、无存量消费方(后端未发版;amount 入参与费率口径在首发前就地迭代,无已上线消费方)。
  • 无新增错误码、无迁移:错误语义沿用 404 / 422;试算接口只读、不写库。
  • 模拟器与结算服务零改动:完成结算模拟层不在本接口范围,SettlementSimulator 与结算服务行为不变;估算层自 2026-09-24 起包含手续费抵扣钱包预计抵扣(plat_fee_wallet_offset,只读模拟、不写库),取数复用结算侧同一 PlatFeeWalletService::minus() 原语,不旁路、不复制换算/取整规则。
  • 无需发布顺序协同:后端先上线即可供数,前端随后按第 4.2 节切换弹窗取数;旧前端不调用新接口时行为不变。
  • 回滚方式:revert 对应后端提交即回滚,纯读取接口回退不影响任何存量数据。