609 lines
17 KiB
Vue
609 lines
17 KiB
Vue
<template>
|
||
<div class="web-detail-container">
|
||
<!-- 页面头部 -->
|
||
<div class="page-header">
|
||
<div class="header-left">
|
||
<el-button :icon="ArrowLeft" @click="handleClickBack">返回</el-button>
|
||
<h2 class="page-title">灾毁详情</h2>
|
||
</div>
|
||
<div class="header-right">
|
||
<el-tag :type="getEventStatusType()" size="large">
|
||
{{ getEventStatusText() }}
|
||
</el-tag>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="content-container">
|
||
<div class="left-panel">
|
||
<!-- 基本信息卡片 -->
|
||
<el-card class="info-card" shadow="never">
|
||
<template #header>
|
||
<div class="card-header">
|
||
<span class="card-title">基本信息</span>
|
||
</div>
|
||
</template>
|
||
|
||
<el-row :gutter="20" class="info-row">
|
||
<el-col :span="8">
|
||
<div class="info-item">
|
||
<span class="info-label">事件类型:</span>
|
||
<span class="info-value">水毁事件</span>
|
||
</div>
|
||
</el-col>
|
||
<el-col :span="8">
|
||
<div class="info-item">
|
||
<span class="info-label">路况类别:</span>
|
||
<span class="info-value">{{ detailData.roadConditionType || '-' }}</span>
|
||
</div>
|
||
</el-col>
|
||
<el-col :span="8">
|
||
<div class="info-item">
|
||
<span class="info-label">是否阻断:</span>
|
||
<span class="info-value">{{ detailData.event?.isBlocked ? '是' : '否' }}</span>
|
||
</div>
|
||
</el-col>
|
||
</el-row>
|
||
|
||
<el-row :gutter="20" class="info-row">
|
||
<el-col :span="8">
|
||
<div class="info-item">
|
||
<span class="info-label">抢险进度:</span>
|
||
<span class="info-value">{{ detailData.event?.repairProgress || '-' }}</span>
|
||
</div>
|
||
</el-col>
|
||
<el-col :span="8">
|
||
<div class="info-item">
|
||
<span class="info-label">处理措施:</span>
|
||
<span class="info-value">{{ getBaseDisposalMeasures() }}</span>
|
||
</div>
|
||
</el-col>
|
||
<el-col :span="8">
|
||
<div class="info-item">
|
||
<span class="info-label">水毁处数:</span>
|
||
<span class="info-value">{{ detailData.event?.damageCount || 0 }}</span>
|
||
</div>
|
||
</el-col>
|
||
</el-row>
|
||
|
||
<el-row :gutter="20" class="info-row">
|
||
<el-col :span="8">
|
||
<div class="info-item">
|
||
<span class="info-label">阻断里程:</span>
|
||
<span class="info-value">{{ detailData.event?.blockedMileage ? detailData.event.blockedMileage + '公里' : '-' }}</span>
|
||
</div>
|
||
</el-col>
|
||
</el-row>
|
||
|
||
<el-row :gutter="20" class="info-row">
|
||
<el-col :span="8">
|
||
<div class="info-item">
|
||
<span class="info-label">地点路线:</span>
|
||
<span class="info-value">{{ detailData.occurLocation || '-' }}</span>
|
||
</div>
|
||
</el-col>
|
||
<el-col :span="8">
|
||
<div class="info-item">
|
||
<span class="info-label">起点桩号:</span>
|
||
<span class="info-value">{{ detailData.event?.startStakeNo || '-' }}</span>
|
||
</div>
|
||
</el-col>
|
||
<el-col :span="8">
|
||
<div class="info-item">
|
||
<span class="info-label">止点桩号:</span>
|
||
<span class="info-value">{{ detailData.event?.endStakeNo || '-' }}</span>
|
||
</div>
|
||
</el-col>
|
||
</el-row>
|
||
|
||
<el-row :gutter="20" class="info-row">
|
||
<el-col :span="8">
|
||
<div class="info-item">
|
||
<span class="info-label">路况位置:</span>
|
||
<span class="info-value">{{ detailData.event?.blockedPointName || detailData.occurLocation || '-' }}</span>
|
||
</div>
|
||
</el-col>
|
||
<el-col :span="8">
|
||
<div class="info-item">
|
||
<span class="info-label">阻断点小地名:</span>
|
||
<span class="info-value">{{ detailData.event?.blockedPointName || '-' }}</span>
|
||
</div>
|
||
</el-col>
|
||
</el-row>
|
||
|
||
<el-row :gutter="20" class="info-row">
|
||
<el-col :span="8">
|
||
<div class="info-item">
|
||
<span class="info-label">所属区县:</span>
|
||
<span class="info-value">{{ detailData.event?.district || '-' }}</span>
|
||
</div>
|
||
</el-col>
|
||
<el-col :span="8">
|
||
<div class="info-item">
|
||
<span class="info-label">发生时间:</span>
|
||
<span class="info-value">{{ detailData.occurTime || '-' }}</span>
|
||
</div>
|
||
</el-col>
|
||
</el-row>
|
||
|
||
<el-row :gutter="20" class="info-row">
|
||
<el-col :span="8">
|
||
<div class="info-item">
|
||
<span class="info-label">是否恢复重建:</span>
|
||
<span class="info-value">{{ detailData.event?.needsRecovery ? '是' : '否' }}</span>
|
||
</div>
|
||
</el-col>
|
||
<el-col :span="16" v-if="detailData.event?.needsRecovery">
|
||
<div class="info-item">
|
||
<span class="info-label">恢复重建预估费用:</span>
|
||
<span class="info-value">{{ detailData.event?.estimatedRecoveryCost ? detailData.event.estimatedRecoveryCost + '万元' : '-' }}</span>
|
||
</div>
|
||
</el-col>
|
||
</el-row>
|
||
</el-card>
|
||
|
||
<!-- 填报信息卡片 -->
|
||
<el-card class="info-card" shadow="never">
|
||
<template #header>
|
||
<div class="card-header">
|
||
<span class="card-title">填报信息</span>
|
||
</div>
|
||
</template>
|
||
|
||
<div v-if="hasReportData">
|
||
<div v-for="(report, index) in allReports" :key="index" class="report-section">
|
||
<div class="report-header">
|
||
<span class="report-title">{{ report?.title }}</span>
|
||
<span class="report-meta">时间:{{ report.reportTime || '-' }}</span>
|
||
</div>
|
||
<div class="content-wrapper">
|
||
<div class="basic-info-wrapper">
|
||
<div class="info-list">
|
||
<div class="info-item">
|
||
<span class="info-label">现场描述:</span>
|
||
<span class="info-value">{{ report.siteDescription || '-' }}</span>
|
||
</div>
|
||
<div class="info-item">
|
||
<span class="info-label">处置措施:</span>
|
||
<span class="info-value">{{ report.disposalMeasures || '-' }}</span>
|
||
</div>
|
||
<div class="info-item">
|
||
<span class="info-label">实际恢复时间:</span>
|
||
<span class="info-value">{{ report.actualRecoverTime || '-' }}</span>
|
||
</div>
|
||
<div class="info-item">
|
||
<span class="info-label">预计恢复时间:</span>
|
||
<span class="info-value">{{ report.expectRecoverTime || '-' }}</span>
|
||
</div>
|
||
|
||
<div class="info-item">
|
||
<span class="info-label">填报人:</span>
|
||
<span class="info-value">{{ report.reporterName ? report.reporterName : '-' }}</span>
|
||
</div>
|
||
|
||
<div class="info-item">
|
||
<span class="info-label">联系电话:</span>
|
||
<span class="info-value">{{ report.phone ? report.phone : '-' }}</span>
|
||
</div>
|
||
</div>
|
||
<div class="file-list">
|
||
<FileUpload v-model="report.fileList" :readonly="!isEdit" />
|
||
</div>
|
||
</div>
|
||
|
||
<div class="detal-info-wrapper">
|
||
<template v-if="report.showDetail">
|
||
<LossListDetail :modelValue="report.lossList" :col-span="8" />
|
||
<el-row :gutter="24">
|
||
<el-col :span="8">
|
||
<div class="info-item margin">
|
||
<span class="info-label">投入机械:</span>
|
||
<span class="info-value">{{ report.investedMachinery ? report.investedMachinery + '台/班' : '-'}}</span>
|
||
</div>
|
||
</el-col>
|
||
<el-col :span="8">
|
||
<div class="info-item margin">
|
||
<span class="info-label">投入人力:</span>
|
||
<span class="info-value">{{ report.investedManpower ? report.investedManpower + '人次' : '-'}}</span>
|
||
</div>
|
||
</el-col>
|
||
<el-col :span="8">
|
||
<div class="info-item margin">
|
||
<span class="info-label">投入资金:</span>
|
||
<span class="info-value">{{ report.investedFunds ? report.investedFunds + '万元' : '-'}}</span>
|
||
</div>
|
||
</el-col>
|
||
</el-row>
|
||
</template>
|
||
|
||
<el-button style="margin-top: 30px" type="primary" link @click="report.showDetail = !report.showDetail">
|
||
{{ report.showDetail ? '点击关闭详情' : '点击查看详情' }}
|
||
</el-button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<el-empty v-else description="暂无填报信息" :image-size="100" />
|
||
</el-card>
|
||
|
||
<!-- 底部按钮 -->
|
||
<!-- <div class="footer-buttons">
|
||
<el-button type="primary" size="large" @click="handleContinueReport" class="footer-btn"> 续报 </el-button>
|
||
</div> -->
|
||
</div>
|
||
<div class="right-panel" v-if="isEdit">
|
||
<ContinueReport ref="continueReport" @refresh="getDisasterDetail" />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { onMounted, ref, computed } from 'vue'
|
||
import { useRouter, useRoute } from 'vue-router'
|
||
import { ElMessage } from 'element-plus'
|
||
import { ArrowLeft, Picture, VideoCamera } from '@element-plus/icons-vue'
|
||
import ContinueReport from './WaterDisasterContinueReportPC.vue'
|
||
import { request } from '@shared/utils/request'
|
||
import LossListDetail from './WaterDisasterLossListDetailPC.vue'
|
||
import FileUpload from '@/component/FileUpload/FileUpload.vue'
|
||
import mockData from '../DisasterReport/waterMockJson.json'
|
||
|
||
const router = useRouter()
|
||
const route = useRoute()
|
||
|
||
// 详情数据
|
||
const detailData = ref({
|
||
event: null,
|
||
report: [],
|
||
fileList: [],
|
||
lossList: [],
|
||
occurLocation: '',
|
||
occurTime: '',
|
||
roadConditionType: '',
|
||
routeNo: ''
|
||
})
|
||
|
||
// 事件状态
|
||
const eventStatus = ref(0)
|
||
|
||
// 是否为编辑
|
||
const isEdit = computed(() => {
|
||
return route.query.mode === 'edit'
|
||
})
|
||
|
||
const continueReport = ref(null)
|
||
|
||
// 所有填报记录(首报 + 续报)
|
||
const allReports = computed(() => {
|
||
const reports =
|
||
detailData.value.report?.map((item, index) => {
|
||
if (index === detailData.value.report.length - 1) {
|
||
item.title = '首报'
|
||
} else {
|
||
item.title = '续报' + (detailData.value.report.length - 1 - index)
|
||
}
|
||
return item
|
||
}) || []
|
||
return reports
|
||
// return reports.reverse()
|
||
})
|
||
|
||
// 是否有填报数据
|
||
const hasReportData = computed(() => {
|
||
return allReports.value.length > 0
|
||
})
|
||
|
||
// 获取事件状态文本
|
||
const getEventStatusText = () => {
|
||
return eventStatus.value === 1 ? '已解除' : '未解除'
|
||
}
|
||
|
||
// 获取事件状态类型
|
||
const getEventStatusType = () => {
|
||
return eventStatus.value === 1 ? 'success' : 'danger'
|
||
}
|
||
|
||
const getBaseDisposalMeasures = () => {
|
||
const firstItem = allReports.value[0]
|
||
if (!firstItem) return '-'
|
||
return formatDisposalMeasures(firstItem.disposalMeasures || '') || '-'
|
||
}
|
||
|
||
// 格式化处置措施
|
||
const formatDisposalMeasures = (measures) => {
|
||
if (!measures) return ''
|
||
const measureMap = {
|
||
半幅封闭: '半幅封闭',
|
||
全副封闭: '全副封闭',
|
||
便道通行: '便道通行',
|
||
正常通行: '正常通行'
|
||
}
|
||
return measures
|
||
.split(',')
|
||
.map((m) => measureMap[m.trim()] || m.trim())
|
||
.join('、')
|
||
}
|
||
|
||
// 获取损失描述
|
||
const getLossDescription = (report) => {
|
||
const lossList = report?.lossList
|
||
if (!lossList || lossList.length === 0) return '-'
|
||
|
||
const totalVolume = lossList.reduce((sum, loss) => {
|
||
const volume = (loss.length || 0) * (loss.width || 0) * (loss.height || 0)
|
||
return sum + volume
|
||
}, 0)
|
||
|
||
const totalAmount = lossList.reduce((sum, loss) => sum + (loss.totalAmount || 0), 0)
|
||
|
||
return `${totalVolume}方,共损失${totalAmount}万元`
|
||
}
|
||
|
||
// 获取车辆滞留文本
|
||
const getVehicleStrandedText = (report) => {
|
||
const count = report?.strandedVehicleCount || 0
|
||
return count > 0 ? `有车滞留,共${count}辆` : '无车滞留'
|
||
}
|
||
|
||
// 获取灾毁详情
|
||
const getDisasterDetail = async () => {
|
||
const id = route.query.id
|
||
if (!id) {
|
||
ElMessage.warning('缺少灾毁ID')
|
||
return
|
||
}
|
||
|
||
try {
|
||
const result = await request({
|
||
url: `/snow-ops-platform/water-damage/getById`,
|
||
method: 'get',
|
||
params: { id }
|
||
})
|
||
|
||
if (result?.data) {
|
||
const data = result.data
|
||
console.log('🚀 ~ getDisasterDetail ~ data:', data)
|
||
detailData.value = {
|
||
event: data.event || null,
|
||
report: data.report || [],
|
||
fileList: data.fileList || [],
|
||
lossList: data.lossList || [],
|
||
occurLocation: data.occurLocation || '',
|
||
occurTime: data.occurTime || '',
|
||
roadConditionType: data.roadConditionType || '',
|
||
routeNo: data.routeNo || ''
|
||
}
|
||
eventStatus.value = data.eventStatus || 0
|
||
|
||
if (isEdit.value) {
|
||
const newFormData = {
|
||
...data,
|
||
lossList: null,
|
||
report: route.query.mock ? mockData.report : {},
|
||
fileList: null
|
||
}
|
||
continueReport.value?.initFormData(newFormData)
|
||
}
|
||
} else {
|
||
ElMessage.warning(result.message || '获取详情失败')
|
||
}
|
||
} catch (error) {
|
||
console.error('获取灾毁详情失败:', error)
|
||
ElMessage.error('获取详情失败,请稍后重试')
|
||
}
|
||
}
|
||
|
||
// 点击返回
|
||
const handleClickBack = () => {
|
||
router.push('/disasterManagement')
|
||
}
|
||
|
||
onMounted(() => {
|
||
getDisasterDetail()
|
||
})
|
||
</script>
|
||
|
||
<style scoped lang="scss">
|
||
.web-detail-container {
|
||
padding: 20px;
|
||
background: #f5f7fa;
|
||
height: 100%;
|
||
overflow: auto;
|
||
padding-bottom: 100px;
|
||
}
|
||
|
||
.page-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 20px;
|
||
padding: 0 20px;
|
||
|
||
.header-left {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 16px;
|
||
|
||
.page-title {
|
||
margin: 0;
|
||
font-size: 20px;
|
||
font-weight: 600;
|
||
color: #303133;
|
||
}
|
||
}
|
||
}
|
||
|
||
.info-card {
|
||
margin-bottom: 20px;
|
||
border-radius: 8px;
|
||
|
||
:deep(.el-card__header) {
|
||
padding: 16px 20px;
|
||
border-bottom: 1px solid #ebeef5;
|
||
background: #fafafa;
|
||
}
|
||
|
||
.card-header {
|
||
.card-title {
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
color: #303133;
|
||
}
|
||
}
|
||
}
|
||
|
||
.info-row {
|
||
margin-bottom: 16px;
|
||
|
||
&:last-child {
|
||
margin-bottom: 0;
|
||
}
|
||
}
|
||
|
||
.info-item {
|
||
display: flex;
|
||
align-items: flex-start;
|
||
line-height: 1.5;
|
||
|
||
& + .info-item {
|
||
margin-top: 10px;
|
||
}
|
||
|
||
&.margin {
|
||
margin-top: 10px;
|
||
}
|
||
|
||
.info-label {
|
||
white-space: nowrap;
|
||
flex-shrink: 0;
|
||
color: #909399;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.info-value {
|
||
flex: 1;
|
||
color: #606266;
|
||
font-size: 14px;
|
||
word-break: break-all;
|
||
}
|
||
}
|
||
|
||
.report-section {
|
||
margin-bottom: 32px;
|
||
padding-bottom: 24px;
|
||
border-bottom: 1px solid #ebeef5;
|
||
|
||
&:last-child {
|
||
border-bottom: none;
|
||
margin-bottom: 0;
|
||
padding-bottom: 0;
|
||
}
|
||
}
|
||
|
||
.report-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: baseline;
|
||
margin-bottom: 20px;
|
||
padding-bottom: 12px;
|
||
border-bottom: 1px dashed #dcdfe6;
|
||
|
||
.report-title {
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
color: #409eff;
|
||
}
|
||
|
||
.report-meta {
|
||
font-size: 13px;
|
||
color: #909399;
|
||
}
|
||
}
|
||
|
||
.attachment-wrapper {
|
||
margin-top: 12px;
|
||
padding-top: 8px;
|
||
border-top: 1px dashed #ebeef5;
|
||
|
||
.attachment-item {
|
||
.attachment-list {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 16px;
|
||
|
||
.attachment-link {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
padding: 6px 12px;
|
||
background: #f5f7fa;
|
||
border-radius: 4px;
|
||
cursor: pointer;
|
||
|
||
&:hover {
|
||
background: #ecf5ff;
|
||
color: #409eff;
|
||
}
|
||
|
||
.file-name {
|
||
font-size: 13px;
|
||
max-width: 200px;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.footer-buttons {
|
||
position: fixed;
|
||
bottom: 0;
|
||
left: 0;
|
||
right: 0;
|
||
display: flex;
|
||
justify-content: center;
|
||
padding: 16px 24px;
|
||
background: #fff;
|
||
box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.08);
|
||
z-index: 100;
|
||
|
||
.footer-btn {
|
||
width: 200px;
|
||
height: 44px;
|
||
font-size: 16px;
|
||
border-radius: 22px;
|
||
}
|
||
}
|
||
.content-container {
|
||
display: flex;
|
||
.left-panel {
|
||
flex: 1;
|
||
margin-right: 10px;
|
||
}
|
||
.right-panel {
|
||
width: 300px;
|
||
}
|
||
}
|
||
.content-wrapper {
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
.basic-info-wrapper {
|
||
display: flex;
|
||
}
|
||
.detal-info-wrapper {
|
||
margin-top: 10px;
|
||
border-top: 1px solid #efefef;
|
||
padding-top: 10px;
|
||
}
|
||
.info-list {
|
||
flex: 1;
|
||
overflow: hidden;
|
||
}
|
||
.file-list {
|
||
|
||
}
|
||
</style>
|