内部加价分离, 不展示

This commit is contained in:
yml2213
2026-05-23 21:07:40 +08:00
parent 9f15609afd
commit 78257097f1
11 changed files with 347 additions and 117 deletions
@@ -3,9 +3,12 @@ import { ElMessage } from 'element-plus'
import { computed, onMounted, ref } from 'vue'
import {
emptyListingSalePriceConfig,
emptyListingPublishOptions,
mergeListingSalePriceConfig,
mergeListingPublishOptions,
type ListingPublishOptions,
type PublishSalePriceConfig,
} from '@/api/listingOptions'
import {
defaultHomeAnnouncements,
@@ -24,22 +27,26 @@ const activeConfig = ref<SystemConfig | null>(null)
const value = ref('')
const description = ref('')
const publishOptionsDraft = ref<ListingPublishOptions>(cloneOptions(emptyListingPublishOptions))
const salePriceConfigDraft = ref<PublishSalePriceConfig>(cloneSalePriceConfig(emptyListingSalePriceConfig))
const homeAnnouncementLines = ref(itemsToLines(defaultHomeAnnouncements))
const homeBannersDraft = ref<HomeBannerSlide[]>(cloneHomeBanners(defaultHomeBanners))
const uploadingBannerIndex = ref<number | null>(null)
const publishConfig = computed(() => configs.value.find((item) => item.key === 'listing.publish_options') || null)
const salePriceConfig = computed(() => configs.value.find((item) => item.key === 'listing.sale_price_config') || null)
const homeAnnouncementsConfig = computed(() => configs.value.find((item) => item.key === 'mobile.home_announcements') || null)
const homeBannersConfig = computed(() => configs.value.find((item) => item.key === 'mobile.home_banners') || null)
const regularConfigs = computed(() =>
configs.value.filter(
(item) =>
item.key !== 'listing.publish_options' &&
item.key !== 'listing.sale_price_config' &&
item.key !== 'mobile.home_announcements' &&
item.key !== 'mobile.home_banners',
),
)
const isPublishOptionsConfig = computed(() => activeConfig.value?.key === 'listing.publish_options')
const isSalePriceConfig = computed(() => activeConfig.value?.key === 'listing.sale_price_config')
const isHomeAnnouncementsConfig = computed(() => activeConfig.value?.key === 'mobile.home_announcements')
const isHomeBannersConfig = computed(() => activeConfig.value?.key === 'mobile.home_banners')
const publishStats = computed(() => {
@@ -54,9 +61,13 @@ 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 salePriceStats = computed(() => {
const config = safeParseSalePriceConfig(salePriceConfig.value?.value || '')
return {
fixedCount: config.fixed_markup_rules.length,
ratioCount: config.ratio_adjustment_rules.length,
}
})
const homeStats = computed(() => {
@@ -72,6 +83,7 @@ const isStructuredConfig = computed(() => {
const trimmed = value.value.trim()
return (
isPublishOptionsConfig.value ||
isSalePriceConfig.value ||
isHomeAnnouncementsConfig.value ||
isHomeBannersConfig.value ||
trimmed.startsWith('{') ||
@@ -80,7 +92,7 @@ const isStructuredConfig = computed(() => {
})
const dialogWidth = computed(() => {
if (isPublishOptionsConfig.value || isHomeBannersConfig.value) return '920px'
if (isPublishOptionsConfig.value || isSalePriceConfig.value || isHomeBannersConfig.value) return '920px'
if (isHomeAnnouncementsConfig.value) return '680px'
return '560px'
})
@@ -103,6 +115,9 @@ function openEdit(row: SystemConfig) {
if (row.key === 'listing.publish_options') {
publishOptionsDraft.value = parsePublishOptions(row.value)
}
if (row.key === 'listing.sale_price_config') {
salePriceConfigDraft.value = parseSalePriceConfig(row.value)
}
if (row.key === 'mobile.home_announcements') {
homeAnnouncementLines.value = itemsToLines(parseHomeAnnouncements(row.value, true))
}
@@ -118,6 +133,9 @@ async function handleSave() {
if (isPublishOptionsConfig.value) {
value.value = JSON.stringify(publishOptionsDraft.value, null, 2)
}
if (isSalePriceConfig.value) {
value.value = JSON.stringify(salePriceConfigDraft.value, null, 2)
}
if (isHomeAnnouncementsConfig.value) {
value.value = JSON.stringify(linesToItems(homeAnnouncementLines.value), null, 2)
}
@@ -161,6 +179,25 @@ function safeParsePublishOptions(raw: string) {
}
}
function parseSalePriceConfig(raw: string) {
try {
const parsed = raw.trim() ? JSON.parse(raw) : emptyListingSalePriceConfig
return cloneSalePriceConfig(mergeListingSalePriceConfig(parsed))
} catch {
ElMessage.warning('出售定价规则 JSON 解析失败,已清空草稿')
return cloneSalePriceConfig(emptyListingSalePriceConfig)
}
}
function safeParseSalePriceConfig(raw: string) {
try {
const parsed = raw.trim() ? JSON.parse(raw) : emptyListingSalePriceConfig
return cloneSalePriceConfig(mergeListingSalePriceConfig(parsed))
} catch {
return cloneSalePriceConfig(emptyListingSalePriceConfig)
}
}
function parseHomeAnnouncements(raw: string, showWarning = false) {
try {
const parsed = raw.trim() ? JSON.parse(raw) : defaultHomeAnnouncements
@@ -185,6 +222,10 @@ function cloneOptions(options: ListingPublishOptions) {
return JSON.parse(JSON.stringify(options)) as ListingPublishOptions
}
function cloneSalePriceConfig(config: PublishSalePriceConfig) {
return JSON.parse(JSON.stringify(config)) as PublishSalePriceConfig
}
function cloneHomeBanners(banners: HomeBannerSlide[]) {
return JSON.parse(JSON.stringify(banners)) as HomeBannerSlide[]
}
@@ -285,7 +326,7 @@ function removeCoinCorrection(index: number) {
}
function addSaleFixedMarkupRule() {
publishOptionsDraft.value.sale_price_config.fixed_markup_rules.push({
salePriceConfigDraft.value.fixed_markup_rules.push({
min_m: 0,
max_m: 0,
markup_amount: 0,
@@ -293,11 +334,11 @@ function addSaleFixedMarkupRule() {
}
function removeSaleFixedMarkupRule(index: number) {
publishOptionsDraft.value.sale_price_config.fixed_markup_rules.splice(index, 1)
salePriceConfigDraft.value.fixed_markup_rules.splice(index, 1)
}
function addSaleRatioAdjustmentRule() {
publishOptionsDraft.value.sale_price_config.ratio_adjustment_rules.push({
salePriceConfigDraft.value.ratio_adjustment_rules.push({
min_m: 0,
max_m: 0,
ratio_subtract: 0,
@@ -305,7 +346,7 @@ function addSaleRatioAdjustmentRule() {
}
function removeSaleRatioAdjustmentRule(index: number) {
publishOptionsDraft.value.sale_price_config.ratio_adjustment_rules.splice(index, 1)
salePriceConfigDraft.value.ratio_adjustment_rules.splice(index, 1)
}
function addHomeBanner() {
@@ -414,9 +455,38 @@ function readError(error: unknown, fallback: string) {
<strong>{{ publishStats.regionCount }}</strong>
<span>地区</span>
</div>
</div>
</section>
<section v-if="salePriceConfig" class="publish-config-panel">
<div class="publish-config-main">
<div>
<p class="eyebrow">Sale Pricing</p>
<h2>内部出售定价规则</h2>
<span>管理出售加价和比例扣减规则仅用于平台内部定价计算不在发布页展示</span>
</div>
<el-button type="primary" @click="openEdit(salePriceConfig)">编辑出售规则</el-button>
</div>
<div class="publish-stat-grid home-stat-grid">
<div class="publish-stat">
<strong>{{ publishStats.saleRuleCount }}</strong>
<span>出售规则</span>
<strong>{{ salePriceStats.fixedCount }}</strong>
<span>固定加价</span>
</div>
<div class="publish-stat">
<strong>{{ salePriceStats.ratioCount }}</strong>
<span>比例扣减</span>
</div>
<div class="publish-stat">
<strong>内部</strong>
<span>不展示给发布用户</span>
</div>
<div class="publish-stat">
<strong>配置</strong>
<span>listing.sale_price_config</span>
</div>
<div class="publish-stat">
<strong>更新</strong>
<span>{{ formatHomeConfigStatus(salePriceConfig, '未初始化') }}</span>
</div>
</div>
</section>
@@ -673,53 +743,6 @@ 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>
@@ -792,6 +815,56 @@ function readError(error: unknown, fallback: string) {
</div>
</div>
<div v-else-if="isSalePriceConfig" class="publish-options-editor">
<div class="editor-toolbar">
<span>内部出售定价规则</span>
</div>
<div class="editor-block">
<div class="editor-block-title subtle-title">
<span>90M 及以下固定加价出售价格 = 回收价格 + 固定加价</span>
<el-button size="small" @click="addSaleFixedMarkupRule">添加固定加价</el-button>
</div>
<el-table :data="salePriceConfigDraft.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="salePriceConfigDraft.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>
<div v-else-if="isHomeAnnouncementsConfig" class="home-config-editor">
<div class="editor-toolbar">
<span>首页公告</span>