增加一个打单功能套餐
This commit is contained in:
@@ -0,0 +1,156 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function listLabelPackage(query) {
|
||||
return request({
|
||||
url: '/price/label/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function getLabelPackage(priceSetId) {
|
||||
return request({
|
||||
url: '/price/label/' + priceSetId,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function updateLabelBasic(data) {
|
||||
return request({
|
||||
url: '/price/label/basic',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function disableLabelPackage(priceSetId) {
|
||||
return request({
|
||||
url: '/price/label/' + priceSetId + '/disable',
|
||||
method: 'put'
|
||||
})
|
||||
}
|
||||
|
||||
export function enableLabelPackage(priceSetId) {
|
||||
return request({
|
||||
url: '/price/label/' + priceSetId + '/enable',
|
||||
method: 'put'
|
||||
})
|
||||
}
|
||||
|
||||
export function delLabelPackage(priceSetIds) {
|
||||
return request({
|
||||
url: '/price/label/' + priceSetIds,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function previewLabel(file, dictValue, progressId, onUploadProgress, priceSetId) {
|
||||
const data = new FormData()
|
||||
data.append('file', file)
|
||||
if (dictValue) data.append('dictValue', dictValue)
|
||||
if (progressId) data.append('progressId', progressId)
|
||||
if (priceSetId) data.append('priceSetId', priceSetId)
|
||||
return request({
|
||||
url: '/price/label/preview',
|
||||
method: 'post',
|
||||
data,
|
||||
headers: { 'Content-Type': 'multipart/form-data', repeatSubmit: false },
|
||||
timeout: 10 * 60 * 1000,
|
||||
onUploadProgress
|
||||
})
|
||||
}
|
||||
|
||||
export function labelParseProgress(progressId) {
|
||||
return request({
|
||||
url: '/price/label/preview/progress',
|
||||
method: 'get',
|
||||
params: { progressId },
|
||||
headers: { repeatSubmit: false }
|
||||
})
|
||||
}
|
||||
|
||||
export function saveLabelImport(data) {
|
||||
return request({
|
||||
url: '/price/label/importSave',
|
||||
method: 'post',
|
||||
data,
|
||||
timeout: 10 * 60 * 1000
|
||||
})
|
||||
}
|
||||
|
||||
export function listLabelVersions(priceSetId) {
|
||||
return request({
|
||||
url: '/price/label/' + priceSetId + '/versions',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function activateLabelVersion(priceSetId, versionNo, data) {
|
||||
return request({
|
||||
url: '/price/label/' + priceSetId + '/versions/' + versionNo + '/activate',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function listLabelProducts(priceSetId, versionNo) {
|
||||
return request({
|
||||
url: '/price/label/' + priceSetId + '/products',
|
||||
method: 'get',
|
||||
params: versionNo != null ? { versionNo } : undefined
|
||||
})
|
||||
}
|
||||
|
||||
export function listLabelCustomer(query) {
|
||||
return request({
|
||||
url: '/price/label/customer/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
})
|
||||
}
|
||||
|
||||
export function addLabelCustomer(data) {
|
||||
return request({
|
||||
url: '/price/label/customer',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function batchAddLabelCustomer(data) {
|
||||
return request({
|
||||
url: '/price/label/customer/batch',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function updateLabelCustomer(data) {
|
||||
return request({
|
||||
url: '/price/label/customer',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function delLabelCustomer(ids) {
|
||||
return request({
|
||||
url: '/price/label/customer/' + ids,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function getLabelProduct(productId, termId) {
|
||||
return request({
|
||||
url: '/price/label/product/' + productId,
|
||||
method: 'get',
|
||||
params: termId ? { termId } : undefined
|
||||
})
|
||||
}
|
||||
|
||||
export function removeLabelProducts(priceSetId, productIds) {
|
||||
return request({
|
||||
url: '/price/label/' + priceSetId + '/products/' + productIds,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
@@ -40,9 +40,9 @@
|
||||
<template #col-termStatus="{ row }">
|
||||
<el-switch
|
||||
v-if="row.termId"
|
||||
:model-value="row.termStatus === '1' ? '1' : '0'"
|
||||
active-value="0"
|
||||
inactive-value="1"
|
||||
:model-value="row.termStatus === '1' ? '1' : '2'"
|
||||
active-value="1"
|
||||
inactive-value="2"
|
||||
inline-prompt
|
||||
active-text="生效"
|
||||
inactive-text="失效"
|
||||
@@ -87,9 +87,9 @@
|
||||
<template #default="{ row }">
|
||||
<el-switch
|
||||
v-if="row.termId"
|
||||
:model-value="row.status === '1' ? '1' : '0'"
|
||||
active-value="0"
|
||||
inactive-value="1"
|
||||
:model-value="row.status === '1' ? '1' : '2'"
|
||||
active-value="1"
|
||||
inactive-value="2"
|
||||
inline-prompt
|
||||
active-text="生效"
|
||||
inactive-text="失效"
|
||||
@@ -385,11 +385,12 @@ function saveTerm() {
|
||||
}
|
||||
|
||||
function changeStatus(row, field, status) {
|
||||
if (!row?.termId || (status !== '0' && status !== '1') || row[field] === status) return
|
||||
// pay_product_term.status:0待生效 1生效 2已失效;开关只在 生效/已失效 间切换
|
||||
if (!row?.termId || (status !== '1' && status !== '2') || row[field] === status) return
|
||||
const previous = row[field]
|
||||
row[field] = status
|
||||
changePayTermStatus({ termId: row.termId, productId: row.productId, status }).then(() => {
|
||||
proxy.$modal.msgSuccess(status === '0' ? '已设为生效' : '已设为失效')
|
||||
proxy.$modal.msgSuccess(status === '1' ? '已设为生效' : '已设为失效')
|
||||
tableRef.value.refresh()
|
||||
if (historyVisible.value) loadHistory()
|
||||
}).catch(() => {
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="visible"
|
||||
title="导入打单价卡"
|
||||
:width="autoFillOnParse ? '560px' : '1080px'"
|
||||
append-to-body
|
||||
destroy-on-close
|
||||
@closed="onClosed"
|
||||
>
|
||||
<label-import-panel
|
||||
ref="panelRef"
|
||||
:auto-fill-on-parse="autoFillOnParse"
|
||||
:price-set-id="priceSetId"
|
||||
@parsed="onParsed"
|
||||
/>
|
||||
<template #footer>
|
||||
<el-button @click="visible = false">{{ autoFillOnParse ? '关闭' : '取消' }}</el-button>
|
||||
<el-button v-if="!autoFillOnParse" type="primary" :loading="saving" @click="save">保存</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ElMessageBox } from 'element-plus'
|
||||
import LabelImportPanel from './LabelImportPanel.vue'
|
||||
|
||||
const props = defineProps({
|
||||
/** 已有套餐时传入,弹窗内直接落库(详情页) */
|
||||
priceSetId: { type: [Number, String], default: null },
|
||||
/**
|
||||
* 仅创建页传 true:解析成功立刻回填页面,不点确定/保存
|
||||
* 详情页默认 false:预览勾选后点保存落库
|
||||
*/
|
||||
autoFillOnParse: { type: Boolean, default: false }
|
||||
})
|
||||
const emit = defineEmits(['saved', 'confirm'])
|
||||
const { proxy } = getCurrentInstance()
|
||||
|
||||
const visible = ref(false)
|
||||
const saving = ref(false)
|
||||
const panelRef = ref()
|
||||
const autoFilled = ref(false)
|
||||
|
||||
function open() {
|
||||
autoFilled.value = false
|
||||
visible.value = true
|
||||
nextTick(() => panelRef.value?.reset())
|
||||
}
|
||||
|
||||
function onClosed() {
|
||||
panelRef.value?.reset()
|
||||
saving.value = false
|
||||
autoFilled.value = false
|
||||
}
|
||||
|
||||
/** 仅创建页(autoFillOnParse)生效 */
|
||||
function onParsed(payload) {
|
||||
if (!props.autoFillOnParse || autoFilled.value) return
|
||||
if (!payload?.products?.length) return
|
||||
autoFilled.value = true
|
||||
emit('confirm', payload)
|
||||
visible.value = false
|
||||
proxy.$modal.msgSuccess(`已导入 ${payload.products.length} 个产品`)
|
||||
}
|
||||
|
||||
async function save() {
|
||||
if (!props.priceSetId) {
|
||||
proxy.$modal.msgError('缺少套餐ID')
|
||||
return
|
||||
}
|
||||
if (!panelRef.value?.validateReady()) return
|
||||
const count = panelRef.value.selectedCount || 0
|
||||
try {
|
||||
await proxy.$modal.confirm(`将保存 ${count} 个应收产品到本套餐。`)
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
saving.value = true
|
||||
try {
|
||||
const result = await panelRef.value.submit({ priceSetId: props.priceSetId })
|
||||
visible.value = false
|
||||
ElMessageBox.close()
|
||||
proxy.$modal.msgSuccess(result.message || '保存成功')
|
||||
emit('saved', { priceSetId: result.priceSetId || props.priceSetId })
|
||||
} finally {
|
||||
saving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({ open })
|
||||
</script>
|
||||
@@ -0,0 +1,345 @@
|
||||
<template>
|
||||
<div class="label-import-panel">
|
||||
<el-form label-width="96px" class="import-form">
|
||||
<el-form-item label="支付类型">
|
||||
<el-tag type="success">应收 AR</el-tag>
|
||||
<span class="form-tip">打单套餐固定应收,不显示建价选项,直接 Excel 导入</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="产品">
|
||||
<el-select v-model="dictValue" clearable filterable placeholder="不选则按工作表名称匹配全部字典产品" style="width: 420px">
|
||||
<el-option v-for="item in payment_product_type" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-upload
|
||||
:key="uploadKey"
|
||||
drag
|
||||
accept=".xlsx"
|
||||
:auto-upload="false"
|
||||
:show-file-list="false"
|
||||
:disabled="recognizing"
|
||||
@change="onFile"
|
||||
>
|
||||
<el-icon class="upload-icon"><UploadFilled /></el-icon>
|
||||
<div class="el-upload__text">将 xlsx 价卡拖到此处,或<em>点击选择</em></div>
|
||||
<template #tip>
|
||||
<div class="upload-tip">
|
||||
{{ autoFillOnParse
|
||||
? '解析成功后自动回填到创建页产品价卡列表;打单保存与应付独立,弹窗内不展示表格。'
|
||||
: '模板以威狮 B2C 末端派送价卡为准。选一个产品就只读对应工作表。' }}
|
||||
</div>
|
||||
</template>
|
||||
</el-upload>
|
||||
|
||||
<div v-if="recognizing" class="parse-progress">
|
||||
<el-progress :percentage="parsePercent" :stroke-width="16" :status="parseStatus" striped striped-flow :duration="12" />
|
||||
<div class="parse-progress-msg">{{ parseMessage }}</div>
|
||||
</div>
|
||||
|
||||
<!-- 创建页 autoFillOnParse:不展示弹窗预览表,结果回填页面;详情等入口保留预览勾选 -->
|
||||
<div v-if="preview && !autoFillOnParse" v-loading="recognizing" class="preview-box">
|
||||
<el-alert
|
||||
:title="`${preview.sourceFile || ''} 归属 ${preview.supplierName || '-'} 生效 ${preview.effectiveDate || '-'} 共 ${products.length} 个产品`"
|
||||
type="info"
|
||||
:closable="false"
|
||||
show-icon
|
||||
/>
|
||||
<div class="preview-bar">
|
||||
<el-switch v-model="overwrite" active-text="本套餐已存在时另存为新版本" />
|
||||
<span class="preview-hint">仅本打单套餐维度;与应付公共价卡互不影响。开启后同产品编号不变,旧价留在历史 term。</span>
|
||||
</div>
|
||||
<el-table
|
||||
ref="tableRef"
|
||||
:data="products"
|
||||
border
|
||||
size="small"
|
||||
max-height="420"
|
||||
row-key="rowKey"
|
||||
@selection-change="onSelect"
|
||||
>
|
||||
<el-table-column type="selection" width="48" :selectable="canSelect" />
|
||||
<el-table-column prop="productName" label="产品" min-width="140" show-overflow-tooltip />
|
||||
<el-table-column prop="sheetName" label="报价工作表" min-width="140" show-overflow-tooltip />
|
||||
<el-table-column prop="countryScope" label="国家/口岸" min-width="110" show-overflow-tooltip />
|
||||
<el-table-column prop="relatedSheet" label="关联分区表" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column prop="weightCount" label="重量段" width="80" align="right" />
|
||||
<el-table-column prop="surchargeCount" label="附加费" width="80" align="right" />
|
||||
<el-table-column label="识别" width="120">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="statusType(row.parseStatus)" size="small">{{ statusText(row.parseStatus) }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="库中" width="90">
|
||||
<template #default="{ row }">
|
||||
<el-tag v-if="row.duplicated" type="warning" size="small">已存在</el-tag>
|
||||
<span v-else>新记录</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="90" align="center" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button link type="primary" icon="View" @click="openDetail(row)">查看</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<div v-if="skippedText" class="upload-tip">未匹配字典、已跳过:{{ skippedText }}</div>
|
||||
</div>
|
||||
|
||||
<el-drawer v-model="detailVisible" :title="detailTitle" size="78%" destroy-on-close append-to-body>
|
||||
<pay-config-detail :product="detailProduct" :editable="false" />
|
||||
<template #footer>
|
||||
<el-button @click="detailVisible = false">关闭</el-button>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { UploadFilled } from '@element-plus/icons-vue'
|
||||
import { previewLabel, labelParseProgress, saveLabelImport } from '@/api/price/label'
|
||||
import { useDict } from '@/utils/dict'
|
||||
import PayConfigDetail from '@/views/price/basic/pay/components/PayConfigDetail.vue'
|
||||
|
||||
const props = defineProps({
|
||||
/** 仅创建页开启:解析成功后立刻抛出勾选结果,其它入口保持预览后手动保存 */
|
||||
autoFillOnParse: { type: Boolean, default: false },
|
||||
/** 详情再导入时传入,用于「本套餐已存在」判断;新建不传 */
|
||||
priceSetId: { type: [Number, String], default: null }
|
||||
})
|
||||
const emit = defineEmits(['parsed'])
|
||||
const { proxy } = getCurrentInstance()
|
||||
const { payment_product_type } = useDict('payment_product_type')
|
||||
|
||||
const recognizing = ref(false)
|
||||
const overwrite = ref(false)
|
||||
const dictValue = ref('')
|
||||
const preview = ref(null)
|
||||
const selected = ref([])
|
||||
const tableRef = ref()
|
||||
const uploadKey = ref(0)
|
||||
const parsePercent = ref(0)
|
||||
const parseMessage = ref('')
|
||||
const parseStatus = ref(undefined)
|
||||
const active = ref(true)
|
||||
const detailVisible = ref(false)
|
||||
const detailProduct = ref(null)
|
||||
|
||||
const products = computed(() => preview.value?.products || [])
|
||||
const skippedText = computed(() => (preview.value?.skippedSheets || []).filter(Boolean).join('、'))
|
||||
const selectedCount = computed(() => selected.value.length)
|
||||
const detailTitle = computed(() => {
|
||||
if (!detailProduct.value) return '产品明细'
|
||||
return detailProduct.value.productName || detailProduct.value.sheetName || '产品明细'
|
||||
})
|
||||
|
||||
let parseSeq = 0
|
||||
let progressTimer = null
|
||||
|
||||
function reset() {
|
||||
parseSeq += 1
|
||||
preview.value = null
|
||||
selected.value = []
|
||||
overwrite.value = false
|
||||
dictValue.value = ''
|
||||
recognizing.value = false
|
||||
parsePercent.value = 0
|
||||
parseMessage.value = ''
|
||||
parseStatus.value = undefined
|
||||
detailVisible.value = false
|
||||
detailProduct.value = null
|
||||
stopProgress()
|
||||
uploadKey.value += 1
|
||||
}
|
||||
|
||||
function openDetail(row) {
|
||||
detailProduct.value = row || null
|
||||
detailVisible.value = true
|
||||
}
|
||||
|
||||
async function onFile(uploadFile) {
|
||||
const raw = uploadFile?.raw
|
||||
if (!raw) return
|
||||
if (!raw.name.toLowerCase().endsWith('.xlsx')) {
|
||||
proxy.$modal.msgError('请上传xlsx价卡')
|
||||
return
|
||||
}
|
||||
const seq = ++parseSeq
|
||||
const progressId = createProgressId()
|
||||
recognizing.value = true
|
||||
parsePercent.value = 0
|
||||
parseMessage.value = '正在上传价卡…'
|
||||
parseStatus.value = undefined
|
||||
startProgress(seq, progressId)
|
||||
try {
|
||||
const res = await previewLabel(raw, dictValue.value, progressId, event => {
|
||||
if (seq !== parseSeq || !event?.total) return
|
||||
const uploaded = Math.min(8, Math.round(event.loaded * 8 / event.total))
|
||||
if (uploaded > parsePercent.value) {
|
||||
parsePercent.value = uploaded
|
||||
parseMessage.value = '正在上传价卡…'
|
||||
}
|
||||
}, props.priceSetId)
|
||||
if (seq !== parseSeq) return
|
||||
parsePercent.value = 100
|
||||
parseMessage.value = '解析完成'
|
||||
parseStatus.value = 'success'
|
||||
const data = res.data || {}
|
||||
data.products = (data.products || []).map((item, index) => ({
|
||||
...item,
|
||||
rowKey: `${item.sheetName || ''}-${item.productName || ''}-${index}`
|
||||
}))
|
||||
preview.value = data
|
||||
const picked = data.products.filter(row => canSelect(row))
|
||||
selected.value = picked
|
||||
// 详情等入口:预览表勾选;创建页不渲染预览表,直接回填页面
|
||||
if (!props.autoFillOnParse) {
|
||||
await nextTick()
|
||||
tableRef.value?.clearSelection()
|
||||
picked.forEach(row => tableRef.value?.toggleRowSelection(row, true))
|
||||
} else if (picked.length) {
|
||||
emit('parsed', getSelectionPayload())
|
||||
} else {
|
||||
proxy.$modal.msgWarning(
|
||||
props.priceSetId
|
||||
? '没有可导入的产品,请调整产品筛选或开启「本套餐已存在时另存为新版本」后重试'
|
||||
: '没有可导入的产品,请调整产品筛选或检查价卡工作表是否匹配字典'
|
||||
)
|
||||
}
|
||||
} catch (error) {
|
||||
if (seq !== parseSeq) return
|
||||
parseStatus.value = 'exception'
|
||||
parseMessage.value = error?.message || '价卡解析失败'
|
||||
} finally {
|
||||
if (seq === parseSeq) {
|
||||
stopProgress()
|
||||
recognizing.value = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createProgressId() {
|
||||
if (window.crypto?.randomUUID) return window.crypto.randomUUID()
|
||||
return `lbl${Date.now().toString(16)}${Math.random().toString(16).slice(2, 10)}`
|
||||
}
|
||||
|
||||
function startProgress(seq, progressId) {
|
||||
stopProgress()
|
||||
progressTimer = window.setInterval(async () => {
|
||||
if (seq !== parseSeq) return
|
||||
try {
|
||||
const res = await labelParseProgress(progressId)
|
||||
if (seq !== parseSeq) return
|
||||
const data = res.data || {}
|
||||
if (!data.status || data.status === 'PENDING') return
|
||||
const server = Math.min(99, Number(data.percent) || 0)
|
||||
if (server >= parsePercent.value) {
|
||||
parsePercent.value = server
|
||||
if (data.message) parseMessage.value = data.message
|
||||
}
|
||||
if (data.status === 'FAIL') parseStatus.value = 'exception'
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
}, 400)
|
||||
}
|
||||
|
||||
function stopProgress() {
|
||||
if (progressTimer) {
|
||||
window.clearInterval(progressTimer)
|
||||
progressTimer = null
|
||||
}
|
||||
}
|
||||
|
||||
function canSelect(row) {
|
||||
if (row.parseStatus === 'MISSING') return false
|
||||
return overwrite.value || !row.duplicated
|
||||
}
|
||||
|
||||
watch(overwrite, async () => {
|
||||
if (!active.value || !preview.value) return
|
||||
const picked = products.value.filter(row => canSelect(row))
|
||||
selected.value = picked
|
||||
await nextTick()
|
||||
tableRef.value?.clearSelection()
|
||||
picked.forEach(row => tableRef.value?.toggleRowSelection(row, true))
|
||||
})
|
||||
|
||||
function onSelect(rows) {
|
||||
if (!active.value) return
|
||||
selected.value = rows || []
|
||||
}
|
||||
|
||||
function statusType(status) {
|
||||
if (status === 'OK') return 'success'
|
||||
if (status === 'EMPTY') return 'warning'
|
||||
return 'danger'
|
||||
}
|
||||
|
||||
function statusText(status) {
|
||||
if (status === 'OK') return '已识别'
|
||||
if (status === 'EMPTY') return '未识别到配置'
|
||||
if (status === 'MISSING') return '缺少工作表'
|
||||
return status || '-'
|
||||
}
|
||||
|
||||
function validateReady() {
|
||||
if (!selected.value.length) {
|
||||
proxy.$modal.msgError('请先上传价卡并勾选要保存的产品')
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
/** 弹窗确认时回传勾选结果(创建页暂存,点完成再落库) */
|
||||
function getSelectionPayload() {
|
||||
return {
|
||||
overwrite: overwrite.value,
|
||||
sourceFile: preview.value?.sourceFile || '',
|
||||
supplierName: preview.value?.supplierName || '',
|
||||
effectiveDate: preview.value?.effectiveDate || '',
|
||||
products: selected.value.map(row => ({ ...row, productType: 'AR' }))
|
||||
}
|
||||
}
|
||||
|
||||
/** 按现有导入逻辑保存;basic 由创建页传入名称/备注 */
|
||||
async function submit(payload = {}) {
|
||||
if (!validateReady()) {
|
||||
throw new Error('NO_SELECTION')
|
||||
}
|
||||
const productsPayload = (payload.products && payload.products.length)
|
||||
? payload.products
|
||||
: selected.value.map(row => ({ ...row, productType: 'AR' }))
|
||||
const res = await saveLabelImport({
|
||||
priceSetId: payload.priceSetId || null,
|
||||
priceSetName: String(payload.priceSetName || '').trim(),
|
||||
priceSetNote: payload.priceSetNote || '',
|
||||
overwrite: payload.overwrite != null ? payload.overwrite : overwrite.value,
|
||||
products: productsPayload
|
||||
})
|
||||
const data = res.data || {}
|
||||
return {
|
||||
message: data.message || res.msg || '保存成功',
|
||||
priceSetId: data.priceSetId || payload.priceSetId
|
||||
}
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
active.value = false
|
||||
stopProgress()
|
||||
})
|
||||
|
||||
defineExpose({ reset, validateReady, submit, getSelectionPayload, selectedCount })
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.import-form { margin-bottom: 8px; }
|
||||
.form-tip { margin-left: 12px; color: #909399; font-size: 12px; }
|
||||
.upload-icon { font-size: 48px; color: #c0c4cc; }
|
||||
.upload-tip { color: #909399; font-size: 12px; margin-top: 6px; }
|
||||
.parse-progress { margin: 12px 0; }
|
||||
.parse-progress-msg { margin-top: 6px; color: #606266; font-size: 13px; }
|
||||
.preview-box { margin-top: 12px; }
|
||||
.preview-bar { display: flex; align-items: center; gap: 12px; margin: 10px 0; }
|
||||
.preview-hint { color: #909399; font-size: 12px; }
|
||||
</style>
|
||||
@@ -0,0 +1,169 @@
|
||||
<template>
|
||||
<el-drawer
|
||||
:model-value="visible"
|
||||
:title="title"
|
||||
size="78%"
|
||||
destroy-on-close
|
||||
append-to-body
|
||||
@close="emit('update:visible', false)"
|
||||
>
|
||||
<div class="toolbar">
|
||||
<el-input v-model="keyword" clearable placeholder="产品名称 / 工作表 / 国家" style="width: 260px" />
|
||||
<el-button type="danger" plain :disabled="!selectedIds.length" @click="handleRemove" v-hasPermi="['price:label:remove']">移除</el-button>
|
||||
</div>
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="filteredRows"
|
||||
border
|
||||
height="calc(100vh - 220px)"
|
||||
row-key="termId"
|
||||
@selection-change="onSelect"
|
||||
>
|
||||
<el-table-column type="selection" width="48" align="center" />
|
||||
<el-table-column prop="productId" label="产品编号" width="90" align="center" />
|
||||
<el-table-column prop="productName" label="产品名称" min-width="150" show-overflow-tooltip />
|
||||
<el-table-column prop="supplierName" label="价卡归属" width="100" align="center" />
|
||||
<el-table-column prop="countryScope" label="国家/口岸" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column prop="chargeType" label="费用类型" width="110" align="center" />
|
||||
<el-table-column prop="sheetName" label="报价工作表" min-width="140" show-overflow-tooltip />
|
||||
<el-table-column prop="versionNo" label="版本" width="70" align="center" />
|
||||
<el-table-column label="有效期" min-width="180" align="center">
|
||||
<template #default="{ row }">{{ termText(row) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" width="90" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="termStatusTag(row.termStatus)" size="small">{{ termStatusText(row.termStatus) }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="weightCount" label="重量段" width="80" align="center" />
|
||||
<el-table-column prop="surchargeCount" label="附加费" width="80" align="center" />
|
||||
<el-table-column label="操作" width="160" align="center" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button link type="primary" @click="openProduct(row)" v-hasPermi="['price:label:query']">查看</el-button>
|
||||
<el-button link type="danger" @click="handleRemove([row.productId])" v-hasPermi="['price:label:remove']">移除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<el-drawer v-model="detailVisible" :title="detailTitle" size="78%" destroy-on-close append-to-body>
|
||||
<pay-config-detail v-loading="detailLoading" :product="detail" :editable="false" />
|
||||
<template #footer>
|
||||
<el-button @click="detailVisible = false">关闭</el-button>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { listLabelProducts, getLabelProduct, removeLabelProducts } from '@/api/price/label'
|
||||
import PayConfigDetail from '@/views/price/basic/pay/components/PayConfigDetail.vue'
|
||||
|
||||
const props = defineProps({
|
||||
visible: { type: Boolean, default: false },
|
||||
priceSetId: { type: [Number, String], default: null },
|
||||
version: { type: Object, default: null }
|
||||
})
|
||||
const emit = defineEmits(['update:visible', 'changed'])
|
||||
const { proxy } = getCurrentInstance()
|
||||
|
||||
const loading = ref(false)
|
||||
const rows = ref([])
|
||||
const keyword = ref('')
|
||||
const selectedIds = ref([])
|
||||
const detailVisible = ref(false)
|
||||
const detailLoading = ref(false)
|
||||
const detail = ref(null)
|
||||
|
||||
const title = computed(() => {
|
||||
const v = props.version || {}
|
||||
const label = v.versionLabel || (v.versionNo != null ? `V${v.versionNo}` : '')
|
||||
return label ? `版本明细 · ${label}` : '版本明细'
|
||||
})
|
||||
|
||||
const detailTitle = computed(() => {
|
||||
if (!detail.value) return '产品明细'
|
||||
const no = detail.value.versionNo ? `第 ${detail.value.versionNo} 版` : ''
|
||||
return `${detail.value.productName || '产品'} ${no}`.trim()
|
||||
})
|
||||
|
||||
const filteredRows = computed(() => {
|
||||
const kw = keyword.value.trim().toLowerCase()
|
||||
if (!kw) return rows.value
|
||||
return rows.value.filter(row => {
|
||||
const text = [row.productName, row.sheetName, row.countryScope, row.supplierName].join(' ').toLowerCase()
|
||||
return text.includes(kw)
|
||||
})
|
||||
})
|
||||
|
||||
function termText(row) {
|
||||
const start = row.termStart || row.effectiveDate || ''
|
||||
const end = row.termEnd || '不限'
|
||||
if (!start) return '未设置'
|
||||
return `${String(start).slice(0, 10)} ~ ${String(end).slice(0, 10)}`
|
||||
}
|
||||
|
||||
function termStatusText(status) {
|
||||
const map = { '0': '待生效', '1': '生效', '2': '已失效' }
|
||||
return map[String(status)] || '-'
|
||||
}
|
||||
|
||||
function termStatusTag(status) {
|
||||
const map = { '0': 'warning', '1': 'success', '2': 'danger' }
|
||||
return map[String(status)] || 'info'
|
||||
}
|
||||
|
||||
function onSelect(selection) {
|
||||
selectedIds.value = (selection || []).map(item => item.productId).filter(Boolean)
|
||||
}
|
||||
|
||||
async function load() {
|
||||
if (!props.priceSetId || props.version?.versionNo == null) {
|
||||
rows.value = []
|
||||
return
|
||||
}
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await listLabelProducts(props.priceSetId, props.version.versionNo)
|
||||
rows.value = res.data || []
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function openProduct(row) {
|
||||
detailVisible.value = true
|
||||
detailLoading.value = true
|
||||
detail.value = null
|
||||
try {
|
||||
const res = await getLabelProduct(row.productId, row.termId)
|
||||
detail.value = res.data || null
|
||||
} finally {
|
||||
detailLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function handleRemove(ids) {
|
||||
const list = (Array.isArray(ids) ? ids : selectedIds.value).filter(Boolean)
|
||||
if (!list.length || !props.priceSetId) return
|
||||
proxy.$modal.confirm(`确认从本套餐移除选中的 ${list.length} 个产品?`).then(() => {
|
||||
return removeLabelProducts(props.priceSetId, list.join(','))
|
||||
}).then(() => {
|
||||
proxy.$modal.msgSuccess('已移除')
|
||||
load()
|
||||
emit('changed')
|
||||
}).catch(() => {})
|
||||
}
|
||||
|
||||
watch(() => [props.visible, props.priceSetId, props.version?.versionNo], ([vis]) => {
|
||||
if (vis) load()
|
||||
}, { immediate: true })
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.toolbar {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
margin-bottom: 12px;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,145 @@
|
||||
<template>
|
||||
<el-card shadow="never" class="ver-card">
|
||||
<template #header>
|
||||
<div class="ver-head">
|
||||
<div class="ver-head-left">
|
||||
<span class="ver-title">套餐版本</span>
|
||||
<el-tag size="small" type="info" effect="plain" round>{{ versions.length }}</el-tag>
|
||||
</div>
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
size="small"
|
||||
:disabled="hasPending"
|
||||
v-hasPermi="['price:label:import']"
|
||||
@click="$emit('create-version')"
|
||||
>新建版本</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-tabs v-model="statusTab" class="ver-tabs">
|
||||
<el-tab-pane :label="tabLabel('all')" name="all" />
|
||||
<el-tab-pane :label="tabLabel('0')" name="0" />
|
||||
<el-tab-pane :label="tabLabel('1')" name="1" />
|
||||
<el-tab-pane :label="tabLabel('2')" name="2" />
|
||||
</el-tabs>
|
||||
|
||||
<el-table :data="filteredVersions" border empty-text="暂无版本,完成导入后在此设置生效时间">
|
||||
<el-table-column label="版本号" width="100" align="center">
|
||||
<template #default="{ row }">{{ row.versionLabel || ('V' + (row.versionNo || 1)) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="生效时间" min-width="160" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-button link type="primary" @click="$emit('open-details', row)">
|
||||
{{ formatDay(row.effectiveTime) || '未设置' }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="失效时间" min-width="160" align="center">
|
||||
<template #default="{ row }">{{ formatDay(row.expireTime) || '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="statusTag(row.status)" size="small">{{ statusText(row.status) }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="产品数" width="90" align="center">
|
||||
<template #default="{ row }">{{ row.productCount || 0 }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="创建时间" min-width="170" align="center">
|
||||
<template #default="{ row }">{{ row.createTime || '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="280" align="center" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button link type="primary" @click="$emit('open-details', row)">查看详情</el-button>
|
||||
<el-button
|
||||
v-if="canEdit(row)"
|
||||
link
|
||||
type="primary"
|
||||
@click="$emit('edit', row)"
|
||||
v-hasPermi="['price:label:edit']"
|
||||
>编辑</el-button>
|
||||
<el-button
|
||||
v-if="canReschedule(row)"
|
||||
link
|
||||
type="primary"
|
||||
@click="$emit('reschedule', row)"
|
||||
v-hasPermi="['price:label:edit']"
|
||||
>修改生效时间</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const props = defineProps({
|
||||
versions: { type: Array, default: () => [] }
|
||||
})
|
||||
defineEmits(['edit', 'reschedule', 'open-details', 'create-version'])
|
||||
|
||||
const statusTab = ref('all')
|
||||
|
||||
const counts = computed(() => {
|
||||
const map = { all: 0, '0': 0, '1': 0, '2': 0 }
|
||||
;(props.versions || []).forEach(v => {
|
||||
map.all++
|
||||
const s = String(v?.status ?? '')
|
||||
if (map[s] != null) map[s]++
|
||||
})
|
||||
return map
|
||||
})
|
||||
|
||||
function tabLabel(key) {
|
||||
const labels = { all: '全部', '0': '待生效', '1': '已生效', '2': '已失效' }
|
||||
return `${labels[key]} (${counts.value[key] || 0})`
|
||||
}
|
||||
|
||||
const hasPending = computed(() => (props.versions || []).some(v => String(v.status) === '0'))
|
||||
|
||||
const filteredVersions = computed(() => {
|
||||
const list = props.versions || []
|
||||
if (statusTab.value === 'all') return list
|
||||
return list.filter(v => String(v.status) === statusTab.value)
|
||||
})
|
||||
|
||||
function formatDay(val) {
|
||||
if (!val) return ''
|
||||
return String(val).slice(0, 10)
|
||||
}
|
||||
|
||||
function statusText(status) {
|
||||
const map = { '0': '待生效', '1': '生效', '2': '已失效' }
|
||||
return map[String(status)] || '-'
|
||||
}
|
||||
|
||||
function statusTag(status) {
|
||||
const map = { '0': 'warning', '1': 'success', '2': 'danger' }
|
||||
return map[String(status)] || 'info'
|
||||
}
|
||||
|
||||
/** 待生效:可编辑价卡 */
|
||||
function canEdit(row) {
|
||||
return row && String(row.status) === '0'
|
||||
}
|
||||
|
||||
/** 仅待生效可改生效时间;已生效不可改 */
|
||||
function canReschedule(row) {
|
||||
return row && String(row.status) === '0'
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.ver-card { margin-bottom: 16px; }
|
||||
.ver-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
width: 100%;
|
||||
}
|
||||
.ver-head-left { display: flex; align-items: center; gap: 8px; }
|
||||
.ver-title { font-weight: 600; }
|
||||
.ver-tabs { margin-bottom: 8px; }
|
||||
.ver-tabs :deep(.el-tabs__header) { margin-bottom: 8px; }
|
||||
</style>
|
||||
@@ -0,0 +1,370 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<div v-if="showBasic" class="create-section">
|
||||
<step-basic-info ref="basicRef" v-model="form.basic" />
|
||||
</div>
|
||||
|
||||
<div v-else class="create-section">
|
||||
<el-alert
|
||||
:title="pageBanner"
|
||||
type="info"
|
||||
:closable="false"
|
||||
show-icon
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="create-section">
|
||||
<el-card shadow="never" class="step-card">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<div>
|
||||
<span>{{ cardTitle }}</span>
|
||||
<span class="header-tip">{{ headerTip }}</span>
|
||||
</div>
|
||||
<el-button type="primary" plain icon="Upload" @click="openImport" v-hasPermi="['price:label:import', 'price:label:add']">
|
||||
导入价卡
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-alert
|
||||
v-if="importMeta.sourceFile"
|
||||
:title="`${importMeta.sourceFile} 归属 ${importMeta.supplierName || '-'} 生效 ${importMeta.effectiveDate || '-'} 已选 ${productRows.length} 个产品`"
|
||||
type="info"
|
||||
:closable="false"
|
||||
show-icon
|
||||
class="meta-alert"
|
||||
/>
|
||||
|
||||
<el-table v-loading="loadingProducts" :data="productRows" border size="small" max-height="420" empty-text="请点击右上角「导入价卡」">
|
||||
<el-table-column prop="productName" label="产品" min-width="140" show-overflow-tooltip />
|
||||
<el-table-column prop="sheetName" label="报价工作表" min-width="140" show-overflow-tooltip />
|
||||
<el-table-column prop="countryScope" label="国家/口岸" min-width="110" show-overflow-tooltip />
|
||||
<el-table-column prop="relatedSheet" label="关联分区表" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column prop="weightCount" label="重量段" width="80" align="right" />
|
||||
<el-table-column prop="surchargeCount" label="附加费" width="80" align="right" />
|
||||
<el-table-column label="识别" width="120">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="statusType(row.parseStatus)" size="small">{{ statusText(row.parseStatus) }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="库中" width="90">
|
||||
<template #default="{ row }">
|
||||
<el-tag v-if="row.duplicated" type="warning" size="small">已存在</el-tag>
|
||||
<span v-else>新记录</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="90" align="center" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button link type="primary" icon="View" @click="openDetail(row)">查看</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<div class="wizard-actions">
|
||||
<el-button @click="goBack">取消</el-button>
|
||||
<el-button type="primary" :loading="saving" @click="finish">完成</el-button>
|
||||
</div>
|
||||
|
||||
<label-import-dialog
|
||||
ref="importRef"
|
||||
:price-set-id="priceSetId"
|
||||
:auto-fill-on-parse="true"
|
||||
@confirm="onImportConfirm"
|
||||
/>
|
||||
|
||||
<el-drawer v-model="detailVisible" :title="detailTitle" size="78%" destroy-on-close append-to-body @closed="onDetailClosed">
|
||||
<pay-config-detail :product="detailProduct" :editable="detailEditing" />
|
||||
<template #footer>
|
||||
<el-button v-if="!detailEditing" type="primary" icon="Edit" @click="startEdit">修改</el-button>
|
||||
<el-button v-else type="primary" @click="applyDetail">保存</el-button>
|
||||
<el-button @click="detailVisible = false">关闭</el-button>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="LabelPackageCreate">
|
||||
import { ElMessageBox } from 'element-plus'
|
||||
import StepBasicInfo from '../set/components/create/StepBasicInfo.vue'
|
||||
import { createEmptyBasicInfo } from '../set/utils/priceSet'
|
||||
import LabelImportDialog from './components/LabelImportDialog.vue'
|
||||
import PayConfigDetail from '@/views/price/basic/pay/components/PayConfigDetail.vue'
|
||||
import { getLabelPackage, getLabelProduct, listLabelProducts, saveLabelImport } from '@/api/price/label'
|
||||
|
||||
const { proxy } = getCurrentInstance()
|
||||
const route = useRoute()
|
||||
const basicRef = ref()
|
||||
const importRef = ref()
|
||||
const saving = ref(false)
|
||||
const loadingProducts = ref(false)
|
||||
const form = reactive({
|
||||
basic: createEmptyBasicInfo()
|
||||
})
|
||||
const productRows = ref([])
|
||||
const importMeta = reactive({
|
||||
sourceFile: '',
|
||||
supplierName: '',
|
||||
effectiveDate: '',
|
||||
overwrite: false
|
||||
})
|
||||
const detailVisible = ref(false)
|
||||
const detailEditing = ref(false)
|
||||
const detailProduct = ref(null)
|
||||
const detailRowKey = ref('')
|
||||
const detailTitle = computed(() => detailProduct.value?.productName || detailProduct.value?.sheetName || '产品明细')
|
||||
|
||||
const priceSetId = computed(() => {
|
||||
const id = Number(route.query.priceSetId)
|
||||
return Number.isFinite(id) && id > 0 ? id : null
|
||||
})
|
||||
const versionNo = computed(() => {
|
||||
const no = Number(route.query.versionNo)
|
||||
return Number.isFinite(no) && no > 0 ? no : null
|
||||
})
|
||||
const newVersionMode = computed(() => String(route.query.newVersion || '') === '1' && !!priceSetId.value)
|
||||
const editVersionMode = computed(() => String(route.query.editVersion || '') === '1' && !!priceSetId.value && !!versionNo.value)
|
||||
const showBasic = computed(() => !newVersionMode.value && !editVersionMode.value)
|
||||
const cardTitle = computed(() => {
|
||||
if (editVersionMode.value) return `编辑版本 V${versionNo.value}`
|
||||
if (newVersionMode.value) return '新版本价卡'
|
||||
return '产品价卡'
|
||||
})
|
||||
const pageBanner = computed(() => {
|
||||
const name = form.basic.priceSetName || ''
|
||||
const code = form.basic.priceSetCode || ''
|
||||
if (editVersionMode.value) return `编辑待生效版本 V${versionNo.value}:${name}(${code})`
|
||||
return `新建版本:${name}(${code})`
|
||||
})
|
||||
const headerTip = computed(() => {
|
||||
if (editVersionMode.value) return '可重新导入或修改明细;完成后覆盖本待生效版本,不新增版本号'
|
||||
if (newVersionMode.value) return '导入后生成待生效新版本;生效时间请回详情页设置'
|
||||
return '打单价卡与应付独立;解析后回填到此表,查看后点修改可改明细'
|
||||
})
|
||||
|
||||
function goBack() {
|
||||
const obj = (newVersionMode.value || editVersionMode.value) && priceSetId.value
|
||||
? { path: '/customer/labelDetail', query: { priceSetId: priceSetId.value } }
|
||||
: { path: '/customer/label' }
|
||||
proxy.$tab.closeOpenPage(obj)
|
||||
}
|
||||
|
||||
async function loadPackageHeader() {
|
||||
if ((!newVersionMode.value && !editVersionMode.value) || !priceSetId.value) return
|
||||
const res = await getLabelPackage(priceSetId.value)
|
||||
const data = res.data || {}
|
||||
form.basic.priceSetId = data.priceSetId
|
||||
form.basic.priceSetCode = data.priceSetCode || ''
|
||||
form.basic.priceSetName = data.priceSetName || ''
|
||||
form.basic.priceSetNote = data.priceSetNote || ''
|
||||
}
|
||||
|
||||
async function loadEditProducts() {
|
||||
if (!editVersionMode.value || !priceSetId.value || !versionNo.value) return
|
||||
loadingProducts.value = true
|
||||
try {
|
||||
const res = await listLabelProducts(priceSetId.value, versionNo.value)
|
||||
const list = res.data || []
|
||||
if (!list.length) {
|
||||
productRows.value = []
|
||||
return
|
||||
}
|
||||
const details = await Promise.all(list.map(async item => {
|
||||
try {
|
||||
const detailRes = await getLabelProduct(item.productId, item.termId)
|
||||
const detail = detailRes.data || item
|
||||
const bands = detail.weightBands || []
|
||||
const fees = detail.surcharges || []
|
||||
const extras = detail.extraLines || []
|
||||
return {
|
||||
...detail,
|
||||
rowKey: `${detail.sheetName || ''}-${detail.productName || ''}-${detail.termId || detail.productId || ''}`,
|
||||
weightCount: bands.length || detail.weightCount || 0,
|
||||
surchargeCount: fees.length || detail.surchargeCount || 0,
|
||||
extraCount: extras.length || detail.extraCount || 0,
|
||||
parseStatus: bands.length + fees.length + extras.length === 0 ? 'EMPTY' : 'OK',
|
||||
duplicated: true
|
||||
}
|
||||
} catch {
|
||||
return {
|
||||
...item,
|
||||
rowKey: `${item.sheetName || ''}-${item.productName || ''}-${item.termId || item.productId || ''}`,
|
||||
parseStatus: 'OK',
|
||||
duplicated: true
|
||||
}
|
||||
}
|
||||
}))
|
||||
productRows.value = details
|
||||
importMeta.sourceFile = details[0]?.sourceFile || ''
|
||||
importMeta.supplierName = details[0]?.supplierName || ''
|
||||
importMeta.overwrite = true
|
||||
} finally {
|
||||
loadingProducts.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function openImport() {
|
||||
importRef.value?.open()
|
||||
}
|
||||
|
||||
function onImportConfirm(payload) {
|
||||
productRows.value = payload?.products || []
|
||||
importMeta.sourceFile = payload?.sourceFile || ''
|
||||
importMeta.supplierName = payload?.supplierName || ''
|
||||
importMeta.effectiveDate = payload?.effectiveDate || ''
|
||||
importMeta.overwrite = editVersionMode.value ? true : !!payload?.overwrite
|
||||
}
|
||||
|
||||
function openDetail(row) {
|
||||
if (!row) return
|
||||
detailEditing.value = false
|
||||
detailRowKey.value = row.rowKey || `${row.sheetName || ''}-${row.productName || ''}`
|
||||
detailProduct.value = JSON.parse(JSON.stringify(row))
|
||||
detailVisible.value = true
|
||||
}
|
||||
|
||||
function startEdit() {
|
||||
detailEditing.value = true
|
||||
}
|
||||
|
||||
function onDetailClosed() {
|
||||
detailEditing.value = false
|
||||
detailProduct.value = null
|
||||
detailRowKey.value = ''
|
||||
}
|
||||
|
||||
function applyDetail() {
|
||||
const edited = detailProduct.value
|
||||
if (!edited) {
|
||||
detailVisible.value = false
|
||||
return
|
||||
}
|
||||
const key = detailRowKey.value
|
||||
const idx = productRows.value.findIndex(item => {
|
||||
const itemKey = item.rowKey || `${item.sheetName || ''}-${item.productName || ''}`
|
||||
return itemKey === key
|
||||
})
|
||||
if (idx < 0) {
|
||||
proxy.$modal.msgError('未找到对应产品行')
|
||||
return
|
||||
}
|
||||
const bands = edited.weightBands || []
|
||||
const fees = edited.surcharges || []
|
||||
const extras = edited.extraLines || []
|
||||
productRows.value.splice(idx, 1, {
|
||||
...edited,
|
||||
rowKey: productRows.value[idx].rowKey || key,
|
||||
weightCount: bands.length,
|
||||
surchargeCount: fees.length,
|
||||
extraCount: extras.length,
|
||||
parseStatus: bands.length + fees.length + extras.length === 0 ? 'EMPTY' : (edited.parseStatus || 'OK')
|
||||
})
|
||||
detailEditing.value = false
|
||||
detailVisible.value = false
|
||||
proxy.$modal.msgSuccess('已更新该产品明细')
|
||||
}
|
||||
|
||||
function statusType(status) {
|
||||
if (status === 'OK') return 'success'
|
||||
if (status === 'EMPTY') return 'warning'
|
||||
return 'danger'
|
||||
}
|
||||
|
||||
function statusText(status) {
|
||||
if (status === 'OK') return '已识别'
|
||||
if (status === 'EMPTY') return '未识别到配置'
|
||||
if (status === 'MISSING') return '缺少工作表'
|
||||
return status || '-'
|
||||
}
|
||||
|
||||
async function finish() {
|
||||
if (showBasic.value) {
|
||||
const ok = await basicRef.value?.validate()
|
||||
if (!ok) {
|
||||
proxy.$modal.msgWarning('请先完善基本信息')
|
||||
return
|
||||
}
|
||||
} else if (!priceSetId.value) {
|
||||
proxy.$modal.msgWarning(editVersionMode.value ? '缺少套餐编号,无法编辑版本' : '缺少套餐编号,无法新建版本')
|
||||
return
|
||||
}
|
||||
if (!productRows.value.length) {
|
||||
proxy.$modal.msgWarning('请先导入并确认价卡产品')
|
||||
return
|
||||
}
|
||||
const tip = editVersionMode.value
|
||||
? `将覆盖待生效版本 V${versionNo.value} 的 ${productRows.value.length} 个产品,确认继续?`
|
||||
: newVersionMode.value
|
||||
? `将为套餐「${form.basic.priceSetName || ''}」新建待生效版本并保存 ${productRows.value.length} 个产品,确认继续?`
|
||||
: `将创建打单套餐并保存 ${productRows.value.length} 个应收产品,确认继续?`
|
||||
try {
|
||||
await proxy.$modal.confirm(tip)
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
saving.value = true
|
||||
try {
|
||||
const payload = {
|
||||
overwrite: editVersionMode.value ? true : importMeta.overwrite,
|
||||
products: productRows.value
|
||||
}
|
||||
if (editVersionMode.value) {
|
||||
payload.priceSetId = priceSetId.value
|
||||
payload.versionNo = versionNo.value
|
||||
} else if (newVersionMode.value) {
|
||||
payload.priceSetId = priceSetId.value
|
||||
} else {
|
||||
payload.priceSetName = form.basic.priceSetName
|
||||
payload.priceSetNote = form.basic.priceSetNote
|
||||
}
|
||||
const res = await saveLabelImport(payload)
|
||||
const data = res.data || {}
|
||||
ElMessageBox.close()
|
||||
proxy.$modal.msgSuccess(data.message || res.msg || '保存成功')
|
||||
const id = data.priceSetId || priceSetId.value
|
||||
if (id) {
|
||||
const obj = { path: '/customer/labelDetail', query: { priceSetId: id } }
|
||||
proxy.$tab.closeOpenPage(obj)
|
||||
} else {
|
||||
goBack()
|
||||
}
|
||||
} finally {
|
||||
saving.value = false
|
||||
}
|
||||
}
|
||||
|
||||
watch([priceSetId, versionNo, () => route.query.editVersion, () => route.query.newVersion], async () => {
|
||||
await loadPackageHeader()
|
||||
await loadEditProducts()
|
||||
}, { immediate: true })
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.create-section {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
width: 100%;
|
||||
}
|
||||
.header-tip {
|
||||
margin-left: 12px;
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
font-weight: normal;
|
||||
}
|
||||
.meta-alert {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.wizard-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 12px;
|
||||
padding: 8px 0 24px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,255 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<el-page-header class="page-header" @back="goBack">
|
||||
<template #content>
|
||||
<span class="title">{{ setInfo.priceSetName || '打单套餐详情' }}</span>
|
||||
<el-tag v-if="setInfo.priceSetCode" size="small" class="code-tag">{{ setInfo.priceSetCode }}</el-tag>
|
||||
<el-tag size="small" type="warning" effect="plain">打单 / LABEL</el-tag>
|
||||
<el-tag v-if="setInfo.status" size="small" :type="setStatusTag" effect="plain" class="status-tag">{{ setStatusText }}</el-tag>
|
||||
</template>
|
||||
<template #extra>
|
||||
<el-button type="primary" plain icon="Upload" @click="importRef.open()" v-hasPermi="['price:label:import']">导入价卡</el-button>
|
||||
</template>
|
||||
</el-page-header>
|
||||
|
||||
<set-customer-table :set="setInfo" @refresh="loadHeader" />
|
||||
|
||||
<label-version-table
|
||||
:versions="versions"
|
||||
@edit="openEditVersion"
|
||||
@reschedule="openReschedule"
|
||||
@open-details="openVersionDetails"
|
||||
@create-version="openCreateVersion"
|
||||
/>
|
||||
|
||||
<label-import-dialog ref="importRef" :price-set-id="priceSetId" @saved="reloadAll" />
|
||||
|
||||
<label-version-product-drawer
|
||||
v-model:visible="productDrawerVisible"
|
||||
:price-set-id="priceSetId"
|
||||
:version="activeVersion"
|
||||
@changed="reloadAll"
|
||||
/>
|
||||
|
||||
<el-dialog
|
||||
v-model="activateVisible"
|
||||
title="修改生效时间"
|
||||
width="460px"
|
||||
append-to-body
|
||||
@closed="onActivateClosed"
|
||||
>
|
||||
<el-form ref="activateFormRef" :model="activateForm" :rules="activateRules" label-width="100px">
|
||||
<el-form-item label="版本号">
|
||||
<span>{{ activateForm.versionLabel }}</span>
|
||||
</el-form-item>
|
||||
<el-form-item label="生效时间" prop="effectiveTime">
|
||||
<el-date-picker
|
||||
v-model="activateForm.effectiveTime"
|
||||
type="date"
|
||||
value-format="YYYY-MM-DD"
|
||||
placeholder="请选择生效时间"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
<div class="activate-hint">仅待生效版本可修改;未到生效日仍为待生效,到日后自动按生效处理。</div>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="activateVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="activateSubmitting" @click="submitActivate">确认修改</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="LabelPackageDetail">
|
||||
import {
|
||||
getLabelPackage,
|
||||
listLabelVersions,
|
||||
activateLabelVersion,
|
||||
listLabelCustomer,
|
||||
addLabelCustomer,
|
||||
batchAddLabelCustomer,
|
||||
updateLabelCustomer,
|
||||
delLabelCustomer
|
||||
} from '@/api/price/label'
|
||||
import { priceSetApi } from '@/api/price/set'
|
||||
import { providePriceSetModule } from '../set/composables/usePriceSetModule'
|
||||
import SetCustomerTable from '../set/components/detail/SetCustomerTable.vue'
|
||||
import LabelImportDialog from './components/LabelImportDialog.vue'
|
||||
import LabelVersionTable from './components/LabelVersionTable.vue'
|
||||
import LabelVersionProductDrawer from './components/LabelVersionProductDrawer.vue'
|
||||
|
||||
const labelModuleApi = {
|
||||
...priceSetApi,
|
||||
listSetCustomer: listLabelCustomer,
|
||||
addSetCustomer: addLabelCustomer,
|
||||
batchAddSetCustomer: batchAddLabelCustomer,
|
||||
updateSetCustomer: updateLabelCustomer,
|
||||
delSetCustomer: delLabelCustomer
|
||||
}
|
||||
|
||||
providePriceSetModule({
|
||||
api: labelModuleApi,
|
||||
permPrefix: 'price:label',
|
||||
exclusiveQuote: false,
|
||||
onlyImportFresh: false,
|
||||
routes: Object.freeze({
|
||||
list: '/customer/label',
|
||||
create: '/customer/labelCreate',
|
||||
detail: '/customer/labelDetail'
|
||||
}),
|
||||
labels: Object.freeze({
|
||||
entity: '打单套餐',
|
||||
entityCode: '套餐编码',
|
||||
entityName: '套餐名称',
|
||||
createButton: '新建打单套餐',
|
||||
saveProgressTitle: '正在保存打单套餐',
|
||||
savedSuccess: '打单套餐已保存',
|
||||
noActiveVersion: '该打单套餐暂无生效版本',
|
||||
disableConfirm: '停用后该打单套餐不再参与计费命中,确认停用【{name}】?',
|
||||
enableConfirm: '启用后该打单套餐将重新参与计费命中,确认启用【{name}】?',
|
||||
basicEditTitle: '修改打单套餐基本信息',
|
||||
keywordPlaceholder: '套餐编码 / 名称',
|
||||
detailTitleFallback: '打单套餐详情'
|
||||
})
|
||||
})
|
||||
|
||||
const { proxy } = getCurrentInstance()
|
||||
const route = useRoute()
|
||||
const priceSetId = computed(() => Number(route.query.priceSetId) || null)
|
||||
const setInfo = reactive({
|
||||
priceSetId: null,
|
||||
priceSetCode: '',
|
||||
priceSetName: '',
|
||||
priceSetNote: '',
|
||||
status: '',
|
||||
customers: []
|
||||
})
|
||||
const versions = ref([])
|
||||
const importRef = ref()
|
||||
const productDrawerVisible = ref(false)
|
||||
const activeVersion = ref(null)
|
||||
|
||||
const setStatusText = computed(() => {
|
||||
const map = { D: '待启用', A: '审核中', E: '生效', R: '驳回', S: '已停用' }
|
||||
return map[setInfo.status] || setInfo.status || '-'
|
||||
})
|
||||
const setStatusTag = computed(() => {
|
||||
const map = { D: 'info', A: 'warning', E: 'success', R: 'danger', S: 'info' }
|
||||
return map[setInfo.status] || 'info'
|
||||
})
|
||||
|
||||
const activateVisible = ref(false)
|
||||
const activateSubmitting = ref(false)
|
||||
const activateFormRef = ref()
|
||||
const activateForm = reactive({
|
||||
versionNo: null,
|
||||
versionLabel: '',
|
||||
effectiveTime: undefined
|
||||
})
|
||||
const activateRules = {
|
||||
effectiveTime: [{ required: true, message: '请选择生效时间', trigger: 'change' }]
|
||||
}
|
||||
|
||||
function goBack() {
|
||||
proxy.$router.push('/customer/label')
|
||||
}
|
||||
|
||||
async function loadHeader() {
|
||||
if (!priceSetId.value) return
|
||||
const res = await getLabelPackage(priceSetId.value)
|
||||
const data = res.data || {}
|
||||
setInfo.priceSetId = data.priceSetId
|
||||
setInfo.priceSetCode = data.priceSetCode || ''
|
||||
setInfo.priceSetName = data.priceSetName || ''
|
||||
setInfo.priceSetNote = data.priceSetNote || ''
|
||||
setInfo.status = data.status || ''
|
||||
setInfo.customers = data.customers || []
|
||||
}
|
||||
|
||||
async function loadVersions() {
|
||||
if (!priceSetId.value) return
|
||||
const res = await listLabelVersions(priceSetId.value)
|
||||
versions.value = res.data || []
|
||||
}
|
||||
|
||||
async function reloadAll() {
|
||||
await loadHeader()
|
||||
await loadVersions()
|
||||
}
|
||||
|
||||
function openVersionDetails(row) {
|
||||
activeVersion.value = row || null
|
||||
productDrawerVisible.value = true
|
||||
}
|
||||
|
||||
/** 跳转新建版本页;已有待生效版时按钮会禁用 */
|
||||
function openCreateVersion() {
|
||||
if (!priceSetId.value) return
|
||||
if ((versions.value || []).some(v => String(v.status) === '0')) {
|
||||
proxy.$modal.msgWarning('已有待生效版本,请先处理后再新建')
|
||||
return
|
||||
}
|
||||
proxy.$router.push({
|
||||
path: '/customer/labelCreate',
|
||||
query: { priceSetId: priceSetId.value, newVersion: '1' }
|
||||
})
|
||||
}
|
||||
|
||||
/** 编辑待生效版本价卡 */
|
||||
function openEditVersion(row) {
|
||||
if (!priceSetId.value || !row?.versionNo) return
|
||||
proxy.$router.push({
|
||||
path: '/customer/labelCreate',
|
||||
query: {
|
||||
priceSetId: priceSetId.value,
|
||||
versionNo: row.versionNo,
|
||||
editVersion: '1'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function openReschedule(row) {
|
||||
activateForm.versionNo = row.versionNo
|
||||
activateForm.versionLabel = row.versionLabel || ('V' + row.versionNo)
|
||||
activateForm.effectiveTime = row.effectiveTime ? String(row.effectiveTime).slice(0, 10) : undefined
|
||||
activateVisible.value = true
|
||||
}
|
||||
|
||||
function onActivateClosed() {
|
||||
activateForm.versionNo = null
|
||||
activateForm.versionLabel = ''
|
||||
activateForm.effectiveTime = undefined
|
||||
activateSubmitting.value = false
|
||||
}
|
||||
|
||||
function submitActivate() {
|
||||
activateFormRef.value?.validate(valid => {
|
||||
if (!valid) return
|
||||
activateSubmitting.value = true
|
||||
activateLabelVersion(priceSetId.value, activateForm.versionNo, {
|
||||
effectiveTime: activateForm.effectiveTime
|
||||
}).then(res => {
|
||||
const data = res.data || {}
|
||||
proxy.$modal.msgSuccess(data.message || res.msg || '操作成功')
|
||||
activateVisible.value = false
|
||||
reloadAll()
|
||||
}).finally(() => {
|
||||
activateSubmitting.value = false
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
watch(priceSetId, async (id) => {
|
||||
if (!id) return
|
||||
await reloadAll()
|
||||
}, { immediate: true })
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page-header { margin-bottom: 16px; }
|
||||
.title { font-weight: 600; margin-right: 8px; }
|
||||
.code-tag { margin-right: 8px; }
|
||||
.status-tag { margin-left: 8px; }
|
||||
.activate-hint { margin: -4px 0 0 100px; color: #909399; font-size: 12px; line-height: 1.5; }
|
||||
</style>
|
||||
@@ -0,0 +1,190 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<basic-table
|
||||
ref="tableRef"
|
||||
:columns="columns"
|
||||
:search-columns="searchColumns"
|
||||
:query="queryList"
|
||||
row-key="priceSetId"
|
||||
>
|
||||
<template #toolbar>
|
||||
<el-col :span="1.5">
|
||||
<el-button type="primary" plain icon="Plus" @click="handleCreate" v-hasPermi="['price:label:add']">新建打单套餐</el-button>
|
||||
</el-col>
|
||||
</template>
|
||||
|
||||
<template #col-setType>
|
||||
<el-tag type="warning" size="small" effect="plain">打单 / LABEL</el-tag>
|
||||
</template>
|
||||
|
||||
<template #col-status="{ row }">
|
||||
<el-tag :type="statusTag(row)" size="small">{{ statusLabel(row) }}</el-tag>
|
||||
</template>
|
||||
|
||||
<template #col-action="{ row }">
|
||||
<el-button link type="primary" @click="handleDetail(row)" v-hasPermi="['price:label:query']">详情</el-button>
|
||||
<el-button link type="primary" @click="openBasicEdit(row)" v-hasPermi="['price:label:edit']">修改</el-button>
|
||||
<el-button
|
||||
v-if="row.status === 'E'"
|
||||
link
|
||||
type="warning"
|
||||
@click="handleDisable(row)"
|
||||
v-hasPermi="['price:label:audit']"
|
||||
>停用</el-button>
|
||||
<el-button
|
||||
v-if="row.status === 'D' || row.status === 'S'"
|
||||
link
|
||||
type="success"
|
||||
@click="handleEnable(row)"
|
||||
v-hasPermi="['price:label:audit']"
|
||||
>启用</el-button>
|
||||
</template>
|
||||
</basic-table>
|
||||
|
||||
<el-dialog v-model="basicDialog.visible" :title="basicDialogTitle" width="520px" append-to-body destroy-on-close>
|
||||
<el-form ref="basicFormRef" :model="basicForm" :rules="basicRules" label-width="96px">
|
||||
<el-form-item label="套餐编码">
|
||||
<el-input :model-value="basicForm.priceSetCode" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item label="套餐名称" prop="priceSetName">
|
||||
<el-input v-model="basicForm.priceSetName" maxlength="50" show-word-limit placeholder="请输入套餐名称" />
|
||||
</el-form-item>
|
||||
<el-form-item label="说明备注" prop="priceSetNote">
|
||||
<el-input v-model="basicForm.priceSetNote" type="textarea" :rows="3" maxlength="200" show-word-limit placeholder="可选" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="basicDialog.visible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="basicDialog.saving" @click="submitBasicEdit">确定</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="LabelPackage">
|
||||
import { setStatusLabel, setStatusTagType } from '@/views/price/set/utils/priceSet'
|
||||
import {
|
||||
listLabelPackage,
|
||||
updateLabelBasic,
|
||||
disableLabelPackage,
|
||||
enableLabelPackage
|
||||
} from '@/api/price/label'
|
||||
|
||||
const { proxy } = getCurrentInstance()
|
||||
const tableRef = ref()
|
||||
const isFirstActivate = ref(true)
|
||||
|
||||
const searchColumns = [
|
||||
{
|
||||
label: '状态',
|
||||
prop: 'status',
|
||||
component: 'select',
|
||||
options: [
|
||||
{ label: '待启用', value: 'D' },
|
||||
{ label: '生效', value: 'E' },
|
||||
{ label: '已停用', value: 'S' }
|
||||
],
|
||||
placeholder: '全部状态',
|
||||
width: '140px'
|
||||
},
|
||||
{ label: '关键字', prop: 'keyword', component: 'input', placeholder: '套餐编码 / 名称', width: '200px' }
|
||||
]
|
||||
|
||||
const columns = [
|
||||
{ label: '套餐编码', prop: 'priceSetCode', width: 110 },
|
||||
{ label: '套餐名称', prop: 'priceSetName', minWidth: 160 },
|
||||
{ label: '类型', prop: 'setType', width: 140 },
|
||||
{ label: '产品数', prop: 'productCount', width: 90, align: 'center' },
|
||||
{ label: '说明', prop: 'priceSetNote', minWidth: 140 },
|
||||
{ label: '状态', prop: 'status', width: 90 },
|
||||
{ label: '操作', prop: 'action', width: 200, showInToolbar: false }
|
||||
]
|
||||
|
||||
function queryList(params) {
|
||||
return listLabelPackage(params)
|
||||
}
|
||||
|
||||
function statusLabel(row) {
|
||||
return setStatusLabel(row)
|
||||
}
|
||||
|
||||
function statusTag(row) {
|
||||
return setStatusTagType(row)
|
||||
}
|
||||
|
||||
function handleCreate() {
|
||||
proxy.$router.push({ path: '/customer/labelCreate' })
|
||||
}
|
||||
|
||||
function handleDetail(row) {
|
||||
proxy.$router.push({ path: '/customer/labelDetail', query: { priceSetId: row.priceSetId } })
|
||||
}
|
||||
|
||||
const basicDialog = reactive({ visible: false, saving: false })
|
||||
const basicFormRef = ref()
|
||||
const basicForm = reactive({
|
||||
priceSetId: null,
|
||||
priceSetCode: '',
|
||||
priceSetName: '',
|
||||
priceSetNote: ''
|
||||
})
|
||||
const basicRules = {
|
||||
priceSetName: [{ required: true, message: '名称不能为空', trigger: 'blur' }]
|
||||
}
|
||||
const basicDialogTitle = '修改打单套餐基本信息'
|
||||
|
||||
function openBasicEdit(row) {
|
||||
if (!row || row.priceSetId == null) return
|
||||
basicForm.priceSetId = row.priceSetId
|
||||
basicForm.priceSetCode = row.priceSetCode || ''
|
||||
basicForm.priceSetName = row.priceSetName || ''
|
||||
basicForm.priceSetNote = row.priceSetNote || ''
|
||||
basicDialog.visible = true
|
||||
nextTick(() => basicFormRef.value && basicFormRef.value.clearValidate())
|
||||
}
|
||||
|
||||
function submitBasicEdit() {
|
||||
basicFormRef.value.validate(valid => {
|
||||
if (!valid) return
|
||||
basicDialog.saving = true
|
||||
updateLabelBasic({
|
||||
priceSetId: basicForm.priceSetId,
|
||||
priceSetName: basicForm.priceSetName,
|
||||
priceSetNote: basicForm.priceSetNote
|
||||
}).then(() => {
|
||||
proxy.$modal.msgSuccess('保存成功')
|
||||
basicDialog.visible = false
|
||||
tableRef.value?.refresh()
|
||||
}).finally(() => {
|
||||
basicDialog.saving = false
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function handleDisable(row) {
|
||||
proxy.$modal.confirm(`停用后该打单套餐不再参与计费命中,确认停用【${row.priceSetName}】?`).then(() => {
|
||||
return disableLabelPackage(row.priceSetId)
|
||||
}).then(() => {
|
||||
proxy.$modal.msgSuccess('已停用')
|
||||
tableRef.value?.refresh()
|
||||
}).catch(() => {})
|
||||
}
|
||||
|
||||
function handleEnable(row) {
|
||||
proxy.$modal.confirm(`启用后该打单套餐将重新参与计费命中,确认启用【${row.priceSetName}】?`).then(() => {
|
||||
return enableLabelPackage(row.priceSetId)
|
||||
}).then(() => {
|
||||
proxy.$modal.msgSuccess('已启用')
|
||||
tableRef.value?.refresh()
|
||||
}).catch(() => {})
|
||||
}
|
||||
|
||||
onActivated(() => {
|
||||
if (isFirstActivate.value) {
|
||||
isFirstActivate.value = false
|
||||
return
|
||||
}
|
||||
tableRef.value?.reload()
|
||||
})
|
||||
</script>
|
||||
Reference in New Issue
Block a user