增加出售设置

This commit is contained in:
yml2213
2026-05-23 20:43:01 +08:00
parent 9cec71ab1a
commit 9f15609afd
8 changed files with 303 additions and 8 deletions
@@ -54,6 +54,9 @@ const publishStats = computed(() => {
resourceCount: options.quantity_items.length,
screenshotCount: options.screenshot_slots.length,
regionCount: options.region_options.length,
saleRuleCount:
options.sale_price_config.fixed_markup_rules.length +
options.sale_price_config.ratio_adjustment_rules.length,
}
})
const homeStats = computed(() => {
@@ -281,6 +284,30 @@ function removeCoinCorrection(index: number) {
publishOptionsDraft.value.ratio_config.coin_corrections.splice(index, 1)
}
function addSaleFixedMarkupRule() {
publishOptionsDraft.value.sale_price_config.fixed_markup_rules.push({
min_m: 0,
max_m: 0,
markup_amount: 0,
})
}
function removeSaleFixedMarkupRule(index: number) {
publishOptionsDraft.value.sale_price_config.fixed_markup_rules.splice(index, 1)
}
function addSaleRatioAdjustmentRule() {
publishOptionsDraft.value.sale_price_config.ratio_adjustment_rules.push({
min_m: 0,
max_m: 0,
ratio_subtract: 0,
})
}
function removeSaleRatioAdjustmentRule(index: number) {
publishOptionsDraft.value.sale_price_config.ratio_adjustment_rules.splice(index, 1)
}
function addHomeBanner() {
homeBannersDraft.value.push({
eyebrow: '首页推荐',
@@ -387,6 +414,10 @@ function readError(error: unknown, fallback: string) {
<strong>{{ publishStats.regionCount }}</strong>
<span>地区</span>
</div>
<div class="publish-stat">
<strong>{{ publishStats.saleRuleCount }}</strong>
<span>出售规则</span>
</div>
</div>
</section>
@@ -642,6 +673,53 @@ function readError(error: unknown, fallback: string) {
</div>
<div class="editor-block">
<div class="editor-block-title">
<strong>出售加价规则</strong>
</div>
<div class="editor-block-title subtle-title">
<span>90M 及以下固定加价出售价格 = 回收价格 + 固定加价</span>
<el-button size="small" @click="addSaleFixedMarkupRule">添加固定加价</el-button>
</div>
<el-table :data="publishOptionsDraft.sale_price_config.fixed_markup_rules" size="small" border>
<el-table-column label="最小 M" min-width="120">
<template #default="{ row }"><el-input-number v-model="row.min_m" :min="0" :step="10" /></template>
</el-table-column>
<el-table-column label="最大 M" min-width="120">
<template #default="{ row }"><el-input-number v-model="row.max_m" :min="0" :step="10" /></template>
</el-table-column>
<el-table-column label="加价金额/元" min-width="140">
<template #default="{ row }"><el-input-number v-model="row.markup_amount" :min="0" :step="1" /></template>
</el-table-column>
<el-table-column label="操作" width="90">
<template #default="{ $index }">
<el-button size="small" type="danger" plain @click="removeSaleFixedMarkupRule($index)">删除</el-button>
</template>
</el-table-column>
</el-table>
<div class="editor-block-title subtle-title">
<span>90M 以上比例调整出售比例 = 回收比例 - 比例扣减最大 M 0 表示无上限</span>
<el-button size="small" @click="addSaleRatioAdjustmentRule">添加比例调整</el-button>
</div>
<el-table :data="publishOptionsDraft.sale_price_config.ratio_adjustment_rules" size="small" border>
<el-table-column label="最小 M" min-width="120">
<template #default="{ row }"><el-input-number v-model="row.min_m" :min="0" :step="10" /></template>
</el-table-column>
<el-table-column label="最大 M" min-width="120">
<template #default="{ row }"><el-input-number v-model="row.max_m" :min="0" :step="10" /></template>
</el-table-column>
<el-table-column label="比例扣减" min-width="130">
<template #default="{ row }"><el-input-number v-model="row.ratio_subtract" :min="0" :step="0.5" /></template>
</el-table-column>
<el-table-column label="操作" width="90">
<template #default="{ $index }">
<el-button size="small" type="danger" plain @click="removeSaleRatioAdjustmentRule($index)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="editor-block">
<div class="editor-block-title">
<strong>皮肤分类</strong>
@@ -498,6 +498,12 @@
font-weight: 800;
}
.muted-result-field :deep(.van-field__control) {
color: #5c6470;
font-size: 12px;
font-weight: 700;
}
.total-price-field :deep(.van-field__control) {
font-size: 16px;
}
@@ -117,6 +117,7 @@ const fireLevelPlaceholder = computed(
() => `等级低于${fireLevelMin.value}级的号无法发布`
);
const ratioConfig = computed(() => publishOptions.value.ratio_config);
const salePriceConfig = computed(() => publishOptions.value.sale_price_config);
const skinGroups = computed(() => publishOptions.value.skin_groups);
const quantityItems = computed(() => publishOptions.value.quantity_items);
const screenshotSlots = computed(() => publishOptions.value.screenshot_slots);
@@ -127,10 +128,11 @@ const screenshotUrls = computed(() =>
);
const coinMAmount = computed(() => Number(form.haf_coin_amount || 0));
const coinWanAmount = computed(() => coinMAmount.value * 100);
const calculatedRatio = computed(() => calculatePublishRatio());
const calculatedCoinBasePrice = computed(() =>
calculatedRatio.value > 0 ? roundMoney(coinWanAmount.value / calculatedRatio.value) : 0
);
const calculatedRecycleRatio = computed(() => calculatePublishRatio());
const calculatedSalePricing = computed(() => calculateSalePricing());
const calculatedRatio = computed(() => calculatedSalePricing.value.saleRatio);
const calculatedCoinBasePrice = computed(() => calculatedSalePricing.value.coinBasePrice);
const calculatedSaleRuleText = computed(() => calculatedSalePricing.value.ruleText);
const calculatedConsumablePrice = computed(() => calculateConsumablePrice());
const calculatedFinalPrice = computed(() =>
calculatedRatio.value > 0
@@ -443,10 +445,14 @@ function buildAssetSummary() {
fire_level: Number(form.fire_level),
publish_ratio: calculatedRatio.value,
price_breakdown: {
recycle_coin_base_price: calculatedSalePricing.value.recycleCoinBasePrice,
coin_base_price: calculatedCoinBasePrice.value,
consumable_price: calculatedConsumablePrice.value,
final_price: calculatedFinalPrice.value,
ratio: calculatedRatio.value,
recycle_ratio: calculatedRecycleRatio.value,
sale_ratio: calculatedRatio.value,
sale_rule_type: calculatedSalePricing.value.ruleType,
sale_rule_text: calculatedSalePricing.value.ruleText,
},
season_insurance: form.season_insurance,
stamina_level: form.stamina_level,
@@ -515,6 +521,79 @@ function calculatePublishRatio() {
return baseRatio + calculateConfigPenalty() + getCoinCorrection(coinMAmount.value);
}
function calculateSalePricing() {
const recycleRatio = calculatedRecycleRatio.value;
if (recycleRatio <= 0 || coinWanAmount.value <= 0) {
return emptySalePricing();
}
const recycleCoinBasePrice = roundMoney(coinWanAmount.value / recycleRatio);
const fixedRule = findSaleFixedMarkupRule();
if (fixedRule) {
const coinBasePrice = roundMoney(recycleCoinBasePrice + Number(fixedRule.markup_amount || 0));
return {
recycleCoinBasePrice,
coinBasePrice,
saleRatio: calculateEffectiveRatio(coinBasePrice),
ruleType: "fixed_markup",
ruleText: `${formatSaleRange(fixedRule)} 加价 ${formatNumber(fixedRule.markup_amount)}`,
};
}
const ratioRule = findSaleRatioAdjustmentRule();
const ratioSubtract = ratioRule ? Number(ratioRule.ratio_subtract || 0) : 0;
const saleRatio = recycleRatio - ratioSubtract;
if (saleRatio <= 0) {
return emptySalePricing(recycleCoinBasePrice);
}
return {
recycleCoinBasePrice,
coinBasePrice: roundMoney(coinWanAmount.value / saleRatio),
saleRatio,
ruleType: ratioRule ? "ratio_subtract" : "none",
ruleText: ratioRule
? `${formatSaleRange(ratioRule)} 出售比例=回收比例-${formatNumber(ratioSubtract)}`
: "未匹配出售加价规则,按回收比例计算",
};
}
function emptySalePricing(recycleCoinBasePrice = 0) {
return {
recycleCoinBasePrice,
coinBasePrice: 0,
saleRatio: 0,
ruleType: "none",
ruleText: "",
};
}
function findSaleFixedMarkupRule() {
return [...salePriceConfig.value.fixed_markup_rules]
.sort((a, b) => a.min_m - b.min_m)
.find((item) => isCoinInSaleRange(item));
}
function findSaleRatioAdjustmentRule() {
return [...salePriceConfig.value.ratio_adjustment_rules]
.sort((a, b) => a.min_m - b.min_m)
.find((item) => isCoinInSaleRange(item));
}
function isCoinInSaleRange(item: { min_m: number; max_m: number }) {
const maxM = Number(item.max_m || 0);
return coinMAmount.value >= Number(item.min_m || 0) && (maxM <= 0 || coinMAmount.value <= maxM);
}
function calculateEffectiveRatio(price: number) {
if (price <= 0) return 0;
return Math.round((coinWanAmount.value / price) * 10) / 10;
}
function formatSaleRange(item: { min_m: number; max_m: number }) {
const minM = formatNumber(Number(item.min_m || 0));
const maxM = Number(item.max_m || 0);
return maxM > 0 ? `${minM}M-${formatNumber(maxM)}M` : `${minM}M以上`;
}
function getInsuranceBaseRatio(insurance: string) {
return ratioConfig.value.insurance_base_ratios.find(
(item) => item.insurance === insurance
@@ -921,15 +1000,21 @@ function readError(error: unknown, fallback: string) {
<div class="result-grid">
<van-field
:model-value="calculatedRatioText"
label="比例"
label="出售比例"
readonly
:placeholder="priceConfig.ratio_description"
class="publish-field result-field"
>
<template #label>
<span class="hint-label" :data-hint="priceConfig.ratio_description" tabindex="0">比例</span>
<span class="hint-label" :data-hint="priceConfig.ratio_description" tabindex="0">出售比例</span>
</template>
</van-field>
<van-field
:model-value="calculatedSaleRuleText"
label="出售规则"
readonly
class="publish-field result-field muted-result-field"
/>
<van-field
:model-value="calculatedCoinBasePrice ? `¥${calculatedCoinBasePrice}` : ''"
label="纯币基础价"
@@ -958,7 +1043,7 @@ function readError(error: unknown, fallback: string) {
/>
</div>
<p class="price-breakdown-hint">
发布总价 = 纯币基础价 + 额外消耗品只有标记为收费的消耗品会计入价格
纯币基础价先按回收比例计算再套出售加价规则发布总价 = 纯币基础价 + 额外消耗品
</p>
<van-field