feat(consignment): 高规格(超配钻级/璀璨)寄卖建议价自动按当前最高档位报价
This commit is contained in:
@@ -531,12 +531,72 @@ test('发布寄卖建议价:按璀璨数精准区分价格,不会同钻级
|
||||
assert.equal(hit3.matchedRules.length, 1)
|
||||
assert.equal(hit3.matchedRules[0].ruleKey, 'rule-5z-3c')
|
||||
|
||||
// 5. 选 4璀(模板库未配 4璀 价格),不命中,返回 null
|
||||
// 5. 选 4璀/5璀(号主出的璀璨比配置高):按当前钻级已配置的最高璀璨(3璀 28000 分)报价
|
||||
const hit4 = suggestConsignmentPriceFromRules(rules, {
|
||||
system: '苹果',
|
||||
series: '怒嚎',
|
||||
diamondLevel: 5,
|
||||
brillianceCount: 4,
|
||||
})
|
||||
assert.equal(hit4, null)
|
||||
assert.ok(hit4, '超出配置的璀璨应命中已配置的最高璀璨')
|
||||
assert.equal(hit4.suggestedPriceFen, 28000)
|
||||
assert.equal(hit4.matchedRules[0].ruleKey, 'rule-5z-3c')
|
||||
|
||||
const hit5 = suggestConsignmentPriceFromRules(rules, {
|
||||
system: '苹果',
|
||||
series: '怒嚎',
|
||||
diamondLevel: 5,
|
||||
brillianceCount: 5,
|
||||
})
|
||||
assert.equal(hit5?.suggestedPriceFen, 28000)
|
||||
})
|
||||
|
||||
test('发布寄卖建议价:号主钻级比后台配置高时,按已配置的最高钻级报价(7钻报6钻价,低钻不报高钻)', () => {
|
||||
const rules = [
|
||||
{ ruleKey: 'rule-1z', productName: '安卓怒嚎1钻', rewardAmountFen: 10000 },
|
||||
{ ruleKey: 'rule-6z-0c', productName: '安卓怒嚎6钻', rewardAmountFen: 35000 },
|
||||
{ ruleKey: 'rule-6z-2c', productName: '安卓怒嚎6钻2璀', rewardAmountFen: 42000 },
|
||||
]
|
||||
|
||||
// 号主出 7钻(后台最高只有 6钻):钻级按 6钻 报价
|
||||
// 7钻 0璀 → 报 6钻 0璀(35000)
|
||||
const hit7z0c = suggestConsignmentPriceFromRules(rules, {
|
||||
system: '安卓',
|
||||
series: '怒嚎',
|
||||
diamondLevel: 7,
|
||||
brillianceCount: 0,
|
||||
})
|
||||
assert.equal(hit7z0c?.suggestedPriceFen, 35000)
|
||||
assert.equal(hit7z0c?.matchedRules[0].ruleKey, 'rule-6z-0c')
|
||||
|
||||
// 7钻 5璀 → 钻级按 6钻,璀璨按 6钻最大配置(2璀)报价(42000)
|
||||
const hit7z5c = suggestConsignmentPriceFromRules(rules, {
|
||||
system: '安卓',
|
||||
series: '怒嚎',
|
||||
diamondLevel: 7,
|
||||
brillianceCount: 5,
|
||||
})
|
||||
assert.equal(hit7z5c?.suggestedPriceFen, 42000)
|
||||
assert.equal(hit7z5c?.matchedRules[0].ruleKey, 'rule-6z-2c')
|
||||
|
||||
// 低配不能充高配:号主出 2钻(未超出 6钻 上限,但未单独配置 2钻):不命中返回 null,绝不误报 6钻
|
||||
const hit2z = suggestConsignmentPriceFromRules(rules, {
|
||||
system: '安卓',
|
||||
series: '怒嚎',
|
||||
diamondLevel: 2,
|
||||
brillianceCount: 0,
|
||||
})
|
||||
assert.equal(hit2z, null)
|
||||
|
||||
// 号主出 1钻,但如果后台只有 3钻 以上规则,不命中返回 null
|
||||
const onlyHighRules = [{ ruleKey: 'rule-3z', productName: '安卓怒嚎3钻', rewardAmountFen: 20000 }]
|
||||
assert.equal(
|
||||
suggestConsignmentPriceFromRules(onlyHighRules, {
|
||||
system: '安卓',
|
||||
series: '怒嚎',
|
||||
diamondLevel: 1,
|
||||
brillianceCount: 0,
|
||||
}),
|
||||
null,
|
||||
)
|
||||
})
|
||||
|
||||
@@ -430,10 +430,13 @@ export type ConsignmentPriceSuggestionRule = {
|
||||
* 从「接单模板」(work_product_rules)里给寄卖提报找建议价。
|
||||
*
|
||||
* 模板的商品名(如「安卓暗潮1钻」)用与订单同一套规格解析器拆解:
|
||||
* 系列、钻级必须完全一致;系统按通配口径比对(规则或提报任一侧是「通用/双端」都算匹配)。
|
||||
* 区服不参与——模板价不分微信/QQ。
|
||||
* 若指定了璀璨数(0~7),模板商品解析出的璀璨数必须一致(0璀对应无璀璨/0璀,3璀对应3璀/3璀璨);未指定则忽略璀璨。
|
||||
* 多条命中取最高价(该规格能卖到的最好价钱),卖家仍可手动改。
|
||||
* 系统(含通用通配)、系列必须一致;区服不参与比对。
|
||||
* 钻级与璀璨数支持高配向下兜底匹配(号主出得比配置高时,报价当前已配置的最高规格):
|
||||
* 1. 钻级对齐:优先精确匹配号主钻级;若号主钻级高于后台配置上限(如号主出7钻但后台只配了1~6钻),
|
||||
* 按后台已配置的最大钻级(6钻)报价。低钻不能配高钻(号主出1钻不报6钻价)。
|
||||
* 2. 璀璨对齐:在该钻级下,优先精确匹配号主璀璨;若号主璀璨高于后台配置上限(如号主出3~5璀但后台只配了1~2璀),
|
||||
* 按后台该钻级已配置的最大璀璨档位报价。
|
||||
* 3. 命中多条(如通用与专属端同存)取最高价,卖家仍可手动修改。
|
||||
*/
|
||||
export function suggestConsignmentPriceFromRules(
|
||||
rules: ConsignmentPriceSuggestionRule[],
|
||||
@@ -455,19 +458,61 @@ export function suggestConsignmentPriceFromRules(
|
||||
: null
|
||||
if (!wantedSystem || !wantedSeries || wantedDiamond <= 0) return null
|
||||
|
||||
const matched = rules.filter((rule) => {
|
||||
const rewardFen = Math.round(Number(rule.rewardAmountFen || 0))
|
||||
if (rewardFen <= 0) return false
|
||||
const parsed = extractPeacekeeperSpecs(rule.productName)
|
||||
if (!parsed.system) return false
|
||||
if (parsed.series !== wantedSeries) return false
|
||||
if (Number(parsed.diamondLevel || 0) !== wantedDiamond) return false
|
||||
if (wantedBrilliance !== null && Number(parsed.brillianceCount || 0) !== wantedBrilliance) {
|
||||
return false
|
||||
// 1. 筛选系统一致(含通用通配)且系列一致、金额大于 0 的有效候选规则
|
||||
const seriesCandidates = rules
|
||||
.map((rule) => {
|
||||
const rewardFen = Math.round(Number(rule.rewardAmountFen || 0))
|
||||
if (rewardFen <= 0) return null
|
||||
const parsed = extractPeacekeeperSpecs(rule.productName)
|
||||
if (!parsed.system) return null
|
||||
if (parsed.series !== wantedSeries) return null
|
||||
const isSystemMatch =
|
||||
parsed.system === wantedSystem || parsed.system === '通用' || wantedSystem === '通用'
|
||||
if (!isSystemMatch) return null
|
||||
const diamondLevel = Number(parsed.diamondLevel || 0)
|
||||
if (diamondLevel <= 0) return null
|
||||
const brillianceCount = Number(parsed.brillianceCount || 0)
|
||||
return { rule, parsed, rewardFen, diamondLevel, brillianceCount }
|
||||
})
|
||||
.filter((item): item is NonNullable<typeof item> => item !== null)
|
||||
|
||||
if (seriesCandidates.length === 0) return null
|
||||
|
||||
// 2. 钻级对齐:
|
||||
// 查找当前系统与系列已配置的最大钻级;若号主出的钻级比后台配置高(如后台只设置了6个价格,号主出7个),
|
||||
// 按后台已配置的最大钻级报价;未超出配置上限时必须精确对齐钻级(低钻不报高钻,中间未配价的钻级不向下误报)
|
||||
const maxConfiguredDiamond = Math.max(...seriesCandidates.map((item) => item.diamondLevel))
|
||||
const targetDiamond = wantedDiamond > maxConfiguredDiamond ? maxConfiguredDiamond : wantedDiamond
|
||||
|
||||
const targetDiamondCandidates = seriesCandidates.filter(
|
||||
(item) => item.diamondLevel === targetDiamond,
|
||||
)
|
||||
if (targetDiamondCandidates.length === 0) return null
|
||||
|
||||
// 3. 璀璨对齐:
|
||||
// 若未指定璀璨(null),取 targetDiamond 下所有规则
|
||||
// 若指定了璀璨:比后台配置高(如后台该钻级只配置到 1~2 璀,号主出 3/4/5 等),按已配置的最大璀璨报价;
|
||||
// 未超出配置上限时严格精确对齐璀璨档位(0璀对0璀、1璀对1璀,不拿高璀价格报给低璀)
|
||||
let matchedItems: typeof targetDiamondCandidates
|
||||
if (wantedBrilliance === null) {
|
||||
matchedItems = targetDiamondCandidates
|
||||
} else {
|
||||
const maxConfiguredBrilliance = Math.max(
|
||||
...targetDiamondCandidates.map((item) => item.brillianceCount),
|
||||
)
|
||||
if (wantedBrilliance > maxConfiguredBrilliance) {
|
||||
matchedItems = targetDiamondCandidates.filter(
|
||||
(item) => item.brillianceCount === maxConfiguredBrilliance,
|
||||
)
|
||||
} else {
|
||||
matchedItems = targetDiamondCandidates.filter(
|
||||
(item) => item.brillianceCount === wantedBrilliance,
|
||||
)
|
||||
}
|
||||
return parsed.system === wantedSystem || parsed.system === '通用' || wantedSystem === '通用'
|
||||
})
|
||||
if (matched.length === 0) return null
|
||||
const suggestedPriceFen = Math.max(...matched.map((rule) => Math.round(rule.rewardAmountFen)))
|
||||
return { suggestedPriceFen, matchedRules: matched }
|
||||
}
|
||||
|
||||
if (matchedItems.length === 0) return null
|
||||
const suggestedPriceFen = Math.max(...matchedItems.map((item) => item.rewardFen))
|
||||
const matchedRules = matchedItems.map((item) => item.rule)
|
||||
return { suggestedPriceFen, matchedRules }
|
||||
}
|
||||
|
||||
+5
-2
@@ -342,9 +342,12 @@
|
||||
- 动态禁用:`BRILLIANCE_OPTIONS` 中 `value > diamondLevel` 自动置灰禁用(1钻最多1璀,2钻最多2璀…)。
|
||||
- 自动收敛:调小钻级时(如 5钻改为 2钻),原选璀璨数超出时自动收敛至新钻级(2璀),并联动重算建议价与物品名。
|
||||
- 默认值与联动:璀璨数默认 `initialValue={0}`(无),`queryKey` 纳入 `${bri}`,切换璀璨即刻重新带价。
|
||||
- 双重校验:前端 Validator 校验 + 后端 `publishWorkerConsignment` 拦截(`brilliance_exceeds_diamond`)。
|
||||
4. ✅ **高规格溢出自动按当前配置最高档位报价**:
|
||||
- 璀璨溢出:当号主提报的璀璨数高于后台已配置上限(如后台该钻级只配了 0~2 璀,号主出 3/4/5 璀等),自动按当前钻级已配置的最高璀璨档位报价。
|
||||
- 钻级溢出:当号主提报的钻级高于后台配置上限(如后台只配了 1~6 钻,号主出 7 钻),自动按后台当前已配置的最大钻级报价(7钻报6钻价)。
|
||||
- 边界安全:仅在超出配置上限时触发兜底;未超出配置上限时严格精确对齐(低钻绝不报高钻价,中间未配价规格返回 null 由号主手动填写,防错价)。
|
||||
|
||||
**验证**:后端 487 / 前端 54 测试全绿;两侧 `typecheck` / `lint:check` / `format:check` 通过。
|
||||
**验证**:后端 488 / 前端 54 测试全绿;两侧 `typecheck` / `lint:check` / `format:check` 通过。
|
||||
### 批次 W · 规格口径:互通通配 + 后台全量/发布端分物品展示(本轮)
|
||||
|
||||
**业务定案**:
|
||||
|
||||
Reference in New Issue
Block a user