优化套餐编辑逻辑

This commit is contained in:
wuweihua
2026-10-21 14:51:44 +08:00
parent 26a3285571
commit 1e8a449dda
11 changed files with 217 additions and 111 deletions
@@ -1,6 +1,6 @@
<template>
<el-card shadow="never" class="step-card">
<template #header><span>第 1 步 · 基本信息</span></template>
<template #header><span>基本信息</span></template>
<el-form ref="formRef" :model="basic" :rules="rules" label-width="120px" class="max-form">
<el-form-item label="套餐名称" prop="priceSetName">
<el-input v-model="basic.priceSetName" maxlength="50" placeholder="如:金牌电商专属套餐" />
@@ -15,7 +15,7 @@
</template>
<script setup name="StepBasicInfo">
/** Step1 basic info. setType always FIXED on save; priceBuildMode chosen on Step2. */
/** Basic info. setType always FIXED on save; priceBuildMode chosen in details panel. */
const basic = defineModel({ type: Object, required: true })
const formRef = ref()
@@ -223,7 +223,7 @@ const props = defineProps({
effectiveTime: { type: String, default: undefined },
versionNo: { type: String, default: '' },
refData: { type: Object, required: true },
headerTitle: { type: String, default: '第 2 步 · 编辑产品价格' },
headerTitle: { type: String, default: '编辑产品价格' },
/** true=edit live DB; false=create local draft until finish */
livePersist: { type: Boolean, default: true },
/** Version status: draft can change build mode; started versions lock it */
@@ -15,7 +15,7 @@
</div>
<el-alert type="info" :closable="false" show-icon class="mb12" :title="hint" />
<el-empty v-if="!filteredProducts.length" :description="emptyProduct" :image-size="72" />
<el-table v-else :data="filteredProducts" border height="calc(100vh - 280px)" @row-click="openProductDetail">
<el-table v-else :data="filteredProducts" border height="calc(100vh - 280px)">
<el-table-column :label="colCode" min-width="100">
<template #default="{ row }"><b>{{ row.productCode }}</b></template>
</el-table-column>
@@ -151,7 +151,7 @@ const activeProduct = ref(null)
const phSearch = '产品代码/名称'
const phDetailSearch = '搜索国家/分区'
const hint = '点击产品行查看国家/重量段明细(仅查看)'
const hint = '点击「查看明细」查看国家/重量段明细(仅查看)'
const emptyProduct = '暂无产品'
const emptyDetail = '暂无明细'
const colCode = '产品代码'
+35 -73
View File
@@ -1,46 +1,34 @@
<template>
<div class="app-container">
<el-steps
v-if="!newVersionMode"
:active="active"
finish-status="success"
align-center
class="wizard-steps"
>
<el-step :title="step1Title" />
<el-step :title="step2Title" />
</el-steps>
<div v-show="active === 0">
<div v-if="showBasic" class="create-section">
<step-basic-info ref="basicRef" v-model="form.basic" />
</div>
<step-details
v-show="active === 1"
ref="detailsRef"
:details="form.details"
:products="form.products"
:price-set-id="form.priceSetId"
:psv-id="form.version.psvId"
@update:psv-id="onPsvIdUpdate"
:set-type="form.basic.setType"
:price-build-mode="form.version.priceBuildMode"
@update:price-build-mode="onPriceBuildModeUpdate"
@update:pef-id="onPefIdUpdate"
:version-no="form.version.versionNo"
:version-status="form.version.status"
:ref-data="refData"
:live-persist="livePersist"
:build-mode-dirty="buildModeDirty"
:header-title="detailsHeaderTitle"
/>
<div class="create-section">
<step-details
ref="detailsRef"
:details="form.details"
:products="form.products"
:price-set-id="form.priceSetId"
:psv-id="form.version.psvId"
@update:psv-id="onPsvIdUpdate"
:set-type="form.basic.setType"
:price-build-mode="form.version.priceBuildMode"
@update:price-build-mode="onPriceBuildModeUpdate"
@update:pef-id="onPefIdUpdate"
:version-no="form.version.versionNo"
:version-status="form.version.status"
:ref-data="refData"
:live-persist="livePersist"
:build-mode-dirty="buildModeDirty"
:header-title="detailsHeaderTitle"
/>
</div>
<div class="wizard-actions">
<el-button @click="goBack">取消</el-button>
<el-button v-if="active > 0 && !directStep2" @click="active--">上一步</el-button>
<el-button v-if="active === 0" type="primary" :loading="creating" @click="goStep2">创建套餐价格</el-button>
<el-button v-if="active === 0" type="info" :loading="saving" @click="saveDraft">保存</el-button>
<el-button v-if="active === 1" type="primary" :loading="creating" @click="finishEdit">完成</el-button>
<el-button v-if="showBasic" type="info" :loading="saving" @click="saveDraft">保存</el-button>
<el-button type="primary" :loading="creating" @click="finishEdit">完成</el-button>
</div>
<el-dialog
@@ -79,7 +67,6 @@ const route = useRoute()
const refData = usePriceSetRefData()
const active = ref(0)
const saving = ref(false)
const creating = ref(false)
const progressVisible = ref(false)
@@ -90,18 +77,14 @@ const basicRef = ref()
const detailsRef = ref()
const copyMode = computed(() => String(route.query.copyVersion || '') === '1')
const newVersionMode = computed(() => String(route.query.newVersion || '') === '1')
/** copy / newVersion: defer DB write until finish (same as create step2) */
/** copy / newVersion: defer DB write until finish */
const deferPersist = computed(() => copyMode.value || newVersionMode.value)
/** Entered from detail: continue-config / copy-version / new-version jump to step2 */
const directStep2 = computed(() => deferPersist.value || String(route.query.step || '') === '2')
/** Continue-config / copy / new-version: hide basic (package already exists) */
const showBasic = computed(() => !deferPersist.value && String(route.query.step || '') !== '2')
/** Edit existing version: live PUT/pull/import. New create / copy / newVersion: defer until finish. */
const livePersist = computed(() => !!form.priceSetId && !deferPersist.value)
const step1Title = '基本信息'
const step2Title = '编辑产品价格'
const detailsHeaderTitle = computed(() =>
newVersionMode.value ? '编辑产品价格' : '第 2 步 · 编辑产品价格'
)
const detailsHeaderTitle = '编辑产品价格'
const form = reactive({
priceSetId: undefined,
@@ -172,18 +155,7 @@ async function runSaveWithProgress(payload) {
}
}
/** Step1 -> Step2: validate only; no DB write on create (defer until finish). */
async function goStep2() {
const validBasic = await basicRef.value.validate()
if (!validBasic) return
if (!(form.products || []).some(p => p && p.productCode) && !form.version.priceBuildMode) {
form.details = []
form.products = []
}
active.value = 1
}
/** Step2 finish: create/copy async save all; edit already live-saved. */
/** Finish: create/copy async save all; edit already live-saved. */
async function finishEdit() {
if (livePersist.value) {
if (!form.priceSetId) {
@@ -235,10 +207,9 @@ async function finishEdit() {
}
return
}
const validBasic = await basicRef.value.validate()
if (!validBasic) {
active.value = 0
return
if (showBasic.value) {
const validBasic = await basicRef.value.validate()
if (!validBasic) return
}
if (!form.version.priceBuildMode) {
proxy.$modal.msgWarning('请先选择创建价格方式')
@@ -277,13 +248,10 @@ async function finishEdit() {
}
}
/** Step0 only: persist basic draft (no detail wipe). */
/** Persist basic draft (no detail wipe). */
async function saveDraft() {
const validBasic = await basicRef.value.validate()
if (!validBasic) {
active.value = 0
return
}
if (!validBasic) return
saving.value = true
try {
const priceSetId = await runSaveWithProgress(buildPayload())
@@ -532,9 +500,6 @@ function applySetData(data, asCopy, asNewVersion) {
function loadExisting(id, asCopy, asNewVersion) {
getPriceSet(id).then(res => {
applySetData(res.data || {}, asCopy, asNewVersion)
if (asCopy || asNewVersion || String(route.query.step || '') === '2') {
active.value = 1
}
})
}
@@ -549,11 +514,8 @@ onMounted(() => {
</script>
<style scoped>
.wizard-steps {
margin-bottom: 20px;
background: #fff;
padding: 20px 12px 12px;
border-radius: 6px;
.create-section {
margin-bottom: 16px;
}
.wizard-actions {
text-align: center;