feat(consignment): 建议价精准匹配璀璨数 + 限制璀璨不超过钻石数量

- 修复价格匹配:parseSpecsFromText 支持「璀」字缩写(1璀/2璀/3璀)与「无璀/0璀」,
  避免生产规则被误判为 0 璀;suggestConsignmentPriceFromRules 增加 brillianceCount
  精准对齐匹配,未配对应模板则返回空,解决同钻级多条规则全中并取最高价的问题
- 透传参数:路由与打手端服务均增加 brillianceCount 传递
- 限制璀璨不超过钻级:
  - 前端选项动态禁用:大于当前钻级的璀璨芯片置灰
  - 钻级调小自动收敛:若原选璀璨大于新钻级,自动 clamp 至新钻级
  - 默认值与联动:璀璨数默认 initialValue=0,queryKey 纳入璀璨,切换即刻带出对应建议价
  - 前后端双重校验:前端表单 Validator 校验 + 后端提报硬拦截(brilliance_exceeds_diamond)
- 后端 487 / 前端 54 测试全绿,docs/寄卖系统优化方案.md 记录批次 Z
This commit is contained in:
yml2213
2026-09-17 19:14:04 +08:00
parent ccb5b6f4d6
commit 1526907005
8 changed files with 193 additions and 13 deletions
@@ -88,7 +88,8 @@ export default function WorkerConsignmentPage() {
const [evidenceSubmitting, setEvidenceSubmitting] = useState(false)
const [cooldownNow, setCooldownNow] = useState(() => Date.now())
const [form] = Form.useForm()
// 建议价:规格选齐后从「接单模板」带出(安卓+暗潮+1钻 → ¥120);卖家手动改价则只提示不覆盖
const currentDiamondLevel = Form.useWatch('diamondLevel', form)
// 建议价:规格选齐后从「接单模板」带出(安卓+暗潮+1钻+0璀 → ¥120);卖家手动改价则只提示不覆盖
const [priceSuggestion, setPriceSuggestion] = useState<{
fen: number
matchedCount: number
@@ -197,6 +198,14 @@ export default function WorkerConsignmentPage() {
if (changed && changed.askingPrice !== undefined) {
priceTouchedRef.current = true
}
// 钻级改变时:璀璨数不能超过钻石等级(如 5钻调成 2钻,原 5璀自动收敛到 2璀)
if (changed && changed.diamondLevel !== undefined) {
const newDia = Number(changed.diamondLevel || 0)
const curBri = form.getFieldValue('brillianceCount')
if (curBri != null && Number(curBri) > newDia) {
form.setFieldsValue({ brillianceCount: newDia })
}
}
const sys = form.getFieldValue('system')
const zone = form.getFieldValue('serverZone')
const ser = form.getFieldValue('series')
@@ -212,11 +221,11 @@ export default function WorkerConsignmentPage() {
})
}
// 规格选齐(系统+系列+钻级)后从「接单模板」带出建议价:安卓+暗潮+1钻 → 模板价 ¥120。
// 规格选齐(系统+系列+钻级+璀璨)后从「接单模板」带出建议价:安卓+暗潮+1钻+0璀 → 模板价 ¥120。
// 防抖 + 同规格去重 + 过期响应丢弃;建议价拿不到不影响发布(静默)。
if (priceFetchTimer.current) clearTimeout(priceFetchTimer.current)
if (sys && ser && dia != null && Number(dia) > 0) {
const queryKey = `${sys}|${ser}|${dia}`
if (sys && ser && dia != null && Number(dia) > 0 && bri != null) {
const queryKey = `${sys}|${ser}|${dia}|${bri}`
if (lastPriceQueryKeyRef.current !== queryKey) {
lastPriceQueryKeyRef.current = queryKey
// 换了规格:重新允许自动带价(上一规格的手改标记不再拦新规格)
@@ -229,6 +238,7 @@ export default function WorkerConsignmentPage() {
system: String(sys),
series: String(ser),
diamondLevel: Number(dia),
brillianceCount: Number(bri),
})
if (lastPriceQueryKeyRef.current !== queryKey) return
const fen = Number(res.data?.suggestedPriceFen || 0)
@@ -610,7 +620,21 @@ export default function WorkerConsignmentPage() {
<Form.Item
name="brillianceCount"
label="璀璨数"
rules={[{ required: true, message: '请选择璀璨数' }]}
rules={[
{ required: true, message: '请选择璀璨数' },
({ getFieldValue }) => ({
validator(_, value) {
const dia = getFieldValue('diamondLevel')
if (value != null && dia != null && Number(value) > Number(dia)) {
return Promise.reject(
new Error(`璀璨数不能超过钻石等级(当前${dia}钻最多选${dia}璀)`),
)
}
return Promise.resolve()
},
}),
]}
initialValue={0}
className="worker-consignment-spec-card is-count"
>
<Radio.Group
@@ -620,6 +644,8 @@ export default function WorkerConsignmentPage() {
options={BRILLIANCE_OPTIONS.map((o) => ({
label: o.value === 0 ? '无' : `${o.value}璀`,
value: o.value,
disabled:
currentDiamondLevel != null && o.value > Number(currentDiamondLevel),
}))}
/>
</Form.Item>
+2 -1
View File
@@ -484,11 +484,12 @@ export function submitWorkerConsignmentGiftEvidence(
)
}
/** 发布寄卖:按规格(系统/系列/钻级)从「接单模板」带出建议价,如 安卓+暗潮+1钻 → ¥120 */
/** 发布寄卖:按规格(系统/系列/钻级/璀璨)从「接单模板」带出建议价,如 安卓+暗潮+1钻+0璀 → ¥120 */
export function fetchWorkerConsignmentPriceSuggestion(params: {
system: string
series: string
diamondLevel: number
brillianceCount?: number
}) {
return apiGet<{
suggestedPriceFen: number | null