feat(web-admin): 承运商去审核 UI 并移除安排运输准入拦截

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
zlwuandCursor committed 2026-07-25 10:58:24 +08:00
1 parent 4eed1183b5
commit fd62043f71
5 files changed
+9 -173

No files matched your search

+1
View File
@@ -49,6 +49,7 @@ export const carrierApi = {
get: (id: string) => request.get<Carrier>(`/transport/carrier/${id}`),
create: (data: Partial<Carrier>) => request.post<Carrier>('/transport/carrier', data),
update: (id: string, data: Partial<Carrier>) => request.put<Carrier>(`/transport/carrier/${id}`, data),
/** @deprecated 承运商审核已移除,后端接口已禁用 */
approve: (id: string) => request.post<Carrier>(`/transport/carrier/${id}/approve`),
reject: (id: string, data?: { remark?: string }) =>
request.post<Carrier>(`/transport/carrier/${id}/reject`, data ?? {}),
@@ -86,8 +86,6 @@ import {
} from '@/composables/usePlVehicleViewDetail'
import { formatDateTime } from '@/utils/format'
import {
getPlCarrierAuditStatusLabel,
getPlCarrierAuditStatusTagType,
getPlCarrierStatusLabel,
getPlCarrierStatusTagType
} from '@/utils/pl-display'
@@ -118,8 +116,7 @@ const heroMeta = computed(() => {
const parts = [
c.contactName || undefined,
c.contactPhone || undefined,
getPlCarrierStatusLabel(c.status),
getPlCarrierAuditStatusLabel(c.auditStatus)
getPlCarrierStatusLabel(c.status)
].filter(Boolean)
return parts.join(' · ')
})
@@ -145,26 +142,6 @@ const carrierInfoRow2Fields = computed<ViewField[]>(() => {
const c = carrier.value
if (!c) return []
return [
{
label: '审核状态',
value: getPlCarrierAuditStatusLabel(c.auditStatus),
tagType: getPlCarrierAuditStatusTagType(c.auditStatus),
long: false
},
{
label: '审核时间',
value: c.auditTime ? formatDateTime(c.auditTime) : '—',
long: false
},
{ label: '审核备注', value: c.auditRemark || '—', long: false, fullSpan: false }
]
})
const carrierInfoRow3Fields = computed<ViewField[]>(() => {
const c = carrier.value
if (!c) return []
return [
{ label: '创建时间', value: formatDateTime(c.createTime), long: false },
{
@@ -192,8 +169,7 @@ const viewSections = computed<ViewSection[]>(() => {
title: '承运商信息',
fieldGroups: [
{ fieldLayout: 'table', tableMode: 'quad', fields: [] },
{ fieldLayout: 'table', tableMode: 'quad', fields: [] },
{ fieldLayout: 'table', tableMode: 'triple', fields: [] }
{ fieldLayout: 'table', tableMode: 'quad', fields: [] }
],
fields: []
},
@@ -214,11 +190,6 @@ const viewSections = computed<ViewSection[]>(() => {
{
fieldLayout: 'table',
tableMode: 'quad',
fields: carrierInfoRow3Fields.value
},
{
fieldLayout: 'table',
tableMode: 'triple',
fields: carrierInfoRow2Fields.value
}
],
@@ -36,14 +36,6 @@
<section v-else class="pl-plan-form-section">
<h3 class="pl-plan-form-section-title">{{ isRearrange ? '调整运输' : '运输安排' }}</h3>
<el-alert
v-if="rearrangeBlocked"
type="warning"
:closable="false"
show-icon
:title="rearrangeBlockedMessage"
class="pl-arrange-block-alert"
/>
<el-form ref="formRef" :model="formData" :rules="formRules" label-position="right" label-width="100px" class="pl-dialog-form">
<div class="form-grid-4">
<el-form-item label="选择车辆" prop="vehicleId">
@@ -304,7 +296,7 @@
<el-button @click="innerVisible = false">
<el-icon><Close /></el-icon>取消
</el-button>
<el-button type="primary" :loading="submitLoading" :disabled="rearrangeBlocked" @click="handleSubmit">
<el-button type="primary" :loading="submitLoading" @click="handleSubmit">
<el-icon><Check /></el-icon>{{ isRearrange ? '确认调整' : '确认安排' }}
</el-button>
</template>
@@ -401,8 +393,6 @@ const vehicleBundle = ref<VehicleViewBundle | null>(null)
const vehicleViewVisible = ref(false)
const hasHistoricalDibang = ref(false)
const hasHistoricalSiteLinks = ref(false)
const rearrangeBlocked = ref(false)
const rearrangeBlockedMessage = ref('')
const formData = reactive({
vehicleId: '',
@@ -488,8 +478,6 @@ const freightCalc = usePlFreightCalc({
freightType: freightTypeRef
})
const selectedVehicle = computed(() => vehicleList.value.find(item => item.id === formData.vehicleId))
const showDibangHint = computed(
() => formData.generateDibangPlan && canGenerateDibangPlan.value
)
@@ -615,8 +603,6 @@ function resetState() {
vehicleViewVisible.value = false
hasHistoricalDibang.value = false
hasHistoricalSiteLinks.value = false
rearrangeBlocked.value = false
rearrangeBlockedMessage.value = ''
Object.assign(formData, {
vehicleId: '',
driverId: '',
@@ -643,47 +629,13 @@ function resetState() {
async function loadMasterData() {
const [vehicleRes, carrierRes] = await Promise.all([
vehicleApi.list({ vehicleStatus: 'available', excludeIneligibleCarrier: true }),
vehicleApi.list({ vehicleStatus: 'available' }),
carrierApi.list({ status: '1', page: 1, pageSize: 100 })
])
vehicleList.value = pickBxList<Vehicle>(vehicleRes)
carrierList.value = pickBxList<Carrier>(carrierRes)
}
async function updateRearrangeBlocked() {
rearrangeBlocked.value = false
rearrangeBlockedMessage.value = ''
if (!isRearrange.value) return
const detail = vehicleBundle.value?.detail
const carrierId = detail?.carrierId || formData.carrierId || selectedVehicle.value?.carrierId
if (!carrierId) return
let carrier = carrierList.value.find(c => c.id === carrierId)
if (!carrier) {
try {
const res = await carrierApi.get(carrierId)
carrier = pickBxData<Carrier>(res)
} catch {
return
}
}
if (!carrier?.qualificationComplete) {
rearrangeBlocked.value = true
rearrangeBlockedMessage.value = '该承运商资质附件不完整,请先补全后再调整运输'
return
}
if (carrier.auditStatus !== 'approved') {
rearrangeBlocked.value = true
rearrangeBlockedMessage.value = '该承运商尚未审核通过,请先完成审核后再调整运输'
return
}
if (carrier.transportAgreementExpired) {
rearrangeBlocked.value = true
rearrangeBlockedMessage.value = '该承运商运输协议已过期,请先更新协议后再调整运输'
}
}
async function handleVehicleChange(vehicleId: string, preferredDriverId?: string) {
if (!vehicleId) {
formData.driverId = ''
@@ -709,7 +661,6 @@ async function handleVehicleChange(vehicleId: string, preferredDriverId?: string
formData.carrierId = vehicleBundle.value.detail.carrierId
}
applyVehiclePersonnel(vehicleBundle.value.personnelList || [], preferredDriverId)
await updateRearrangeBlocked()
} finally {
vehicleLoading.value = false
}
@@ -746,10 +697,6 @@ function handleClosed() {
}
async function handleSubmit() {
if (rearrangeBlocked.value) {
ElMessage.warning(rearrangeBlockedMessage.value || '当前承运商不可调整运输')
return
}
const valid = await formRef.value?.validate().catch(() => false)
if (!valid) return
@@ -886,10 +833,6 @@ function handlePrintSubpackSlip() {
padding-right: 4px;
}
.pl-arrange-block-alert {
margin-bottom: 12px;
}
.pl-plan-logistics-fields {
display: flex;
flex-direction: column;
@@ -811,7 +811,7 @@ function handleClosed() {
async function loadMasterData() {
try {
const [vehicleRes, carrierRes] = await Promise.all([
vehicleApi.list({ vehicleStatus: 'available', excludeIneligibleCarrier: true }),
vehicleApi.list({ vehicleStatus: 'available' }),
carrierApi.list({ status: '1', page: 1, pageSize: 100 })
])
vehicleList.value = pickBxList<Vehicle>(vehicleRes)
+3 -82
View File
@@ -24,13 +24,6 @@
<el-option label="已终止" value="0" />
</el-select>
</el-form-item>
<el-form-item label="审核状态">
<el-select v-model="searchForm.auditStatus" placeholder="全部" clearable>
<el-option label="待审核" value="pending" />
<el-option label="已通过" value="approved" />
<el-option label="已驳回" value="rejected" />
</el-select>
</el-form-item>
</div>
<div class="filter-actions">
<div class="filter-actions-end">
@@ -67,14 +60,6 @@
>
<el-icon><Edit /></el-icon>编辑
</el-button>
<el-button
class="btn-ghost"
:disabled="selectedRows.length !== 1 || !canApproveCarrier(selectedRows[0])"
:loading="selectedRows.length === 1 && auditLoadingMap[selectedRows[0].id]"
@click="handleToolbarApprove"
>
<el-icon><Select /></el-icon>审核通过
</el-button>
<el-button
class="btn-ghost"
type="danger"
@@ -157,19 +142,6 @@
</el-tag>
</template>
</el-table-column>
<el-table-column
v-if="isColumnVisible('auditStatus')"
label="审核状态"
min-width="100"
align="center"
header-align="center"
>
<template #default="{ row }">
<el-tag :type="getPlCarrierAuditStatusTagType(row.auditStatus)" size="small">
{{ getPlCarrierAuditStatusLabel(row.auditStatus) }}
</el-tag>
</template>
</el-table-column>
<el-table-column
v-if="isColumnVisible('qualificationHint')"
label="资质提示"
@@ -322,14 +294,6 @@
<el-button class="btn-main" type="primary" @click="handleEdit(viewingRow)">
<el-icon><Edit /></el-icon>编辑
</el-button>
<el-button
v-if="canApproveCarrier(viewingRow)"
class="btn-ghost"
:loading="auditLoadingMap[viewingRow.id]"
@click="handleApprove(viewingRow)"
>
<el-icon><Select /></el-icon>审核通过
</el-button>
<el-button
class="btn-ghost"
type="danger"
@@ -345,7 +309,7 @@
</template>
<script setup lang="ts">
import { Check, Close, Delete, Edit, Plus, RefreshLeft, Search, Select } from '@element-plus/icons-vue'
import { Check, Close, Delete, Edit, Plus, RefreshLeft, Search } from '@element-plus/icons-vue'
import { carrierApi, type Carrier } from '@/api/pl'
import AttachmentUploadField from '@/components/business/attachment-upload-field/index.vue'
import PlCarrierViewDialog from '@/components/business/pl-carrier-view-dialog/index.vue'
@@ -356,11 +320,6 @@ import { useDbInstantSearch } from '@/composables/useDbInstantSearch'
import { pickBxPageResult } from '@/utils/http/bx'
import { DEFAULT_LIST_PAGE_SIZE } from '@/utils/table/tableConfig'
import { canDeleteByCreator, filterDeletableByCreator, allRowsDeletableByCreator, CREATOR_DELETE_TIP } from '@/utils/creator-delete'
import {
getPlCarrierAuditStatusLabel,
getPlCarrierAuditStatusTagType
} from '@/utils/pl-display'
const loading = ref(false)
const quickSearchKeyword = ref('')
@@ -368,7 +327,6 @@ const listColumnDefs = [
{ prop: 'contactName', label: '联系人' },
{ prop: 'contactPhone', label: '联系电话' },
{ prop: 'status', label: '合作状态' },
{ prop: 'auditStatus', label: '审核状态' },
{ prop: 'qualificationHint', label: '资质提示' },
{ prop: 'transportAgreementExpireDate', label: '协议有效期' },
{ prop: 'remark', label: '备注', defaultVisible: false }
@@ -383,7 +341,6 @@ const {
} = usePersistedListColumns('pl-carrier-list-columns', listColumnDefs)
const submitLoading = ref(false)
const auditLoadingMap = reactive<Record<string, boolean>>({})
const carrierList = ref<Carrier[]>([])
const selectedRows = ref<Carrier[]>([])
const dialogVisible = ref(false)
@@ -400,8 +357,7 @@ const viewDialogRef = ref<InstanceType<typeof PlCarrierViewDialog>>()
const searchForm = reactive({
q: '',
status: '',
auditStatus: ''
status: ''
})
const pagination = reactive({
@@ -490,7 +446,6 @@ async function fetchData() {
const res = await carrierApi.list({
q: quickSearchKeyword.value.trim() || searchForm.q || undefined,
status: searchForm.status || undefined,
auditStatus: searchForm.auditStatus || undefined,
page: pagination.page,
pageSize: pagination.pageSize
})
@@ -513,7 +468,6 @@ function handleSearch() {
function handleReset() {
searchForm.q = ''
searchForm.status = ''
searchForm.auditStatus = ''
quickSearchKeyword.value = ''
selectedRows.value = []
pagination.page = 1
@@ -540,10 +494,6 @@ function handleSizeChange() {
fetchData()
}
function canApproveCarrier(row: Carrier) {
return row.auditStatus !== 'approved' && row.qualificationComplete
}
function syncViewingRowFromList() {
if (!viewingRow.value?.id) return
const updated = carrierList.value.find(row => row.id === viewingRow.value!.id)
@@ -556,27 +506,6 @@ async function refreshViewIfOpen() {
await viewDialogRef.value?.reload()
}
async function handleApprove(row: Carrier) {
if (!canApproveCarrier(row)) {
ElMessage.warning('承运商资质不完整,无法审核通过')
return
}
await ElMessageBox.confirm(
`确认审核通过承运商「${row.carrierName}」?通过后其车辆可用于运输安排。`,
'审核确认',
{ type: 'info', confirmButtonText: '审核通过', cancelButtonText: '取消' }
)
auditLoadingMap[row.id] = true
try {
await carrierApi.approve(row.id)
ElMessage.success('审核通过')
await fetchData()
await refreshViewIfOpen()
} finally {
auditLoadingMap[row.id] = false
}
}
function handleSelectionChange(rows: Carrier[]) {
selectedRows.value = rows
}
@@ -589,14 +518,6 @@ function handleToolbarEdit() {
handleEdit(selectedRows.value[0])
}
function handleToolbarApprove() {
if (selectedRows.value.length !== 1) {
ElMessage.warning('请选择一条承运商')
return
}
handleApprove(selectedRows.value[0])
}
function handleToolbarDelete() {
if (selectedRows.value.length !== 1) {
ElMessage.warning('请选择一条承运商')
@@ -707,7 +628,7 @@ async function handleDelete(row: Carrier) {
}
useDbInstantSearch(
() => ({ q: searchForm.q, status: searchForm.status, auditStatus: searchForm.auditStatus }),
() => ({ q: searchForm.q, status: searchForm.status }),
handleSearch
)