优化
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, nextTick, reactive, ref, watch } from 'vue'
|
||||
import { computed, nextTick, onMounted, reactive, ref, watch } from 'vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import { ArrowLeft, Eye, FilePenLine, PackageCheck } from '@lucide/vue'
|
||||
@@ -24,13 +24,14 @@ import StatusBadge from '@/shared/components/StatusBadge.vue'
|
||||
import DataTable, { type DataTableColumn } from '@/shared/components/DataTable.vue'
|
||||
import QueryToolbar, { type QueryField, type QueryModel } from '@/shared/components/QueryToolbar.vue'
|
||||
import { useAccessPreviewStore } from '@/core/access/accessPreview'
|
||||
import { listPlatformTenants, type PlatformTenantResource } from '@/modules/iam'
|
||||
|
||||
const PHASE_ONE_TENANT_ID = '10001'
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const access = useAccessPreviewStore()
|
||||
const loadedTenantId = ref(PHASE_ONE_TENANT_ID)
|
||||
const orders = ref<PlatformFirstLegOrderResource[]>([])
|
||||
const tenants = ref<PlatformTenantResource[]>([])
|
||||
const tenantLoadError = ref<ApiErrorDetails | null>(null)
|
||||
const total = ref(0)
|
||||
const page = ref(1)
|
||||
const pageSize = ref(20)
|
||||
@@ -49,17 +50,26 @@ const expressFormRef = ref<FormInstance>()
|
||||
const noteFormRef = ref<FormInstance>()
|
||||
const expressForm = reactive({ expressCompany: '', expressTrackingNo: '' })
|
||||
const filters = ref<QueryModel & {
|
||||
tenantId: string
|
||||
keyword: string
|
||||
status: PlatformFirstLegOrderStatus | ''
|
||||
dateRange: string[]
|
||||
}>({
|
||||
tenantId: '',
|
||||
keyword: '',
|
||||
status: '',
|
||||
status: 'SUBMITTED',
|
||||
dateRange: [],
|
||||
})
|
||||
|
||||
const queryFields: QueryField[] = [
|
||||
{ key: 'keyword', type: 'input', placeholder: '订单号或客户名称', props: { 'aria-label': '订单关键词' } },
|
||||
const queryFields = computed<QueryField[]>(() => [
|
||||
{
|
||||
key: 'tenantId',
|
||||
type: 'select',
|
||||
placeholder: tenantLoadError.value ? '企业列表加载失败' : '全部企业',
|
||||
props: { 'aria-label': '企业客户', filterable: true, disabled: Boolean(tenantLoadError.value) },
|
||||
options: tenants.value.map((tenant) => ({ value: String(tenant.id), label: `${tenant.tenantName}(${tenant.tenantCode || tenant.id})` })),
|
||||
},
|
||||
{ key: 'keyword', type: 'input', placeholder: '订单号或发货客户名称', props: { 'aria-label': '订单关键词' } },
|
||||
{
|
||||
key: 'status',
|
||||
type: 'select',
|
||||
@@ -77,7 +87,7 @@ const queryFields: QueryField[] = [
|
||||
],
|
||||
},
|
||||
{ key: 'dateRange', type: 'daterange', props: { 'aria-label': '订单创建日期' } },
|
||||
]
|
||||
])
|
||||
|
||||
const orderColumns: DataTableColumn[] = [
|
||||
{ key: 'actions', label: '操作', minWidth: 200, fixed: 'left', slotName: 'actions' },
|
||||
@@ -102,11 +112,14 @@ const noteRules: FormRules = {
|
||||
content: [{ required: true, message: '请填写内部备注', trigger: 'blur' }],
|
||||
}
|
||||
|
||||
const tenantReady = computed(() => loadedTenantId.value === PHASE_ONE_TENANT_ID)
|
||||
const detailOrderId = computed(() => {
|
||||
const orderId = route.query.orderId
|
||||
return typeof orderId === 'string' && orderId ? orderId : ''
|
||||
})
|
||||
const detailTenantId = computed(() => {
|
||||
const tenantId = route.query.tenantId
|
||||
return typeof tenantId === 'string' && tenantId ? tenantId : ''
|
||||
})
|
||||
const isDetailPage = computed(() => Boolean(detailOrderId.value))
|
||||
|
||||
const statusOptions: Array<{ value: PlatformFirstLegOrderStatus; label: string }> = [
|
||||
@@ -135,6 +148,29 @@ function formattedDate(value: string | null | undefined) {
|
||||
return value ? value.replace('T', ' ') : '-'
|
||||
}
|
||||
|
||||
function tenantName(tenantId: number | string) {
|
||||
return tenants.value.find((tenant) => String(tenant.id) === String(tenantId))?.tenantName || `企业 ${tenantId}`
|
||||
}
|
||||
|
||||
async function loadTenants() {
|
||||
tenantLoadError.value = null
|
||||
try {
|
||||
const records: PlatformTenantResource[] = []
|
||||
let currentPage = 1
|
||||
let pages = 1
|
||||
do {
|
||||
const result = await listPlatformTenants({ page: currentPage, size: 200 })
|
||||
records.push(...result.records)
|
||||
pages = Math.max(1, result.pages)
|
||||
currentPage += 1
|
||||
} while (currentPage <= pages)
|
||||
tenants.value = records
|
||||
} catch (error) {
|
||||
tenants.value = []
|
||||
tenantLoadError.value = getApiErrorDetails(error, '企业列表加载失败,暂时无法按企业筛选;订单仍可正常审核')
|
||||
}
|
||||
}
|
||||
|
||||
function can(action: string) {
|
||||
return access.can(action)
|
||||
}
|
||||
@@ -152,11 +188,11 @@ function actionLabel(order: PlatformFirstLegOrderResource) {
|
||||
}
|
||||
|
||||
async function loadOrders() {
|
||||
const targetTenantId = PHASE_ONE_TENANT_ID
|
||||
loadError.value = null
|
||||
loading.value = true
|
||||
try {
|
||||
const result = await listPlatformFirstLegOrders(targetTenantId, {
|
||||
const result = await listPlatformFirstLegOrders({
|
||||
tenantId: filters.value.tenantId || undefined,
|
||||
keyword: filters.value.keyword.trim() || undefined,
|
||||
status: filters.value.status || undefined,
|
||||
createdFrom: filters.value.dateRange.length === 2 ? `${filters.value.dateRange[0]}T00:00:00` : undefined,
|
||||
@@ -166,7 +202,6 @@ async function loadOrders() {
|
||||
})
|
||||
orders.value = result.records
|
||||
total.value = result.total
|
||||
loadedTenantId.value = targetTenantId
|
||||
} catch (error) {
|
||||
orders.value = []
|
||||
total.value = 0
|
||||
@@ -184,22 +219,34 @@ function searchOrders() {
|
||||
void loadOrders()
|
||||
}
|
||||
|
||||
async function resetOrders() {
|
||||
filters.value = { ...filters.value, status: 'SUBMITTED' }
|
||||
await nextTick()
|
||||
searchOrders()
|
||||
}
|
||||
|
||||
watch([page, pageSize], () => {
|
||||
void loadOrders()
|
||||
})
|
||||
|
||||
async function openDetail(order: PlatformFirstLegOrderResource) {
|
||||
if (!tenantReady.value) return
|
||||
selectedOrder.value = order
|
||||
await router.push({ path: route.path, query: { ...route.query, orderId: String(order.id) } })
|
||||
await router.push({
|
||||
path: route.path,
|
||||
query: { ...route.query, orderId: String(order.id), tenantId: String(order.tenantId) },
|
||||
})
|
||||
}
|
||||
|
||||
async function loadDetail(orderId: string) {
|
||||
if (!tenantReady.value) return
|
||||
async function loadDetail(orderId: string, tenantId = detailTenantId.value) {
|
||||
if (!tenantId) {
|
||||
detail.value = null
|
||||
ElMessage.error('订单详情缺少企业租户标识,请从订单列表重新打开')
|
||||
return
|
||||
}
|
||||
detail.value = null
|
||||
detailLoading.value = true
|
||||
try {
|
||||
detail.value = await getPlatformFirstLegOrder(loadedTenantId.value, orderId)
|
||||
detail.value = await getPlatformFirstLegOrder(tenantId, orderId)
|
||||
selectedOrder.value = detail.value.order
|
||||
} catch (error) {
|
||||
const details = getApiErrorDetails(error, '订单详情加载失败')
|
||||
@@ -217,7 +264,7 @@ async function refreshAfterAction(orderId: string) {
|
||||
}
|
||||
|
||||
function closeDetailPage() {
|
||||
const { orderId: _orderId, ...query } = route.query
|
||||
const { orderId: _orderId, tenantId: _tenantId, ...query } = route.query
|
||||
void router.replace({ path: route.path, query })
|
||||
}
|
||||
|
||||
@@ -233,7 +280,6 @@ function getFieldValidationMessage(error: unknown, field: string, fallback: stri
|
||||
}
|
||||
|
||||
async function runLifecycleAction(order: PlatformFirstLegOrderResource) {
|
||||
if (!tenantReady.value) return
|
||||
const label = actionLabel(order)
|
||||
if (!label) return
|
||||
try {
|
||||
@@ -243,10 +289,11 @@ async function runLifecycleAction(order: PlatformFirstLegOrderResource) {
|
||||
type: 'warning',
|
||||
})
|
||||
actionLoadingId.value = String(order.id)
|
||||
if (order.status === 'SUBMITTED') await approvePlatformFirstLegOrder(loadedTenantId.value, String(order.id))
|
||||
if (order.status === 'APPROVED') await acceptPlatformFirstLegOrder(loadedTenantId.value, String(order.id))
|
||||
if (order.status === 'ACCEPTED') await startPlatformFirstLegOrder(loadedTenantId.value, String(order.id))
|
||||
if (order.status === 'PROCESSING') await completePlatformFirstLegOrder(loadedTenantId.value, String(order.id))
|
||||
const tenantId = String(order.tenantId)
|
||||
if (order.status === 'SUBMITTED') await approvePlatformFirstLegOrder(tenantId, String(order.id))
|
||||
if (order.status === 'APPROVED') await acceptPlatformFirstLegOrder(tenantId, String(order.id))
|
||||
if (order.status === 'ACCEPTED') await startPlatformFirstLegOrder(tenantId, String(order.id))
|
||||
if (order.status === 'PROCESSING') await completePlatformFirstLegOrder(tenantId, String(order.id))
|
||||
await refreshAfterAction(String(order.id))
|
||||
ElMessage.success(`${label}已完成`)
|
||||
} catch (error) {
|
||||
@@ -258,7 +305,6 @@ async function runLifecycleAction(order: PlatformFirstLegOrderResource) {
|
||||
}
|
||||
|
||||
async function cancelOrder(order: PlatformFirstLegOrderResource) {
|
||||
if (!tenantReady.value) return
|
||||
try {
|
||||
const result = await ElMessageBox.prompt('请填写取消原因。后端要求该字段必填,并将写入订单状态历史。', '取消订单', {
|
||||
confirmButtonText: '确认取消',
|
||||
@@ -268,7 +314,7 @@ async function cancelOrder(order: PlatformFirstLegOrderResource) {
|
||||
inputPlaceholder: '例如:客户取消本次运输安排',
|
||||
})
|
||||
actionLoadingId.value = String(order.id)
|
||||
await cancelPlatformFirstLegOrder(loadedTenantId.value, String(order.id), result.value.trim())
|
||||
await cancelPlatformFirstLegOrder(String(order.tenantId), String(order.id), result.value.trim())
|
||||
await refreshAfterAction(String(order.id))
|
||||
ElMessage.success('订单已取消')
|
||||
} catch (error) {
|
||||
@@ -288,12 +334,12 @@ function openExpress(order: PlatformFirstLegOrderResource) {
|
||||
}
|
||||
|
||||
async function saveExpress() {
|
||||
if (!selectedOrder.value || !tenantReady.value) return
|
||||
if (!selectedOrder.value) return
|
||||
const valid = await expressFormRef.value?.validate().catch(() => false)
|
||||
if (!valid) return
|
||||
expressSaving.value = true
|
||||
try {
|
||||
await updatePlatformFirstLegOrderExpress(loadedTenantId.value, String(selectedOrder.value.id), {
|
||||
await updatePlatformFirstLegOrderExpress(String(selectedOrder.value.tenantId), String(selectedOrder.value.id), {
|
||||
expressCompany: expressForm.expressCompany.trim(),
|
||||
expressTrackingNo: expressForm.expressTrackingNo.trim(),
|
||||
})
|
||||
@@ -315,12 +361,12 @@ function openNote(order: PlatformFirstLegOrderResource) {
|
||||
}
|
||||
|
||||
async function saveNote() {
|
||||
if (!selectedOrder.value || !tenantReady.value) return
|
||||
if (!selectedOrder.value) return
|
||||
const valid = await noteFormRef.value?.validate().catch(() => false)
|
||||
if (!valid) return
|
||||
noteSaving.value = true
|
||||
try {
|
||||
await addPlatformFirstLegOrderNote(loadedTenantId.value, String(selectedOrder.value.id), noteForm.content.trim())
|
||||
await addPlatformFirstLegOrderNote(String(selectedOrder.value.tenantId), String(selectedOrder.value.id), noteForm.content.trim())
|
||||
noteDialogOpen.value = false
|
||||
await refreshAfterAction(String(selectedOrder.value.id))
|
||||
ElMessage.success('内部备注已保存')
|
||||
@@ -331,15 +377,17 @@ async function saveNote() {
|
||||
}
|
||||
}
|
||||
|
||||
watch(detailOrderId, (orderId) => {
|
||||
watch([detailOrderId, detailTenantId], ([orderId, tenantId]) => {
|
||||
if (orderId) {
|
||||
void loadDetail(orderId)
|
||||
void loadDetail(orderId, tenantId)
|
||||
return
|
||||
}
|
||||
detail.value = null
|
||||
selectedOrder.value = null
|
||||
void loadOrders()
|
||||
}, { immediate: true })
|
||||
|
||||
onMounted(() => void loadTenants())
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -359,7 +407,7 @@ watch(detailOrderId, (orderId) => {
|
||||
<div>
|
||||
<span>{{ transportLabel(detail.order) }}</span>
|
||||
<h2>{{ detail.order.orderNo || detail.order.id }}</h2>
|
||||
<p>{{ detail.order.customerName }} · {{ detail.order.referenceId || '无客户参考号' }}</p>
|
||||
<p>{{ tenantName(detail.order.tenantId) }} · {{ detail.order.customerName }} · {{ detail.order.referenceId || '无客户参考号' }}</p>
|
||||
</div>
|
||||
<StatusBadge :status="statusLabel(detail.order.status)" />
|
||||
</div>
|
||||
@@ -430,10 +478,16 @@ watch(detailOrderId, (orderId) => {
|
||||
ariaLabel="头程订单筛选"
|
||||
:fields="queryFields"
|
||||
search-text="查询"
|
||||
:search-on-reset="true"
|
||||
:search-on-reset="false"
|
||||
@search="searchOrders"
|
||||
@reset="resetOrders"
|
||||
/>
|
||||
|
||||
<el-alert v-if="tenantLoadError" type="warning" :closable="false" show-icon role="alert">
|
||||
<template #title><div class="api-error-alert-title"><span>{{ tenantLoadError.message }}</span><ApiErrorMeta :details="tenantLoadError" /></div></template>
|
||||
<el-button link type="warning" @click="loadTenants">重新加载企业列表</el-button>
|
||||
</el-alert>
|
||||
|
||||
<el-alert v-if="loadError" type="error" :closable="false" show-icon role="alert">
|
||||
<template #title><div class="api-error-alert-title"><span>{{ loadError.message }}</span><ApiErrorMeta :details="loadError" /></div></template>
|
||||
<el-button link type="danger" @click="loadOrders">重新加载</el-button>
|
||||
@@ -453,7 +507,7 @@ watch(detailOrderId, (orderId) => {
|
||||
>
|
||||
<template #actions="{ row }"><div class="table-actions"><el-button link type="primary" @click="openDetail(row as PlatformFirstLegOrderResource)"><Eye :size="15" />详情</el-button><el-button v-if="actionLabel(row as PlatformFirstLegOrderResource)" link type="success" :loading="actionLoadingId === String((row as PlatformFirstLegOrderResource).id)" @click="runLifecycleAction(row as PlatformFirstLegOrderResource)">{{ actionLabel(row as PlatformFirstLegOrderResource) }}</el-button><el-button v-if="canCancel(row as PlatformFirstLegOrderResource)" link type="danger" :loading="actionLoadingId === String((row as PlatformFirstLegOrderResource).id)" @click="cancelOrder(row as PlatformFirstLegOrderResource)">取消</el-button><el-button v-if="can('platform:order:fulfillment') && !['DRAFT', 'REJECTED', 'CANCELLED'].includes((row as PlatformFirstLegOrderResource).status)" link type="primary" @click="openExpress(row as PlatformFirstLegOrderResource)"><PackageCheck :size="15" />快递</el-button><el-button v-if="can('platform:order:note')" link type="primary" @click="openNote(row as PlatformFirstLegOrderResource)"><FilePenLine :size="15" />备注</el-button></div></template>
|
||||
<template #orderInfo="{ row }"><div class="primary-cell"><strong>{{ (row as PlatformFirstLegOrderResource).orderNo || '-' }}</strong><span>{{ (row as PlatformFirstLegOrderResource).referenceId || '无客户参考号' }} · {{ formattedDate((row as PlatformFirstLegOrderResource).createdAt) }}</span></div></template>
|
||||
<template #customer="{ row }"><div class="primary-cell"><strong>{{ (row as PlatformFirstLegOrderResource).customerName }}</strong><span>租户 {{ (row as PlatformFirstLegOrderResource).tenantId }}</span></div></template>
|
||||
<template #customer="{ row }"><div class="primary-cell"><strong>{{ tenantName((row as PlatformFirstLegOrderResource).tenantId) }}</strong><span>{{ (row as PlatformFirstLegOrderResource).customerName }} · {{ (row as PlatformFirstLegOrderResource).tenantId }}</span></div></template>
|
||||
<template #transport="{ row }"><div class="primary-cell"><strong>{{ transportLabel(row as PlatformFirstLegOrderResource) }}</strong><span>{{ (row as PlatformFirstLegOrderResource).channelName || '未填写渠道' }}</span></div></template>
|
||||
<template #destination="{ row }"><div class="primary-cell"><strong>{{ (row as PlatformFirstLegOrderResource).destinationWarehouseName || '-' }}</strong><span>{{ (row as PlatformFirstLegOrderResource).destinationCountryCode || '-' }}</span></div></template>
|
||||
<template #receivingWarehouse="{ row }"><div class="primary-cell"><strong>{{ (row as PlatformFirstLegOrderResource).receivingWarehouseName || '-' }}</strong><span>{{ (row as PlatformFirstLegOrderResource).receivingWarehouseAddress || '-' }}</span></div></template>
|
||||
|
||||
Reference in New Issue
Block a user