提交价格套餐功能

This commit is contained in:
wuweihua
2026-09-04 14:56:05 +08:00
parent f8b9681583
commit 5e15ab9c44
47 changed files with 6243 additions and 9 deletions
@@ -0,0 +1,542 @@
<template>
<div class="app-container">
<!-- 重量段模板 -->
<basic-table
ref="templateTableRef"
:columns="templateColumns"
:search-columns="templateSearchColumns"
:query="queryTemplateList"
row-key="wstId"
@row-click="handleTemplateRowClick"
>
<template #toolbar="{ selection, ids }">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="Plus"
@click="handleTemplateAdd"
v-hasPermi="['price:weight:add']"
>新建模板</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="Edit"
:disabled="selection.length !== 1"
@click="handleTemplateUpdate(selection[0])"
v-hasPermi="['price:weight:edit']"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
:disabled="!selection.length"
@click="handleTemplateDelete(ids)"
v-hasPermi="['price:weight:remove']"
>删除</el-button>
</el-col>
</template>
<template #col-ssCode="{ row }">
<el-tag :type="row.ssCode === 'on' || row.ssCode === 'ON' ? 'success' : 'warning'" size="small">
{{ (row.ssCode || '').toLowerCase() === 'on' ? 'on' : 'of' }}
</el-tag>
</template>
<template #col-action="{ row }">
<el-button link type="primary" icon="List" @click.stop="handleShowDetail(row)" v-hasPermi="['price:weight:query']">明细</el-button>
<el-button link type="primary" icon="Edit" @click.stop="handleTemplateUpdate(row)" v-hasPermi="['price:weight:edit']">编辑</el-button>
<el-button link type="primary" icon="Delete" @click.stop="handleTemplateDelete(row.wstId)" v-hasPermi="['price:weight:remove']">删除</el-button>
</template>
</basic-table>
<!-- 明细 + 可视化标尺 -->
<el-card shadow="never" class="detail-card" v-loading="detailLoading">
<template #header>
<div class="card-header">
<span>
重量段明细
<span v-if="selectedTemplate" class="sub-hint">
当前模板:{{ selectedTemplate.wstName }}(wstId={{ selectedTemplate.wstId }},共 {{ detailList.length }} 段)
</span>
<span v-else class="sub-hint">请点击上方模板行或「明细」查看重量段</span>
</span>
<el-button
type="primary"
plain
icon="Plus"
size="small"
:disabled="!selectedTemplate"
@click="handleDetailAdd"
v-hasPermi="['price:weight:add']"
>新增明细</el-button>
</div>
</template>
<div v-if="selectedTemplate && detailList.length" class="ruler-block">
<div class="section-title">重量段可视化标尺</div>
<div class="weight-ruler">
<el-tag
v-for="item in detailList"
:key="item.wsdId"
class="weight-chip"
effect="plain"
type="primary"
round
>
{{ formatEndWeight(item) }}
<span class="chip-range">{{ item.wlStartweight }}~{{ item.wlEndweight }}</span>
</el-tag>
</div>
</div>
<el-table
:data="detailList"
border
row-key="wsdId"
empty-text="暂无明细数据"
>
<el-table-column label="wsdId" prop="wsdId" align="center" width="80" />
<el-table-column label="标题" prop="wlTitle" align="center" min-width="110" show-overflow-tooltip />
<el-table-column label="起始重量" prop="wlStartweight" align="center" width="110" />
<el-table-column label="截止重量" prop="wlEndweight" align="center" width="110" />
<el-table-column label="计费类别" prop="weightBillingCode" align="center" width="110" />
<el-table-column label="计费单位" prop="fvUnitweight" align="center" width="110" />
<el-table-column label="生效日期" prop="effectiveDate" align="center" width="120">
<template #default="{ row }">{{ parseDate(row.effectiveDate) }}</template>
</el-table-column>
<el-table-column label="失效日期" prop="expireDate" align="center" width="120">
<template #default="{ row }">{{ parseDate(row.expireDate) || '-' }}</template>
</el-table-column>
<el-table-column label="操作" align="center" width="160" fixed="right">
<template #default="{ row }">
<el-button link type="primary" icon="Edit" @click="handleDetailUpdate(row)" v-hasPermi="['price:weight:edit']">编辑</el-button>
<el-button link type="primary" icon="Delete" @click="handleDetailDelete(row.wsdId)" v-hasPermi="['price:weight:remove']">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
<!-- 模板表单 -->
<el-dialog :title="templateTitle" v-model="templateOpen" width="600px" append-to-body>
<el-form ref="templateFormRef" :model="templateForm" :rules="templateRules" label-width="100px">
<el-form-item label="模板名称" prop="wstName">
<el-input v-model="templateForm.wstName" placeholder="请输入模板名称" maxlength="60" />
</el-form-item>
<el-form-item label="状态" prop="ssCode">
<el-radio-group v-model="templateForm.ssCode">
<el-radio value="on">有效(on)</el-radio>
<el-radio value="of">停用(of)</el-radio>
</el-radio-group>
</el-form-item>
<el-row>
<el-col :span="12">
<el-form-item label="产品组" prop="pgCode">
<el-input v-model="templateForm.pgCode" placeholder="如 EXP" maxlength="10" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="渠道ID" prop="snId">
<el-input v-model="templateForm.snId" placeholder="snId" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="货物类型" prop="ctCode">
<el-input v-model="templateForm.ctCode" placeholder="ctCode" maxlength="5" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="付款方式" prop="pmCode">
<el-input v-model="templateForm.pmCode" placeholder="pmCode" maxlength="5" />
</el-form-item>
</el-col>
</el-row>
<el-form-item label="备注" prop="wstNote">
<el-input v-model="templateForm.wstNote" type="textarea" placeholder="请输入备注" :rows="3" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitTemplateForm">确 定</el-button>
<el-button @click="templateOpen = false">取 消</el-button>
</div>
</template>
</el-dialog>
<!-- 明细表单 -->
<el-dialog :title="detailTitle" v-model="detailOpen" width="600px" append-to-body>
<el-form ref="detailFormRef" :model="detailForm" :rules="detailRules" label-width="110px">
<el-form-item label="标题" prop="wlTitle">
<el-input v-model="detailForm.wlTitle" placeholder="如 0.5kg段" maxlength="50" />
</el-form-item>
<el-row>
<el-col :span="12">
<el-form-item label="起始重量" prop="wlStartweight">
<el-input-number v-model="detailForm.wlStartweight" :min="0" :precision="3" :step="0.1" controls-position="right" style="width: 100%" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="截止重量" prop="wlEndweight">
<el-input-number v-model="detailForm.wlEndweight" :min="0" :precision="3" :step="0.1" controls-position="right" style="width: 100%" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="计费类别" prop="weightBillingCode">
<el-input v-model="detailForm.weightBillingCode" placeholder="如 W/P/C" maxlength="5" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="计费单位" prop="fvUnitweight">
<el-input-number v-model="detailForm.fvUnitweight" :min="0" :precision="3" :step="0.1" controls-position="right" style="width: 100%" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="生效日期" prop="effectiveDate">
<el-date-picker
v-model="detailForm.effectiveDate"
type="date"
value-format="YYYY-MM-DD"
placeholder="选择生效日期"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="失效日期" prop="expireDate">
<el-date-picker
v-model="detailForm.expireDate"
type="date"
value-format="YYYY-MM-DD"
placeholder="可选"
style="width: 100%"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitDetailForm">确 定</el-button>
<el-button @click="detailOpen = false">取 消</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="PriceWeight">
import {
listTemplate, getTemplate, addTemplate, updateTemplate, delTemplate,
listDetail, addDetail, updateDetail, delDetail
} from '@/api/price/weight'
import { parseTime } from '@/utils/ruoyi'
const { proxy } = getCurrentInstance()
const templateTableRef = ref()
const selectedTemplate = ref(null)
const detailList = ref([])
const detailLoading = ref(false)
const templateOpen = ref(false)
const templateTitle = ref('')
const templateFormRef = ref()
const templateForm = ref({})
const templateRules = {
wstName: [{ required: true, message: '模板名称不能为空', trigger: 'blur' }],
ssCode: [{ required: true, message: '状态不能为空', trigger: 'change' }]
}
const detailOpen = ref(false)
const detailTitle = ref('')
const detailFormRef = ref()
const detailForm = ref({})
const validateWeightRange = (rule, value, callback) => {
const start = detailForm.value.wlStartweight
const end = detailForm.value.wlEndweight
if (start == null || end == null) {
callback()
return
}
if (Number(start) >= Number(end)) {
callback(new Error('起始重量必须小于截止重量'))
} else {
callback()
}
}
const detailRules = {
wlStartweight: [
{ required: true, message: '起始重量不能为空', trigger: 'blur' },
{ validator: validateWeightRange, trigger: 'blur' }
],
wlEndweight: [
{ required: true, message: '截止重量不能为空', trigger: 'blur' },
{ validator: validateWeightRange, trigger: 'blur' }
],
weightBillingCode: [{ required: true, message: '计费类别不能为空', trigger: 'blur' }],
effectiveDate: [{ required: true, message: '生效日期不能为空', trigger: 'change' }]
}
const templateSearchColumns = [
{ label: '模板名称', prop: 'wstName', component: 'input', placeholder: '请输入模板名称', width: '220px' },
{
label: '状态',
prop: 'ssCode',
component: 'select',
options: [
{ label: '有效(on)', value: 'on' },
{ label: '停用(of)', value: 'of' }
],
placeholder: '状态',
width: '160px'
},
{ label: '产品组', prop: 'pgCode', component: 'input', placeholder: '产品组', width: '140px' }
]
const templateColumns = [
{ label: 'wstId', prop: 'wstId', align: 'center', width: 80 },
{ label: '模板名称', prop: 'wstName', align: 'center', minWidth: 140 },
{ label: '状态', prop: 'ssCode', align: 'center', width: 90 },
{ label: '产品组', prop: 'pgCode', align: 'center', width: 90 },
{ label: '渠道', prop: 'snId', align: 'center', width: 90 },
{ label: '货物类型', prop: 'ctCode', align: 'center', width: 90 },
{ label: '付款方式', prop: 'pmCode', align: 'center', width: 90 },
{ label: '明细数', prop: 'detailCount', align: 'center', width: 90 },
{ label: '操作', prop: 'action', align: 'center', width: 220, showInToolbar: false }
]
function queryTemplateList(params) {
return listTemplate(params)
}
function parseDate(val) {
if (!val) return ''
return parseTime(val, '{y}-{m}-{d}')
}
function formatEndWeight(item) {
const end = item.wlEndweight
if (end == null) return item.wlTitle || ''
return Number(end) + 'kg'
}
function handleTemplateRowClick(row) {
handleShowDetail(row)
}
function handleShowDetail(row) {
if (!row?.wstId) return
selectedTemplate.value = row
loadDetailList(row.wstId)
}
function loadDetailList(wstId) {
if (!wstId) {
detailList.value = []
return
}
detailLoading.value = true
listDetail({ wstId, pageNum: 1, pageSize: 500 }).then(res => {
const rows = res.rows || []
detailList.value = rows.slice().sort((a, b) => Number(a.wlStartweight) - Number(b.wlStartweight))
}).catch(() => {
detailList.value = []
}).finally(() => {
detailLoading.value = false
})
}
function normalizeOptionalNumber(val) {
if (val === '' || val === null || val === undefined) return undefined
return Number(val)
}
function resetTemplateForm() {
templateForm.value = {
wstId: undefined,
wstName: undefined,
ssCode: 'on',
pgCode: undefined,
snId: undefined,
ctCode: undefined,
pmCode: undefined,
wstNote: undefined
}
proxy.resetForm('templateFormRef')
}
function handleTemplateAdd() {
resetTemplateForm()
templateOpen.value = true
templateTitle.value = '新建重量段模板'
}
function handleTemplateUpdate(row) {
resetTemplateForm()
getTemplate(row.wstId).then(res => {
const data = res.data || {}
if (data.ssCode) data.ssCode = String(data.ssCode).toLowerCase()
templateForm.value = data
templateOpen.value = true
templateTitle.value = '编辑重量段模板'
})
}
function submitTemplateForm() {
proxy.$refs['templateFormRef'].validate(valid => {
if (!valid) return
const payload = {
...templateForm.value,
snId: normalizeOptionalNumber(templateForm.value.snId)
}
const req = payload.wstId != null ? updateTemplate(payload) : addTemplate(payload)
req.then(() => {
proxy.$modal.msgSuccess(payload.wstId != null ? '修改成功' : '新增成功')
templateOpen.value = false
templateTableRef.value.refresh()
if (selectedTemplate.value?.wstId === payload.wstId) {
loadDetailList(payload.wstId)
}
})
})
}
function handleTemplateDelete(wstIds) {
proxy.$modal.confirm('是否确认删除重量段模板编号为"' + wstIds + '"的数据项?').then(() => {
return delTemplate(wstIds)
}).then(() => {
templateTableRef.value.refresh()
if (selectedTemplate.value && String(wstIds).split(',').map(String).includes(String(selectedTemplate.value.wstId))) {
selectedTemplate.value = null
detailList.value = []
}
proxy.$modal.msgSuccess('删除成功')
}).catch(() => {})
}
function resetDetailForm() {
detailForm.value = {
wsdId: undefined,
wstId: selectedTemplate.value?.wstId,
wlTitle: undefined,
wlStartweight: undefined,
wlEndweight: undefined,
weightBillingCode: 'W',
fvUnitweight: undefined,
effectiveDate: undefined,
expireDate: undefined
}
proxy.resetForm('detailFormRef')
}
function handleDetailAdd() {
if (!selectedTemplate.value) {
proxy.$modal.msgWarning('请先选择重量段模板')
return
}
resetDetailForm()
detailOpen.value = true
detailTitle.value = '新增重量段明细'
}
function handleDetailUpdate(row) {
resetDetailForm()
detailForm.value = {
...row,
effectiveDate: parseDate(row.effectiveDate) || row.effectiveDate,
expireDate: parseDate(row.expireDate) || row.expireDate
}
detailOpen.value = true
detailTitle.value = '编辑重量段明细'
}
function submitDetailForm() {
proxy.$refs['detailFormRef'].validate(valid => {
if (!valid) return
const start = Number(detailForm.value.wlStartweight)
const end = Number(detailForm.value.wlEndweight)
if (!(start < end)) {
proxy.$modal.msgError('起始重量必须小于截止重量')
return
}
const payload = {
...detailForm.value,
wstId: selectedTemplate.value.wstId,
wlStartweight: start,
wlEndweight: end,
fvUnitweight: normalizeOptionalNumber(detailForm.value.fvUnitweight)
}
const req = payload.wsdId != null ? updateDetail(payload) : addDetail(payload)
req.then(() => {
proxy.$modal.msgSuccess(payload.wsdId != null ? '修改成功' : '新增成功')
detailOpen.value = false
loadDetailList(selectedTemplate.value.wstId)
templateTableRef.value.refresh()
})
})
}
function handleDetailDelete(wsdIds) {
proxy.$modal.confirm('是否确认删除重量段明细编号为"' + wsdIds + '"的数据项?').then(() => {
return delDetail(wsdIds)
}).then(() => {
loadDetailList(selectedTemplate.value.wstId)
templateTableRef.value.refresh()
proxy.$modal.msgSuccess('删除成功')
}).catch(() => {})
}
</script>
<style scoped>
.detail-card {
margin-top: 16px;
}
.card-header {
display: flex;
align-items: center;
justify-content: space-between;
}
.sub-hint {
margin-left: 10px;
color: #909399;
font-size: 13px;
font-weight: normal;
}
.ruler-block {
margin-bottom: 16px;
}
.section-title {
font-size: 14px;
font-weight: 600;
margin-bottom: 10px;
padding-left: 8px;
border-left: 3px solid var(--el-color-primary);
}
.weight-ruler {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.weight-chip {
height: auto;
padding: 6px 12px;
line-height: 1.3;
}
.chip-range {
margin-left: 6px;
color: #909399;
font-size: 12px;
}
</style>
@@ -0,0 +1,548 @@
<template>
<div class="app-container">
<!-- 分区方案 -->
<basic-table
ref="schemeTableRef"
:columns="schemeColumns"
:search-columns="schemeSearchColumns"
:query="querySchemeList"
row-key="zsId"
@row-click="handleSchemeRowClick"
>
<template #toolbar="{ selection, ids }">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="Plus"
@click="handleSchemeAdd"
v-hasPermi="['price:zone:add']"
>新建分区方案</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="Edit"
:disabled="selection.length !== 1"
@click="handleSchemeUpdate(selection[0])"
v-hasPermi="['price:zone:edit']"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
:disabled="!selection.length"
@click="handleSchemeDelete(ids)"
v-hasPermi="['price:zone:remove']"
>删除</el-button>
</el-col>
</template>
<template #col-ssCode="{ row }">
<el-tag :type="row.ssCode === 'on' ? 'success' : 'info'" size="small">
{{ row.ssCode === 'on' ? 'on' : 'of' }}
</el-tag>
</template>
<template #col-action="{ row }">
<el-button link type="primary" icon="Edit" @click.stop="handleSchemeUpdate(row)" v-hasPermi="['price:zone:edit']">编辑</el-button>
<el-button link type="primary" icon="Delete" @click.stop="handleSchemeDelete(row.zsId)" v-hasPermi="['price:zone:remove']">删除</el-button>
</template>
</basic-table>
<!-- 区划明细 -->
<el-card shadow="never" class="detail-card" v-loading="divisionLoading">
<template #header>
<div class="card-header">
<span>
区划明细
<span v-if="selectedScheme" class="sub-hint">当前方案:{{ selectedScheme.zsName }}(zsId={{ selectedScheme.zsId }})</span>
<span v-else class="sub-hint">请点击上方方案行查看区划</span>
</span>
<el-button
type="primary"
plain
icon="Plus"
size="small"
:disabled="!selectedScheme"
@click="handleDivisionAdd"
v-hasPermi="['price:zone:add']"
>新增区划</el-button>
</div>
</template>
<el-table
:data="divisionList"
border
highlight-current-row
row-key="zdId"
empty-text="暂无区划数据"
>
<el-table-column label="zdId" prop="zdId" align="center" width="80" />
<el-table-column label="区划代码" prop="zdCode" align="center" min-width="120" show-overflow-tooltip />
<el-table-column label="中文名" prop="znName" align="center" min-width="120" show-overflow-tooltip />
<el-table-column label="英文名" prop="znEname" align="center" min-width="140" show-overflow-tooltip />
<el-table-column label="国家数" prop="countryCount" align="center" width="90" />
<el-table-column label="操作" align="center" width="240" fixed="right">
<template #default="{ row }">
<el-button link type="primary" icon="View" @click="openCountryDrawer(row)" v-hasPermi="['price:zone:query']">查看国家</el-button>
<el-button link type="primary" icon="Edit" @click="handleDivisionUpdate(row)" v-hasPermi="['price:zone:edit']">编辑</el-button>
<el-button link type="primary" icon="Delete" @click="handleDivisionDelete(row.zdId)" v-hasPermi="['price:zone:remove']">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
<!-- 方案表单 -->
<el-dialog :title="schemeTitle" v-model="schemeOpen" width="560px" append-to-body>
<el-form ref="schemeFormRef" :model="schemeForm" :rules="schemeRules" label-width="100px">
<el-form-item label="方案名称" prop="zsName">
<el-input v-model="schemeForm.zsName" placeholder="请输入分区方案名称" maxlength="50" />
</el-form-item>
<el-form-item label="状态" prop="ssCode">
<el-radio-group v-model="schemeForm.ssCode">
<el-radio value="on">有效(on)</el-radio>
<el-radio value="of">停用(of)</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="产品组" prop="pgCode">
<el-input v-model="schemeForm.pgCode" placeholder="如 EXP / EMS / LINE" maxlength="10" />
</el-form-item>
<el-form-item label="渠道ID" prop="snId">
<el-input v-model="schemeForm.snId" placeholder="请输入渠道 snId" />
</el-form-item>
<el-form-item label="备注" prop="zsNote">
<el-input v-model="schemeForm.zsNote" type="textarea" placeholder="请输入备注" :rows="3" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitSchemeForm">确 定</el-button>
<el-button @click="schemeOpen = false">取 消</el-button>
</div>
</template>
</el-dialog>
<!-- 区划表单 -->
<el-dialog :title="divisionTitle" v-model="divisionOpen" width="560px" append-to-body>
<el-form ref="divisionFormRef" :model="divisionForm" :rules="divisionRules" label-width="100px">
<el-form-item label="区划代码" prop="zdCode">
<el-input v-model="divisionForm.zdCode" placeholder="如 DHL-ASIA" maxlength="50" />
</el-form-item>
<el-form-item label="中文名" prop="znName">
<el-input v-model="divisionForm.znName" placeholder="请输入中文名" maxlength="50" />
</el-form-item>
<el-form-item label="英文名" prop="znEname">
<el-input v-model="divisionForm.znEname" placeholder="请输入英文名" maxlength="50" />
</el-form-item>
<el-form-item label="排序号" prop="zdSort">
<el-input v-model="divisionForm.zdSort" placeholder="显示排序号" maxlength="3" />
</el-form-item>
<el-form-item label="备注" prop="znNote">
<el-input v-model="divisionForm.znNote" type="textarea" placeholder="请输入备注" :rows="3" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitDivisionForm">确 定</el-button>
<el-button @click="divisionOpen = false">取 消</el-button>
</div>
</template>
</el-dialog>
<!-- 国家抽屉 -->
<el-drawer v-model="countryDrawerVisible" size="640px" append-to-body>
<template #header>
<div class="drawer-head">
<span class="drawer-title">区划国家</span>
<span v-if="selectedDivision" class="drawer-sub">
{{ selectedDivision.zdCode }} {{ selectedDivision.znName }}
</span>
</div>
</template>
<div class="drawer-toolbar">
<el-button
type="primary"
plain
icon="Plus"
size="small"
@click="handleCountryAdd"
v-hasPermi="['price:zone:add']"
>新增国家</el-button>
</div>
<el-table v-loading="countryLoading" :data="countryList" border row-key="zcId" empty-text="暂无国家">
<el-table-column label="zcId" prop="zcId" align="center" width="80" />
<el-table-column label="国家代码" prop="countryCode" align="center" width="100" />
<el-table-column label="划分类型" prop="zcDividekind" align="center" width="120">
<template #default="{ row }">
<el-tag size="small" :type="divideKindTag(row.zcDividekind)">
{{ divideKindLabel(row.zcDividekind) }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" align="center" width="160">
<template #default="{ row }">
<el-button link type="primary" icon="Edit" @click="handleCountryUpdate(row)" v-hasPermi="['price:zone:edit']">编辑</el-button>
<el-button link type="primary" icon="Delete" @click="handleCountryDelete(row.zcId)" v-hasPermi="['price:zone:remove']">删除</el-button>
</template>
</el-table-column>
</el-table>
</el-drawer>
<!-- 国家表单 -->
<el-dialog :title="countryTitle" v-model="countryOpen" width="480px" append-to-body>
<el-form ref="countryFormRef" :model="countryForm" :rules="countryRules" label-width="100px">
<el-form-item label="国家代码" prop="countryCode">
<el-input v-model="countryForm.countryCode" placeholder="ISO两位码,如 DE" maxlength="2" style="text-transform: uppercase" />
</el-form-item>
<el-form-item label="划分类型" prop="zcDividekind">
<el-radio-group v-model="countryForm.zcDividekind">
<el-radio value="C">国家(C)</el-radio>
<el-radio value="T">城市(T)</el-radio>
<el-radio value="P">邮编(P)</el-radio>
</el-radio-group>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitCountryForm">确 定</el-button>
<el-button @click="countryOpen = false">取 消</el-button>
</div>
</template>
</el-dialog>
</div>
</template>
<script setup name="PriceZone">
import {
listScheme, getScheme, addScheme, updateScheme, delScheme,
listDivision, addDivision, updateDivision, delDivision,
listCountry, addCountry, updateCountry, delCountry
} from '@/api/price/zone'
const { proxy } = getCurrentInstance()
const schemeTableRef = ref()
const selectedScheme = ref(null)
const divisionList = ref([])
const divisionLoading = ref(false)
const schemeOpen = ref(false)
const schemeTitle = ref('')
const schemeFormRef = ref()
const schemeForm = ref({})
const schemeRules = {
zsName: [{ required: true, message: '方案名称不能为空', trigger: 'blur' }],
ssCode: [{ required: true, message: '状态不能为空', trigger: 'change' }]
}
const divisionOpen = ref(false)
const divisionTitle = ref('')
const divisionFormRef = ref()
const divisionForm = ref({})
const divisionRules = {
zdCode: [{ required: true, message: '区划代码不能为空', trigger: 'blur' }],
znName: [{ required: true, message: '中文名不能为空', trigger: 'blur' }]
}
const countryDrawerVisible = ref(false)
const selectedDivision = ref(null)
const countryList = ref([])
const countryLoading = ref(false)
const countryOpen = ref(false)
const countryTitle = ref('')
const countryFormRef = ref()
const countryForm = ref({})
const countryRules = {
countryCode: [
{ required: true, message: '国家代码不能为空', trigger: 'blur' },
{ min: 2, max: 2, message: '国家代码须为2位', trigger: 'blur' }
],
zcDividekind: [{ required: true, message: '划分类型不能为空', trigger: 'change' }]
}
const schemeSearchColumns = [
{ label: '方案名称', prop: 'zsName', component: 'input', placeholder: '请输入方案名称', width: '220px' },
{
label: '状态',
prop: 'ssCode',
component: 'select',
options: [
{ label: '有效(on)', value: 'on' },
{ label: '停用(of)', value: 'of' }
],
placeholder: '状态',
width: '160px'
}
]
const schemeColumns = [
{ label: 'zsId', prop: 'zsId', align: 'center', width: 80 },
{ label: '方案名称', prop: 'zsName', align: 'center', minWidth: 140 },
{ label: '状态', prop: 'ssCode', align: 'center', width: 90 },
{ label: '产品组', prop: 'pgCode', align: 'center', width: 100 },
{ label: '渠道', prop: 'snId', align: 'center', width: 100 },
{ label: '区划数', prop: 'divisionCount', align: 'center', width: 90 },
{ label: '操作', prop: 'action', align: 'center', width: 160, showInToolbar: false }
]
function querySchemeList(params) {
return listScheme(params)
}
function handleSchemeRowClick(row) {
if (!row?.zsId) return
selectedScheme.value = row
loadDivisionList(row.zsId)
}
function loadDivisionList(zsId) {
if (!zsId) {
divisionList.value = []
return
}
divisionLoading.value = true
listDivision({ zsId, pageNum: 1, pageSize: 200 }).then(res => {
divisionList.value = res.rows || []
}).catch(() => {
divisionList.value = []
}).finally(() => {
divisionLoading.value = false
})
}
function resetSchemeForm() {
schemeForm.value = {
zsId: undefined,
zsName: undefined,
ssCode: 'on',
pgCode: undefined,
snId: undefined,
zsNote: undefined
}
proxy.resetForm('schemeFormRef')
}
function handleSchemeAdd() {
resetSchemeForm()
schemeOpen.value = true
schemeTitle.value = '新建分区方案'
}
function handleSchemeUpdate(row) {
resetSchemeForm()
getScheme(row.zsId).then(res => {
schemeForm.value = res.data || {}
schemeOpen.value = true
schemeTitle.value = '编辑分区方案'
})
}
function submitSchemeForm() {
proxy.$refs['schemeFormRef'].validate(valid => {
if (!valid) return
const payload = { ...schemeForm.value }
if (payload.snId === '' || payload.snId === null) {
payload.snId = undefined
} else if (payload.snId !== undefined) {
payload.snId = Number(payload.snId)
}
const req = payload.zsId != null ? updateScheme(payload) : addScheme(payload)
req.then(() => {
proxy.$modal.msgSuccess(payload.zsId != null ? '修改成功' : '新增成功')
schemeOpen.value = false
schemeTableRef.value.refresh()
if (selectedScheme.value?.zsId === payload.zsId) {
loadDivisionList(payload.zsId)
}
})
})
}
function handleSchemeDelete(zsIds) {
proxy.$modal.confirm('是否确认删除分区方案编号为"' + zsIds + '"的数据项?').then(() => {
return delScheme(zsIds)
}).then(() => {
schemeTableRef.value.refresh()
if (selectedScheme.value && String(zsIds).split(',').map(String).includes(String(selectedScheme.value.zsId))) {
selectedScheme.value = null
divisionList.value = []
}
proxy.$modal.msgSuccess('删除成功')
}).catch(() => {})
}
function resetDivisionForm() {
divisionForm.value = {
zdId: undefined,
zsId: selectedScheme.value?.zsId,
zdCode: undefined,
znName: undefined,
znEname: undefined,
zdSort: undefined,
znNote: undefined
}
proxy.resetForm('divisionFormRef')
}
function handleDivisionAdd() {
if (!selectedScheme.value) {
proxy.$modal.msgWarning('请先选择分区方案')
return
}
resetDivisionForm()
divisionOpen.value = true
divisionTitle.value = '新增区划'
}
function handleDivisionUpdate(row) {
resetDivisionForm()
divisionForm.value = { ...row }
divisionOpen.value = true
divisionTitle.value = '编辑区划'
}
function submitDivisionForm() {
proxy.$refs['divisionFormRef'].validate(valid => {
if (!valid) return
const payload = { ...divisionForm.value, zsId: selectedScheme.value.zsId }
const req = payload.zdId != null ? updateDivision(payload) : addDivision(payload)
req.then(() => {
proxy.$modal.msgSuccess(payload.zdId != null ? '修改成功' : '新增成功')
divisionOpen.value = false
loadDivisionList(selectedScheme.value.zsId)
schemeTableRef.value.refresh()
})
})
}
function handleDivisionDelete(zdIds) {
proxy.$modal.confirm('是否确认删除区划编号为"' + zdIds + '"的数据项?').then(() => {
return delDivision(zdIds)
}).then(() => {
loadDivisionList(selectedScheme.value.zsId)
schemeTableRef.value.refresh()
proxy.$modal.msgSuccess('删除成功')
}).catch(() => {})
}
function divideKindLabel(kind) {
const map = { C: '国家(C)', T: '城市(T)', P: '邮编(P)' }
return map[kind] || kind
}
function divideKindTag(kind) {
const map = { C: 'primary', T: 'warning', P: 'success' }
return map[kind] || 'info'
}
function openCountryDrawer(row) {
selectedDivision.value = row
countryDrawerVisible.value = true
loadCountryList(row.zdId)
}
function loadCountryList(zdId) {
if (!zdId) {
countryList.value = []
return
}
countryLoading.value = true
listCountry({ zdId, pageNum: 1, pageSize: 500 }).then(res => {
countryList.value = res.rows || []
}).catch(() => {
countryList.value = []
}).finally(() => {
countryLoading.value = false
})
}
function resetCountryForm() {
countryForm.value = {
zcId: undefined,
zdId: selectedDivision.value?.zdId,
countryCode: undefined,
zcDividekind: 'C'
}
proxy.resetForm('countryFormRef')
}
function handleCountryAdd() {
resetCountryForm()
countryOpen.value = true
countryTitle.value = '新增国家'
}
function handleCountryUpdate(row) {
resetCountryForm()
countryForm.value = { ...row }
countryOpen.value = true
countryTitle.value = '编辑国家'
}
function submitCountryForm() {
proxy.$refs['countryFormRef'].validate(valid => {
if (!valid) return
const payload = {
...countryForm.value,
zdId: selectedDivision.value.zdId,
countryCode: (countryForm.value.countryCode || '').toUpperCase()
}
const req = payload.zcId != null ? updateCountry(payload) : addCountry(payload)
req.then(() => {
proxy.$modal.msgSuccess(payload.zcId != null ? '修改成功' : '新增成功')
countryOpen.value = false
loadCountryList(selectedDivision.value.zdId)
loadDivisionList(selectedScheme.value.zsId)
})
})
}
function handleCountryDelete(zcIds) {
proxy.$modal.confirm('是否确认删除国家编号为"' + zcIds + '"的数据项?').then(() => {
return delCountry(zcIds)
}).then(() => {
loadCountryList(selectedDivision.value.zdId)
loadDivisionList(selectedScheme.value.zsId)
proxy.$modal.msgSuccess('删除成功')
}).catch(() => {})
}
</script>
<style scoped>
.detail-card {
margin-top: 16px;
}
.card-header {
display: flex;
align-items: center;
justify-content: space-between;
}
.sub-hint {
margin-left: 10px;
color: #909399;
font-size: 13px;
font-weight: normal;
}
.drawer-head {
display: flex;
align-items: center;
gap: 10px;
}
.drawer-title {
font-size: 16px;
font-weight: 600;
}
.drawer-sub {
color: #909399;
font-size: 13px;
}
.drawer-toolbar {
margin-bottom: 12px;
}
</style>