修改类型

This commit is contained in:
wuweihua
2026-11-10 14:38:38 +08:00
parent de5784cbac
commit e6a9fcf0a2
12 changed files with 808 additions and 337 deletions
@@ -60,9 +60,10 @@
<el-table-column prop="priceUnit" label="单位" width="110" show-overflow-tooltip>
<template #default="{ row }"><cell-text v-model="row.priceUnit" :edit="editable" /></template>
</el-table-column>
<el-table-column v-if="editable" label="操作" width="70" align="center">
<el-table-column v-if="editable" label="操作" width="120" align="center" fixed="right">
<template #default="{ row }">
<el-button link type="danger" @click="removeRow(pane.item.weightBands, row)">删除</el-button>
<el-button link type="primary" :loading="isRowSaving(row)" @click="saveBandRow(pane, row)">保存</el-button>
<el-button link type="danger" :disabled="!!savingRowKey" @click="removeRow(pane.item.weightBands, row)">删除</el-button>
</template>
</el-table-column>
</el-table>
@@ -82,8 +83,27 @@
<el-button v-if="editable" size="small" type="primary" plain @click="addFee(pane)">添加附加费</el-button>
</div>
<el-table :data="pageFees(pane)" border size="small" max-height="360" empty-text="没有附加费">
<el-table-column prop="feeName" label="附加费用" min-width="160" show-overflow-tooltip>
<template #default="{ row }"><cell-text v-model="row.feeName" :edit="editable" /></template>
<el-table-column prop="feeName" label="附加费用" min-width="180" show-overflow-tooltip>
<template #default="{ row }">
<el-select
v-if="editable"
v-model="row.feeName"
filterable
clearable
size="small"
style="width: 100%"
:placeholder="'请选择附加费'"
@change="name => onFeeNameChange(row, name)"
>
<el-option
v-for="item in feeNameOptions(row)"
:key="item"
:label="item"
:value="item"
/>
</el-select>
<span v-else>{{ row.feeName || '-' }}</span>
</template>
</el-table-column>
<el-table-column prop="zoneName" label="地区" min-width="160" show-overflow-tooltip>
<template #default="{ row }"><cell-text v-model="row.zoneName" :edit="editable" /></template>
@@ -94,10 +114,52 @@
<span v-else>{{ money(row.amount) }}</span>
</template>
</el-table-column>
<el-table-column label="货币" width="120" show-overflow-tooltip>
<el-table-column label="币种" width="110" show-overflow-tooltip>
<template #default="{ row }">
<cell-text v-if="editable" v-model="row.priceUnit" :edit="true" />
<span v-else>{{ row.priceUnit || row.currency || '-' }}</span>
<el-select
v-if="editable"
:model-value="feeCurrencyOf(row)"
filterable
allow-create
default-first-option
clearable
size="small"
style="width: 100%"
:placeholder="'币种'"
@update:model-value="value => setFeeCurrency(row, value)"
>
<el-option
v-for="item in currencyOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<span v-else>{{ feeCurrencyOf(row) || '-' }}</span>
</template>
</el-table-column>
<el-table-column label="单位" width="110" show-overflow-tooltip>
<template #default="{ row }">
<el-select
v-if="editable"
:model-value="feeUnitOf(row)"
filterable
allow-create
default-first-option
clearable
size="small"
style="width: 100%"
:placeholder="'单位'"
@update:model-value="value => setFeeUnit(row, value)"
>
<el-option
v-for="item in feeUnitOptions"
:key="item"
:label="item"
:value="item"
/>
</el-select>
<span v-else>{{ feeUnitOf(row) || '-' }}</span>
</template>
</el-table-column>
<el-table-column label="收费标准" min-width="180" show-overflow-tooltip>
@@ -119,13 +181,21 @@
</el-table-column>
<el-table-column prop="calcParam" label="条件参数" min-width="220" show-overflow-tooltip>
<template #default="{ row }">
<div>{{ feeCondition(row) }}</div>
<cell-text v-if="editable" v-model="row.calcParam" :edit="editable" />
<span v-if="!editable">{{ feeCondition(row) }}</span>
<template v-else>
<div v-if="conditionHint(row)" class="pay-cond-hint">{{ conditionHint(row) }}</div>
<cell-text
v-if="showCalcParamEditor(row)"
v-model="row.calcParam"
:edit="true"
/>
</template>
</template>
</el-table-column>
<el-table-column v-if="editable" label="操作" width="70" align="center">
<el-table-column v-if="editable" label="操作" width="120" align="center" fixed="right">
<template #default="{ row }">
<el-button link type="danger" @click="removeRow(pane.item.surcharges, row)">删除</el-button>
<el-button link type="primary" :loading="isRowSaving(row)" @click="saveFeeRow(pane, row)">保存</el-button>
<el-button link type="danger" :disabled="!!savingRowKey" @click="removeRow(pane.item.surcharges, row)">删除</el-button>
</template>
</el-table-column>
</el-table>
@@ -163,8 +233,9 @@
<script setup>
// 重量段和附加费。传入 products 时一次展示全部产品。
import { h } from 'vue'
import { h, onMounted } from 'vue'
import { ElInput } from 'element-plus'
import { listSurchargeOptions } from '@/api/price/surcharge'
const props = defineProps({
product: {
@@ -178,9 +249,140 @@ const props = defineProps({
editable: {
type: Boolean,
default: false
},
savingRowKey: {
type: [String, Number],
default: ''
}
})
const emit = defineEmits(['save-row'])
function rowKeyOf(row) {
if (!row) return ''
if (row.surchargeId != null) return 'fee-' + row.surchargeId
if (row.bandId != null) return 'band-' + row.bandId
if (row.__rowKey) return row.__rowKey
row.__rowKey = 'tmp-' + Date.now() + '-' + Math.random().toString(36).slice(2, 8)
return row.__rowKey
}
function isRowSaving(row) {
return props.savingRowKey && String(props.savingRowKey) === String(rowKeyOf(row))
}
function saveBandRow(pane, row) {
emit('save-row', { kind: 'band', product: pane.item, row, rowKey: rowKeyOf(row) })
}
function saveFeeRow(pane, row) {
emit('save-row', { kind: 'fee', product: pane.item, row, rowKey: rowKeyOf(row) })
}
const surchargeOptions = ref([])
const { bms_currency } = useDict('bms_currency')
const currencyOptions = computed(() => (bms_currency.value || []).map(item => ({
label: item.label || item.value,
value: item.value
})))
const feeUnitOptions = ['ITEM', 'KG', 'PCS', 'PARCEL', '%']
function parseFeeUnit(priceUnit) {
const text = String(priceUnit || '').trim()
if (!text) return ''
if (text === '%') return '%'
const slash = text.lastIndexOf('/')
if (slash >= 0) {
return text.slice(slash + 1).trim().toUpperCase()
}
if (/^[A-Za-z]{3}$/.test(text)) return ''
return text.toUpperCase()
}
function feeCurrencyOf(row) {
const currency = String(row?.currency || '').trim()
if (currency) return currency.toUpperCase()
const text = String(row?.priceUnit || '').trim()
const match = text.match(/^([A-Za-z]{3})(?:\/|$)/)
return match ? match[1].toUpperCase() : ''
}
function feeUnitOf(row) {
return parseFeeUnit(row?.priceUnit)
}
function syncFeePriceUnit(row, unitOverride) {
const currency = feeCurrencyOf(row)
const unit = unitOverride != null ? String(unitOverride || '').trim().toUpperCase() : feeUnitOf(row)
if (unit === '%') {
row.priceUnit = '%'
return
}
if (currency && unit) {
row.priceUnit = currency + '/' + unit
return
}
if (currency) {
row.priceUnit = currency
return
}
row.priceUnit = unit || ''
}
function setFeeCurrency(row, value) {
const currency = String(value || '').trim().toUpperCase()
row.currency = currency
syncFeePriceUnit(row)
}
function setFeeUnit(row, value) {
syncFeePriceUnit(row, value)
}
function loadSurchargeOptions() {
return listSurchargeOptions({ ssCode: 'on' }).then(res => {
surchargeOptions.value = res.data || []
}).catch(() => {
surchargeOptions.value = []
})
}
function feeNameOptions(row) {
const names = []
const seen = new Set()
for (const item of surchargeOptions.value || []) {
const name = String(item?.scName || '').trim()
if (!name || seen.has(name)) continue
seen.add(name)
names.push(name)
}
const current = String(row?.feeName || '').trim()
if (current && !seen.has(current)) {
names.unshift(current)
}
return names
}
function onFeeNameChange(row, name) {
const matched = (surchargeOptions.value || []).find(item => String(item?.scName || '').trim() === String(name || '').trim())
if (!matched) {
row.scId = undefined
return
}
row.scId = matched.scId
const currency = matched.currency || feeCurrencyOf(row)
if (currency) {
setFeeCurrency(row, currency)
}
if (!feeUnitOf(row)) {
setFeeUnit(row, 'ITEM')
}
}
onMounted(() => {
loadSurchargeOptions()
})
const CellText = {
props: { modelValue: { default: '' }, edit: Boolean },
emits: ['update:modelValue'],
@@ -210,7 +412,7 @@ function calcRuleLabel(value) {
return calcRules.find(item => item.value === value)?.label || '人工确认'
}
function feeCondition(row) {
function conditionHint(row) {
const parts = []
const hasMin = row.weightMin != null && row.weightMin !== ''
const hasMax = row.weightMax != null && row.weightMax !== ''
@@ -220,9 +422,24 @@ function feeCondition(row) {
if (row.postcodeParam) {
parts.push(`邮编 ${row.postcodeParam}`)
}
if (row.calcParam && row.calcParam !== row.postcodeParam) {
parts.push(String(row.calcParam))
}
return parts.join(';')
}
function hasCalcParam(row) {
const text = String(row?.calcParam ?? '').trim()
if (!text) return false
return text !== String(row?.postcodeParam ?? '').trim()
}
function showCalcParamEditor(row) {
return hasCalcParam(row) || !conditionHint(row)
}
function feeCondition(row) {
const parts = []
const hint = conditionHint(row)
if (hint) parts.push(hint)
if (hasCalcParam(row)) parts.push(String(row.calcParam).trim())
return parts.join(';') || '-'
}
@@ -261,7 +478,19 @@ function addBand(pane) {
function addFee(pane) {
if (!pane.item.surcharges) pane.item.surcharges = []
pane.item.surcharges.push({ feeName: '', zoneName: '', chargeText: '', amount: '', priceUnit: '', currency: '', feeDesc: '', calcRule: 'MANUAL', calcParam: '' })
const currency = String(pane.item.currency || 'EUR').trim().toUpperCase() || 'EUR'
pane.item.surcharges.push({
feeName: '',
scId: undefined,
zoneName: '',
chargeText: '',
amount: '',
priceUnit: currency + '/ITEM',
currency,
feeDesc: '',
calcRule: 'MANUAL',
calcParam: ''
})
pane.feePageNo = Math.ceil(pane.item.surcharges.length / pageSize) || 1
}
@@ -384,6 +613,10 @@ function statusText(status) {
margin-top: 8px;
justify-content: flex-end;
}
.pay-cond-hint {
line-height: 1.5;
color: var(--el-text-color-regular);
}
.limit-tag {
margin-right: 6px;
}
+40 -12
View File
@@ -134,13 +134,31 @@
</el-table>
</el-drawer>
<el-drawer v-model="detailVisible" :title="detailTitle" size="78%" destroy-on-close>
<pay-config-detail v-loading="detailLoading" :product="detail" :editable="editing" />
<el-drawer
v-model="detailVisible"
:title="detailTitle"
size="78%"
append-to-body
:close-on-click-modal="false"
@closed="editing = false"
>
<pay-config-detail
v-loading="detailLoading || !!savingRowKey"
:product="detail"
:editable="editing"
:saving-row-key="savingRowKey"
@save-row="saveProductRow"
/>
<template #footer>
<el-button v-if="detail" @click="downloadSource(detail)" v-hasPermi="['price:pay:query']">下载源文件</el-button>
<el-button v-if="!editing" type="primary" @click="editing = true" v-hasPermi="['price:pay:import']">编辑</el-button>
<el-button v-else type="primary" :loading="saving" @click="saveDetail">保存</el-button>
<el-button @click="detailVisible = false">关闭</el-button>
<el-button v-if="detail" @click="downloadSource(detail)" v-hasPermi="['price:pay:query']">下载源文件</el-button>
<el-button
v-if="!editing"
type="primary"
@click="editing = true"
v-hasPermi="['price:pay:import']"
>编辑</el-button>
<el-button v-else @click="editing = false">完成</el-button>
</template>
</el-drawer>
</div>
@@ -157,7 +175,7 @@ const importRef = ref()
const detailVisible = ref(false)
const detailLoading = ref(false)
const editing = ref(false)
const saving = ref(false)
const savingRowKey = ref('')
const detail = ref(null)
const historyVisible = ref(false)
const historyLoading = ref(false)
@@ -275,6 +293,7 @@ function handleDelete(ids) {
function openDetail(row) {
detailVisible.value = true
editing.value = false
savingRowKey.value = ''
detailLoading.value = true
detail.value = null
getPay(row.versionProductId || row.productId).then(res => {
@@ -284,15 +303,24 @@ function openDetail(row) {
})
}
function saveDetail() {
function saveProductRow(payload) {
if (!detail.value || savingRowKey.value) return
cleanMoney(detail.value)
saving.value = true
;(detail.value.surcharges || []).forEach(row => {
if (row.amount === '') row.amount = null
})
const productId = detail.value.productId
savingRowKey.value = payload?.rowKey || 'row'
updatePay(detail.value).then(() => {
proxy.$modal.msgSuccess('已保存这一版。产品编号不变,绑定该产品的渠道按有效期取价')
editing.value = false
tableRef.value.refresh()
proxy.$modal.msgSuccess('该行已保存')
if (!productId) return
return getPay(productId).then(res => {
if (res.data) detail.value = res.data
})
}).then(() => {
tableRef.value?.refresh()
}).finally(() => {
saving.value = false
savingRowKey.value = ''
})
}