<script setup lang="ts">
|
import { computed, onMounted, ref } from 'vue'
|
import { useRoute } from 'vue-router'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { getParkingPlateSubmissionDetail, updateParkingPlateSubmissionStatus } from '../api/admin'
|
|
const route = useRoute()
|
const loading = ref(false)
|
const processing = ref(false)
|
const detail = ref<Record<string, any>>({})
|
|
function text(value: unknown) {
|
return value === undefined || value === null || value === '' ? '-' : String(value)
|
}
|
|
function pick(group: Record<string, any> | undefined, ...keys: string[]) {
|
if (!group) return ''
|
for (const key of keys) {
|
if (group[key] !== undefined && group[key] !== null && group[key] !== '') return group[key]
|
}
|
return ''
|
}
|
|
function formatDate(value: unknown) {
|
return text(value).replace('T', ' ')
|
}
|
|
function statusName(value: unknown, fallback = '') {
|
const raw = String(value ?? '').trim().toUpperCase().replace('-', '_')
|
const label = fallback.trim()
|
if (label === '已拒绝') return '已驳回'
|
if (label) return label
|
if (raw === 'ACTIVE' || raw === 'PROCESSED' || raw === 'PASSED' || raw === 'APPROVED') return '已处理'
|
if (raw === 'REJECTED' || raw === 'REFUSED' || raw === 'DENIED') return '已驳回'
|
if (raw === 'CANCELLED' || raw === 'CANCELED') return '已取消'
|
return '待处理'
|
}
|
|
const talentInfo = computed(() => detail.value.talentInfo || {})
|
const submissionInfo = computed(() => detail.value.submissionInfo || {})
|
const statusInfo = computed(() => detail.value.statusInfo || {})
|
|
const cardholderItems = computed(() => [
|
{ label: '持卡人姓名:', value: text(pick(talentInfo.value, 'talentName') || pick(detail.value, 'talentName')) },
|
{ label: '手机号:', value: text(pick(talentInfo.value, 'talentMobile') || pick(detail.value, 'talentMobile')) },
|
{ label: '人才等级:', value: text(pick(talentInfo.value, 'cardLevel') || pick(detail.value, 'cardLevel', 'talentLevel')) },
|
])
|
|
const submissionItems = computed(() => [
|
{ label: '车牌号:', value: text(pick(submissionInfo.value, 'plateNumber', 'plateNo') || pick(detail.value, 'plateNumber', 'plateNo')) },
|
{ label: '停车场:', value: text(pick(submissionInfo.value, 'parkingLotName', 'parkingLot', 'serviceName') || pick(detail.value, 'parkingLotName', 'parkingLot', 'serviceName')) },
|
{ label: '提交时间:', value: formatDate(pick(submissionInfo.value, 'submittedAt', 'createdAt') || pick(detail.value, 'submittedAt', 'createdAt')) },
|
])
|
|
const currentStatus = computed(() => statusName(
|
pick(statusInfo.value, 'status') || pick(detail.value, 'status'),
|
String(pick(statusInfo.value, 'statusName') || pick(detail.value, 'statusName') || ''),
|
))
|
|
const statusItems = computed(() => [
|
{ label: '状态:', value: currentStatus.value },
|
{ label: '处理时间:', value: formatDate(pick(statusInfo.value, 'handledAt', 'processedAt') || pick(detail.value, 'handledAt', 'processedAt')) },
|
{ label: '处理人:', value: text(pick(statusInfo.value, 'handledByName', 'handlerName', 'processedBy') || pick(detail.value, 'handledByName', 'handlerName', 'processedBy')) },
|
])
|
|
const canProcess = computed(() => !['已处理', '已驳回', '已取消'].includes(currentStatus.value))
|
|
async function loadData() {
|
loading.value = true
|
try {
|
detail.value = await getParkingPlateSubmissionDetail(String(route.params.id)) || {}
|
} finally {
|
loading.value = false
|
}
|
}
|
|
async function markHandled() {
|
const id = detail.value.id || detail.value.registrationId
|
if (!id || processing.value || !canProcess.value) return
|
try {
|
await ElMessageBox.confirm('确认将该停车车牌申请标记为已处理吗?', '确认处理', {
|
type: 'warning',
|
confirmButtonText: '确认处理',
|
cancelButtonText: '取消',
|
})
|
} catch {
|
return
|
}
|
processing.value = true
|
try {
|
detail.value = await updateParkingPlateSubmissionStatus(id, '已处理')
|
ElMessage.success('已处理该车牌申请')
|
} finally {
|
processing.value = false
|
}
|
}
|
|
onMounted(loadData)
|
</script>
|
|
<template>
|
<div v-loading="loading" class="parking-plate-detail-page">
|
<section class="parking-plate-detail-panel">
|
<div class="reservation-detail-section">
|
<h3>持卡人信息</h3>
|
<div class="reservation-detail-grid parking-plate-cardholder-grid">
|
<div v-for="item in cardholderItems" :key="item.label" class="reservation-detail-item">
|
<span>{{ item.label }}</span><strong>{{ item.value }}</strong>
|
</div>
|
</div>
|
</div>
|
|
<div class="reservation-detail-section">
|
<h3>提交信息</h3>
|
<div class="reservation-detail-grid parking-plate-submit-grid">
|
<div v-for="item in submissionItems" :key="item.label" class="reservation-detail-item">
|
<span>{{ item.label }}</span><strong>{{ item.value }}</strong>
|
</div>
|
</div>
|
</div>
|
|
<div class="reservation-detail-section">
|
<h3>状态信息</h3>
|
<div class="reservation-detail-grid parking-plate-status-grid">
|
<div v-for="item in statusItems" :key="item.label" class="reservation-detail-item">
|
<span>{{ item.label }}</span><strong>{{ item.value }}</strong>
|
</div>
|
</div>
|
</div>
|
</section>
|
|
<el-button v-if="canProcess" type="primary" class="reservation-detail-action" :loading="processing" @click="markHandled">处理</el-button>
|
</div>
|
</template>
|
|
<style scoped>
|
.parking-plate-detail-page {
|
display: grid;
|
gap: 20px;
|
}
|
|
.parking-plate-detail-panel {
|
min-height: 0;
|
padding: 20px 18px 26px;
|
background: #ffffff;
|
}
|
|
.parking-plate-detail-panel .reservation-detail-section {
|
margin-bottom: 24px;
|
}
|
|
.parking-plate-detail-panel .reservation-detail-section:last-child {
|
margin-bottom: 0;
|
}
|
|
.parking-plate-detail-panel .reservation-detail-grid {
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
min-height: 74px;
|
padding: 22px 16px;
|
background: #f1f3f5;
|
}
|
|
.parking-plate-detail-panel .parking-plate-submit-grid {
|
min-height: 92px;
|
align-content: start;
|
}
|
|
@media (max-width: 900px) {
|
.parking-plate-detail-panel .reservation-detail-grid {
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
}
|
}
|
</style>
|