feat: 灾毁管理
This commit is contained in:
parent
6203cf9ab9
commit
210128041e
@ -17,7 +17,7 @@ const props = defineProps({
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['back'])
|
||||
const emit = defineEmits(['click-back'])
|
||||
|
||||
const onClickLeft = () => {
|
||||
emit('click-back')
|
||||
|
||||
@ -105,6 +105,11 @@ const routes = [
|
||||
path: '/disasterReport',
|
||||
name: 'DisasterReport',
|
||||
component: () => import('../views/DisasterManagement/DisasterReport.vue')
|
||||
},
|
||||
{
|
||||
path: '/disasterDetail',
|
||||
name: 'DisasterDetail',
|
||||
component: () => import('../views/DisasterManagement/DisasterDetail.vue')
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
565
packages/mobile/src/views/DisasterManagement/DisasterDetail.vue
Normal file
565
packages/mobile/src/views/DisasterManagement/DisasterDetail.vue
Normal file
@ -0,0 +1,565 @@
|
||||
<template>
|
||||
<PageContainer title="灾毁详情" @click-back="handleClickBack" class="page-container">
|
||||
<!-- 当前站点信息 -->
|
||||
<CurrentSite />
|
||||
|
||||
<!-- 基本信息 -->
|
||||
<PanelItem title="基本信息">
|
||||
<template #headerExtra>
|
||||
<!-- 状态标签(需要从续报中判断是否已解除,或接口增加 eventStatus 字段) -->
|
||||
<div class="status-wrapper">
|
||||
<van-tag :type="getEventStatusType()" size="medium" plain>
|
||||
{{ getEventStatusText() }}
|
||||
</van-tag>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 事件类型 -->
|
||||
<div class="info-row">
|
||||
<span class="info-label">事件类型:</span>
|
||||
<span class="info-value">水毁事件</span>
|
||||
</div>
|
||||
|
||||
<!-- 路况类别 -->
|
||||
<div class="info-row">
|
||||
<span class="info-label">路况类别:</span>
|
||||
<span class="info-value">{{ detailData.roadConditionType || '-' }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 是否阻断 -->
|
||||
<div class="info-row">
|
||||
<span class="info-label">是否阻断:</span>
|
||||
<span class="info-value">{{ detailData.event?.isBlocked ? '是' : '否' }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 抢修进度 -->
|
||||
<div class="info-row">
|
||||
<span class="info-label">抢修进度:</span>
|
||||
<span class="info-value">{{ detailData.event?.repairProgress || '-' }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 处理措施(从首报中获取) -->
|
||||
<div class="info-row">
|
||||
<span class="info-label">处理措施:</span>
|
||||
<span class="info-value">{{ formatDisposalMeasures(firstReport?.disposalMeasures) || '-' }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 水毁处数 -->
|
||||
<div class="info-row">
|
||||
<span class="info-label">水毁处数:</span>
|
||||
<span class="info-value">{{ detailData.event?.damageCount || 0 }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 阻断里程 -->
|
||||
<div class="info-row">
|
||||
<span class="info-label">阻断里程:</span>
|
||||
<span class="info-value">{{ detailData.event?.blockedMileage ? detailData.event.blockedMileage + '公里' : '-' }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 发生时间 -->
|
||||
<div class="info-row">
|
||||
<span class="info-label">发生时间:</span>
|
||||
<span class="info-value">{{ detailData.occurTime || '-' }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 线路编号 -->
|
||||
<div class="info-row">
|
||||
<span class="info-label">线路编号:</span>
|
||||
<span class="info-value">{{ detailData.routeNo || '-' }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 地点路线 -->
|
||||
<div class="info-row">
|
||||
<span class="info-label">地点路线:</span>
|
||||
<span class="info-value">{{ detailData.occurLocation || '-' }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 起点桩号及经纬度 -->
|
||||
<div class="info-row">
|
||||
<span class="info-label">起点桩号:</span>
|
||||
<span class="info-value">{{ detailData.event?.startStakeNo || '-' }}</span>
|
||||
</div>
|
||||
<div class="info-row sub-row">
|
||||
<span class="info-label">起点桩经度:</span>
|
||||
<span class="info-value">{{ detailData.event?.startStakeLng || '-' }}</span>
|
||||
</div>
|
||||
<div class="info-row sub-row">
|
||||
<span class="info-label">起点桩纬度:</span>
|
||||
<span class="info-value">{{ detailData.event?.startStakeLat || '-' }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 止点桩号及经纬度 -->
|
||||
<div class="info-row">
|
||||
<span class="info-label">止点桩号:</span>
|
||||
<span class="info-value">{{ detailData.event?.endStakeNo || '-' }}</span>
|
||||
</div>
|
||||
<div class="info-row sub-row">
|
||||
<span class="info-label">止点桩经度:</span>
|
||||
<span class="info-value">{{ detailData.event?.endStakeLng || '-' }}</span>
|
||||
</div>
|
||||
<div class="info-row sub-row">
|
||||
<span class="info-label">止点桩纬度:</span>
|
||||
<span class="info-value">{{ detailData.event?.endStakeLat || '-' }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 路况位置(使用阻断点小地名或发生地点) -->
|
||||
<div class="info-row">
|
||||
<span class="info-label">路况位置:</span>
|
||||
<span class="info-value">{{ detailData.event?.blockedPointName || detailData.occurLocation || '-' }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 阻断点小地名 -->
|
||||
<div class="info-row">
|
||||
<span class="info-label">阻断点小地名:</span>
|
||||
<span class="info-value">{{ detailData.event?.blockedPointName || '-' }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 上报区县 -->
|
||||
<div class="info-row">
|
||||
<span class="info-label">上报区县:</span>
|
||||
<span class="info-value">{{ detailData.event?.district || '-' }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 巡查里程 -->
|
||||
<div class="info-row">
|
||||
<span class="info-label">巡查里程:</span>
|
||||
<span class="info-value">{{ detailData.event?.inspectionMileage ? detailData.event.inspectionMileage + '公里' : '-' }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 是否恢复重建 -->
|
||||
<div class="info-row">
|
||||
<span class="info-label">是否恢复重建:</span>
|
||||
<span class="info-value">{{ detailData.event?.needsRecovery ? '是' : '否' }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 恢复重建预估费用 -->
|
||||
<div class="info-row">
|
||||
<span class="info-label">恢复重建预估费用:</span>
|
||||
<span class="info-value">{{ detailData.event?.estimatedRecoveryCost ? detailData.event.estimatedRecoveryCost + '万元' : '-' }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 联系人 -->
|
||||
<div class="info-row">
|
||||
<span class="info-label">联系人:</span>
|
||||
<span class="info-value">{{ detailData.event?.contactPerson || '-' }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 联系电话 -->
|
||||
<div class="info-row">
|
||||
<span class="info-label">联系电话:</span>
|
||||
<span class="info-value">{{ detailData.event?.contactPhone || '-' }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 填报单位 -->
|
||||
<div class="info-row">
|
||||
<span class="info-label">填报单位:</span>
|
||||
<span class="info-value">{{ detailData.event?.reporterUnit || '-' }}</span>
|
||||
</div>
|
||||
</PanelItem>
|
||||
|
||||
<!-- 填报信息 -->
|
||||
<PanelItem title="填报信息">
|
||||
<!-- 首报信息 -->
|
||||
<div class="report-section" v-if="firstReport">
|
||||
<div class="report-header">
|
||||
<span class="report-title">首报</span>
|
||||
<span class="report-meta">{{ firstReport.reporterName || '-' }} {{ firstReport.reportTime || '-' }}</span>
|
||||
</div>
|
||||
<div class="report-content">
|
||||
<div class="info-row">
|
||||
<span class="info-label">处置情况:</span>
|
||||
<span class="info-value">{{ formatDisposalMeasures(firstReport.disposalMeasures) || '-' }}</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">塌方及损失:</span>
|
||||
<span class="info-value">{{ getLossDescription(firstReport) }}</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">路产损失:</span>
|
||||
<span class="info-value">{{ firstReport.totalLossAmount ? firstReport.totalLossAmount + '万元' : '-' }}</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">有无车辆滞留:</span>
|
||||
<span class="info-value">{{ getVehicleStrandedText(firstReport) }}</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">滞留车辆:</span>
|
||||
<span class="info-value">{{ firstReport.strandedVehicleCount || 0 }}辆</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">预计恢复时间:</span>
|
||||
<span class="info-value">{{ firstReport.expectRecoverTime || '-' }}</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">实际恢复时间:</span>
|
||||
<span class="info-value">{{ firstReport.actualRecoverTime || '-' }}</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">现场描述:</span>
|
||||
<span class="info-value">{{ firstReport.siteDescription || '-' }}</span>
|
||||
</div>
|
||||
<!-- 附件 -->
|
||||
<div class="info-row" v-if="firstReport.fileList && firstReport.fileList.length > 0">
|
||||
<span class="info-label">附件:</span>
|
||||
<div class="attachment-list">
|
||||
<div v-for="(file, index) in firstReport.fileList" :key="index" class="attachment-item">
|
||||
<van-icon :name="file.fileType === 1 ? 'photo-o' : 'video-o'" />
|
||||
<span class="file-name">{{ file.fileName }}</span>
|
||||
<van-button size="mini" type="primary" plain @click="previewFile(file)">预览</van-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 续报列表 -->
|
||||
<div v-for="(report, index) in continueReports" :key="index" class="report-section">
|
||||
<div class="report-header">
|
||||
<span class="report-title">续报{{ index + 1 }}</span>
|
||||
<span class="report-meta">{{ report.reporterName || '-' }} {{ report.reportTime || '-' }}</span>
|
||||
</div>
|
||||
<div class="report-content">
|
||||
<div class="info-row">
|
||||
<span class="info-label">处置情况:</span>
|
||||
<span class="info-value">{{ formatDisposalMeasures(report.disposalMeasures) || '-' }}</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">塌方及损失:</span>
|
||||
<span class="info-value">{{ getLossDescription(report) }}</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">路产损失:</span>
|
||||
<span class="info-value">{{ report.totalLossAmount ? report.totalLossAmount + '万元' : '-' }}</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">有无车辆滞留:</span>
|
||||
<span class="info-value">{{ getVehicleStrandedText(report) }}</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">滞留车辆:</span>
|
||||
<span class="info-value">{{ report.strandedVehicleCount || 0 }}辆</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">预计恢复时间:</span>
|
||||
<span class="info-value">{{ report.expectRecoverTime || '-' }}</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">实际恢复时间:</span>
|
||||
<span class="info-value">{{ report.actualRecoverTime || '-' }}</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-label">现场描述:</span>
|
||||
<span class="info-value">{{ report.siteDescription || '-' }}</span>
|
||||
</div>
|
||||
<!-- 附件 -->
|
||||
<div class="info-row" v-if="report.fileList && report.fileList.length > 0">
|
||||
<span class="info-label">附件:</span>
|
||||
<div class="attachment-list">
|
||||
<div v-for="(file, fileIndex) in report.fileList" :key="fileIndex" class="attachment-item">
|
||||
<van-icon :name="file.fileType === 1 ? 'photo-o' : 'video-o'" />
|
||||
<span class="file-name">{{ file.fileName }}</span>
|
||||
<van-button size="mini" type="primary" plain @click="previewFile(file)">预览</van-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 无填报信息时显示 -->
|
||||
<EmptyBox v-if="!hasReportData" placeholder="暂无填报信息" />
|
||||
</PanelItem>
|
||||
|
||||
<!-- 底部按钮:未解除状态显示续报按钮 -->
|
||||
<div class="footer-buttons" v-if="!isEventResolved">
|
||||
<van-button type="primary" class="footer-btn" @click="handleContinueReport">续报</van-button>
|
||||
</div>
|
||||
</PageContainer>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted, ref, computed } from 'vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { showToast } from 'vant'
|
||||
import PageContainer from '@/components/PageContainer.vue'
|
||||
import PanelItem from '@/components/PanelItem.vue'
|
||||
import CurrentSite from '@/components/CurrentSite.vue'
|
||||
import EmptyBox from '@/components/EmptyBox.vue'
|
||||
import { request } from '@shared/utils/request'
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
|
||||
// 详情数据(对应 Data 接口)
|
||||
const detailData = ref({
|
||||
event: null, // Event 对象
|
||||
report: null, // Report 对象(首报)
|
||||
reportList: [], // 续报列表(可选,如果接口返回)
|
||||
fileList: [], // 附件列表
|
||||
lossList: [], // 损失列表
|
||||
occurLocation: '',
|
||||
occurTime: '',
|
||||
roadConditionType: '',
|
||||
routeNo: ''
|
||||
})
|
||||
|
||||
// 首报(优先使用 report,如果没有则从 reportList 中找 reportType === 1)
|
||||
const firstReport = computed(() => {
|
||||
if (detailData.value.report) {
|
||||
return detailData.value.report
|
||||
}
|
||||
return detailData.value.reportList?.find(r => r.reportType === 1)
|
||||
})
|
||||
|
||||
// 续报列表(reportType === 2)
|
||||
const continueReports = computed(() => {
|
||||
return detailData.value.reportList?.filter(r => r.reportType === 2) || []
|
||||
})
|
||||
|
||||
// 是否有填报数据
|
||||
const hasReportData = computed(() => {
|
||||
return firstReport.value || continueReports.value.length > 0
|
||||
})
|
||||
|
||||
// 判断事件是否已解除(根据实际恢复时间或续报状态判断)
|
||||
const isEventResolved = computed(() => {
|
||||
// 如果首报有实际恢复时间且不为空,则认为已解除
|
||||
// if (firstReport.value?.actualRecoverTime) {
|
||||
// return true
|
||||
// }
|
||||
// // 检查续报中是否有实际恢复时间
|
||||
// return continueReports.value.some(r => r.actualRecoverTime)
|
||||
})
|
||||
|
||||
// 获取事件状态文本
|
||||
const getEventStatusText = () => {
|
||||
return isEventResolved.value ? '已解除' : '未解除'
|
||||
}
|
||||
|
||||
// 获取事件状态类型
|
||||
const getEventStatusType = () => {
|
||||
return isEventResolved.value ? 'success' : 'danger'
|
||||
}
|
||||
|
||||
// 格式化处置措施(逗号分隔转中文)
|
||||
const formatDisposalMeasures = (measures) => {
|
||||
if (!measures) return ''
|
||||
const measureMap = {
|
||||
halfClose: '半幅封闭',
|
||||
fullClose: '全副封闭',
|
||||
bypass: '便道通行',
|
||||
normal: '正常通行'
|
||||
}
|
||||
return measures
|
||||
.split(',')
|
||||
.map((m) => measureMap[m.trim()] || m.trim())
|
||||
.join('、')
|
||||
}
|
||||
|
||||
// 获取损失描述(从 lossList 计算塌方体积和总损失)
|
||||
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) {
|
||||
showToast('缺少灾毁ID')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await request({
|
||||
url: `/snow-ops-platform/water-damage/getById`,
|
||||
method: 'get',
|
||||
params: { id }
|
||||
})
|
||||
|
||||
if (result?.data) {
|
||||
// 接口返回 Data 结构
|
||||
const data = result.data
|
||||
detailData.value = {
|
||||
event: data.event || null,
|
||||
report: data.report || null,
|
||||
reportList: data.reportList || [],
|
||||
fileList: data.fileList || [],
|
||||
lossList: data.lossList || [],
|
||||
occurLocation: data.occurLocation || '',
|
||||
occurTime: data.occurTime || '',
|
||||
roadConditionType: data.roadConditionType || '',
|
||||
routeNo: data.routeNo || ''
|
||||
}
|
||||
} else {
|
||||
showToast(result.message || '获取详情失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取灾毁详情失败:', error)
|
||||
showToast('获取详情失败,请稍后重试')
|
||||
}
|
||||
}
|
||||
|
||||
// 点击返回
|
||||
const handleClickBack = () => {
|
||||
router.push('/disasterManagement')
|
||||
}
|
||||
|
||||
// 续报
|
||||
const handleContinueReport = () => {
|
||||
router.push({
|
||||
path: '/disasterReport',
|
||||
query: {
|
||||
id: route.query.id,
|
||||
eventId: detailData.value.event?.id,
|
||||
isContinue: 'true'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 预览附件
|
||||
const previewFile = (file) => {
|
||||
if (file.fileUrl) {
|
||||
window.open(file.fileUrl, '_blank')
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getDisasterDetail()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.page-container {
|
||||
padding-bottom: 80px;
|
||||
}
|
||||
|
||||
.status-wrapper {
|
||||
border-bottom: 1px solid #ebedf0;
|
||||
}
|
||||
|
||||
.info-row {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 12px;
|
||||
line-height: 1.4;
|
||||
|
||||
&.sub-row {
|
||||
margin-left: 20px;
|
||||
margin-top: -8px;
|
||||
}
|
||||
}
|
||||
|
||||
.info-label {
|
||||
width: 110px;
|
||||
flex-shrink: 0;
|
||||
color: #969799;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.info-value {
|
||||
flex: 1;
|
||||
color: #323233;
|
||||
font-size: 14px;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.report-section {
|
||||
margin-bottom: 24px;
|
||||
padding-bottom: 16px;
|
||||
border-bottom: 1px solid #ebedf0;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.report-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: baseline;
|
||||
margin-bottom: 12px;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 1px dashed #ebedf0;
|
||||
|
||||
.report-title {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #1989fa;
|
||||
}
|
||||
|
||||
.report-meta {
|
||||
font-size: 12px;
|
||||
color: #969799;
|
||||
}
|
||||
}
|
||||
|
||||
.report-content {
|
||||
.info-row {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.attachment-list {
|
||||
flex: 1;
|
||||
|
||||
.attachment-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin-bottom: 8px;
|
||||
padding: 8px;
|
||||
background: #f7f8fa;
|
||||
border-radius: 4px;
|
||||
|
||||
.van-icon {
|
||||
font-size: 20px;
|
||||
color: #1989fa;
|
||||
}
|
||||
|
||||
.file-name {
|
||||
flex: 1;
|
||||
font-size: 13px;
|
||||
color: #323233;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.footer-buttons {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
padding: 12px 16px;
|
||||
background: #fff;
|
||||
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.05);
|
||||
z-index: 10;
|
||||
|
||||
.footer-btn {
|
||||
flex: 1;
|
||||
height: 44px;
|
||||
border-radius: 22px;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -3,24 +3,24 @@
|
||||
<CurrentSite />
|
||||
|
||||
<div class="list-panel">
|
||||
<CardItem v-for="(item, index) in list" :key="index" :title="item.title" @click="handleClickItem(item)">
|
||||
<CardItem v-for="(item, index) in list" :key="index" :title="getEventTitle(item)" @click="handleClickItem(item)">
|
||||
<template #headerExtra>
|
||||
<van-tag :type="item.status === '未解除' ? 'danger' : 'success'" plain size="medium">
|
||||
{{ item.status }}
|
||||
<van-tag :type="getEventStatusType(item.eventStatus)" plain size="medium">
|
||||
{{ getEventStatusText(item.eventStatus) }}
|
||||
</van-tag>
|
||||
</template>
|
||||
|
||||
<div class="info-block">
|
||||
<div class="time-box">
|
||||
<span class="info-label">发生时间:</span>
|
||||
<span class="info-value">{{ item.occurTime }}</span>
|
||||
<span class="info-value">{{ item.occurTime || '-' }}</span>
|
||||
</div>
|
||||
<div class="time-box">
|
||||
<span class="info-label">预计恢复时间:</span>
|
||||
<span class="info-value">{{ item.estimateRecoverTime }}</span>
|
||||
<span class="info-value">{{ item.expectRecoverTime || '-' }}</span>
|
||||
</div>
|
||||
<div class="disaster-type-wrapper">
|
||||
<van-tag type="primary" size="medium" plain>{{ item.disasterType }}</van-tag>
|
||||
<van-tag class="tag" type="primary" size="medium" plain>{{ getDisasterTypeText(item) }}</van-tag>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -34,7 +34,7 @@
|
||||
<EmptyBox v-if="!loading && list.length === 0" :placeholder="emptyText" />
|
||||
</div>
|
||||
|
||||
<van-button type="primary" class="footer-btn" @click="handleAdd"> 灾害填报 </van-button>
|
||||
<van-button type="primary" class="footer-btn" @click="handleAdd">灾害填报</van-button>
|
||||
|
||||
<!-- 筛选组件:v-model 绑定选中的值,visible 控制显示隐藏 -->
|
||||
<TagFilter
|
||||
@ -78,7 +78,7 @@ const showFilter = ref(false)
|
||||
// 当前选中的灾毁类型(通过 v-model 传给 TagFilter)
|
||||
const selectedDisasterType = ref('all')
|
||||
|
||||
// 灾毁类型列表
|
||||
// 灾毁类型列表(根据实际数据中的路况类别或其他字段定义)
|
||||
const disasterTypes = [
|
||||
{ label: '全部', value: 'all' },
|
||||
{ label: '边坡坍塌', value: '边坡坍塌' },
|
||||
@ -91,6 +91,53 @@ const disasterTypes = [
|
||||
{ label: '其他', value: '其他' }
|
||||
]
|
||||
|
||||
// 获取事件标题
|
||||
const getEventTitle = (item) => {
|
||||
// 优先使用 eventName,其次使用发生地点+线路编号组合
|
||||
if (item.eventName) {
|
||||
return item.eventName
|
||||
}
|
||||
const parts = []
|
||||
if (item.routeNo) parts.push(item.routeNo)
|
||||
if (item.occurLocation) parts.push(item.occurLocation)
|
||||
if (item.startStakeNo) parts.push(item.startStakeNo)
|
||||
|
||||
if (parts.length > 0) {
|
||||
return parts.join(' ')
|
||||
}
|
||||
return '未命名事件'
|
||||
}
|
||||
|
||||
// 获取事件状态文本
|
||||
const getEventStatusText = (status) => {
|
||||
// eventStatus: 0-未解除 1-已解除
|
||||
return status === 1 ? '已解除' : '未解除'
|
||||
}
|
||||
|
||||
// 获取事件状态类型(用于标签颜色)
|
||||
const getEventStatusType = (status) => {
|
||||
return status === 1 ? 'success' : 'danger'
|
||||
}
|
||||
|
||||
// 获取灾毁类型文本(根据实际情况映射)
|
||||
const getDisasterTypeText = (item) => {
|
||||
// 可以根据 roadConditionType、repairProgress 或其他字段来生成类型标签
|
||||
// 这里提供几种可能的映射方式
|
||||
|
||||
// 方式1:根据抢修进度
|
||||
if (item.repairProgress) {
|
||||
return item.repairProgress
|
||||
}
|
||||
|
||||
// 方式2:根据路况类别
|
||||
if (item.roadConditionType) {
|
||||
return item.roadConditionType
|
||||
}
|
||||
|
||||
// 方式3:默认返回"水毁灾害"
|
||||
return '水毁灾害'
|
||||
}
|
||||
|
||||
// 获取简短类型名称
|
||||
const getShortTypeName = (type) => {
|
||||
const typeMap = {
|
||||
@ -101,9 +148,15 @@ const getShortTypeName = (type) => {
|
||||
'行道树倒塌': '树倒',
|
||||
'积水': '积水',
|
||||
'积雪': '积雪',
|
||||
'其他': '其他'
|
||||
'其他': '其他',
|
||||
'未抢修': '待抢修',
|
||||
'抢修中': '抢修中',
|
||||
'已完成': '已完成',
|
||||
'高速公路': '高速',
|
||||
'国道': '国道',
|
||||
'省道': '省道'
|
||||
}
|
||||
return typeMap[type] || type.substring(0, 2)
|
||||
return typeMap[type] || (type ? type.substring(0, 2) : '灾害')
|
||||
}
|
||||
|
||||
// 获取灾毁列表数据
|
||||
@ -115,12 +168,20 @@ const getDisasterList = async (keyword = '', disasterType = 'all') => {
|
||||
url: '/snow-ops-platform/water-damage/list',
|
||||
method: 'get',
|
||||
params: {
|
||||
keyword: keyword.trim(),
|
||||
disasterType: disasterType === 'all' ? '' : disasterType
|
||||
keyword: keyword.trim(),
|
||||
disasterType: disasterType === 'all' ? '' : disasterType
|
||||
}
|
||||
})
|
||||
if (result?.data?.records) {
|
||||
list.value = result.data.records
|
||||
list.value = result.data.records.map(item => ({
|
||||
...item,
|
||||
// 数据转换,确保前端使用的字段存在
|
||||
title: getEventTitle(item),
|
||||
status: getEventStatusText(item.eventStatus),
|
||||
occurTime: item.occurTime,
|
||||
estimateRecoverTime: item.expectRecoverTime,
|
||||
disasterType: getDisasterTypeText(item)
|
||||
}))
|
||||
} else {
|
||||
showToast(result.message || '获取数据失败')
|
||||
list.value = []
|
||||
@ -162,14 +223,9 @@ const handleClickBack = () => {
|
||||
// 点击列表项
|
||||
const handleClickItem = (item) => {
|
||||
router.push({
|
||||
path: '/disaster-detail',
|
||||
path: '/disasterDetail',
|
||||
query: {
|
||||
id: item.id,
|
||||
title: item.title,
|
||||
status: item.status,
|
||||
occurTime: item.occurTime,
|
||||
estimateRecoverTime: item.estimateRecoverTime,
|
||||
disasterType: item.disasterType
|
||||
id: item.id
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -271,4 +327,7 @@ onMounted(() => {
|
||||
border-color: #1989fa;
|
||||
}
|
||||
}
|
||||
:deep(.van-tag) {
|
||||
white-space: nowrap;
|
||||
}
|
||||
</style>
|
||||
@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<PageContainer title="灾毁填报" @click-back="handleClickBack" class="page-container">
|
||||
<PageContainer :title="title" @click-back="handleClickBack" class="page-container">
|
||||
<!-- 当前站点信息 -->
|
||||
<CurrentSite />
|
||||
|
||||
<!-- 事件类型 -->
|
||||
<PanelItem title="事件类型">
|
||||
<PanelItem title="事件类型" style="margin-bottom: 10px;" v-if="!isContinue">
|
||||
<van-radio-group v-model="eventType" direction="horizontal" class="event-type-group">
|
||||
<van-radio name="water">水毁灾害</van-radio>
|
||||
<van-radio name="ice">冰雪灾害</van-radio>
|
||||
@ -30,8 +30,8 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { ref, onMounted, computed } from 'vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { showToast, showSuccessToast, showFailToast } from 'vant'
|
||||
import PageContainer from '@/components/PageContainer.vue'
|
||||
import CurrentSite from '@/components/CurrentSite.vue'
|
||||
@ -41,6 +41,12 @@ import { request } from "@shared/utils/request";
|
||||
import mockFormData from './waterDisasterFormData.json'
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
|
||||
// 是否为续报
|
||||
const isContinue = computed(() => route.query.isContinue)
|
||||
|
||||
const title = ref(!isContinue ? '灾毁填报' : '灾毁续报')
|
||||
|
||||
// 事件类型
|
||||
const eventType = ref('water')
|
||||
@ -83,16 +89,17 @@ const handleSubmit = async () => {
|
||||
method: 'post',
|
||||
data: submitData
|
||||
})
|
||||
|
||||
|
||||
// 模拟提交接口
|
||||
await new Promise(resolve => setTimeout(resolve, 1000))
|
||||
showSuccessToast('提交成功')
|
||||
|
||||
if(res?.code === '00000') {
|
||||
showSuccessToast('提交成功')
|
||||
} else {
|
||||
showFailToast(res.message)
|
||||
}
|
||||
|
||||
// 提交成功后返回列表页
|
||||
setTimeout(() => {
|
||||
router.replace('/disasterManagement')
|
||||
}, 1500)
|
||||
}, 1000)
|
||||
} catch (error) {
|
||||
showFailToast('提交失败,请重试')
|
||||
console.error('提交失败:', error)
|
||||
@ -101,8 +108,45 @@ const handleSubmit = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
// 获取灾毁详情
|
||||
const getDisasterDetail = async () => {
|
||||
const id = route.query.id
|
||||
if (!id) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await request({
|
||||
url: `/snow-ops-platform/water-damage/getById`,
|
||||
method: 'get',
|
||||
params: { id }
|
||||
})
|
||||
|
||||
if (result?.data) {
|
||||
// 接口返回 Data 结构
|
||||
const data = result.data
|
||||
const newFormData = {
|
||||
...data,
|
||||
lossList: null,
|
||||
report: formData.value.report,
|
||||
fileList: null
|
||||
}
|
||||
waterDisasterRef.value.initFormData(newFormData)
|
||||
} else {
|
||||
showToast(result.message || '获取详情失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取灾毁详情失败:', error)
|
||||
showToast('获取详情失败,请稍后重试')
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
waterDisasterRef.value.initFormData(formData.value)
|
||||
if(route.query?.id) {
|
||||
getDisasterDetail()
|
||||
} else {
|
||||
waterDisasterRef.value.initFormData(formData.value)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<!-- 损失计算弹窗 -->
|
||||
<van-dialog
|
||||
v-model:show="visible"
|
||||
title="塌方损失信息"
|
||||
:title="itemName + '损失信息'"
|
||||
show-cancel-button
|
||||
@confirm="confirm"
|
||||
@cancel="cancelLoss"
|
||||
@ -11,21 +11,21 @@
|
||||
>
|
||||
<div class="loss-dialog-content">
|
||||
<!-- 塌方长 -->
|
||||
<van-field v-model="formData.length" label="塌方长" placeholder="请填写长度" type="digit" clearable>
|
||||
<van-field v-model="formData.length" :label="itemName + '长'" placeholder="请填写长度" type="digit" clearable>
|
||||
<template #button>
|
||||
<span class="field-unit">米</span>
|
||||
</template>
|
||||
</van-field>
|
||||
|
||||
<!-- 塌方宽 -->
|
||||
<van-field v-model="formData.width" label="塌方宽" placeholder="请填写宽度" type="digit" clearable>
|
||||
<van-field v-model="formData.width" :label="itemName + '宽'" placeholder="请填写宽度" type="digit" clearable>
|
||||
<template #button>
|
||||
<span class="field-unit">米</span>
|
||||
</template>
|
||||
</van-field>
|
||||
|
||||
<!-- 塌方高 -->
|
||||
<van-field v-model="formData.height" label="塌方高" placeholder="请填写高度" type="digit" clearable>
|
||||
<van-field v-model="formData.height" :label="itemName + '高'" placeholder="请填写高度" type="digit" clearable>
|
||||
<template #button>
|
||||
<span class="field-unit">米</span>
|
||||
</template>
|
||||
@ -38,7 +38,7 @@
|
||||
</template>
|
||||
</van-field>
|
||||
|
||||
<van-field v-model="formData.totalPrice" label="塌方损失金额" placeholder="请填写金额" type="digit" clearable>
|
||||
<van-field v-model="formData.totalAmount" :label="itemName + '损失金额'" placeholder="请填写金额" type="digit" clearable>
|
||||
<template #button>
|
||||
<span class="field-unit">元</span>
|
||||
</template>
|
||||
@ -61,7 +61,9 @@ const formData = ref({
|
||||
unitPrice: ''
|
||||
})
|
||||
|
||||
const totalPrice = computed(() => {
|
||||
const itemName = ref('')
|
||||
|
||||
const totalAmount = computed(() => {
|
||||
const l = parseFloat(formData.value.length)
|
||||
const w = parseFloat(formData.value.width)
|
||||
const h = parseFloat(formData.value.height)
|
||||
@ -84,14 +86,25 @@ const totalPrice = computed(() => {
|
||||
return (l * w * h * price)
|
||||
})
|
||||
|
||||
watch(totalPrice, ()=>{
|
||||
formData.value.totalPrice = totalPrice.value
|
||||
watch(totalAmount, ()=>{
|
||||
formData.value.totalAmount = totalAmount.value
|
||||
})
|
||||
// 显示弹窗
|
||||
const show = () => {
|
||||
const show = (item) => {
|
||||
console.log("🚀 ~ show ~ item:", item)
|
||||
formData.value.length = item.length
|
||||
formData.value.width = item.width
|
||||
formData.value.height = item.height
|
||||
formData.value.unitPrice = item.unitPrice
|
||||
formData.value.totalAmount = item.totalAmount
|
||||
itemName.value = getItemName(item)
|
||||
visible.value = true
|
||||
}
|
||||
|
||||
const getItemName = (item) => {
|
||||
return item.lossTypeName
|
||||
}
|
||||
|
||||
// 验证表单数据
|
||||
const validateForm = () => {
|
||||
const l = parseFloat(formData.length)
|
||||
@ -125,11 +138,11 @@ const validateForm = () => {
|
||||
|
||||
// 确认损失计算
|
||||
const confirm = () => {
|
||||
if(!formData.value.totalPrice) {
|
||||
if(!formData.value.totalAmount) {
|
||||
showToast('请填写损失金额')
|
||||
return
|
||||
}
|
||||
emit('confirm', formData.value.totalPrice)
|
||||
emit('confirm', formData.value)
|
||||
// 重置表单
|
||||
resetForm()
|
||||
visible.value = false
|
||||
@ -147,7 +160,7 @@ const resetForm = () => {
|
||||
formData.value.width = ''
|
||||
formData.value.height = ''
|
||||
formData.value.unitPrice = ''
|
||||
formData.value.totalPrice
|
||||
formData.value.totalAmount
|
||||
}
|
||||
// 定义事件
|
||||
const emit = defineEmits(['confirm'])
|
||||
|
||||
@ -1,14 +1,15 @@
|
||||
<template>
|
||||
<div class="loss-list">
|
||||
<template v-for="item in modelValue">
|
||||
<van-field v-model="item.totalAmount" :label="getItemLabel(item)" placeholder="请填写" type="digit" @click="cubeCalculateDialog.show()">
|
||||
<template v-for="(item, index) in modelValue">
|
||||
<van-field v-model="item.totalAmount" :label="getItemLabel(item)" placeholder="请填写" type="digit" @click="showCalculateDialog(item, index)">
|
||||
<template #button>
|
||||
<span class="field-unit">方/万元</span>
|
||||
<span class="field-unit">{{ item.unit }}</span>
|
||||
<van-icon @click.stop="removeItem(index)" class="remove-icon" name="delete-o" />
|
||||
</template>
|
||||
</van-field>
|
||||
</template>
|
||||
<van-button size="small" block type="primary" plain @click="addLoss">添加损失</van-button>
|
||||
<CubeCalculateDialog ref="cubeCalculateDialog" />
|
||||
<CubeCalculateDialog ref="cubeCalculateDialog" @confirm="confirmCalculate" />
|
||||
<LossPicker ref="lossPicker" :options="options" @confirm="confirmAddLoss" />
|
||||
</div>
|
||||
</template>
|
||||
@ -31,6 +32,9 @@ const props = defineProps({
|
||||
const lossPicker = ref(null)
|
||||
|
||||
const options = ref({})
|
||||
|
||||
const dialogItemIndex = ref(null)
|
||||
|
||||
// 添加损失项
|
||||
const addLoss = () => {
|
||||
lossPicker.value?.show()
|
||||
@ -40,6 +44,10 @@ const confirmAddLoss = (item) => {
|
||||
emit('update:modelValue', [...props.modelValue, item])
|
||||
}
|
||||
|
||||
const removeItem = (index) => {
|
||||
emit('update:modelValue', [...props.modelValue.slice(0, index), ...props.modelValue.slice(index + 1)])
|
||||
}
|
||||
|
||||
const cubeCalculateDialog = ref(null)
|
||||
|
||||
const getItemLabel = (item) => {
|
||||
@ -62,6 +70,18 @@ const getLossDict = async (params) => {
|
||||
})
|
||||
}
|
||||
|
||||
const showCalculateDialog = (item, index) => {
|
||||
if(item.unit?.indexOf('方') > -1) {
|
||||
dialogItemIndex.value = index
|
||||
cubeCalculateDialog.value?.show(item)
|
||||
}
|
||||
}
|
||||
|
||||
const confirmCalculate = (newValue) => {
|
||||
const oldItem = props.modelValue[dialogItemIndex.value]
|
||||
props.modelValue[dialogItemIndex.value] = { ...oldItem, ...newValue }
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await getLossDict()
|
||||
})
|
||||
@ -109,4 +129,10 @@ onMounted(async () => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.remove-icon {
|
||||
margin-left: 5px;
|
||||
font-size: 16px;
|
||||
color: #ee0a24;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="water-disaster">
|
||||
<!-- 基本信息 -->
|
||||
<PanelItem title="基本信息">
|
||||
<PanelItem title="基本信息" v-if="!isContinue">
|
||||
<van-form>
|
||||
<!-- 路况类别 -->
|
||||
<BasePicker v-model="formData.roadConditionType" :options="roadConditionOptions" label="路况类别" placeholder="请选择" />
|
||||
@ -175,7 +175,7 @@
|
||||
<!-- 是否需要恢复重建 (event.needsRecovery) -->
|
||||
<BasePicker v-model="formData.event.needsRecovery" :options="needsRecoveryOptions" label="是否需要恢复重建" placeholder="请选择" />
|
||||
<!-- 恢复重建预估费用 (event.estimatedRecoveryCost) -->
|
||||
<van-field v-model="formData.event.estimatedRecoveryCost" label="恢复重建预估费用" placeholder="请填写" type="digit">
|
||||
<van-field v-model="formData.event.estimatedRecoveryCost" v-if="!isContinue" label="恢复重建预估费用" placeholder="请填写" type="digit">
|
||||
<template #button>
|
||||
<span class="field-unit">万元</span>
|
||||
</template>
|
||||
@ -191,7 +191,12 @@ import PanelItem from '@/components/PanelItem.vue'
|
||||
import BasePicker from '@/components/BasePicker.vue'
|
||||
import BaseDatePicker from '@/components/BaseDatePicker.vue'
|
||||
import LossList from './LossList.vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
|
||||
const route = useRoute()
|
||||
|
||||
// 是否为续报
|
||||
const isContinue = computed(() => route.query.isContinue)
|
||||
|
||||
// 处置措施数组(用于多选框组,需要转换为逗号分隔的字符串)
|
||||
const disposalMeasuresArray = ref([])
|
||||
|
||||
@ -40,24 +40,6 @@
|
||||
"totalLossAmount": 85.6
|
||||
},
|
||||
"lossList": [
|
||||
{
|
||||
"length": 50,
|
||||
"width": 8.5,
|
||||
"height": 2.5,
|
||||
"unitPrice": 380,
|
||||
"totalAmount": 38.9,
|
||||
"lossCategory": "路面损毁",
|
||||
"remark": "沥青路面严重损坏"
|
||||
},
|
||||
{
|
||||
"length": 30,
|
||||
"width": 2.5,
|
||||
"height": 6,
|
||||
"unitPrice": 520,
|
||||
"totalAmount": 23.4,
|
||||
"lossCategory": "挡墙损毁",
|
||||
"remark": "浆砌片石挡墙垮塌"
|
||||
}
|
||||
],
|
||||
"fileList": []
|
||||
}
|
||||
@ -66,7 +66,6 @@ const routes = [
|
||||
breadcrumb: true
|
||||
},
|
||||
component: () => import('../views/airSkyLand/AirSkyLand.vue')
|
||||
|
||||
},
|
||||
{
|
||||
path: '/3DSituationalAwareness',
|
||||
@ -74,7 +73,7 @@ const routes = [
|
||||
meta: {
|
||||
title: '三维态势感知',
|
||||
screen: true,
|
||||
skipInitialCameraView: true, // 跳过MapViewport的自动初始视图,由页面自己控制相机
|
||||
skipInitialCameraView: true, // 跳过MapViewport的自动初始视图,由页面自己控制相机
|
||||
breadcrumb: true
|
||||
},
|
||||
component: () => import('../views/3DSituationalAwarenessRefactor/index.vue')
|
||||
@ -149,6 +148,24 @@ const routes = [
|
||||
title: '项目管理',
|
||||
breadcrumb: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/disasterManagement',
|
||||
name: 'disasterManagement',
|
||||
component: () => import('../views/DisasterManagement/DisasterManagement.vue'),
|
||||
meta: {
|
||||
title: '灾害巡检事件',
|
||||
breadcrumb: true
|
||||
}
|
||||
},
|
||||
{
|
||||
path: '/disasterReport',
|
||||
name: 'DisasterReport',
|
||||
component: () => import('../views/DisasterManagement/DisasterReport/DisasterReport.vue'),
|
||||
meta: {
|
||||
title: '水毁事件填报',
|
||||
breadcrumb: true
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
@ -0,0 +1,403 @@
|
||||
<template>
|
||||
<div class="page-container">
|
||||
<!-- 筛选栏 -->
|
||||
<el-card class="filter-card" shadow="never">
|
||||
<el-form :model="filterForm" label-width="100px" @submit.prevent>
|
||||
<el-row :gutter="20">
|
||||
<el-col :xs="24" :sm="12" :md="8" :lg="6">
|
||||
<el-form-item label="所属单位">
|
||||
<el-input v-model="filterForm.unit" placeholder="请输入" clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="12" :md="8" :lg="6">
|
||||
<el-form-item label="发生地点">
|
||||
<el-input v-model="filterForm.occurLocation" placeholder="请输入" clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="12" :md="8" :lg="6">
|
||||
<el-form-item label="路线编号">
|
||||
<el-input v-model="filterForm.routeNo" placeholder="请输入" clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="12" :md="8" :lg="6">
|
||||
<el-form-item label="事件类别">
|
||||
<el-select v-model="filterForm.disasterType" placeholder="请选择" clearable>
|
||||
<el-option label="水毁事件" value="水毁事件" />
|
||||
<el-option label="塌方事件" value="塌方事件" />
|
||||
<el-option label="泥石流" value="泥石流" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="12" :md="8" :lg="6">
|
||||
<el-form-item label="事件状态">
|
||||
<el-select v-model="filterForm.eventStatus" placeholder="请选择" clearable>
|
||||
<el-option label="未解除" :value="0" />
|
||||
<el-option label="已解除" :value="1" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="12" :md="8" :lg="6">
|
||||
<el-form-item label="是否阻断">
|
||||
<el-select v-model="filterForm.isBlocked" placeholder="请选择" clearable>
|
||||
<el-option label="是" value="是" />
|
||||
<el-option label="否" value="否" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="12" :md="8" :lg="6">
|
||||
<el-form-item label="路线类型">
|
||||
<el-select v-model="filterForm.roadConditionType" placeholder="请选择" clearable>
|
||||
<el-option label="国省道" value="国省道" />
|
||||
<el-option label="县乡道" value="县乡道" />
|
||||
<el-option label="高速" value="高速" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="12" :md="8" :lg="6">
|
||||
<el-form-item label="日期">
|
||||
<el-date-picker
|
||||
v-model="dateRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始时间"
|
||||
end-placeholder="结束日期"
|
||||
value-format="YYYY-MM-DD"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :xs="24" :sm="24" :md="24" :lg="24">
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleQuery">查询</el-button>
|
||||
<el-button @click="toReport">新增</el-button>
|
||||
<el-button type="success" @click="handleExport">导出Excel</el-button>
|
||||
<el-button @click="resetFilters">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<!-- 数据表格卡片 -->
|
||||
<el-card class="table-card" shadow="never">
|
||||
<div class="table-container">
|
||||
<el-table :data="tableData" border stripe v-loading="loading" style="width: 100%" height="100%">
|
||||
<el-table-column label="序号" width="60">
|
||||
<template #default="scope">
|
||||
{{ scope.$index + 1 }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="routeNo" label="所属区县" min-width="120" />
|
||||
<el-table-column prop="routeNo" label="路线编号" min-width="120" />
|
||||
<el-table-column prop="routeName" label="路线名称" min-width="150" show-overflow-tooltip />
|
||||
<el-table-column prop="startPile" label="起点桩号" min-width="110" />
|
||||
<el-table-column prop="endPile" label="终点桩号" min-width="110" />
|
||||
<el-table-column prop="occurLocation" label="发生地点" min-width="180" show-overflow-tooltip />
|
||||
<el-table-column prop="isBlocked" label="是否阻断" width="90" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.isBlocked === '是' ? 'danger' : 'success'" size="small">
|
||||
{{ row.isBlocked || '—' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="disasterType" label="灾害类型" min-width="120" />
|
||||
<el-table-column prop="roadConditionType" label="路线类别" min-width="110" />
|
||||
<el-table-column prop="eventStatus" label="事件状态" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="row.eventStatus === 1 ? 'success' : 'danger'" size="small">
|
||||
{{ row.eventStatus === 1 ? '已解除' : '未解除' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="measure" label="处理措施" min-width="120" show-overflow-tooltip />
|
||||
<el-table-column prop="occurTime" label="发生时间" width="170" />
|
||||
<el-table-column prop="expectRecoverTime" label="预计恢复时间" width="170" />
|
||||
<el-table-column prop="contactPerson" label="联系人" width="110" />
|
||||
<el-table-column prop="contactPhone" label="联系电话" width="120" />
|
||||
<el-table-column label="图片" width="80" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-button v-if="row.hasImage" link type="primary" size="small" @click="viewImages(row)">查看</el-button>
|
||||
<span v-else>—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="视频" width="80" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-button v-if="row.hasVideo" link type="primary" size="small" @click="viewVideos(row)">播放</el-button>
|
||||
<span v-else>—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="100" fixed="right" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-button link type="primary" size="small" @click="handleDetail(row)">详情</el-button>
|
||||
<el-button link type="warning" size="small" @click="handleEdit(row)">编辑</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination-container">
|
||||
<el-pagination
|
||||
v-model:current-page="pagination.currentPage"
|
||||
v-model:page-size="pagination.pageSize"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:total="pagination.total"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { request } from '@/utils/request'
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
// 筛选表单
|
||||
const filterForm = reactive({
|
||||
unit: '', // 所属单位
|
||||
occurLocation: '', // 发生地点
|
||||
routeNo: '', // 路线编号
|
||||
disasterType: '', // 灾害类型/事件类别
|
||||
eventStatus: '', // 事件状态 (0-未解除, 1-已解除)
|
||||
isBlocked: '', // 是否阻断
|
||||
roadConditionType: '', // 路线类型
|
||||
pushStatus: '' // 推送状态
|
||||
})
|
||||
|
||||
// 日期范围
|
||||
const dateRange = ref(null)
|
||||
|
||||
// 表格数据
|
||||
const tableData = ref([])
|
||||
const loading = ref(false)
|
||||
|
||||
// 分页参数
|
||||
const pagination = reactive({
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
total: 0
|
||||
})
|
||||
|
||||
// 构建查询参数
|
||||
const buildQueryParams = () => {
|
||||
const params = {
|
||||
pageNum: pagination.currentPage,
|
||||
pageSize: pagination.pageSize,
|
||||
unit: filterForm.unit,
|
||||
occurLocation: filterForm.occurLocation,
|
||||
routeNo: filterForm.routeNo,
|
||||
disasterType: filterForm.disasterType,
|
||||
eventStatus: filterForm.eventStatus,
|
||||
isBlocked: filterForm.isBlocked,
|
||||
roadConditionType: filterForm.roadConditionType
|
||||
}
|
||||
|
||||
if (dateRange.value && dateRange.value.length === 2) {
|
||||
params.startDate = dateRange.value[0]
|
||||
params.endDate = dateRange.value[1]
|
||||
}
|
||||
|
||||
// 过滤空字符串或null的参数
|
||||
Object.keys(params).forEach((key) => {
|
||||
if (params[key] === '' || params[key] === null || params[key] === undefined) {
|
||||
delete params[key]
|
||||
}
|
||||
})
|
||||
return params
|
||||
}
|
||||
|
||||
// 查询数据
|
||||
const fetchData = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const params = buildQueryParams()
|
||||
|
||||
// 实际接口调用
|
||||
const response = await request({
|
||||
url: '/snow-ops-platform/unified-disaster/list',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
|
||||
if (response.code === '00000') {
|
||||
const records = response.data.records || response.data || []
|
||||
tableData.value = records.map((item) => ({
|
||||
...item,
|
||||
// 转换状态显示
|
||||
eventStatusText: item.eventStatus === 1 ? '已解除' : '未解除',
|
||||
// 保留原始数据
|
||||
...item
|
||||
}))
|
||||
pagination.total = response.data.total || records.length
|
||||
} else {
|
||||
ElMessage.error(response.message || '查询失败')
|
||||
}
|
||||
} catch (error) {
|
||||
ElMessage.error('数据加载失败')
|
||||
console.error(error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 查询按钮
|
||||
const handleQuery = () => {
|
||||
pagination.currentPage = 1
|
||||
fetchData()
|
||||
}
|
||||
|
||||
// 导出Excel
|
||||
const handleExport = async () => {
|
||||
try {
|
||||
const params = buildQueryParams()
|
||||
const response = await request({
|
||||
url: '/api/disaster/record/export',
|
||||
method: 'post',
|
||||
data: params,
|
||||
responseType: 'blob'
|
||||
})
|
||||
|
||||
// 创建下载链接
|
||||
const blob = new Blob([response], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' })
|
||||
const link = document.createElement('a')
|
||||
const url = URL.createObjectURL(blob)
|
||||
link.href = url
|
||||
link.download = `水毁事件列表_${new Date().getTime()}.xlsx`
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
URL.revokeObjectURL(url)
|
||||
|
||||
ElMessage.success('导出成功')
|
||||
} catch (error) {
|
||||
ElMessage.error('导出失败')
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
|
||||
// 重置筛选条件
|
||||
const resetFilters = () => {
|
||||
filterForm.unit = ''
|
||||
filterForm.occurLocation = ''
|
||||
filterForm.routeNo = ''
|
||||
filterForm.disasterType = ''
|
||||
filterForm.eventStatus = ''
|
||||
filterForm.isBlocked = ''
|
||||
filterForm.roadConditionType = ''
|
||||
filterForm.pushStatus = ''
|
||||
dateRange.value = null
|
||||
handleQuery()
|
||||
}
|
||||
|
||||
// 查看详情
|
||||
const handleDetail = (row) => {
|
||||
router.push({ path: '/disasterDetail', query: { id: row.id } })
|
||||
}
|
||||
|
||||
// 编辑
|
||||
const handleEdit = (row) => {
|
||||
router.push({ path: '/disasterReport', query: { id: row.id, mode: 'edit' } })
|
||||
}
|
||||
|
||||
// 新增跳转
|
||||
const toReport = () => {
|
||||
router.push('/disasterReport')
|
||||
}
|
||||
|
||||
// 查看图片
|
||||
const viewImages = (row) => {
|
||||
if (row.images && row.images.length) {
|
||||
// 打开图片预览
|
||||
ElMessage.info('图片预览功能开发中')
|
||||
} else {
|
||||
ElMessage.info('暂无图片')
|
||||
}
|
||||
}
|
||||
|
||||
// 查看视频
|
||||
const viewVideos = (row) => {
|
||||
if (row.videos && row.videos.length) {
|
||||
ElMessage.info('视频播放功能开发中')
|
||||
} else {
|
||||
ElMessage.info('暂无视频')
|
||||
}
|
||||
}
|
||||
|
||||
// 分页大小改变
|
||||
const handleSizeChange = (val) => {
|
||||
pagination.pageSize = val
|
||||
fetchData()
|
||||
}
|
||||
|
||||
// 页码改变
|
||||
const handleCurrentChange = (val) => {
|
||||
pagination.currentPage = val
|
||||
fetchData()
|
||||
}
|
||||
|
||||
// 初始化加载数据
|
||||
onMounted(() => {
|
||||
fetchData()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.page-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
padding: 20px;
|
||||
background-color: #f5f7fa;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
|
||||
.filter-card {
|
||||
flex-shrink: 0;
|
||||
margin-bottom: 20px;
|
||||
|
||||
:deep(.el-card__body) {
|
||||
padding: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.table-card {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
|
||||
:deep(.el-card__body) {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.table-container {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
padding: 0 20px;
|
||||
|
||||
:deep(.el-table) {
|
||||
--el-table-border-color: #ebeef5;
|
||||
}
|
||||
}
|
||||
|
||||
.pagination-container {
|
||||
flex-shrink: 0;
|
||||
padding: 16px 20px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
border-top: 1px solid #ebeef5;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,115 @@
|
||||
<template>
|
||||
<div class="disaster-report">
|
||||
<el-page-header @back="handleBack" class="page-header">
|
||||
<template #content>
|
||||
<span class="title">{{ isEdit ? '灾毁填报' : '灾毁填报' }}</span>
|
||||
</template>
|
||||
</el-page-header>
|
||||
|
||||
<WaterDisasterReport />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, computed, onMounted } from 'vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { Plus, Upload } from '@element-plus/icons-vue'
|
||||
import { request } from '@/utils/request'
|
||||
import WaterDisasterReport from './WaterDisasterReport.vue'
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const isEdit = computed(() => !!route.query.id)
|
||||
|
||||
const handleBack = () => {
|
||||
router.back()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.disaster-report {
|
||||
padding: 20px;
|
||||
background-color: #f5f7fa;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
|
||||
.page-header {
|
||||
margin-bottom: 20px;
|
||||
padding: 0 0 16px 0;
|
||||
border-bottom: 1px solid #e4e7ed;
|
||||
|
||||
.title {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
}
|
||||
|
||||
.disaster-form {
|
||||
.form-section {
|
||||
margin-bottom: 20px;
|
||||
|
||||
:deep(.el-card__header) {
|
||||
padding: 12px 20px;
|
||||
background-color: #fafafa;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
}
|
||||
|
||||
:deep(.el-card__body) {
|
||||
padding: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.section-header {
|
||||
.section-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
position: relative;
|
||||
padding-left: 10px;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 3px;
|
||||
height: 16px;
|
||||
background-color: #409eff;
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sub-section-title {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: #606266;
|
||||
margin: 8px 0 16px 0;
|
||||
padding-left: 8px;
|
||||
border-left: 3px solid #409eff;
|
||||
}
|
||||
|
||||
.unit-suffix {
|
||||
margin-left: 8px;
|
||||
color: #909399;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.upload-tip {
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 16px;
|
||||
padding: 20px 0 40px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,735 @@
|
||||
<template>
|
||||
<div class="disaster-form-page">
|
||||
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="140px" class="disaster-form" @submit.prevent>
|
||||
<!-- 基础信息区块 -->
|
||||
<el-card class="form-section" shadow="never">
|
||||
<template #header>
|
||||
<div class="section-header">
|
||||
<span class="section-title">基础信息</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-row :gutter="24">
|
||||
<!-- 填报人员信息 -->
|
||||
<el-col :span="24">
|
||||
<div class="sub-section-title">填报人员信息</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="填报单位" prop="reportUnit">
|
||||
<el-input v-model="formData.reportUnit" placeholder="请输入填报单位" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="联系人" prop="contactPerson">
|
||||
<el-input v-model="formData.contactPerson" placeholder="请输入联系人" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="联系电话" prop="contactPhone">
|
||||
<el-input v-model="formData.contactPhone" placeholder="请输入联系电话" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<!-- 路况事件信息 -->
|
||||
<el-col :span="24">
|
||||
<div class="sub-section-title">路况事件信息</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="事件类型" prop="eventType">
|
||||
<el-select v-model="formData.eventType" placeholder="请选择" style="width: 100%">
|
||||
<el-option label="水毁灾害" value="水毁灾害" />
|
||||
<el-option label="冰雪灾害" value="冰雪灾害" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="路况类别" prop="blockedMileage">
|
||||
<el-input-number v-model="formData.blockedMileage" :min="0" :precision="3" style="width: 100%" placeholder="请填写" />
|
||||
<span class="unit-suffix">公里</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="是否阻断" prop="isBlocked">
|
||||
<el-select v-model="formData.isBlocked" placeholder="请选择" style="width: 100%">
|
||||
<el-option label="是" value="是" />
|
||||
<el-option label="否" value="否" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="抢险进度" prop="isBlocked">
|
||||
<el-select v-model="formData.isBlocked" placeholder="请选择" style="width: 100%">
|
||||
<el-option label="是" value="是" />
|
||||
<el-option label="否" value="否" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="处理措施" prop="measure">
|
||||
<el-select v-model="formData.measure" placeholder="请选择" style="width: 100%">
|
||||
<el-option label="正常通行" value="正常通行" />
|
||||
<el-option label="交通管制" value="交通管制" />
|
||||
<el-option label="封闭施工" value="封闭施工" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="水毁处数" prop="waterDamageCount">
|
||||
<el-input-number v-model="formData.waterDamageCount" :min="0" :step="1" style="width: 100%" placeholder="请填写" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="24">
|
||||
<el-row>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="阻断里程" prop="blockedMileage">
|
||||
<el-input-number v-model="formData.blockedMileage" :min="0" :precision="3" style="width: 100%" placeholder="请填写" />
|
||||
<span class="unit-suffix">公里</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="发现时间" prop="discoverTime">
|
||||
<el-date-picker v-model="formData.discoverTime" type="datetime" placeholder="请选择日期时间" style="width: 100%" value-format="YYYY-MM-DD HH:mm:ss" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="预计恢复" prop="predictRecoverTime">
|
||||
<el-date-picker v-model="formData.predictRecoverTime" type="datetime" placeholder="请选择日期时间" style="width: 100%" value-format="YYYY-MM-DD HH:mm:ss" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="24">
|
||||
<el-form-item label="现场描述" prop="siteDescription">
|
||||
<el-input v-model="formData.siteDescription" type="textarea" :rows="3" placeholder="请输入现场描述及续行方案" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-card>
|
||||
|
||||
<!-- 位置信息区块 -->
|
||||
<el-card class="form-section" shadow="never">
|
||||
<template #header>
|
||||
<div class="section-header">
|
||||
<span class="section-title">位置信息</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="路线类型" prop="routeType">
|
||||
<el-select v-model="formData.routeType" placeholder="请选择" style="width: 100%">
|
||||
<el-option label="国省道" value="国省道" />
|
||||
<el-option label="县乡道" value="县乡道" />
|
||||
<el-option label="高速" value="高速" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="所属区县" prop="district">
|
||||
<el-select v-model="formData.district" placeholder="请选择" style="width: 100%">
|
||||
<el-option label="万州区" value="万州区" />
|
||||
<el-option label="开州区" value="开州区" />
|
||||
<el-option label="黔江区" value="黔江区" />
|
||||
<el-option label="涪陵区" value="涪陵区" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="地点路线" prop="routeCode">
|
||||
<el-input v-model="formData.routeCode" placeholder="请输入地点路线" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="起点桩号" prop="startPile">
|
||||
<el-input v-model="formData.startPile" placeholder="K_请填写" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="止点桩号" prop="endPile">
|
||||
<el-input v-model="formData.endPile" placeholder="K_请填写" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="路况位置" prop="locationPath">
|
||||
<el-cascader v-model="formData.locationPath" :options="locationOptions" placeholder="请选择" style="width: 100%" clearable />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="阻断点小地名" prop="smallPlaceName">
|
||||
<el-input v-model="formData.smallPlaceName" placeholder="请填写" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="经度" prop="longitude">
|
||||
<el-input v-model="formData.longitude" placeholder="请输入经度" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="纬度" prop="latitude">
|
||||
<el-input v-model="formData.latitude" placeholder="请输入纬度" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-card>
|
||||
|
||||
<!-- 附件上传区块 -->
|
||||
<el-card class="form-section" shadow="never">
|
||||
<template #header>
|
||||
<div class="section-header">
|
||||
<span class="section-title">附件上传</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="图片上传" prop="images">
|
||||
<el-upload
|
||||
v-model:file-list="formData.images"
|
||||
action="#"
|
||||
list-type="picture-card"
|
||||
:auto-upload="false"
|
||||
:limit="9"
|
||||
:on-preview="handlePicturePreview"
|
||||
:on-remove="handlePictureRemove"
|
||||
:before-upload="beforeImageUpload"
|
||||
accept="image/jpeg,image/png"
|
||||
>
|
||||
<el-icon><Plus /></el-icon>
|
||||
</el-upload>
|
||||
<div class="upload-tip">只能上传jpg/png格式,且不超过500kb</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="视频上传" prop="videos">
|
||||
<el-upload v-model:file-list="formData.videos" action="#" :auto-upload="false" :limit="3" :before-upload="beforeVideoUpload" accept="video/*">
|
||||
<el-button type="primary"
|
||||
><el-icon><Upload /></el-icon> 选择文件</el-button
|
||||
>
|
||||
</el-upload>
|
||||
<div class="upload-tip">仅支持3M以内的视频</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-card>
|
||||
|
||||
<!-- 灾毁损失区块 -->
|
||||
<el-card class="form-section" shadow="never">
|
||||
<template #header>
|
||||
<div class="section-header">
|
||||
<span class="section-title">灾毁损失</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="24">
|
||||
<div class="sub-section-title">路况事件信息</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="受伤人员" prop="injuredCount">
|
||||
<el-input-number v-model="formData.injuredCount" :min="0" :step="1" style="width: 100%" />
|
||||
<span class="unit-suffix">个</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="死亡人员" prop="deathCount">
|
||||
<el-input-number v-model="formData.deathCount" :min="0" :step="1" style="width: 100%" />
|
||||
<span class="unit-suffix">个</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="滞留人员" prop="deathCount">
|
||||
<el-input-number v-model="formData.deathCount" :min="0" :step="1" style="width: 100%" />
|
||||
<span class="unit-suffix">个</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="滞留车辆" prop="strandedVehicles">
|
||||
<el-input-number v-model="formData.strandedVehicles" :min="0" :step="1" style="width: 100%" />
|
||||
<span class="unit-suffix">辆</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="损坏车辆" prop="damagedVehicles">
|
||||
<el-input-number v-model="formData.damagedVehicles" :min="0" :step="1" style="width: 100%" />
|
||||
<span class="unit-suffix">辆</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="24">
|
||||
<div class="sub-section-title">道路损失及其他</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="清理方量" prop="clearVolume">
|
||||
<el-input-number v-model="formData.clearVolume" :min="0" :precision="2" style="width: 100%" />
|
||||
<span class="unit-suffix">立方米</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="填方及损失" prop="fillLoss">
|
||||
<el-input v-model="formData.fillLoss" placeholder="填方及损失" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="路面及损失" prop="roadLoss">
|
||||
<el-input v-model="formData.roadLoss" placeholder="路面及损失" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="护坡及损失" prop="slopeLoss">
|
||||
<el-input v-model="formData.slopeLoss" placeholder="护坡及损失" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="桥梁及损失" prop="bridgeLoss">
|
||||
<el-input v-model="formData.bridgeLoss" placeholder="桥梁及损失" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="隧道及损失" prop="tunnelLoss">
|
||||
<el-input v-model="formData.tunnelLoss" placeholder="隧道及损失" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="涵洞及损失" prop="culvertLoss">
|
||||
<el-input v-model="formData.culvertLoss" placeholder="涵洞及损失" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="护栏" prop="guardrailLength">
|
||||
<el-input-number v-model="formData.guardrailLength" :min="0" :precision="3" style="width: 100%" />
|
||||
<span class="unit-suffix">公里</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="8">
|
||||
<el-form-item label="行道树" prop="roadsideTrees">
|
||||
<el-input-number v-model="formData.roadsideTrees" :min="0" :step="1" style="width: 100%" />
|
||||
<span class="unit-suffix">棵</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="其他损失" prop="otherLossAmount">
|
||||
<el-input-number v-model="formData.otherLossAmount" :min="0" :precision="2" style="width: 100%" />
|
||||
<span class="unit-suffix">万元</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="24">
|
||||
<el-form-item label="其他损失描述" prop="otherLossDesc">
|
||||
<el-input v-model="formData.otherLossDesc" type="textarea" :rows="2" placeholder="请输入" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
<el-col :span="24">
|
||||
<div class="sub-section-title">已投入机械</div>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="投入机械" prop="inputMachinery">
|
||||
<el-input-number v-model="formData.inputMachinery" :min="0" :precision="1" style="width: 100%" />
|
||||
<span class="unit-suffix">台/班</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="投入人力" prop="inputLabor">
|
||||
<el-input-number v-model="formData.inputLabor" :min="0" :step="1" style="width: 100%" />
|
||||
<span class="unit-suffix">人</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="8">
|
||||
<el-form-item label="投入资金" prop="inputFunds">
|
||||
<el-input-number v-model="formData.inputFunds" :min="0" :precision="2" style="width: 100%" />
|
||||
<span class="unit-suffix">万元</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-card>
|
||||
|
||||
<!-- 恢复重建预估费用区块 -->
|
||||
<el-card class="form-section" shadow="never">
|
||||
<template #header>
|
||||
<div class="section-header">
|
||||
<span class="section-title">恢复重建预估费用</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="是否需要恢复重建" prop="needReconstruction">
|
||||
<el-radio-group v-model="formData.needReconstruction">
|
||||
<el-radio label="是">是</el-radio>
|
||||
<el-radio label="否">否</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="恢复重建预估费用" prop="reconstructionCost">
|
||||
<el-input-number v-model="formData.reconstructionCost" :min="0" :precision="2" style="width: 100%" />
|
||||
<span class="unit-suffix">万元</span>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-card>
|
||||
|
||||
<!-- 提交按钮 -->
|
||||
<div class="form-actions">
|
||||
<el-button @click="handleBack">取消</el-button>
|
||||
<el-button type="primary" @click="handleSubmit" :loading="submitting">提交</el-button>
|
||||
</div>
|
||||
</el-form>
|
||||
|
||||
<!-- 图片预览对话框 -->
|
||||
<el-dialog v-model="previewDialogVisible" title="图片预览" width="600px">
|
||||
<img :src="previewImageUrl" style="width: 100%" alt="预览图片" />
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, computed, onMounted } from 'vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { Plus, Upload } from '@element-plus/icons-vue'
|
||||
import { request } from '@/utils/request'
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const formRef = ref(null)
|
||||
const submitting = ref(false)
|
||||
|
||||
// 是否为编辑模式
|
||||
const isEdit = computed(() => !!route.query.id)
|
||||
|
||||
// 图片预览
|
||||
const previewDialogVisible = ref(false)
|
||||
const previewImageUrl = ref('')
|
||||
|
||||
// 地点级联选择器选项(示例数据)
|
||||
const locationOptions = [
|
||||
{
|
||||
value: 'chongqing',
|
||||
label: '重庆市',
|
||||
children: [
|
||||
{
|
||||
value: 'wanzhou',
|
||||
label: '万州区',
|
||||
children: [
|
||||
{ value: 'shuanghekou', label: '双河口街道' },
|
||||
{ value: 'zhoujiaba', label: '周家坝街道' }
|
||||
]
|
||||
},
|
||||
{
|
||||
value: 'kaizhou',
|
||||
label: '开州区',
|
||||
children: [
|
||||
{ value: 'hanfeng', label: '汉丰街道' },
|
||||
{ value: 'wenfeng', label: '文峰街道' }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
// 表单数据
|
||||
const formData = reactive({
|
||||
// 填报人员信息
|
||||
reportUnit: '',
|
||||
contactPerson: '',
|
||||
contactPhone: '',
|
||||
// 路况事件信息
|
||||
eventType: '',
|
||||
dangerDesc: '',
|
||||
measure: '',
|
||||
isBlocked: '',
|
||||
waterDamageCount: 0,
|
||||
blockedMileage: 0,
|
||||
discoverTime: '',
|
||||
predictRecoverTime: '',
|
||||
siteDescription: '',
|
||||
// 位置信息
|
||||
routeType: '国省道',
|
||||
district: '',
|
||||
routeCode: '',
|
||||
routeName: '',
|
||||
startPile: '',
|
||||
endPile: '',
|
||||
locationPath: [],
|
||||
smallPlaceName: '',
|
||||
longitude: '',
|
||||
latitude: '',
|
||||
// 附件
|
||||
images: [],
|
||||
videos: [],
|
||||
// 灾毁损失
|
||||
injuredCount: 0,
|
||||
deathCount: 0,
|
||||
strandedVehicles: 0,
|
||||
damagedVehicles: 0,
|
||||
clearVolume: 0,
|
||||
fillLoss: '',
|
||||
roadLoss: '',
|
||||
slopeLoss: '',
|
||||
bridgeLoss: '',
|
||||
tunnelLoss: '',
|
||||
culvertLoss: '',
|
||||
guardrailLength: 0,
|
||||
roadsideTrees: 0,
|
||||
otherLossAmount: 0,
|
||||
otherLossDesc: '',
|
||||
inputMachinery: 0,
|
||||
inputLabor: 0,
|
||||
inputFunds: 0,
|
||||
// 恢复重建
|
||||
needReconstruction: '是',
|
||||
reconstructionCost: 0
|
||||
})
|
||||
|
||||
// 表单校验规则
|
||||
const formRules = {
|
||||
reportUnit: [{ required: true, message: '请输入填报单位', trigger: 'blur' }],
|
||||
contactPerson: [{ required: true, message: '请输入联系人', trigger: 'blur' }],
|
||||
contactPhone: [
|
||||
{ required: true, message: '请输入联系电话', trigger: 'blur' },
|
||||
{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码', trigger: 'blur' }
|
||||
],
|
||||
eventType: [{ required: true, message: '请选择事件类型', trigger: 'change' }],
|
||||
isBlocked: [{ required: true, message: '请选择是否阻断', trigger: 'change' }],
|
||||
discoverTime: [{ required: true, message: '请选择发现时间', trigger: 'change' }],
|
||||
routeType: [{ required: true, message: '请选择路线类型', trigger: 'change' }],
|
||||
district: [{ required: true, message: '请选择所属区县', trigger: 'change' }],
|
||||
routeCode: [{ required: true, message: '请输入路线编号', trigger: 'blur' }]
|
||||
}
|
||||
|
||||
// 图片上传前校验
|
||||
const beforeImageUpload = (file) => {
|
||||
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png'
|
||||
const isLt500k = file.size / 1024 < 500
|
||||
|
||||
if (!isJpgOrPng) {
|
||||
ElMessage.error('只能上传 JPG/PNG 格式的图片!')
|
||||
return false
|
||||
}
|
||||
if (!isLt500k) {
|
||||
ElMessage.error('图片大小不能超过 500KB!')
|
||||
return false
|
||||
}
|
||||
return false // 返回false阻止自动上传,由提交时统一处理
|
||||
}
|
||||
|
||||
// 视频上传前校验
|
||||
const beforeVideoUpload = (file) => {
|
||||
const isLt3M = file.size / 1024 / 1024 < 3
|
||||
if (!isLt3M) {
|
||||
ElMessage.error('视频大小不能超过 3MB!')
|
||||
return false
|
||||
}
|
||||
return false // 返回false阻止自动上传,由提交时统一处理
|
||||
}
|
||||
|
||||
// 图片预览
|
||||
const handlePicturePreview = (file) => {
|
||||
previewImageUrl.value = file.url
|
||||
previewDialogVisible.value = true
|
||||
}
|
||||
|
||||
// 图片移除
|
||||
const handlePictureRemove = (file, fileList) => {
|
||||
formData.images = fileList
|
||||
}
|
||||
|
||||
// 返回上一页
|
||||
const handleBack = () => {
|
||||
router.back()
|
||||
}
|
||||
|
||||
// 提交表单
|
||||
const handleSubmit = async () => {
|
||||
if (!formRef.value) return
|
||||
|
||||
await formRef.value.validate(async (valid) => {
|
||||
if (!valid) {
|
||||
ElMessage.warning('请完善表单信息')
|
||||
return
|
||||
}
|
||||
|
||||
submitting.value = true
|
||||
try {
|
||||
// 构建提交数据
|
||||
const submitData = {
|
||||
...formData,
|
||||
// 处理级联选择器值
|
||||
locationPath: formData.locationPath.join('/'),
|
||||
// 处理附件列表
|
||||
imageList: formData.images.map((item) => item.raw),
|
||||
videoList: formData.videos.map((item) => item.raw)
|
||||
}
|
||||
|
||||
// 模拟提交,实际使用时取消注释
|
||||
// if (isEdit.value) {
|
||||
// await request({ url: `/api/water-damage/events/${route.query.id}`, method: 'put', data: submitData })
|
||||
// ElMessage.success('编辑成功')
|
||||
// } else {
|
||||
// await request({ url: '/api/water-damage/events', method: 'post', data: submitData })
|
||||
// ElMessage.success('新增成功')
|
||||
// }
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 500))
|
||||
ElMessage.success(isEdit.value ? '编辑成功' : '新增成功')
|
||||
router.back()
|
||||
} catch (error) {
|
||||
ElMessage.error('提交失败,请重试')
|
||||
console.error(error)
|
||||
} finally {
|
||||
submitting.value = false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 加载编辑数据
|
||||
const loadEditData = async () => {
|
||||
if (!isEdit.value) return
|
||||
|
||||
try {
|
||||
// 模拟获取详情数据,实际使用时取消注释
|
||||
// const response = await request({ url: `/api/water-damage/events/${route.query.id}`, method: 'get' })
|
||||
// const data = response.data
|
||||
// Object.assign(formData, data)
|
||||
|
||||
// 模拟数据
|
||||
await new Promise((resolve) => setTimeout(resolve, 300))
|
||||
Object.assign(formData, {
|
||||
reportUnit: '万州区公路中心',
|
||||
contactPerson: '王强',
|
||||
contactPhone: '15978906789',
|
||||
eventType: '水毁事件',
|
||||
dangerDesc: '抢险中',
|
||||
measure: '交通管制',
|
||||
isBlocked: '是',
|
||||
waterDamageCount: 3,
|
||||
blockedMileage: 1.25,
|
||||
discoverTime: '2024-07-11 16:00:00',
|
||||
predictRecoverTime: '2024-08-12 16:30:00',
|
||||
siteDescription: '边坡塌方导致道路中断,正在组织抢通',
|
||||
routeType: '国省道',
|
||||
district: '万州区',
|
||||
routeCode: 'S202',
|
||||
routeName: '开云路',
|
||||
startPile: 'K17.200',
|
||||
endPile: 'K17.350',
|
||||
locationPath: ['chongqing', 'wanzhou', 'shuanghekou'],
|
||||
smallPlaceName: '三汇口',
|
||||
longitude: '108.408',
|
||||
latitude: '30.808',
|
||||
injuredCount: 0,
|
||||
deathCount: 0,
|
||||
strandedVehicles: 5,
|
||||
damagedVehicles: 1,
|
||||
clearVolume: 1200,
|
||||
guardrailLength: 0.15,
|
||||
roadsideTrees: 8,
|
||||
otherLossAmount: 10,
|
||||
otherLossDesc: '部分边沟损毁',
|
||||
inputMachinery: 6,
|
||||
inputLabor: 25,
|
||||
inputFunds: 8,
|
||||
needReconstruction: '是',
|
||||
reconstructionCost: 50
|
||||
})
|
||||
} catch (error) {
|
||||
ElMessage.error('加载数据失败')
|
||||
console.error(error)
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadEditData()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.disaster-form-page {
|
||||
padding: 20px;
|
||||
background-color: #f5f7fa;
|
||||
|
||||
.disaster-form {
|
||||
.form-section {
|
||||
margin-bottom: 20px;
|
||||
|
||||
:deep(.el-card__header) {
|
||||
padding: 12px 20px;
|
||||
background-color: #fafafa;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
}
|
||||
|
||||
:deep(.el-card__body) {
|
||||
padding: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.section-header {
|
||||
.section-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
position: relative;
|
||||
padding-left: 10px;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 3px;
|
||||
height: 16px;
|
||||
background-color: #409eff;
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sub-section-title {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: #606266;
|
||||
margin: 8px 0 16px 0;
|
||||
padding-left: 8px;
|
||||
border-left: 3px solid #409eff;
|
||||
}
|
||||
|
||||
.unit-suffix {
|
||||
margin-left: 8px;
|
||||
color: #909399;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.upload-tip {
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.form-actions {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 16px;
|
||||
padding: 20px 0 40px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
202
packages/screen/src/views/DisasterManagement/mockDataList.json
Normal file
202
packages/screen/src/views/DisasterManagement/mockDataList.json
Normal file
@ -0,0 +1,202 @@
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"reportUnit": "开州区交通建设发展中心",
|
||||
"routeCode": "S202",
|
||||
"routeName": "开云路",
|
||||
"startPile": "17.200",
|
||||
"endPile": "17.350",
|
||||
"locationDesc": "三汇口",
|
||||
"isBlocked": "是",
|
||||
"eventType": "水毁事件",
|
||||
"routeCategory": "国省道",
|
||||
"eventStatus": "已解除",
|
||||
"measure": "正常通行",
|
||||
"discoverTime": "2024-07-11",
|
||||
"predictRecoverTime": "2024-08-12",
|
||||
"contactPerson": "郭玲雅",
|
||||
"contactPhone": "18223732276",
|
||||
"hasImage": true,
|
||||
"hasVideo": false
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"reportUnit": "彭水苗族土家族自治县...",
|
||||
"routeCode": "G319",
|
||||
"routeName": "高雄-成都",
|
||||
"startPile": "2272",
|
||||
"endPile": "2273",
|
||||
"locationDesc": "高谷",
|
||||
"isBlocked": "否",
|
||||
"eventType": "水毁事件",
|
||||
"routeCategory": "国省道",
|
||||
"eventStatus": "已解除",
|
||||
"measure": "正常通行",
|
||||
"discoverTime": "2025-06-04",
|
||||
"predictRecoverTime": "2025-06-04",
|
||||
"contactPerson": "朱小明",
|
||||
"contactPhone": "18996180931",
|
||||
"hasImage": false,
|
||||
"hasVideo": false
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"reportUnit": "巫溪县交通局",
|
||||
"routeCode": "S301",
|
||||
"routeName": "溪城路",
|
||||
"startPile": "40.970",
|
||||
"endPile": "40.990",
|
||||
"locationDesc": "重庆市巫溪县通城镇通江街",
|
||||
"isBlocked": "否",
|
||||
"eventType": "水毁事件",
|
||||
"routeCategory": "国省道",
|
||||
"eventStatus": "已解除",
|
||||
"measure": "正常通行",
|
||||
"discoverTime": "2025-07-04",
|
||||
"predictRecoverTime": "2025-08-20",
|
||||
"contactPerson": "宁阳",
|
||||
"contactPhone": "18182310829",
|
||||
"hasImage": true,
|
||||
"hasVideo": false
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"reportUnit": "綦江区公路事务中心",
|
||||
"routeCode": "S534",
|
||||
"routeName": "一赶路",
|
||||
"startPile": "132.550",
|
||||
"endPile": "132.600",
|
||||
"locationDesc": "重庆市綦江区赶水镇280县道..",
|
||||
"isBlocked": "否",
|
||||
"eventType": "水毁事件",
|
||||
"routeCategory": "国省道",
|
||||
"eventStatus": "已解除",
|
||||
"measure": "正常通行",
|
||||
"discoverTime": "2025-07-22",
|
||||
"predictRecoverTime": "2025-07-22",
|
||||
"contactPerson": "沈伟",
|
||||
"contactPhone": "13637759650",
|
||||
"hasImage": false,
|
||||
"hasVideo": false
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"reportUnit": "酉阳土家族苗族自治县...",
|
||||
"routeCode": "G211",
|
||||
"routeName": "银川一榕江",
|
||||
"startPile": "1828.8",
|
||||
"endPile": "1828.81",
|
||||
"locationDesc": "重庆市酉阳土家族苗族自治县.",
|
||||
"isBlocked": "否",
|
||||
"eventType": "水毁事件",
|
||||
"routeCategory": "国省道",
|
||||
"eventStatus": "已解除",
|
||||
"measure": "正常通行",
|
||||
"discoverTime": "2025-10-20",
|
||||
"predictRecoverTime": "2025-10-21",
|
||||
"contactPerson": "陈建琼",
|
||||
"contactPhone": "",
|
||||
"hasImage": false,
|
||||
"hasVideo": false
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"reportUnit": "黔江区公路事务中心",
|
||||
"routeCode": "S203",
|
||||
"routeName": "黔彭路",
|
||||
"startPile": "48.720",
|
||||
"endPile": "48.750",
|
||||
"locationDesc": "重庆市黔江区小南海镇209省道",
|
||||
"isBlocked": "是",
|
||||
"eventType": "水毁事件",
|
||||
"routeCategory": "国省道",
|
||||
"eventStatus": "已解除",
|
||||
"measure": "正常通行",
|
||||
"discoverTime": "2023-09-25",
|
||||
"predictRecoverTime": "2023-09-25",
|
||||
"contactPerson": "刘昭君",
|
||||
"contactPhone": "13594943712",
|
||||
"hasImage": true,
|
||||
"hasVideo": false
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"reportUnit": "武隆区公路养护公司",
|
||||
"routeCode": "S521",
|
||||
"routeName": "后沧路",
|
||||
"startPile": "7.050",
|
||||
"endPile": "7.070",
|
||||
"locationDesc": "代家窑脚",
|
||||
"isBlocked": "是",
|
||||
"eventType": "水毁事件",
|
||||
"routeCategory": "国省道",
|
||||
"eventStatus": "已解除",
|
||||
"measure": "正常通行",
|
||||
"discoverTime": "2020-06-21",
|
||||
"predictRecoverTime": "2020-07-11",
|
||||
"contactPerson": "向显凤",
|
||||
"contactPhone": "18696935340",
|
||||
"hasImage": false,
|
||||
"hasVideo": false
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"reportUnit": "石柱县公路局",
|
||||
"routeCode": "G350",
|
||||
"routeName": "利川一炉霍",
|
||||
"startPile": "87.850",
|
||||
"endPile": "87.900",
|
||||
"locationDesc": "三块石",
|
||||
"isBlocked": "是",
|
||||
"eventType": "水毁事件",
|
||||
"routeCategory": "国省道",
|
||||
"eventStatus": "已解除",
|
||||
"measure": "正常通行",
|
||||
"discoverTime": "2020-07-12",
|
||||
"predictRecoverTime": "2020-07-12",
|
||||
"contactPerson": "陈世良",
|
||||
"contactPhone": "13609484536",
|
||||
"hasImage": true,
|
||||
"hasVideo": false
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"reportUnit": "梁平区公路局",
|
||||
"routeCode": "G243",
|
||||
"routeName": "开县一凭祥",
|
||||
"startPile": "67.88",
|
||||
"endPile": "67.885",
|
||||
"locationDesc": "合兴街道老拱桥",
|
||||
"isBlocked": "否",
|
||||
"eventType": "水毁事件",
|
||||
"routeCategory": "国省道",
|
||||
"eventStatus": "已解除",
|
||||
"measure": "正常通行",
|
||||
"discoverTime": "2021-05-15",
|
||||
"predictRecoverTime": "2021-05-15",
|
||||
"contactPerson": "江勇",
|
||||
"contactPhone": "13628409515",
|
||||
"hasImage": false,
|
||||
"hasVideo": false
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"reportUnit": "奉节公路事务中心",
|
||||
"routeCode": "G348",
|
||||
"routeName": "武汉一大理",
|
||||
"startPile": "806.8",
|
||||
"endPile": "806.86",
|
||||
"locationDesc": "麻牛坨",
|
||||
"isBlocked": "是",
|
||||
"eventType": "水毁事件",
|
||||
"routeCategory": "国省道",
|
||||
"eventStatus": "已解除",
|
||||
"measure": "正常通行",
|
||||
"discoverTime": "2021-07-08",
|
||||
"predictRecoverTime": "2021-07-10",
|
||||
"contactPerson": "王大平",
|
||||
"contactPhone": "13983502063",
|
||||
"hasImage": true,
|
||||
"hasVideo": false
|
||||
}
|
||||
]
|
||||
Loading…
x
Reference in New Issue
Block a user