新增订单计费失败原因的价格周期字段,并优化前端展示,支持查看价格周期详情。
This commit is contained in:
@@ -0,0 +1,165 @@
|
||||
<template>
|
||||
<el-drawer
|
||||
:model-value="modelValue"
|
||||
:title="drawerTitle"
|
||||
size="720px"
|
||||
append-to-body
|
||||
destroy-on-close
|
||||
@close="close"
|
||||
>
|
||||
<div v-loading="loading" class="cycle-body">
|
||||
<el-empty v-if="!loading && !versions.length" :description="emptyText" :image-size="72" />
|
||||
<el-table v-else :data="versions" border height="calc(100vh - 220px)">
|
||||
<el-table-column :label="colVer" prop="versionNo" width="90" align="center" />
|
||||
<el-table-column :label="colEff" min-width="170">
|
||||
<template #default="{ row }">{{ row.effectiveTime || '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="colExp" min-width="170">
|
||||
<template #default="{ row }">{{ row.expireTime || '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="colStatus" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="versionStatusTag(row.status)" size="small">{{ versionStatusLabel(row.status) }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="colRows" width="90" align="center">
|
||||
<template #default="{ row }">{{ row.detailCount != null ? row.detailCount : '-' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="colAction" width="100" align="center" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button link type="primary" @click="openDetail(row)">查看</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-button @click="close">关闭</el-button>
|
||||
</template>
|
||||
|
||||
<set-version-detail-drawer
|
||||
v-model="detailVisible"
|
||||
:version="detailVersion"
|
||||
:set-type="setType || 'FIXED'"
|
||||
/>
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
||||
<script setup name="OrderBillPriceCycleListDrawer">
|
||||
import { priceSetApi } from '@/api/price/set'
|
||||
import { exclusiveQuoteApi } from '@/api/price/exclusive'
|
||||
import { versionStatusLabel, versionStatusTag } from '../../set/utils/priceSet'
|
||||
import SetVersionDetailDrawer from '../../set/components/detail/SetVersionDetailDrawer.vue'
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: { type: Boolean, default: false },
|
||||
priceSetId: { type: [Number, String], default: null },
|
||||
priceSetCode: { type: String, default: '' },
|
||||
priceSetName: { type: String, default: '' },
|
||||
setType: { type: String, default: 'FIXED' }
|
||||
})
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
|
||||
const loading = ref(false)
|
||||
const versions = ref([])
|
||||
const detailVisible = ref(false)
|
||||
const detailVersion = ref(null)
|
||||
|
||||
const emptyText = '暂无价格周期'
|
||||
const colVer = '版本号'
|
||||
const colEff = '生效时间'
|
||||
const colExp = '失效时间'
|
||||
const colStatus = '状态'
|
||||
const colRows = '明细行数'
|
||||
const colAction = '操作'
|
||||
|
||||
const drawerTitle = computed(() => {
|
||||
const code = (props.priceSetCode || '').trim()
|
||||
const name = (props.priceSetName || '').trim()
|
||||
let pkg = '-'
|
||||
if (code && name && code !== name) pkg = code + ' / ' + name
|
||||
else if (code || name) pkg = code || name
|
||||
return '价格周期列表 · ' + pkg
|
||||
})
|
||||
|
||||
function close() {
|
||||
emit('update:modelValue', false)
|
||||
}
|
||||
|
||||
function toEffMs(v) {
|
||||
if (!v || !v.effectiveTime) return NaN
|
||||
const t = new Date(String(v.effectiveTime).replace(/-/g, '/')).getTime()
|
||||
return Number.isNaN(t) ? NaN : t
|
||||
}
|
||||
|
||||
function statusRank(v) {
|
||||
const s = String(v && v.status != null ? v.status : '')
|
||||
if (s === '0') return 0
|
||||
if (s === '3') return 1
|
||||
if (s === '1') return 2
|
||||
if (s === '2') return 3
|
||||
return 9
|
||||
}
|
||||
|
||||
function sortVersions(list) {
|
||||
return (list || []).slice().sort((a, b) => {
|
||||
const ra = statusRank(a)
|
||||
const rb = statusRank(b)
|
||||
if (ra !== rb) return ra - rb
|
||||
const ta = toEffMs(a)
|
||||
const tb = toEffMs(b)
|
||||
const aNull = Number.isNaN(ta)
|
||||
const bNull = Number.isNaN(tb)
|
||||
if (aNull && bNull) return (Number(b.versionSeq) || 0) - (Number(a.versionSeq) || 0)
|
||||
if (aNull) return 1
|
||||
if (bNull) return -1
|
||||
if (tb !== ta) return tb - ta
|
||||
return (Number(b.versionSeq) || 0) - (Number(a.versionSeq) || 0)
|
||||
})
|
||||
}
|
||||
|
||||
async function loadVersions() {
|
||||
versions.value = []
|
||||
if (!props.priceSetId) return
|
||||
loading.value = true
|
||||
try {
|
||||
let data = null
|
||||
try {
|
||||
const res = await priceSetApi.getPriceSet(props.priceSetId)
|
||||
data = (res && res.data) || null
|
||||
} catch (e1) {
|
||||
const res2 = await exclusiveQuoteApi.getPriceSet(props.priceSetId)
|
||||
data = (res2 && res2.data) || null
|
||||
}
|
||||
const list = (data && data.versions) || []
|
||||
versions.value = sortVersions(list.filter(v => v && String(v.isDel) !== '1'))
|
||||
} catch (e) {
|
||||
versions.value = []
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function openDetail(row) {
|
||||
if (!row || row.psvId == null) return
|
||||
detailVersion.value = {
|
||||
psvId: row.psvId,
|
||||
versionNo: row.versionNo,
|
||||
effectiveTime: row.effectiveTime || null,
|
||||
expireTime: row.expireTime || null
|
||||
}
|
||||
detailVisible.value = true
|
||||
}
|
||||
|
||||
watch(
|
||||
() => [props.modelValue, props.priceSetId],
|
||||
([vis]) => {
|
||||
if (vis) loadVersions()
|
||||
}
|
||||
)
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.cycle-body {
|
||||
min-height: 240px;
|
||||
}
|
||||
</style>
|
||||
@@ -342,10 +342,28 @@
|
||||
<span :class="frValueClass(failReason.destPostcode || '-')">{{ failReason.destPostcode || '-' }}</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label-class-name="fr-label-key" class-name="fr-cell-key" label="套餐">
|
||||
<span :class="frValueClass(joinCodeName(failReason.priceSetCode, failReason.priceSetName), true)">{{ joinCodeName(failReason.priceSetCode, failReason.priceSetName) }}</span>
|
||||
<div class="fr-cycle-row">
|
||||
<span :class="frValueClass(joinCodeName(failReason.priceSetCode, failReason.priceSetName), true)">{{ joinCodeName(failReason.priceSetCode, failReason.priceSetName) }}</span>
|
||||
<el-button
|
||||
v-if="failReason.priceSetId"
|
||||
link
|
||||
type="primary"
|
||||
class="fr-cycle-btn"
|
||||
@click="openPackagePriceCycles"
|
||||
>查看</el-button>
|
||||
</div>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="套餐版本">
|
||||
<span :class="frValueClass(failReason.versionNo || '-')">{{ failReason.versionNo || '-' }}</span>
|
||||
<el-descriptions-item label-class-name="fr-label-key" class-name="fr-cell-key" label="价格周期">
|
||||
<div class="fr-cycle-row">
|
||||
<span :class="frValueClass(formatPriceCycle(failReason), true)">{{ formatPriceCycle(failReason) }}</span>
|
||||
<el-button
|
||||
v-if="failReason.psvId"
|
||||
link
|
||||
type="primary"
|
||||
class="fr-cycle-btn"
|
||||
@click="openPriceCycleDetail"
|
||||
>查看</el-button>
|
||||
</div>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="重量段">
|
||||
<span :class="frValueClass(failReason.weightLabel || formatWeightRange(failReason.weightMin, failReason.weightMax))">{{ failReason.weightLabel || formatWeightRange(failReason.weightMin, failReason.weightMax) }}</span>
|
||||
@@ -380,6 +398,20 @@
|
||||
<el-button type="primary" @click="failReasonVisible = false">关闭</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<set-version-detail-drawer
|
||||
v-model="priceCycleDrawerVisible"
|
||||
:version="priceCycleVersion"
|
||||
:set-type="failReason.setType || 'FIXED'"
|
||||
/>
|
||||
|
||||
<order-bill-price-cycle-list-drawer
|
||||
v-model="packageCycleDrawerVisible"
|
||||
:price-set-id="failReason.priceSetId"
|
||||
:price-set-code="failReason.priceSetCode"
|
||||
:price-set-name="failReason.priceSetName"
|
||||
:set-type="failReason.setType || 'FIXED'"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -391,6 +423,8 @@ import ExcelExportFieldDialog from '@/components/ExcelExportFieldDialog/index.vu
|
||||
import { ORDER_BILL_EXPORT_FIELDS } from '@/utils/exportFieldDefs'
|
||||
import OrderSourceSyncLogDrawer from '../../monitor/orderSource/components/OrderSourceSyncLogDrawer.vue'
|
||||
import OrderBillProductCheckDrawer from './components/OrderBillProductCheckDrawer.vue'
|
||||
import SetVersionDetailDrawer from '../set/components/detail/SetVersionDetailDrawer.vue'
|
||||
import OrderBillPriceCycleListDrawer from './components/OrderBillPriceCycleListDrawer.vue'
|
||||
|
||||
const tableRef = ref()
|
||||
const exportFieldRef = ref()
|
||||
@@ -1171,9 +1205,14 @@ const failReason = reactive({
|
||||
zoneCode: '',
|
||||
zoneName: '',
|
||||
destPostcode: '',
|
||||
priceSetId: null,
|
||||
priceSetCode: '',
|
||||
priceSetName: '',
|
||||
setType: '',
|
||||
psvId: null,
|
||||
versionNo: '',
|
||||
effectiveTime: null,
|
||||
expireTime: null,
|
||||
weightLabel: '',
|
||||
weightMin: null,
|
||||
weightMax: null,
|
||||
@@ -1225,6 +1264,37 @@ function formatDateTime(val) {
|
||||
' ' + pad(d.getHours()) + ':' + pad(d.getMinutes()) + ':' + pad(d.getSeconds())
|
||||
}
|
||||
|
||||
function formatPriceCycle(row) {
|
||||
const r = row || {}
|
||||
const eff = formatDateTime(r.effectiveTime)
|
||||
const exp = formatDateTime(r.expireTime)
|
||||
if (eff === '-' && exp === '-') {
|
||||
return r.versionNo || '-'
|
||||
}
|
||||
return eff + ' ~ ' + exp
|
||||
}
|
||||
|
||||
const priceCycleDrawerVisible = ref(false)
|
||||
const priceCycleVersion = ref(null)
|
||||
|
||||
function openPriceCycleDetail() {
|
||||
if (!failReason.psvId) return
|
||||
priceCycleVersion.value = {
|
||||
psvId: failReason.psvId,
|
||||
versionNo: failReason.versionNo,
|
||||
effectiveTime: failReason.effectiveTime ? formatDateTime(failReason.effectiveTime) : null,
|
||||
expireTime: failReason.expireTime ? formatDateTime(failReason.expireTime) : null
|
||||
}
|
||||
priceCycleDrawerVisible.value = true
|
||||
}
|
||||
|
||||
const packageCycleDrawerVisible = ref(false)
|
||||
|
||||
function openPackagePriceCycles() {
|
||||
if (!failReason.priceSetId) return
|
||||
packageCycleDrawerVisible.value = true
|
||||
}
|
||||
|
||||
function applyFailReason(data, row) {
|
||||
const src = data || {}
|
||||
const base = row || {}
|
||||
@@ -1241,9 +1311,14 @@ function applyFailReason(data, row) {
|
||||
failReason.zoneCode = src.zoneCode || ''
|
||||
failReason.zoneName = src.zoneName || ''
|
||||
failReason.destPostcode = src.destPostcode || base.destPostcode || ''
|
||||
failReason.priceSetId = src.priceSetId != null ? src.priceSetId : (base.priceSetId != null ? base.priceSetId : null)
|
||||
failReason.priceSetCode = src.priceSetCode || base.priceSetCode || ''
|
||||
failReason.priceSetName = src.priceSetName || base.priceSetName || ''
|
||||
failReason.setType = src.setType || base.setType || ''
|
||||
failReason.psvId = src.psvId != null ? src.psvId : (base.psvId != null ? base.psvId : null)
|
||||
failReason.versionNo = src.versionNo || ''
|
||||
failReason.effectiveTime = src.effectiveTime || null
|
||||
failReason.expireTime = src.expireTime || null
|
||||
failReason.weightLabel = src.weightLabel || base.weightLabel || ''
|
||||
failReason.weightMin = src.weightMin != null ? src.weightMin : base.weightMin
|
||||
failReason.weightMax = src.weightMax != null ? src.weightMax : base.weightMax
|
||||
@@ -1487,6 +1562,16 @@ onBeforeUnmount(() => {
|
||||
color: #0f172a;
|
||||
font-weight: 500;
|
||||
}
|
||||
.fr-cycle-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.fr-cycle-btn {
|
||||
flex-shrink: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.fr-val-key {
|
||||
color: #c2410c;
|
||||
font-weight: 700;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
:model-value="modelValue"
|
||||
:title="title"
|
||||
size="72%"
|
||||
append-to-body
|
||||
destroy-on-close
|
||||
@close="close"
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user