Files
BMS/bms-front/src/views/price/set/components/create/SurchargePickerDialog.vue
T

149 lines
5.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<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>