feat: H5端冰雪灾害填报改造
This commit is contained in:
parent
9979660218
commit
d831a04968
@ -212,7 +212,7 @@ const handleClickItem = (item) => {
|
|||||||
}
|
}
|
||||||
if (item.disasterType === 'ICE_SNOW') {
|
if (item.disasterType === 'ICE_SNOW') {
|
||||||
router.push({
|
router.push({
|
||||||
name: 'IceEventDetail',
|
path: '/iceDisasterDetail',
|
||||||
query: {
|
query: {
|
||||||
id: item.relationId
|
id: item.relationId
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,7 +26,7 @@ import PageContainer from '@/components/PageContainer.vue'
|
|||||||
import CurrentSite from '@/components/CurrentSite.vue'
|
import CurrentSite from '@/components/CurrentSite.vue'
|
||||||
import PanelItem from '@/components/PanelItem.vue'
|
import PanelItem from '@/components/PanelItem.vue'
|
||||||
import WaterDisaster from './WaterDisaster/WaterDisaster.vue'
|
import WaterDisaster from './WaterDisaster/WaterDisaster.vue'
|
||||||
import IceDisaster from './IceDisaster.vue'
|
import IceDisaster from './IceDisaster/IceDisaster.vue'
|
||||||
import { request } from '@shared/utils/request'
|
import { request } from '@shared/utils/request'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
@ -38,7 +38,7 @@ const isContinue = computed(() => route.query.isContinue)
|
|||||||
const title = ref(!isContinue ? '灾毁填报' : '灾毁续报')
|
const title = ref(!isContinue ? '灾毁填报' : '灾毁续报')
|
||||||
|
|
||||||
// 事件类型
|
// 事件类型
|
||||||
const eventType = ref('water')
|
const eventType = ref(route.query.eventType ? route.query.eventType : 'water')
|
||||||
const eventTypeOptions = [
|
const eventTypeOptions = [
|
||||||
{
|
{
|
||||||
label: '水毁灾害',
|
label: '水毁灾害',
|
||||||
|
|||||||
@ -1,601 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="home">
|
|
||||||
<div class="content">
|
|
||||||
<PanelItem title="基本信息">
|
|
||||||
<van-form class="IceEventAddForm" label-align="left" colon>
|
|
||||||
<van-field v-model="form.occurTime" label="发生时间" center>
|
|
||||||
<template #button>
|
|
||||||
<van-button plain round type="primary" size="mini" @click="getCurrentTime">校准时间</van-button>
|
|
||||||
</template>
|
|
||||||
</van-field>
|
|
||||||
<!-- 线路编号 (顶层 routeNo) -->
|
|
||||||
<RoadRoutesPicker v-model="form.routeNo" label="线路编号" placeholder="请线路" @change="handleRouteNoChange" />
|
|
||||||
<van-field v-model="form.event.occurLocation" label="发生地点" center placeholder="请填写" />
|
|
||||||
<van-field v-model="form.occurLocation" label="路况位置" center placeholder="请填写" />
|
|
||||||
<van-field v-model="form.event.startStakeNo" label="起点桩号" center placeholder="请填写" />
|
|
||||||
<van-field v-model="form.event.endStakeNo" label="止点桩号" center placeholder="请填写" />
|
|
||||||
<van-field v-model="form.event.disasterMileage" label="受灾里程" center type="number" placeholder="请填写" />
|
|
||||||
</van-form>
|
|
||||||
</PanelItem>
|
|
||||||
|
|
||||||
<PanelItem title="处置情况">
|
|
||||||
<van-form class="IceEventAddForm" label-align="left" colon>
|
|
||||||
<van-field label="处置措施" center>
|
|
||||||
<template #input>
|
|
||||||
<div class="disposal-buttons">
|
|
||||||
<van-button
|
|
||||||
v-for="item in options['iceDisposalMeasures'] || []"
|
|
||||||
:key="item.value"
|
|
||||||
plain
|
|
||||||
:type="form.report.disposalMeasures === item.value ? 'primary' : 'default'"
|
|
||||||
size="small"
|
|
||||||
@click="toggleDisposal(item.value)"
|
|
||||||
>
|
|
||||||
{{ item.label }}
|
|
||||||
</van-button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</van-field>
|
|
||||||
<van-field v-model="form.report.expectRecoverTime" label="预计恢复时间" center placeholder="请选择" readonly clickable @click="showExpectPicker = true" />
|
|
||||||
<van-popup :show="showExpectPicker" round position="bottom" close-on-click-overlay @close="showExpectPicker = false">
|
|
||||||
<van-picker-group title="选择日期时间" :tabs="['选择日期', '选择时间']" @confirm="handleConfirmExpectTime" @cancel="showExpectPicker = false">
|
|
||||||
<van-date-picker v-model="expectDate" :min-date="minDate" :max-date="maxDate" />
|
|
||||||
<van-time-picker v-model="expectTime" />
|
|
||||||
</van-picker-group>
|
|
||||||
</van-popup>
|
|
||||||
</van-form>
|
|
||||||
</PanelItem>
|
|
||||||
|
|
||||||
<PanelItem title="实施情况">
|
|
||||||
<van-form class="IceEventAddForm" label-align="left" colon>
|
|
||||||
<van-field v-model="form.report.inputManpower" type="number" label="投入人力" center placeholder="请填写">
|
|
||||||
<template #extra> 人次 </template>
|
|
||||||
</van-field>
|
|
||||||
<van-field v-model="form.report.inputFunds" type="number" label="投入资金" center placeholder="请填写">
|
|
||||||
<template #extra> 万元 </template>
|
|
||||||
</van-field>
|
|
||||||
<van-field v-model="form.report.inputEquipment" type="number" label="投入设备" center placeholder="请填写">
|
|
||||||
<template #extra> 台班 </template>
|
|
||||||
</van-field>
|
|
||||||
|
|
||||||
<!-- 选择物资列表 -->
|
|
||||||
<van-field
|
|
||||||
v-for="(material, index) in form.yhzMaterialList"
|
|
||||||
:key="material.rid"
|
|
||||||
v-model="material.usageAmount"
|
|
||||||
type="number"
|
|
||||||
@input="checkMaterialAmount(material, index)"
|
|
||||||
:label="material.wzmc"
|
|
||||||
center
|
|
||||||
:placeholder="`余额: ${material.ye} `"
|
|
||||||
>
|
|
||||||
<template #extra>
|
|
||||||
<span style="margin-right: 10px">{{ material.dw }}</span>
|
|
||||||
<van-button size="small" type="danger" @click.stop="form.yhzMaterialList.splice(index, 1)"> 删除 </van-button>
|
|
||||||
</template>
|
|
||||||
</van-field>
|
|
||||||
|
|
||||||
<van-button class="add-wzbtn" type="primary" icon="plus" plain @click="handleOpenAddMaterial">添加物资 </van-button>
|
|
||||||
<van-popup :show="showAddMaterialPopup" position="bottom" close-on-click-overlay @close="showAddMaterialPopup = false">
|
|
||||||
<div style="padding: 16px">
|
|
||||||
<h3 style="text-align: center; margin-bottom: 16px">添加物资</h3>
|
|
||||||
|
|
||||||
<!-- 搜索框 -->
|
|
||||||
<van-field v-model="searchText" placeholder="输入物资名称搜索" clearable @update:model-value="handleSearch"> </van-field>
|
|
||||||
|
|
||||||
<van-checkbox-group v-model="checked">
|
|
||||||
<van-cell-group inset style="margin: 16px 0">
|
|
||||||
<div style="display: flex; justify-content: space-between; padding: 8px 16px">
|
|
||||||
<span>共 {{ materialList.length }} 项</span>
|
|
||||||
<van-button size="mini" @click="toggleSelectAll" :type="isAllSelected ? 'primary' : 'default'">
|
|
||||||
{{ isAllSelected ? '取消全选' : '全选' }}
|
|
||||||
</van-button>
|
|
||||||
</div>
|
|
||||||
<van-cell v-for="(item, index) in materialList" clickable :key="item.rid" :title="item.wzmc" @click="toggle(index)">
|
|
||||||
<template #right-icon>
|
|
||||||
<van-checkbox :name="item.rid" :ref="(el) => (checkboxRefs[index] = el)" @click.stop />
|
|
||||||
</template>
|
|
||||||
</van-cell>
|
|
||||||
</van-cell-group>
|
|
||||||
</van-checkbox-group>
|
|
||||||
|
|
||||||
<van-button type="primary" block @click="addSelectedMaterials" style="margin-top: 10px"> 确认添加 </van-button>
|
|
||||||
</div>
|
|
||||||
</van-popup>
|
|
||||||
<van-field label="有无车辆滞留" center>
|
|
||||||
<template #input>
|
|
||||||
<div class="disposal-buttons">
|
|
||||||
<van-button plain :type="form.report.hasStrandedVehicles === 1 ? 'primary' : 'default'" size="small" @click="form.report.hasStrandedVehicles = 1">
|
|
||||||
有滞留
|
|
||||||
</van-button>
|
|
||||||
<van-button
|
|
||||||
plain
|
|
||||||
:type="form.report.hasStrandedVehicles === 0 ? 'primary' : 'default'"
|
|
||||||
size="small"
|
|
||||||
@click="
|
|
||||||
() => {
|
|
||||||
form.report.hasStrandedVehicles = 0
|
|
||||||
form.report.strandedVehicleCount = null
|
|
||||||
}
|
|
||||||
"
|
|
||||||
class="last-button"
|
|
||||||
>
|
|
||||||
无滞留
|
|
||||||
</van-button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</van-field>
|
|
||||||
<van-field v-if="form.report.hasStrandedVehicles === 1" v-model="form.report.strandedVehicleCount" type="number" label="滞留车辆数" center placeholder="请填写" />
|
|
||||||
|
|
||||||
<van-field v-model="form.report.actualRecoverTime" label="实际恢复时间" center placeholder="请选择" readonly clickable @click="showActualPicker = true" />
|
|
||||||
<van-popup :show="showActualPicker" round position="bottom" close-on-click-overlay @close="showActualPicker = false">
|
|
||||||
<van-picker-group title="选择日期时间" :tabs="['选择日期', '选择时间']" @confirm="handleConfirmActualTime" @cancel="showActualPicker = false">
|
|
||||||
<van-date-picker v-model="actualDate" :min-date="minDate" :max-date="maxDate" />
|
|
||||||
<van-time-picker v-model="actualTime" />
|
|
||||||
</van-picker-group>
|
|
||||||
</van-popup>
|
|
||||||
|
|
||||||
<van-field v-model="form.report.siteDescription" label="现场情况描述" type="textarea" rows="2" autosize center placeholder="请填写" />
|
|
||||||
|
|
||||||
<van-field label="附件" center>
|
|
||||||
<template #input>
|
|
||||||
<van-uploader
|
|
||||||
:modelValue="getFileList()"
|
|
||||||
name="photos"
|
|
||||||
:file-type="['image/jpeg', 'image/png']"
|
|
||||||
:after-read="afterRead"
|
|
||||||
multiple
|
|
||||||
:max-count="6"
|
|
||||||
@delete="removeFile"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
</van-field>
|
|
||||||
</van-form>
|
|
||||||
</PanelItem>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<van-button type="primary" class="add-btn" @click="handleAdd"> 提交 </van-button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { ref, onMounted, reactive, watch, computed } from 'vue'
|
|
||||||
import { useRouter } from 'vue-router'
|
|
||||||
import { showToast, showLoadingToast } from 'vant'
|
|
||||||
import PanelItem from '@/components/PanelItem.vue'
|
|
||||||
import { request } from '../../../../shared/utils/request'
|
|
||||||
import { useYHZStore } from '@/stores/yhzStore'
|
|
||||||
import RoadRoutesPicker from './RoadRoutesPicker.vue'
|
|
||||||
import { useOptions } from '@shared/composables/useOptions'
|
|
||||||
|
|
||||||
const router = useRouter()
|
|
||||||
const yhzStore = useYHZStore()
|
|
||||||
const { options } = useOptions()
|
|
||||||
|
|
||||||
// 组件挂载时获取数据
|
|
||||||
const INIT_FORM = reactive({
|
|
||||||
occurLocation: '',
|
|
||||||
occurTime: '',
|
|
||||||
routeNo: '',
|
|
||||||
event: {
|
|
||||||
occurLocation: '', // 发生地点
|
|
||||||
startStakeNo: '', // 起点桩号
|
|
||||||
endStakeNo: '', // 止点桩号
|
|
||||||
startStakeLng: null,
|
|
||||||
startStakeLat: null,
|
|
||||||
endStakeLng: null,
|
|
||||||
endStakeLat: null,
|
|
||||||
disasterMileage: '', // 受灾里程
|
|
||||||
serviceStationId: '', // 养护站ID
|
|
||||||
district: '', // 所属区县
|
|
||||||
reporterName: '',
|
|
||||||
reportTime: '', // 填报时间
|
|
||||||
reporterPhone: '', // 填报人手机号
|
|
||||||
reportUnit: '',
|
|
||||||
routeNo: '',
|
|
||||||
occurTime: '',
|
|
||||||
roadConditionLocation: '',
|
|
||||||
routeType: '',
|
|
||||||
createTime: '', // 创建时间
|
|
||||||
updateTime: '', // 更新时间
|
|
||||||
isDeleted: '' // 是否删除 0-未删除 1-已删除
|
|
||||||
},
|
|
||||||
report: {
|
|
||||||
inputManpower: null, // 投入人力
|
|
||||||
inputFunds: null, // 投入资金
|
|
||||||
inputEquipment: null, // 投入设备
|
|
||||||
disposalMeasures: '',
|
|
||||||
expectRecoverTime: '',
|
|
||||||
actualRecoverTime: '',
|
|
||||||
hasStrandedVehicles: 0,
|
|
||||||
strandedVehicleCount: null,
|
|
||||||
siteDescription: '',
|
|
||||||
reporterName: '',
|
|
||||||
reporterPhone: '',
|
|
||||||
reportTime: '',
|
|
||||||
industrialSalt: null,
|
|
||||||
antiSlipSand: null,
|
|
||||||
sandbags: null,
|
|
||||||
createTime: '', // 创建时间
|
|
||||||
updateTime: '' // 更新时间
|
|
||||||
},
|
|
||||||
yhzMaterialList: [], // 养护站物资列表
|
|
||||||
fileList: []
|
|
||||||
})
|
|
||||||
const form = reactive({ ...INIT_FORM })
|
|
||||||
|
|
||||||
const getFileList = () => {
|
|
||||||
return (
|
|
||||||
form.fileList?.map((item) => ({
|
|
||||||
url: item.fileUrl,
|
|
||||||
name: item.fileName
|
|
||||||
})) || []
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 日期格式化
|
|
||||||
const formatTime = (date = new Date()) => {
|
|
||||||
const pad = (n) => n.toString().padStart(2, '0')
|
|
||||||
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ` + `${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`
|
|
||||||
}
|
|
||||||
|
|
||||||
const getCurrentTime = () => {
|
|
||||||
form.occurTime = formatTime()
|
|
||||||
}
|
|
||||||
|
|
||||||
const toggleDisposal = (type) => {
|
|
||||||
form.report.disposalMeasures = form.report.disposalMeasures === type ? '' : type
|
|
||||||
}
|
|
||||||
|
|
||||||
// 组件挂载时获取数据
|
|
||||||
onMounted(() => {
|
|
||||||
form.occurTime = formatTime() // 初始化为当前时间
|
|
||||||
})
|
|
||||||
|
|
||||||
// 添加物资相关
|
|
||||||
const showAddMaterialPopup = ref(false)
|
|
||||||
const materialList = ref([])
|
|
||||||
const checkboxRefs = ref([])
|
|
||||||
const checked = ref([])
|
|
||||||
const toggle = (index) => {
|
|
||||||
checkboxRefs.value[index].toggle()
|
|
||||||
}
|
|
||||||
|
|
||||||
const searchText = ref('')
|
|
||||||
const handleSearch = () => {
|
|
||||||
getMaterialList(searchText.value)
|
|
||||||
}
|
|
||||||
// 全选功能
|
|
||||||
const toggleSelectAll = () => {
|
|
||||||
if (isAllSelected.value) {
|
|
||||||
checked.value = []
|
|
||||||
} else {
|
|
||||||
checked.value = materialList.value.map((item) => item.rid)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 计算是否全选
|
|
||||||
const isAllSelected = computed(() => {
|
|
||||||
return materialList.value.length > 0 && materialList.value.every((item) => checked.value.includes(item.rid))
|
|
||||||
})
|
|
||||||
|
|
||||||
// 添加物资到表单
|
|
||||||
const addSelectedMaterials = () => {
|
|
||||||
checked.value.forEach((rid) => {
|
|
||||||
const material = materialList.value.find((m) => m.rid === rid)
|
|
||||||
if (material && !form.yhzMaterialList.some((m) => m.rid === rid)) {
|
|
||||||
form.yhzMaterialList.push({
|
|
||||||
rid: rid,
|
|
||||||
wzmc: material.wzmc,
|
|
||||||
usageAmount: null,
|
|
||||||
dw: material.dw,
|
|
||||||
ye: material.ye
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
showAddMaterialPopup.value = false
|
|
||||||
checked.value = []
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查余额
|
|
||||||
const checkMaterialAmount = (material, index) => {
|
|
||||||
if (material.usageAmount > material.ye) {
|
|
||||||
showToast({
|
|
||||||
type: 'fail',
|
|
||||||
message: '输入数量不能超过物资余额'
|
|
||||||
})
|
|
||||||
form.yhzMaterialList[index].usageAmount = material.ye
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 查询物资列表
|
|
||||||
const getMaterialList = async (wzmc) => {
|
|
||||||
try {
|
|
||||||
const data = {
|
|
||||||
yhzid: yhzStore.getYHZInfo.id,
|
|
||||||
wzmc,
|
|
||||||
pageNum: 1,
|
|
||||||
pageSize: 9999
|
|
||||||
}
|
|
||||||
const res = await request({
|
|
||||||
url: '/snow-ops-platform/yjwz/list',
|
|
||||||
method: 'GET',
|
|
||||||
params: data
|
|
||||||
})
|
|
||||||
if (res.code === '00000') {
|
|
||||||
materialList.value = res.data.records
|
|
||||||
} else {
|
|
||||||
throw new Error(res.message)
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
showToast({
|
|
||||||
type: 'fail',
|
|
||||||
message: error.message
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 打开添加物资弹窗
|
|
||||||
const handleOpenAddMaterial = async () => {
|
|
||||||
await getMaterialList()
|
|
||||||
showAddMaterialPopup.value = true
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleAdd = async () => {
|
|
||||||
try {
|
|
||||||
const toast = showLoadingToast({
|
|
||||||
message: '上报中...',
|
|
||||||
forbidClick: true,
|
|
||||||
duration: 0 // 设置为0表示不会自动关闭
|
|
||||||
})
|
|
||||||
form.event.serviceStationId = yhzStore.getYHZInfo?.id || ''
|
|
||||||
form.event.district = yhzStore.getYHZInfo?.qxmc || ''
|
|
||||||
const reportTime = form.report.reportTime || form.event.reportTime || formatTime()
|
|
||||||
const submitData = {
|
|
||||||
...form,
|
|
||||||
event: {
|
|
||||||
...form.event,
|
|
||||||
routeNo: form.routeNo,
|
|
||||||
occurTime: form.occurTime,
|
|
||||||
reportTime,
|
|
||||||
reportUnit: form.event.reportUnit,
|
|
||||||
disposalMeasures: form.report.disposalMeasures,
|
|
||||||
expectRecoverTime: form.report.expectRecoverTime,
|
|
||||||
actualRecoverTime: form.report.actualRecoverTime || null,
|
|
||||||
roadConditionLocation: form.occurLocation,
|
|
||||||
eventType: '冰雪事件'
|
|
||||||
},
|
|
||||||
report: {
|
|
||||||
...form.report,
|
|
||||||
reporterName: form.report.reporterName || form.event.reporterName,
|
|
||||||
reporterPhone: form.report.reporterPhone || form.event.reporterPhone,
|
|
||||||
reportTime
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (submitData.report.hasStrandedVehicles !== 1) {
|
|
||||||
submitData.report.strandedVehicleCount = null
|
|
||||||
}
|
|
||||||
const res = await request({
|
|
||||||
url: '/snow-ops-platform/event/addOrUpdate',
|
|
||||||
method: 'POST',
|
|
||||||
data: submitData
|
|
||||||
})
|
|
||||||
if (res.code === '00000') {
|
|
||||||
toast.close()
|
|
||||||
showToast({
|
|
||||||
type: 'success',
|
|
||||||
message: '上报成功'
|
|
||||||
})
|
|
||||||
setTimeout(() => {
|
|
||||||
router.replace('/disasterManagement')
|
|
||||||
}, 500)
|
|
||||||
} else {
|
|
||||||
toast.close()
|
|
||||||
throw new Error(res.message)
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
showToast({
|
|
||||||
type: 'fail',
|
|
||||||
message: error.message
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const expectDate = ref([])
|
|
||||||
const expectTime = ref([])
|
|
||||||
const actualDate = ref([])
|
|
||||||
const actualTime = ref([])
|
|
||||||
|
|
||||||
// 预计恢复时间相关
|
|
||||||
const showExpectPicker = ref(false)
|
|
||||||
const minDate = new Date()
|
|
||||||
const maxDate = new Date(2050, 11, 31)
|
|
||||||
const handleConfirmExpectTime = () => {
|
|
||||||
const [year, month, day] = expectDate.value
|
|
||||||
const [hour, minute] = expectTime.value
|
|
||||||
form.report.expectRecoverTime =
|
|
||||||
`${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')} ` + `${String(hour).padStart(2, '0')}:${String(minute).padStart(2, '0')}:00`
|
|
||||||
showExpectPicker.value = false
|
|
||||||
}
|
|
||||||
// 实际恢复时间相关
|
|
||||||
const showActualPicker = ref(false)
|
|
||||||
const handleConfirmActualTime = () => {
|
|
||||||
const [year, month, day] = actualDate.value
|
|
||||||
const [hour, minute] = actualTime.value
|
|
||||||
form.report.actualRecoverTime =
|
|
||||||
`${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')} ` + `${String(hour).padStart(2, '0')}:${String(minute).padStart(2, '0')}:00`
|
|
||||||
showActualPicker.value = false
|
|
||||||
}
|
|
||||||
|
|
||||||
// 在打开选择器时设置初始值
|
|
||||||
watch(showExpectPicker, (val) => {
|
|
||||||
if (val) {
|
|
||||||
const current = form.report.expectRecoverTime ? new Date(form.report.expectRecoverTime) : new Date()
|
|
||||||
expectDate.value = [current.getFullYear(), current.getMonth() + 1, current.getDate()]
|
|
||||||
expectTime.value = [current.getHours(), current.getMinutes()]
|
|
||||||
}
|
|
||||||
})
|
|
||||||
watch(showActualPicker, (val) => {
|
|
||||||
if (val) {
|
|
||||||
const current = form.report.actualRecoverTime ? new Date(form.report.actualRecoverTime) : new Date()
|
|
||||||
actualDate.value = [current.getFullYear(), current.getMonth() + 1, current.getDate()]
|
|
||||||
actualTime.value = [current.getHours(), current.getMinutes()]
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const parsePointValue = (point) => {
|
|
||||||
if (!point) {
|
|
||||||
return { longitude: null, latitude: null }
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Array.isArray(point) && point.length >= 2) {
|
|
||||||
return {
|
|
||||||
longitude: point[0] ?? null,
|
|
||||||
latitude: point[1] ?? null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof point === 'string') {
|
|
||||||
try {
|
|
||||||
const parsed = JSON.parse(point)
|
|
||||||
if (Array.isArray(parsed) && parsed.length >= 2) {
|
|
||||||
return {
|
|
||||||
longitude: parsed[0] ?? null,
|
|
||||||
latitude: parsed[1] ?? null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (_error) {
|
|
||||||
return { longitude: null, latitude: null }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return { longitude: null, latitude: null }
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleRouteNoChange = (item) => {
|
|
||||||
form.routeNo = item.routeCode
|
|
||||||
form.event.startStakeNo = item.startStakeNo
|
|
||||||
form.event.endStakeNo = item.endStakeNo
|
|
||||||
|
|
||||||
const startPoint = parsePointValue(item.startPoint ?? item.startpoint)
|
|
||||||
const endPoint = parsePointValue(item.endPoint ?? item.endpoint)
|
|
||||||
|
|
||||||
form.event.startStakeLng = startPoint.longitude
|
|
||||||
form.event.startStakeLat = startPoint.latitude
|
|
||||||
form.event.endStakeLng = endPoint.longitude
|
|
||||||
form.event.endStakeLat = endPoint.latitude
|
|
||||||
}
|
|
||||||
|
|
||||||
// 文件上传
|
|
||||||
const afterRead = async (file) => {
|
|
||||||
try {
|
|
||||||
const toast = showLoadingToast({
|
|
||||||
message: '上传中...',
|
|
||||||
forbidClick: true,
|
|
||||||
duration: 0 // 设置为0表示不会自动关闭
|
|
||||||
})
|
|
||||||
const formData = new FormData()
|
|
||||||
formData.append('file', file.file)
|
|
||||||
const res = await request({
|
|
||||||
url: '/snow-ops-platform/file/upload',
|
|
||||||
method: 'post',
|
|
||||||
data: formData
|
|
||||||
})
|
|
||||||
toast.close()
|
|
||||||
if (res.code === '00000') {
|
|
||||||
form.fileList.push({
|
|
||||||
fileName: file.file.name,
|
|
||||||
fileUrl: res.data,
|
|
||||||
fileType: 1,
|
|
||||||
fileSize: file.file.size
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
throw new Error(res.message)
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
toast.close()
|
|
||||||
showToast({
|
|
||||||
type: 'fail',
|
|
||||||
message: error.message
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 文件删除
|
|
||||||
const removeFile = (file, index) => {
|
|
||||||
form.fileList.splice(index, 1)
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.home {
|
|
||||||
/* 自动匹配导航栏高度 */
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
|
||||||
}
|
|
||||||
|
|
||||||
.content .van-cell-group .van-cell {
|
|
||||||
margin-bottom: 10px;
|
|
||||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
|
||||||
}
|
|
||||||
|
|
||||||
.add-wzbtn {
|
|
||||||
width: calc(100% - 32px);
|
|
||||||
margin: 10px 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.add-btn {
|
|
||||||
position: fixed;
|
|
||||||
bottom: 20px;
|
|
||||||
left: 16px;
|
|
||||||
right: 16px;
|
|
||||||
width: calc(100% - 32px);
|
|
||||||
margin: 0 auto;
|
|
||||||
border-radius: 24px;
|
|
||||||
font-size: 16px;
|
|
||||||
height: 44px;
|
|
||||||
z-index: 999;
|
|
||||||
}
|
|
||||||
|
|
||||||
.grid {
|
|
||||||
margin-top: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn {
|
|
||||||
margin-top: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-tag {
|
|
||||||
display: inline-block;
|
|
||||||
padding: 3px 8px;
|
|
||||||
border-radius: 4px;
|
|
||||||
color: white;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-good {
|
|
||||||
background-color: #07c160;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-warning {
|
|
||||||
background-color: #ff976a;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-danger {
|
|
||||||
background-color: #ee0a24;
|
|
||||||
}
|
|
||||||
|
|
||||||
.disposal-buttons {
|
|
||||||
display: flex;
|
|
||||||
gap: 10px;
|
|
||||||
padding: 8px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.disposal-buttons .van-button {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.last-button {
|
|
||||||
margin-right: 16px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -0,0 +1,535 @@
|
|||||||
|
<template>
|
||||||
|
<PageContainer title="冰毁详情" @click-back="handleClickBack" class="page-container">
|
||||||
|
<!-- 当前站点信息 -->
|
||||||
|
<CurrentSite />
|
||||||
|
|
||||||
|
<!-- 基本信息 -->
|
||||||
|
<PanelItem title="基本信息" v-if="!loading">
|
||||||
|
<template #headerExtra>
|
||||||
|
<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(detailData.event?.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">
|
||||||
|
<span class="info-label">止点桩号:</span>
|
||||||
|
<span class="info-value">{{ detailData.event?.endStakeNo || '-' }}</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?.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="填报信息" v-if="!loading">
|
||||||
|
<!-- 遍历所有填报记录(首报 + 续报) -->
|
||||||
|
<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.reporterName || '-' }} {{ report.reportTime || '-' }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="report-content">
|
||||||
|
<div class="info-row">
|
||||||
|
<span class="info-label">处置措施:</span>
|
||||||
|
<span class="info-value">{{ report.disposalMeasures || '-' }}</span>
|
||||||
|
</div>
|
||||||
|
<template v-for="(lossItem, idx) of report.lossList" :key="idx">
|
||||||
|
<div class="info-row">
|
||||||
|
<span class="info-label">{{ lossItem.lossCategory }}:</span>
|
||||||
|
<span class="info-value">{{ lossItem.totalAmount }}{{ lossItem.unit }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="info-row" v-if="lossItem.lossCategory == '其他损失'">
|
||||||
|
<span class="info-label">其它损失描述:</span>
|
||||||
|
<span class="info-value">{{ lossItem.remark }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<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 column" 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">
|
||||||
|
<div class="preview-image-block" v-if="file.fileType === 1" @click="previewFile(report, file)">
|
||||||
|
<img :src="file.fileUrl" alt="" />
|
||||||
|
</div>
|
||||||
|
<div class="preview-video-block" v-else>
|
||||||
|
<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(report, file)">预览</van-button> -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 无填报信息时显示 -->
|
||||||
|
<EmptyBox v-if="!hasReportData" placeholder="暂无填报信息" />
|
||||||
|
</PanelItem>
|
||||||
|
|
||||||
|
<!-- 底部按钮:未解除状态显示续报按钮 -->
|
||||||
|
<div class="footer-buttons" v-if="!loading">
|
||||||
|
<van-button type="primary" class="footer-btn" @click="handleContinueReport">续报</van-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<van-loading class="loading-icon" v-if="loading">加载中...</van-loading>
|
||||||
|
|
||||||
|
<van-image-preview :startPosition="startPosition" v-model:show="previewImagesVisible" :images="imagesForPreview">
|
||||||
|
<template v-slot:index="{ index }">第{{ index + 1 }}页</template>
|
||||||
|
</van-image-preview>
|
||||||
|
</PageContainer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { onMounted, ref, computed } from 'vue'
|
||||||
|
import { useRouter, useRoute } from 'vue-router'
|
||||||
|
import { showToast, showImagePreview } 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: [], // 填报列表(包含首报和续报)
|
||||||
|
fileList: [], // 附件列表
|
||||||
|
lossList: [], // 损失列表
|
||||||
|
occurLocation: '',
|
||||||
|
occurTime: '',
|
||||||
|
roadConditionType: '',
|
||||||
|
routeNo: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const loading = ref(true)
|
||||||
|
|
||||||
|
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 detailData.eventStatus === 1 ? '已解除' : '未解除'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取事件状态类型
|
||||||
|
const getEventStatusType = () => {
|
||||||
|
return detailData.eventStatus === 1 ? 'success' : 'danger'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 格式化处置措施(逗号分隔转中文)
|
||||||
|
const formatDisposalMeasures = (measures) => {
|
||||||
|
if (!measures) return ''
|
||||||
|
const measureMap = {
|
||||||
|
半幅封闭: '半幅封闭',
|
||||||
|
全副封闭: '全副封闭',
|
||||||
|
便道通行: '便道通行',
|
||||||
|
正常通行: '正常通行'
|
||||||
|
}
|
||||||
|
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 ? `有车滞留` : '无车滞留'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取灾毁详情
|
||||||
|
const getDisasterDetail = async () => {
|
||||||
|
const id = route.query.id
|
||||||
|
if (!id) {
|
||||||
|
showToast('缺少灾毁ID')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
loading.value = true
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await request({
|
||||||
|
url: `/snow-ops-platform/event/getById`,
|
||||||
|
method: 'get',
|
||||||
|
params: { id }
|
||||||
|
})
|
||||||
|
|
||||||
|
if (result?.data) {
|
||||||
|
// 接口返回 Data 结构
|
||||||
|
const data = result.data
|
||||||
|
detailData.value = {
|
||||||
|
event: data.event || null,
|
||||||
|
report: data.reportList || [], // 直接使用 report,包含首报和续报
|
||||||
|
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('获取详情失败,请稍后重试')
|
||||||
|
}
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 点击返回
|
||||||
|
const handleClickBack = () => {
|
||||||
|
router.push('/disasterManagement')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 续报
|
||||||
|
const handleContinueReport = () => {
|
||||||
|
router.push({
|
||||||
|
path: '/disasterReport',
|
||||||
|
query: {
|
||||||
|
id: route.query.id,
|
||||||
|
eventType: 'ice',
|
||||||
|
isContinue: 'true'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const isImageFile = (file) => {
|
||||||
|
// 根据url后缀判断
|
||||||
|
const imageExtensions = /\.(jpg|jpeg|png|gif|webp|bmp|svg)$/i
|
||||||
|
if (file.fileUrl && imageExtensions.test(file.fileUrl)) return true
|
||||||
|
// 根据文件类型判断
|
||||||
|
if (file.type && file.type.startsWith('image/')) return true
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const imagesForPreview = ref([])
|
||||||
|
const previewImagesVisible = ref(false)
|
||||||
|
const startPosition = ref(0)
|
||||||
|
|
||||||
|
// 预览附件
|
||||||
|
const previewFile = (report, file) => {
|
||||||
|
const images = report.fileList.filter((file) => isImageFile(file))
|
||||||
|
imagesForPreview.value = images.map((item) => item.fileUrl)
|
||||||
|
startPosition.value = imagesForPreview.value.indexOf(file.fileUrl)
|
||||||
|
previewImagesVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.column {
|
||||||
|
flex-direction: column;
|
||||||
|
.info-label {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.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 {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
flex: 1;
|
||||||
|
gap: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.attachment-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-image-block {
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-icon {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,535 @@
|
|||||||
|
<template>
|
||||||
|
<PageContainer title="冰毁详情" @click-back="handleClickBack" class="page-container">
|
||||||
|
<!-- 当前站点信息 -->
|
||||||
|
<CurrentSite />
|
||||||
|
|
||||||
|
<!-- 基本信息 -->
|
||||||
|
<PanelItem title="基本信息" v-if="!loading">
|
||||||
|
<template #headerExtra>
|
||||||
|
<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(detailData.event?.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">
|
||||||
|
<span class="info-label">止点桩号:</span>
|
||||||
|
<span class="info-value">{{ detailData.event?.endStakeNo || '-' }}</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?.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="填报信息" v-if="!loading">
|
||||||
|
<!-- 遍历所有填报记录(首报 + 续报) -->
|
||||||
|
<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.reporterName || '-' }} {{ report.reportTime || '-' }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="report-content">
|
||||||
|
<div class="info-row">
|
||||||
|
<span class="info-label">处置措施:</span>
|
||||||
|
<span class="info-value">{{ report.disposalMeasures || '-' }}</span>
|
||||||
|
</div>
|
||||||
|
<template v-for="(lossItem, idx) of report.lossList" :key="idx">
|
||||||
|
<div class="info-row">
|
||||||
|
<span class="info-label">{{ lossItem.lossCategory }}:</span>
|
||||||
|
<span class="info-value">{{ lossItem.totalAmount }}{{ lossItem.unit }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="info-row" v-if="lossItem.lossCategory == '其他损失'">
|
||||||
|
<span class="info-label">其它损失描述:</span>
|
||||||
|
<span class="info-value">{{ lossItem.remark }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<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 column" 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">
|
||||||
|
<div class="preview-image-block" v-if="file.fileType === 1" @click="previewFile(report, file)">
|
||||||
|
<img :src="file.fileUrl" alt="" />
|
||||||
|
</div>
|
||||||
|
<div class="preview-video-block" v-else>
|
||||||
|
<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(report, file)">预览</van-button> -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 无填报信息时显示 -->
|
||||||
|
<EmptyBox v-if="!hasReportData" placeholder="暂无填报信息" />
|
||||||
|
</PanelItem>
|
||||||
|
|
||||||
|
<!-- 底部按钮:未解除状态显示续报按钮 -->
|
||||||
|
<div class="footer-buttons" v-if="!loading">
|
||||||
|
<van-button type="primary" class="footer-btn" @click="handleContinueReport">续报</van-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<van-loading class="loading-icon" v-if="loading">加载中...</van-loading>
|
||||||
|
|
||||||
|
<van-image-preview :startPosition="startPosition" v-model:show="previewImagesVisible" :images="imagesForPreview">
|
||||||
|
<template v-slot:index="{ index }">第{{ index + 1 }}页</template>
|
||||||
|
</van-image-preview>
|
||||||
|
</PageContainer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { onMounted, ref, computed } from 'vue'
|
||||||
|
import { useRouter, useRoute } from 'vue-router'
|
||||||
|
import { showToast, showImagePreview } 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: [], // 填报列表(包含首报和续报)
|
||||||
|
fileList: [], // 附件列表
|
||||||
|
lossList: [], // 损失列表
|
||||||
|
occurLocation: '',
|
||||||
|
occurTime: '',
|
||||||
|
roadConditionType: '',
|
||||||
|
routeNo: ''
|
||||||
|
})
|
||||||
|
|
||||||
|
const loading = ref(true)
|
||||||
|
|
||||||
|
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 detailData.eventStatus === 1 ? '已解除' : '未解除'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取事件状态类型
|
||||||
|
const getEventStatusType = () => {
|
||||||
|
return detailData.eventStatus === 1 ? 'success' : 'danger'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 格式化处置措施(逗号分隔转中文)
|
||||||
|
const formatDisposalMeasures = (measures) => {
|
||||||
|
if (!measures) return ''
|
||||||
|
const measureMap = {
|
||||||
|
半幅封闭: '半幅封闭',
|
||||||
|
全副封闭: '全副封闭',
|
||||||
|
便道通行: '便道通行',
|
||||||
|
正常通行: '正常通行'
|
||||||
|
}
|
||||||
|
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 ? `有车滞留` : '无车滞留'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取灾毁详情
|
||||||
|
const getDisasterDetail = async () => {
|
||||||
|
const id = route.query.id
|
||||||
|
if (!id) {
|
||||||
|
showToast('缺少灾毁ID')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
loading.value = true
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await request({
|
||||||
|
url: `/snow-ops-platform/event/getById`,
|
||||||
|
method: 'get',
|
||||||
|
params: { id }
|
||||||
|
})
|
||||||
|
|
||||||
|
if (result?.data) {
|
||||||
|
// 接口返回 Data 结构
|
||||||
|
const data = result.data
|
||||||
|
detailData.value = {
|
||||||
|
event: data.event || null,
|
||||||
|
report: data.reportList || [], // 直接使用 report,包含首报和续报
|
||||||
|
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('获取详情失败,请稍后重试')
|
||||||
|
}
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 点击返回
|
||||||
|
const handleClickBack = () => {
|
||||||
|
router.push('/disasterManagement')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 续报
|
||||||
|
const handleContinueReport = () => {
|
||||||
|
router.push({
|
||||||
|
path: '/disasterReport',
|
||||||
|
query: {
|
||||||
|
id: route.query.id,
|
||||||
|
eventType: 'ice',
|
||||||
|
isContinue: 'true'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const isImageFile = (file) => {
|
||||||
|
// 根据url后缀判断
|
||||||
|
const imageExtensions = /\.(jpg|jpeg|png|gif|webp|bmp|svg)$/i
|
||||||
|
if (file.fileUrl && imageExtensions.test(file.fileUrl)) return true
|
||||||
|
// 根据文件类型判断
|
||||||
|
if (file.type && file.type.startsWith('image/')) return true
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
const imagesForPreview = ref([])
|
||||||
|
const previewImagesVisible = ref(false)
|
||||||
|
const startPosition = ref(0)
|
||||||
|
|
||||||
|
// 预览附件
|
||||||
|
const previewFile = (report, file) => {
|
||||||
|
const images = report.fileList.filter((file) => isImageFile(file))
|
||||||
|
imagesForPreview.value = images.map((item) => item.fileUrl)
|
||||||
|
startPosition.value = imagesForPreview.value.indexOf(file.fileUrl)
|
||||||
|
previewImagesVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.column {
|
||||||
|
flex-direction: column;
|
||||||
|
.info-label {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.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 {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
flex: 1;
|
||||||
|
gap: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.attachment-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
margin-bottom: 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview-image-block {
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-icon {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -161,7 +161,7 @@ import PanelItem from '@/components/PanelItem.vue'
|
|||||||
import BasePicker from '@/components/BasePicker.vue'
|
import BasePicker from '@/components/BasePicker.vue'
|
||||||
import BaseDatePicker from '@/components/BaseDatePicker.vue'
|
import BaseDatePicker from '@/components/BaseDatePicker.vue'
|
||||||
import RoadRoutesPicker from '../RoadRoutesPicker.vue'
|
import RoadRoutesPicker from '../RoadRoutesPicker.vue'
|
||||||
import LossList from './LossList.vue'
|
import LossList from './components/LossList.vue'
|
||||||
import { useRouter, useRoute } from 'vue-router'
|
import { useRouter, useRoute } from 'vue-router'
|
||||||
import { request } from '@shared/utils/request'
|
import { request } from '@shared/utils/request'
|
||||||
import { useOptions } from '@shared/composables/useOptions'
|
import { useOptions } from '@shared/composables/useOptions'
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<PageContainer title="灾毁详情" @click-back="handleClickBack" class="page-container">
|
<PageContainer title="水毁详情" @click-back="handleClickBack" class="page-container">
|
||||||
<!-- 当前站点信息 -->
|
<!-- 当前站点信息 -->
|
||||||
<CurrentSite />
|
<CurrentSite />
|
||||||
|
|
||||||
@ -1,40 +0,0 @@
|
|||||||
{
|
|
||||||
"occurLocation": "G108国道 K2250+300处",
|
|
||||||
"occurTime": null,
|
|
||||||
"roadConditionType": "国道",
|
|
||||||
"routeNo": "G108",
|
|
||||||
"event": {
|
|
||||||
"blockedMileage": 1.5,
|
|
||||||
"blockedPointName": "磨盘山隧道口",
|
|
||||||
"contactPerson": "张明",
|
|
||||||
"contactPhone": "13812345678",
|
|
||||||
"damageCount": 3,
|
|
||||||
"district": "武侯区",
|
|
||||||
"endStakeNo": "K2251+200",
|
|
||||||
"estimatedRecoveryCost": 120.5,
|
|
||||||
"isBlocked": true,
|
|
||||||
"needsRecovery": true,
|
|
||||||
"repairProgress": "抢险中",
|
|
||||||
"reporterUnit": "武侯区交通运输局",
|
|
||||||
"startStakeNo": "K2250+300"
|
|
||||||
},
|
|
||||||
"report": {
|
|
||||||
"damagedVehicleCount": 2,
|
|
||||||
"strandedPersonCount": 12,
|
|
||||||
"deadCount": 0,
|
|
||||||
"strandedVehicleCount": 12,
|
|
||||||
"disposalMeasures": null,
|
|
||||||
"actualRecoverTime": null,
|
|
||||||
"expectRecoverTime": null,
|
|
||||||
"injuredCount": 1,
|
|
||||||
"investedFunds": 35.8,
|
|
||||||
"investedMachinery": 6,
|
|
||||||
"investedManpower": 45,
|
|
||||||
"remark": "已组织抢险队伍进行抢通,便道已修建完成",
|
|
||||||
"siteDescription": "因持续强降雨导致山体滑坡,掩埋路面约50米,边坡垮塌严重",
|
|
||||||
"totalLossAmount": 85.6
|
|
||||||
},
|
|
||||||
"lossList": [
|
|
||||||
],
|
|
||||||
"fileList": []
|
|
||||||
}
|
|
||||||
Loading…
x
Reference in New Issue
Block a user