149 lines
5.0 KiB
Vue
149 lines
5.0 KiB
Vue
<template>
|
||
<el-dialog
|
||
v-model="visible"
|
||
:title="title"
|
||
width="1000px"
|
||
append-to-body
|
||
class="ps-dialog"
|
||
>
|
||
<div class="ps-picker-bar">
|
||
<span>共 {{ rows.length }} 项附加费配置,勾选后写入所选范围的明细行</span>
|
||
<span class="ps-picker-bar__picked">已选 {{ picked.length }} 项</span>
|
||
</div>
|
||
|
||
<el-table
|
||
ref="tableRef"
|
||
:data="rows"
|
||
row-key="scId"
|
||
border
|
||
size="small"
|
||
max-height="400"
|
||
empty-text="暂无附加费配置"
|
||
@selection-change="onSelectionChange"
|
||
>
|
||
<el-table-column type="selection" width="46" />
|
||
<el-table-column label="附加费名称" prop="scName" min-width="150" show-overflow-tooltip />
|
||
<el-table-column label="计费方式" width="200" align="center">
|
||
<template #default="{ row }">{{ chargeTypeLabel(row.chargeType) }}</template>
|
||
</el-table-column>
|
||
<el-table-column label="计费值" width="130" align="right">
|
||
<template #default="{ row }">{{ formatChargeValue(row) }}</template>
|
||
</el-table-column>
|
||
<el-table-column label="作用范围" min-width="170" show-overflow-tooltip>
|
||
<template #default="{ row }">{{ row.scopeText }}</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
|
||
<div class="ps-hint ps-hint--block">取消勾选即不纳入本套餐;「作用范围」表示该附加费自身计费适用的国家(如「燃油附加费 RO」仅对罗马尼亚计费),勾选后按所选范围写回明细行,计费时再按国家匹配。</div>
|
||
|
||
<template #footer>
|
||
<el-button @click="visible = false">取 消</el-button>
|
||
<el-button type="primary" @click="submit">确 定</el-button>
|
||
</template>
|
||
</el-dialog>
|
||
</template>
|
||
|
||
<script setup name="SurchargePickerDialog">
|
||
/**
|
||
* 套餐 · 附加费勾选弹窗(新建流程第 3 步)
|
||
*
|
||
* 数据来源:产品已关联的附加费配置(prc_surcharge_rel ∩ prc_surcharge),
|
||
* 与明细表格里「附加费」列展示的口径一致;勾选结果由父级写回该产品的明细行。
|
||
*/
|
||
import { formatChargeValue, surchargeScopeLabel } from '../../utils/priceSet'
|
||
|
||
const props = defineProps({
|
||
modelValue: { type: Boolean, default: false },
|
||
title: { type: String, default: '附加费' },
|
||
/** 附加费配置主表全量(refData.allSurchargeConfigs()) */
|
||
list: { type: Array, default: () => [] },
|
||
/** 当前已勾选的 scId 集合,用于打开时回显 */
|
||
selectedIds: { type: Array, default: () => [] }
|
||
})
|
||
const emit = defineEmits(['update:modelValue', 'confirm'])
|
||
|
||
const tableRef = ref()
|
||
const picked = ref([])
|
||
|
||
const visible = computed({
|
||
get: () => props.modelValue,
|
||
set: v => emit('update:modelValue', v)
|
||
})
|
||
|
||
/** 同一附加费可能同时挂在产品级与国家/重量段上,按 scId 合并成一行,作用范围拼接展示 */
|
||
const rows = computed(() => {
|
||
const map = new Map()
|
||
;(props.list || []).forEach(rel => {
|
||
if (!rel || rel.scId == null) return
|
||
const key = String(rel.scId)
|
||
if (!map.has(key)) {
|
||
map.set(key, { ...rel, scopeTexts: [] })
|
||
}
|
||
const item = map.get(key)
|
||
const text = surchargeScopeLabel(rel)
|
||
if (!item.scopeTexts.includes(text)) item.scopeTexts.push(text)
|
||
})
|
||
return [...map.values()].map(item => ({
|
||
...item,
|
||
scopeText: item.scopeTexts.join(' / ')
|
||
}))
|
||
})
|
||
|
||
const chargeTypeLabelMap = {
|
||
MANUAL: '暂不计费',
|
||
ALWAYS: '每票都收',
|
||
POSTCODE: '命中邮编',
|
||
ZONE: '命中分区',
|
||
EXTRA_KG: '超重续收',
|
||
WEIGHT: '超重',
|
||
SIZE: '超尺寸',
|
||
RETURN: '退件',
|
||
FIXED: '每票都收',
|
||
RATE: '暂不计费'
|
||
}
|
||
|
||
function chargeTypeLabel(val) {
|
||
if (!val) return chargeTypeLabelMap.MANUAL
|
||
return chargeTypeLabelMap[val] || chargeTypeLabelMap[String(val).toUpperCase()] || val
|
||
}
|
||
|
||
function onSelectionChange(selection) {
|
||
picked.value = selection
|
||
}
|
||
|
||
/** 确定:以表格当前选中为准(回显/重渲染可能清掉 selection,不能只信 selection-change 的快照) */
|
||
function submit() {
|
||
const table = tableRef.value
|
||
let list = picked.value
|
||
if (table && typeof table.getSelection === 'function') {
|
||
const cur = table.getSelection() || []
|
||
if (cur.length || !list.length) list = cur
|
||
}
|
||
emit('confirm', list)
|
||
visible.value = false
|
||
}
|
||
|
||
/** 回显勾选:首次打开时 el-dialog 内容才挂载,取不到表格就再等一帧(最多 5 帧) */
|
||
function applySelection(ids, tries) {
|
||
const table = tableRef.value
|
||
if (!table) {
|
||
if ((tries || 0) < 5) nextTick(() => applySelection(ids, (tries || 0) + 1))
|
||
return
|
||
}
|
||
table.clearSelection()
|
||
rows.value.forEach(row => {
|
||
table.toggleRowSelection(row, ids.includes(String(row.scId)))
|
||
})
|
||
picked.value = rows.value.filter(row => ids.includes(String(row.scId)))
|
||
}
|
||
|
||
watch(() => props.modelValue, v => {
|
||
if (!v) return
|
||
const ids = (props.selectedIds || []).map(id => String(id))
|
||
nextTick(() => applySelection(ids, 0))
|
||
})
|
||
</script>
|
||
|
||
<!-- 非 scoped:弹窗被 append-to-body 传送到 body,样式需全局生效;.ps-picker-bar 工具类见 styles/dialog.scss -->
|
||
<style lang="scss" src="../../styles/dialog.scss"></style>
|