智能押金与33优化

This commit is contained in:
yml
2026-05-24 23:19:37 +08:00
parent fd73bb39be
commit 95ded72b66
8 changed files with 350 additions and 13 deletions
@@ -101,6 +101,7 @@ const skinGroups = computed(() => publishOptions.value.skin_groups)
const quantityItems = computed(() => publishOptions.value.quantity_items)
const screenshotSlots = computed(() => publishOptions.value.screenshot_slots)
const priceConfig = computed(() => publishOptions.value.price_config)
const depositRecommendConfig = computed(() => publishOptions.value.deposit_recommend_config)
const fireLevelMin = computed(() => publishOptions.value.fire_level_min || 38)
const fireLevelPlaceholder = computed(() => `等级低于${fireLevelMin.value}级的号无法发布`)
const screenshotUrls = computed(() =>
@@ -143,6 +144,7 @@ const acceleratedSaleRatioPlaceholder = computed(() => {
const selectedSkinCount = computed(() => selectedSkins.value.length)
const uploadedScreenshotCount = computed(() => screenshotUrls.value.length)
const requiredScreenshotCount = computed(() => screenshotSlots.value.filter((item) => isScreenshotRequired(item)).length)
const recommendedDepositAmount = computed(() => calculateRecommendedDeposit())
const publishTitle = computed(() => {
const parts = [form.server_region, form.rank_level, coinMAmount.value ? `${coinMAmount.value}M哈夫币` : ''].filter(Boolean)
return parts.length ? parts.join(' ') : '待完善账号信息'
@@ -165,6 +167,18 @@ watch(
{ deep: true },
)
watch(recommendedDepositAmount, () => {
syncRecommendedDeposit()
}, { immediate: true })
watch(
[() => form.season_insurance, quantityItems],
() => {
clearForbiddenQuantityItems()
},
{ deep: true },
)
async function loadPublishOptions() {
try {
const [nextPublishOptions, nextSalePriceConfig] = await Promise.all([
@@ -354,6 +368,53 @@ function handleAcceleratedSaleRatioInput(value: string | number | undefined) {
form.accelerated_sale_ratio = Number.isFinite(ratio) ? ratio : ''
}
function syncRecommendedDeposit() {
const recommended = recommendedDepositAmount.value
if (recommended <= 0) return
const current = Number(form.deposit_amount)
if (form.deposit_amount === '' || !Number.isFinite(current) || current < recommended) {
form.deposit_amount = recommended
}
}
function calculateRecommendedDeposit() {
const baseAmount = Number(depositRecommendConfig.value.base_amount || 0)
const skinAmount = depositRecommendConfig.value.skin_group_rules.reduce((sum, rule) => {
const group = skinGroups.value.find((item) => item.key === rule.group_key)
if (!group) return sum
const selectedCount = group.options.filter((skin) => selectedSkins.value.includes(skin)).length
return sum + selectedCount * Number(rule.amount_per_item || 0)
}, 0)
return roundMoney(baseAmount + skinAmount)
}
function useRecommendedDeposit() {
if (recommendedDepositAmount.value > 0) {
form.deposit_amount = recommendedDepositAmount.value
}
}
function isGridCardQuantityItem(item: { key: string; label: string }) {
return item.key === 'gridCard9' || item.label.includes('9格体验卡')
}
function isQuantityItemDisabled(item: { key: string; label: string }) {
return form.season_insurance === '3*3' && isGridCardQuantityItem(item)
}
function clearForbiddenQuantityItems() {
for (const item of quantityItems.value) {
if (!isQuantityItemDisabled(item)) continue
quantityValues[item.key] = 0
quantityModes[item.key] = '赠送'
}
}
function setQuantityMode(item: { key: string; label: string }, mode: ChargeMode) {
if (isQuantityItemDisabled(item)) return
quantityModes[item.key] = mode
}
function clampAcceleratedSaleRatioInput() {
if (!hasAcceleratedSaleRatioInput() || calculatedDefaultSaleRatio.value <= 0) return
const ratio = Number(form.accelerated_sale_ratio)
@@ -432,6 +493,9 @@ function validateForm() {
if (banRecordOptions.value.length && !form.ban_record) return '请选择封禁记录'
if (form.deposit_amount === '' || Number(form.deposit_amount) < 0) return '请填写押金'
if (!Number.isFinite(Number(form.deposit_amount))) return '押金格式不正确'
if (recommendedDepositAmount.value > 0 && Number(form.deposit_amount) < recommendedDepositAmount.value) {
return `押金不能低于智能推荐 ¥${recommendedDepositAmount.value}`
}
if (calculatedConsumablePrice.value > 0 && Number(form.deposit_amount) <= calculatedConsumablePrice.value) {
return `押金必须大于额外消耗品总价值 ¥${calculatedConsumablePrice.value}`
}
@@ -440,6 +504,11 @@ function validateForm() {
for (const item of screenshotSlots.value) {
if (isScreenshotRequired(item) && !screenshotFiles[item.key]) return `请上传${item.label}`
}
for (const item of quantityItems.value) {
if (isQuantityItemDisabled(item) && Number(quantityValues[item.key] || 0) > 0) {
return '赛季保险选择 3*3 时不能填写 9格体验卡'
}
}
return ''
}
@@ -481,8 +550,8 @@ function buildAssetSummary() {
key: item.key,
label: item.label,
price: item.price,
quantity: Number(quantityValues[item.key] || 0),
mode: quantityModes[item.key] || '收费',
quantity: isQuantityItemDisabled(item) ? 0 : Number(quantityValues[item.key] || 0),
mode: isQuantityItemDisabled(item) ? '赠送' : quantityModes[item.key] || '收费',
})),
skin_groups: skinGroups.value.reduce<Record<string, string[]>>((groups, group) => {
groups[group.key] = group.options.filter((skin) => selectedSkins.value.includes(skin))
@@ -506,6 +575,7 @@ function calculateConsumablePrice() {
const total = quantityItems.value.reduce((sum, item) => {
const quantity = Number(quantityValues[item.key] || 0)
const mode = quantityModes[item.key] || '收费'
if (isQuantityItemDisabled(item)) return sum
if (quantity <= 0 || mode !== '收费') return sum
return sum + quantity * readUnitPrice(item.price)
}, 0)
@@ -808,24 +878,36 @@ function readError(error: unknown, fallback: string) {
<span>收费项会计入每日价格</span>
</div>
<div class="quantity-grid">
<div v-for="item in quantityItems" :key="item.key" class="quantity-item">
<div
v-for="item in quantityItems"
:key="item.key"
class="quantity-item"
:class="{ disabled: isQuantityItemDisabled(item) }"
>
<div class="quantity-meta">
<strong :title="item.placeholder || item.label">{{ item.label }}</strong>
<small>{{ item.price }}</small>
<small>{{ isQuantityItemDisabled(item) ? '3*3 已包含,不能填写' : item.price }}</small>
</div>
<el-input-number v-model="quantityValues[item.key]" :min="0" :controls="false" />
<el-input-number
v-model="quantityValues[item.key]"
:min="0"
:controls="false"
:disabled="isQuantityItemDisabled(item)"
/>
<div class="mode-toggle">
<button
type="button"
:class="{ active: quantityModes[item.key] === '赠送' }"
@click="quantityModes[item.key] = '赠送'"
:disabled="isQuantityItemDisabled(item)"
@click="setQuantityMode(item, '赠送')"
>
赠送
</button>
<button
type="button"
:class="{ active: (quantityModes[item.key] || '收费') === '收费' }"
@click="quantityModes[item.key] = '收费'"
:disabled="isQuantityItemDisabled(item)"
@click="setQuantityMode(item, '收费')"
>
收费
</button>
@@ -973,6 +1055,9 @@ function readError(error: unknown, fallback: string) {
:controls="false"
:placeholder="priceConfig.deposit_placeholder"
/>
<button class="recommend-button" type="button" @click="useRecommendedDeposit">
推荐押金 ¥{{ recommendedDepositAmount }}
</button>
</label>
<label class="input-block">
<span>每日损耗<b>*</b></span>
@@ -1078,6 +1163,10 @@ function readError(error: unknown, fallback: string) {
<span>押金</span>
<strong>{{ form.deposit_amount === '' ? '--' : `¥${form.deposit_amount}` }}</strong>
</div>
<div>
<span>推荐押金</span>
<strong>¥{{ recommendedDepositAmount }}</strong>
</div>
<div>
<span>截图材料</span>
<strong>{{ uploadedScreenshotCount }}/{{ requiredScreenshotCount }}</strong>
@@ -1321,6 +1410,10 @@ function readError(error: unknown, fallback: string) {
font-weight: 700;
}
.quantity-item.disabled {
opacity: 0.62;
}
.quantity-item :deep(.el-input-number) {
width: 100%;
min-width: 0;
@@ -1341,12 +1434,29 @@ function readError(error: unknown, fallback: string) {
white-space: nowrap;
}
.mode-toggle button:disabled {
cursor: not-allowed;
}
.mode-toggle button.active {
border-color: #ff6a00;
background: #fff3ea;
color: #e65f00;
}
.recommend-button {
justify-self: start;
height: 28px;
padding: 0 10px;
border: 1px solid #ffba86;
border-radius: 14px;
background: #fff7f0;
color: #e65f00;
font-size: 12px;
font-weight: 800;
cursor: pointer;
}
.skin-groups {
display: grid;
gap: 12px;