Compare commits

..

No commits in common. "285bc95b918eb77cde66ef38e9d5c16dc0232d77" and "4e7d16f67fa6874bd922e55b218542d054fc0f18" have entirely different histories.

15 changed files with 1971 additions and 1074 deletions

View File

@ -3,15 +3,13 @@
<div class="content"> <div class="content">
<PanelItem title="基本信息"> <PanelItem title="基本信息">
<van-form class="IceEventAddForm" label-align="left" colon> <van-form class="IceEventAddForm" label-align="left" colon>
<van-field v-model="form.occurTime" label="发生时间" center> <van-field v-model="form.event.occurTime" label="发生时间" center>
<template #button> <template #button>
<van-button plain round type="primary" size="mini" @click="getCurrentTime">校准时间</van-button> <van-button plain round type="primary" size="mini" @click="getCurrentTime">校准时间</van-button>
</template> </template>
</van-field> </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.event.occurLocation" label="发生地点" center placeholder="请填写" />
<van-field v-model="form.occurLocation" label="路况位置" center placeholder="请填写" /> <van-field v-model="form.event.routeNo" label="线路编号" center placeholder="请填写" />
<van-field v-model="form.event.startStakeNo" 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.endStakeNo" label="止点桩号" center placeholder="请填写" />
<van-field v-model="form.event.disasterMileage" label="受灾里程" center type="number" placeholder="请填写" /> <van-field v-model="form.event.disasterMileage" label="受灾里程" center type="number" placeholder="请填写" />
@ -23,20 +21,16 @@
<van-field label="处置措施" center> <van-field label="处置措施" center>
<template #input> <template #input>
<div class="disposal-buttons"> <div class="disposal-buttons">
<van-button <van-button plain :type="form.event.disposalMeasures === '限速通行' ? 'primary' : 'default'" size="small" @click="toggleDisposal('限速通行')">
v-for="item in options['iceDisposalMeasures'] || []" 限速通行
:key="item.value" </van-button>
plain <van-button plain :type="form.event.disposalMeasures === '封闭交通' ? 'primary' : 'default'" size="small" @click="toggleDisposal('封闭交通')" class="last-button">
:type="form.report.disposalMeasures === item.value ? 'primary' : 'default'" 封闭交通
size="small"
@click="toggleDisposal(item.value)"
>
{{ item.label }}
</van-button> </van-button>
</div> </div>
</template> </template>
</van-field> </van-field>
<van-field v-model="form.report.expectRecoverTime" label="预计恢复时间" center placeholder="请选择" readonly clickable @click="showExpectPicker = true" /> <van-field v-model="form.event.expectRecoverTime" label="预计恢复时间" center placeholder="请选择" readonly clickable @click="showExpectPicker = true" />
<van-popup :show="showExpectPicker" round position="bottom" close-on-click-overlay @close="showExpectPicker = false"> <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-picker-group title="选择日期时间" :tabs="['选择日期', '选择时间']" @confirm="handleConfirmExpectTime" @cancel="showExpectPicker = false">
<van-date-picker v-model="expectDate" :min-date="minDate" :max-date="maxDate" /> <van-date-picker v-model="expectDate" :min-date="minDate" :max-date="maxDate" />
@ -48,13 +42,13 @@
<PanelItem title="实施情况"> <PanelItem title="实施情况">
<van-form class="IceEventAddForm" label-align="left" colon> <van-form class="IceEventAddForm" label-align="left" colon>
<van-field v-model="form.report.inputManpower" type="number" label="投入人力" center placeholder="请填写"> <van-field v-model="form.material.inputManpower" type="number" label="投入人力" center placeholder="请填写">
<template #extra> 人次 </template> <template #extra> 人次 </template>
</van-field> </van-field>
<van-field v-model="form.report.inputFunds" type="number" label="投入资金" center placeholder="请填写"> <van-field v-model="form.material.inputFunds" type="number" label="投入资金" center placeholder="请填写">
<template #extra> 万元 </template> <template #extra> 万元 </template>
</van-field> </van-field>
<van-field v-model="form.report.inputEquipment" type="number" label="投入设备" center placeholder="请填写"> <van-field v-model="form.material.inputEquipment" type="number" label="投入设备" center placeholder="请填写">
<template #extra> 台班 </template> <template #extra> 台班 </template>
</van-field> </van-field>
@ -102,20 +96,32 @@
<van-button type="primary" block @click="addSelectedMaterials" style="margin-top: 10px"> 确认添加 </van-button> <van-button type="primary" block @click="addSelectedMaterials" style="margin-top: 10px"> 确认添加 </van-button>
</div> </div>
</van-popup> </van-popup>
<van-field label="当前通行情况" center>
<template #input>
<div class="disposal-buttons">
<van-button plain :type="form.traffic.currentStatus === 1 ? 'primary' : 'default'" size="small" @click="form.traffic.currentStatus = 1"> 正常通行 </van-button>
<van-button plain :type="form.traffic.currentStatus === 2 ? 'primary' : 'default'" size="small" @click="form.traffic.currentStatus = 2"> 限速通行 </van-button>
<van-button plain :type="form.traffic.currentStatus === 3 ? 'primary' : 'default'" size="small" @click="form.traffic.currentStatus = 3" class="last-button">
封闭交通
</van-button>
</div>
</template>
</van-field>
<van-field label="有无车辆滞留" center> <van-field label="有无车辆滞留" center>
<template #input> <template #input>
<div class="disposal-buttons"> <div class="disposal-buttons">
<van-button plain :type="form.report.hasStrandedVehicles === 1 ? 'primary' : 'default'" size="small" @click="form.report.hasStrandedVehicles = 1"> <van-button plain :type="form.traffic.hasStrandedVehicles === 1 ? 'primary' : 'default'" size="small" @click="form.traffic.hasStrandedVehicles = 1">
有滞留 有滞留
</van-button> </van-button>
<van-button <van-button
plain plain
:type="form.report.hasStrandedVehicles === 0 ? 'primary' : 'default'" :type="form.traffic.hasStrandedVehicles === 0 ? 'primary' : 'default'"
size="small" size="small"
@click=" @click="
() => { () => {
form.report.hasStrandedVehicles = 0 form.traffic.hasStrandedVehicles = 0
form.report.strandedVehicleCount = null form.traffic.strandedVehicleCount = null
} }
" "
class="last-button" class="last-button"
@ -125,9 +131,9 @@
</div> </div>
</template> </template>
</van-field> </van-field>
<van-field v-if="form.report.hasStrandedVehicles === 1" v-model="form.report.strandedVehicleCount" type="number" label="滞留车辆数" center placeholder="请填写" /> <van-field v-if="form.traffic.hasStrandedVehicles === 1" v-model="form.traffic.strandedVehicleCount" type="number" label="滞留车辆数" center placeholder="请填写" />
<van-field v-model="form.report.actualRecoverTime" label="实际恢复时间" center placeholder="请选择" readonly clickable @click="showActualPicker = true" /> <van-field v-model="form.traffic.actualRecoverTime" label="实际恢复时间" center placeholder="请选择" readonly clickable @click="showActualPicker = true" />
<van-popup :show="showActualPicker" round position="bottom" close-on-click-overlay @close="showActualPicker = false"> <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-picker-group title="选择日期时间" :tabs="['选择日期', '选择时间']" @confirm="handleConfirmActualTime" @cancel="showActualPicker = false">
<van-date-picker v-model="actualDate" :min-date="minDate" :max-date="maxDate" /> <van-date-picker v-model="actualDate" :min-date="minDate" :max-date="maxDate" />
@ -135,18 +141,17 @@
</van-picker-group> </van-picker-group>
</van-popup> </van-popup>
<van-field v-model="form.report.siteDescription" label="现场情况描述" type="textarea" rows="2" autosize center placeholder="请填写" />
<van-field label="附件" center> <van-field label="附件" center>
<template #input> <template #input>
<van-uploader <van-uploader
:modelValue="getFileList()" v-model="fileList"
@delete="handleDelete"
name="photos" name="photos"
:file-list="fileList"
:file-type="['image/jpeg', 'image/png']" :file-type="['image/jpeg', 'image/png']"
:after-read="afterRead" :after-read="afterRead"
multiple multiple
:max-count="6" :max-count="6"
@delete="removeFile"
/> />
</template> </template>
</van-field> </van-field>
@ -159,80 +164,57 @@
</template> </template>
<script setup> <script setup>
import { ref, onMounted, reactive, watch, computed } from 'vue' import { ref, onMounted, reactive, toRaw, watch, computed } from 'vue'
import { useRouter } from 'vue-router' import { useRouter, useRoute } from 'vue-router'
import { showToast, showLoadingToast } from 'vant' import { showToast, showLoadingToast } from 'vant'
import PanelItem from '@/components/PanelItem.vue' import PanelItem from '@/components/PanelItem.vue'
import { request } from '../../../../shared/utils/request' import { request } from '../../../../shared/utils/request'
import { useYHZStore } from '@/stores/yhzStore' import { useYHZStore } from '@/stores/yhzStore';
import RoadRoutesPicker from './RoadRoutesPicker.vue'
import { useOptions } from '@shared/composables/useOptions'
const router = useRouter() const router = useRouter()
const route = useRoute()
const yhzStore = useYHZStore() const yhzStore = useYHZStore()
const { options } = useOptions()
const DEFAULT_REPORTER_UNIT = '万州区公路中心'
// //
const INIT_FORM = reactive({ const INIT_FORM = reactive({
occurLocation: '',
occurTime: '',
routeNo: '',
event: { event: {
occurLocation: '', // occurLocation: '', //
routeNo: '', // 线
occurTime: '', //
startStakeNo: '', // startStakeNo: '', //
endStakeNo: '', // endStakeNo: '', //
startStakeLng: null,
startStakeLat: null,
endStakeLng: null,
endStakeLat: null,
disasterMileage: '', // disasterMileage: '', //
expectRecoverTime: '', //
actualRecoverTime: '', //
serviceStationId: '', // ID serviceStationId: '', // ID
district: '', // district: '', //
reporterName: '',
reportTime: '', // reportTime: '', //
reporterPhone: '', // reporterPhone: '', //
reportUnit: DEFAULT_REPORTER_UNIT, disposalMeasures: '', //
routeNo: '',
occurTime: '',
roadConditionLocation: '',
routeType: '',
createTime: '', // createTime: '', //
updateTime: '', // updateTime: '', //
isDeleted: '' // 0- 1- isDeleted: '' // 0- 1-
}, },
report: { material: {
inputManpower: null, // inputManpower: null, //
inputFunds: null, // inputFunds: null, //
inputEquipment: null, // inputEquipment: null, //
disposalMeasures: '', createTime: '', //
expectRecoverTime: '', updateTime: '' //
actualRecoverTime: '', },
hasStrandedVehicles: 0, traffic: {
strandedVehicleCount: null, currentStatus: 0, // 1- 2- 3-
siteDescription: '', hasStrandedVehicles: 0, // 0- 1-
reporterName: '', strandedVehicleCount: null, //
reporterPhone: '', actualRecoverTime: '', //
reportTime: '',
industrialSalt: null,
antiSlipSand: null,
sandbags: null,
createTime: '', // createTime: '', //
updateTime: '' // updateTime: '' //
}, },
yhzMaterialList: [], // yhzMaterialList: [], //
fileList: [] photos: []
}) })
const form = reactive({ ...INIT_FORM }) const form = reactive({ ...INIT_FORM })
const fileList = ref([])
const getFileList = () => {
return (
form.fileList?.map((item) => ({
url: item.fileUrl,
name: item.fileName
})) || []
)
}
// //
const formatTime = (date = new Date()) => { const formatTime = (date = new Date()) => {
@ -241,16 +223,16 @@ const formatTime = (date = new Date()) => {
} }
const getCurrentTime = () => { const getCurrentTime = () => {
form.occurTime = formatTime() form.event.occurTime = formatTime()
} }
const toggleDisposal = (type) => { const toggleDisposal = (type) => {
form.report.disposalMeasures = form.report.disposalMeasures === type ? '' : type form.event.disposalMeasures = form.event.disposalMeasures === type ? '' : type
} }
// //
onMounted(() => { onMounted(() => {
form.occurTime = formatTime() // form.event.occurTime = formatTime() //
}) })
// //
@ -304,6 +286,7 @@ const checkMaterialAmount = (material, index) => {
type: 'fail', type: 'fail',
message: '输入数量不能超过物资余额' message: '输入数量不能超过物资余额'
}) })
//
form.yhzMaterialList[index].usageAmount = material.ye form.yhzMaterialList[index].usageAmount = material.ye
} }
} }
@ -348,37 +331,14 @@ const handleAdd = async () => {
forbidClick: true, forbidClick: true,
duration: 0 // 0 duration: 0 // 0
}) })
form.event.serviceStationId = yhzStore.getYHZInfo?.id || '' form.event.serviceStationId = yhzStore.getYHZInfo.id
form.event.district = yhzStore.getYHZInfo?.qxmc || '' form.event.district = yhzStore.getYHZInfo.qxmc
const reportTime = form.report.reportTime || form.event.reportTime || formatTime() console.log('yhzDetail', toRaw(yhzStore.getYHZInfo))
const submitData = { console.log('form', toRaw(form))
...form,
event: {
...form.event,
routeNo: form.routeNo,
occurTime: form.occurTime,
reportTime,
reportUnit: form.event.reportUnit || DEFAULT_REPORTER_UNIT,
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({ const res = await request({
url: '/snow-ops-platform/event/addOrUpdate', url: '/snow-ops-platform/event/add',
method: 'POST', method: 'POST',
data: submitData data: form
}) })
if (res.code === '00000') { if (res.code === '00000') {
toast.close() toast.close()
@ -413,7 +373,7 @@ const maxDate = new Date(2050, 11, 31)
const handleConfirmExpectTime = () => { const handleConfirmExpectTime = () => {
const [year, month, day] = expectDate.value const [year, month, day] = expectDate.value
const [hour, minute] = expectTime.value const [hour, minute] = expectTime.value
form.report.expectRecoverTime = form.event.expectRecoverTime =
`${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')} ` + `${String(hour).padStart(2, '0')}:${String(minute).padStart(2, '0')}:00` `${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 showExpectPicker.value = false
} }
@ -422,7 +382,7 @@ const showActualPicker = ref(false)
const handleConfirmActualTime = () => { const handleConfirmActualTime = () => {
const [year, month, day] = actualDate.value const [year, month, day] = actualDate.value
const [hour, minute] = actualTime.value const [hour, minute] = actualTime.value
form.report.actualRecoverTime = form.traffic.actualRecoverTime =
`${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')} ` + `${String(hour).padStart(2, '0')}:${String(minute).padStart(2, '0')}:00` `${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 showActualPicker.value = false
} }
@ -430,62 +390,19 @@ const handleConfirmActualTime = () => {
// //
watch(showExpectPicker, (val) => { watch(showExpectPicker, (val) => {
if (val) { if (val) {
const current = form.report.expectRecoverTime ? new Date(form.report.expectRecoverTime) : new Date() const current = form.event.expectRecoverTime ? new Date(form.event.expectRecoverTime) : new Date()
expectDate.value = [current.getFullYear(), current.getMonth() + 1, current.getDate()] expectDate.value = [current.getFullYear(), current.getMonth() + 1, current.getDate()]
expectTime.value = [current.getHours(), current.getMinutes()] expectTime.value = [current.getHours(), current.getMinutes()]
} }
}) })
watch(showActualPicker, (val) => { watch(showActualPicker, (val) => {
if (val) { if (val) {
const current = form.report.actualRecoverTime ? new Date(form.report.actualRecoverTime) : new Date() const current = form.traffic.actualRecoverTime ? new Date(form.traffic.actualRecoverTime) : new Date()
actualDate.value = [current.getFullYear(), current.getMonth() + 1, current.getDate()] actualDate.value = [current.getFullYear(), current.getMonth() + 1, current.getDate()]
actualTime.value = [current.getHours(), current.getMinutes()] 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) => { const afterRead = async (file) => {
try { try {
@ -503,12 +420,14 @@ const afterRead = async (file) => {
}) })
toast.close() toast.close()
if (res.code === '00000') { if (res.code === '00000') {
form.fileList.push({ form.photos.push({ photoUrl: res.data })
fileName: file.file.name, const index = fileList.value.findIndex((f) => f.file === file.file)
fileUrl: res.data, if (index !== -1) {
fileType: 1, fileList.value[index].serverUrl = res.data
fileSize: file.file.size }
})
console.log('form.photos', toRaw(form.photos))
console.log('fileList.value', fileList.value)
} else { } else {
throw new Error(res.message) throw new Error(res.message)
} }
@ -522,8 +441,13 @@ const afterRead = async (file) => {
} }
// //
const removeFile = (file, index) => { const handleDelete = (file) => {
form.fileList.splice(index, 1) if (file.serverUrl) {
const index = form.photos.findIndex((p) => p.photoUrl === file.serverUrl)
if (index !== -1) {
form.photos.splice(index, 1)
}
}
} }
</script> </script>

View File

@ -295,47 +295,9 @@ const isVideoFile = (file) => {
if (file.fileUrl && videoExtensions.test(file.fileUrl)) return true if (file.fileUrl && videoExtensions.test(file.fileUrl)) return true
} }
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) => { const handleRouteNoChange = (item) => {
formData.routeNo = item.routeCode formData.value.event.startStakeNo = item.startStakeNo
formData.event.startStakeNo = item.startStakeNo formData.value.event.endStakeNo = item.endStakeNo
formData.event.endStakeNo = item.endStakeNo
const startPoint = parsePointValue(item.startPoint)
const endPoint = parsePointValue(item.endPoint)
formData.event.startStakeLongitude = startPoint.longitude
formData.event.startStakeLatitude = startPoint.latitude
formData.event.endStakeLongitude = endPoint.longitude
formData.event.endStakeLatitude = endPoint.latitude
} }
/** /**
@ -442,7 +404,7 @@ const afterRead = async (options) => {
if (res.code === '00000') { if (res.code === '00000') {
const name = file.name const name = file.name
const url = res.data const url = res.data
const type = isImageFile({ fileUrl: url }) ? 1 : isVideoFile({ fileUrl: url }) ? 2 : 3 const type = isImageFile({ fileUrl: url}) ? 1 : isVideoFile({ fileUrl: url}) ? 2 : 3
const fileData = { const fileData = {
fileName: name, fileName: name,
fileUrl: url, fileUrl: url,

View File

@ -1,71 +0,0 @@
<template>
<el-input
v-bind="$attrs"
:model-value="displayValue"
@update:modelValue="handleUpdate"
@change="handleChange"
@blur="handleBlur"
@focus="handleFocus"
>
<template v-if="$slots.prepend" #prepend>
<slot name="prepend" />
</template>
<template v-if="$slots.prefix" #prefix>
<slot name="prefix" />
</template>
<template v-if="$slots.suffix" #suffix>
<slot name="suffix" />
</template>
<template v-if="$slots.append" #append>
<slot name="append" />
</template>
</el-input>
</template>
<script setup>
import { computed } from 'vue'
import { updateValueForNumber } from '@/utils/math'
defineOptions({
inheritAttrs: false
})
const props = defineProps({
modelValue: {
type: [String, Number],
default: ''
},
precision: {
type: Number,
default: 0
}
})
const emit = defineEmits(['update:modelValue', 'input', 'change', 'blur', 'focus'])
const displayValue = computed(() => props.modelValue ?? '')
const normalizeValue = (value) => {
const target = { value: props.modelValue }
updateValueForNumber(target, 'value', value, props.precision)
return target.value
}
const handleUpdate = (value) => {
const normalizedValue = normalizeValue(value)
emit('update:modelValue', normalizedValue)
emit('input', normalizedValue)
}
const handleChange = (value) => {
emit('change', normalizeValue(value))
}
const handleBlur = (event) => {
emit('blur', event)
}
const handleFocus = (event) => {
emit('focus', event)
}
</script>

View File

@ -1,18 +0,0 @@
export const updateValueForNumber = (obj, key, value, precision = 2) => {
let normalizedValue = String(value ?? '').replace(/[^\d.]/g, '')
normalizedValue = normalizedValue.replace(/^\./, '')
if (precision <= 0) {
obj[key] = normalizedValue.replace(/\./g, '')
return
}
const firstDotIndex = normalizedValue.indexOf('.')
if (firstDotIndex !== -1) {
const integerPart = normalizedValue.slice(0, firstDotIndex)
const decimalPart = normalizedValue.slice(firstDotIndex + 1).replace(/\./g, '').slice(0, precision)
normalizedValue = decimalPart ? `${integerPart}.${decimalPart}` : `${integerPart}.`
}
obj[key] = normalizedValue
}

View File

@ -1,88 +1,130 @@
<template> <template>
<div class="ice-disaster-pc"> <div class="water-disaster-pc">
<el-card class="info-card" shadow="never"> <!-- 合并后的单个卡片 -->
<template #header> <el-card class="form-card" shadow="never">
<div class="card-header"> <div slot="header" class="card-header">
<span class="card-title">续报信息</span> <span>续报信息</span>
</div> </div>
</template>
<el-form :model="formData" v-if="formData.report"> <!-- 所有表单项合并到一个区域每行一个 -->
<BlockItem title="处置情况"> <el-form :model="formData" label-width="120px" size="small">
<el-form-item label="处理措施"> <!-- 处置措施 -->
<el-select v-model="formData.report.disposalMeasures" placeholder="请选择" style="width: 100%"> <el-form-item label="处置措施">
<el-option v-for="(option, idx) in options['iceDisposalMeasures']" :key="idx" :label="option.label" :value="option.value" /> <el-select v-model="formData.report.disposalMeasures">
<el-option label="半幅封闭" value="半幅封闭" />
<el-option label="全副封闭" value="全副封闭" />
<el-option label="便道通行" value="便道通行" />
<el-option label="正常通行" value="正常通行" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<!-- 预计恢复时间 -->
<el-form-item label="预计恢复时间"> <el-form-item label="预计恢复时间">
<el-date-picker <el-date-picker
v-model="formData.report.expectRecoverTime" v-model="formData.report.expectRecoverTime"
type="datetime" type="datetime"
placeholder="请选择时间" placeholder="请选择时间"
value-format="YYYY-MM-DD HH:mm:ss" value-format="yyyy-MM-dd HH:mm"
:picker-options="pickerOptions" :picker-options="pickerOptions"
style="width: 100%" style="width: 100%"
/> />
</el-form-item> </el-form-item>
{{ formData.report.expectRecoverTime }}
<el-form-item label="实际预计恢复时间"> <!-- 实际恢复时间 -->
<el-form-item label="实际恢复时间">
<el-date-picker <el-date-picker
v-model="formData.report.actualRecoverTime" v-model="formData.report.actualRecoverTime"
type="datetime" type="datetime"
placeholder="请选择时间" placeholder="请选择时间"
value-format="YYYY-MM-DD HH:mm:ss" value-format="yyyy-MM-dd HH:mm"
:picker-options="pickerOptions" :picker-options="pickerOptions"
style="width: 100%" style="width: 100%"
/> />
</el-form-item> </el-form-item>
</BlockItem>
<BlockItem title="实施情况"> <!-- 受伤人员 -->
<MaterialList v-model="formData.yhzMaterialList" :yhzId="formData.event.serviceStationId" :col-span="24" /> <el-form-item label="受伤人员">
<el-form-item label="投入资金"> <el-input-number v-model="formData.report.injuredCount" :min="0" :controls="false" placeholder="请填写" style="width: 300px">
<NumberInput v-model="formData.report.inputFunds" :precision="2" placeholder="请填写" style="width: 300px"> <template slot="append"></template>
<template #append>万元</template> </el-input-number>
</NumberInput>
</el-form-item> </el-form-item>
<el-form-item label="投入人力"> <!-- 死亡人员 -->
<NumberInput v-model="formData.report.inputManpower" :precision="0" placeholder="请填写" style="width: 300px"> <el-form-item label="死亡人员">
<template #append>人次</template> <el-input-number v-model="formData.report.deadCount" :min="0" :controls="false" placeholder="请填写" style="width: 300px">
</NumberInput> <template slot="append"></template>
</el-input-number>
</el-form-item> </el-form-item>
<el-form-item label="投入设备"> <!-- 滞留人员 -->
<NumberInput v-model="formData.report.inputEquipment" :precision="1" placeholder="请填写" style="width: 300px"> <el-form-item label="滞留人员">
<template #append>/</template> <el-input-number v-model="formData.report.strandedPersonCount" :min="0" :controls="false" placeholder="请填写" style="width: 300px">
</NumberInput> <template slot="append"></template>
</el-input-number>
</el-form-item> </el-form-item>
<el-form-item label="有无滞留车辆"> <!-- 损坏车辆 -->
<el-select v-model="formData.report.hasStrandedVehicles" placeholder="请选择" style="width: 300px" @change="handleHasStrandedVehiclesChange"> <el-form-item label="损坏车辆">
<el-option label="有" :value="1" /> <el-input-number v-model="formData.report.damagedVehicleCount" :min="0" :controls="false" placeholder="请填写" style="width: 300px">
<el-option label="无" :value="0" /> <template slot="append"></template>
</el-select> </el-input-number>
</el-form-item> </el-form-item>
<!-- 滞留车辆 -->
<el-form-item label="滞留车辆"> <el-form-item label="滞留车辆">
<NumberInput v-model="formData.report.strandedVehicleCount" :precision="0" placeholder="请填写" style="width: 300px"> <el-input-number v-model="formData.report.strandedVehicleCount" :min="0" :controls="false" placeholder="请填写" style="width: 300px">
<template #append></template> <template slot="append"></template>
</NumberInput> </el-input-number>
</el-form-item> </el-form-item>
<el-form-item label="现场情况描述"> <!-- 损失列表组件 -->
<el-input v-model="formData.report.siteDescription" type="textarea" :rows="3" placeholder="请输入" /> <loss-list :col-span="24" v-model="formData.lossList" />
<!-- 处理情况 -->
<el-form-item label="处理情况">
<el-input v-model="formData.report.remark" type="textarea" :rows="2" placeholder="请填写(选填)" style="width: 60%" />
</el-form-item> </el-form-item>
<el-form-item label="附件"> <!-- 损失总金额 -->
<div class="upload-wrapper"> <el-form-item label="损失总金额">
<FileUpload v-model="formData.fileList" type="image" :limit="6" /> <el-input v-model="formData.report.totalLossAmount" placeholder="请填写(选填)" style="width: 300px">
<div class="upload-tip">只能上传jpg/png文件且不超过500kb 最多上传6张照片</div> <template slot="append">万元</template>
</div> </el-input>
</el-form-item>
<!-- 已投机械 -->
<el-form-item label="已投机械">
<el-input v-model="formData.report.investedMachinery" placeholder="请填写" style="width: 300px">
<template slot="append">/</template>
</el-input>
</el-form-item>
<!-- 投入人力 -->
<el-form-item label="投入人力">
<el-input-number v-model="formData.report.investedManpower" :min="0" :controls="false" placeholder="请填写" style="width: 300px">
<template slot="append">人次</template>
</el-input-number>
</el-form-item>
<!-- 投入资金 -->
<el-form-item label="投入资金">
<el-input v-model="formData.report.investedFunds" placeholder="请填写" style="width: 300px">
<template slot="append">万元</template>
</el-input>
</el-form-item>
<!-- 现场描述 -->
<el-form-item label="现场描述">
<el-input v-model="formData.report.siteDescription" type="textarea" :rows="2" placeholder="请填写" style="width: 60%" />
</el-form-item>
<!-- 是否需要恢复重建 -->
<el-form-item label="是否需要恢复重建">
<el-radio-group v-model="formData.event.needsRecovery">
<el-radio :label="true"></el-radio>
<el-radio :label="false"></el-radio>
</el-radio-group>
</el-form-item> </el-form-item>
</BlockItem>
<el-form-item> <el-form-item>
<el-button type="primary" @click="handleSubmit">追加记录</el-button> <el-button type="primary" @click="handleSubmit">追加记录</el-button>
@ -93,15 +135,12 @@
</template> </template>
<script setup> <script setup>
import { ref, watch } from 'vue' import { ref, reactive, watch, computed } from 'vue'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { request } from '@shared/utils/request' import { request } from '@shared/utils/request'
import BlockItem from '@/component/BlockItem.vue' import LossList from '../WaterDisasterReport/WaterDisasterLossListPC.vue'
import FileUpload from '@/component/FileUpload/FileUpload.vue'
import NumberInput from '@/component/NumberInput/NumberInput.vue'
import MaterialList from '../components/MaterialList.vue'
import { useOptions } from '@shared/composables/useOptions'
// Props
const props = defineProps({ const props = defineProps({
value: { value: {
type: Object, type: Object,
@ -109,55 +148,137 @@ const props = defineProps({
} }
}) })
const emit = defineEmits(['refresh']) // Emits
const emit = defineEmits(['input', 'change', 'submit'])
const { options } = useOptions() //
const formData = reactive({
occurLocation: '',
occurTime: '',
roadConditionType: '',
routeNo: '',
event: {
blockedMileage: '',
blockedPointName: '',
contactPerson: '',
contactPhone: '',
damageCount: '',
district: '',
endStakeNo: '',
estimatedRecoveryCost: '',
isBlocked: '',
needsRecovery: '',
repairProgress: '',
reporterUnit: '',
startStakeNo: ''
},
report: {
actualRecoverTime: '',
damagedVehicleCount: '',
deadCount: '',
disposalMeasures: '',
expectRecoverTime: '',
injuredCount: '',
investedFunds: '',
investedMachinery: '',
investedManpower: '',
remark: '',
siteDescription: '',
strandedPersonCount: '',
strandedVehicleCount: '',
totalLossAmount: ''
},
lossList: [],
fileList: []
})
//
const disposalMeasureValue = ref('')
const formData = ref({}) //
const roadConditionOptions = [
{ label: '高速公路', value: '高速公路' },
{ label: '国道', value: '国道' },
{ label: '省道', value: '省道' },
{ label: '县道', value: '县道' },
{ label: '乡道', value: '乡道' },
{ label: '村道', value: '村道' }
]
const blockedOptions = [
{ label: '是', value: true },
{ label: '否', value: false }
]
const repairProgressOptions = [
{ label: '未抢险', value: '未抢险' },
{ label: '抢险中', value: '抢险中' },
{ label: '已完成', value: '已完成' }
]
//
const pickerOptions = { const pickerOptions = {
disabledDate(time) { disabledDate(time) {
return time.getTime() < new Date(2020, 0, 1) || time.getTime() > new Date(2030, 11, 31) return time.getTime() < new Date(2020, 0, 1) || time.getTime() > new Date(2030, 11, 31)
} }
} }
const initFormData = (data = {}) => { //
formData.value = data watch(disposalMeasureValue, (newVal) => {
} formData.report.disposalMeasures = newVal
})
const validate = () => {
const form = formData.value //
if (!form.report.disposalMeasures) { watch(
ElMessage.warning('请选择处理措施') () => props.value,
return false (newVal) => {
} if (newVal && Object.keys(newVal).length > 0) {
if (!form.report.expectRecoverTime) { initFormData(newVal)
ElMessage.warning('请选择预计恢复时间') }
return false },
} { immediate: true, deep: true }
if (!form.report.siteDescription) { )
ElMessage.warning('请填写现场情况描述')
return false //
} watch(
return true () => formData,
} (newVal) => {
emit('input', newVal)
const getFormData = () => { emit('change', newVal)
const submitData = { },
...formData.value, { deep: true }
report: { )
...formData.value.report
} // report.disposalMeasures
} watch(
() => formData.report.disposalMeasures,
if (submitData.report.hasStrandedVehicles !== 1) { (newVal) => {
submitData.report.strandedVehicleCount = null if (newVal && typeof newVal === 'string') {
} disposalMeasureValue.value = newVal
}
return submitData },
{ immediate: true }
)
//
const initFormData = (data) => {
Object.assign(formData, {
occurLocation: data.occurLocation || '',
occurTime: data.occurTime || '',
roadConditionType: data.roadConditionType || '',
routeNo: data.routeNo || '',
event: { ...formData.event, ...(data.event || {}) },
report: { ...formData.report, ...(data.report || {}) },
lossList: data.lossList || [],
fileList: data.fileList || []
})
if (data.report?.disposalMeasures) {
disposalMeasureValue.value = data.report.disposalMeasures
}
} }
//
const calibrateTime = () => { const calibrateTime = () => {
const now = new Date() const now = new Date()
const year = now.getFullYear() const year = now.getFullYear()
@ -165,89 +286,162 @@ const calibrateTime = () => {
const day = String(now.getDate()).padStart(2, '0') const day = String(now.getDate()).padStart(2, '0')
const hours = String(now.getHours()).padStart(2, '0') const hours = String(now.getHours()).padStart(2, '0')
const minutes = String(now.getMinutes()).padStart(2, '0') const minutes = String(now.getMinutes()).padStart(2, '0')
formData.value.occurTime = `${year}-${month}-${day} ${hours}:${minutes}` formData.occurTime = `${year}-${month}-${day} ${hours}:${minutes}`
ElMessage.success('时间已校准为当前时间') ElMessage.success('时间已校准为当前时间')
} }
const handleHasStrandedVehiclesChange = (value) => { //
if (value !== 1) { const validate = () => {
formData.value.report.strandedVehicleCount = null if (!formData.occurTime) {
ElMessage.warning('请填写发生时间')
return false
}
if (!formData.routeNo) {
ElMessage.warning('请填写线路编号')
return false
}
return true
}
//
const getFormData = () => {
return { ...formData }
}
//
const resetForm = () => {
Object.assign(formData, {
occurLocation: '',
occurTime: '',
roadConditionType: '',
routeNo: '',
event: {
blockedMileage: '',
blockedPointName: '',
contactPerson: '',
contactPhone: '',
damageCount: '',
district: '',
endStakeNo: '',
estimatedRecoveryCost: '',
isBlocked: '',
needsRecovery: '',
repairProgress: '',
reporterUnit: '',
startStakeNo: ''
},
report: {
actualRecoverTime: '',
damagedVehicleCount: '',
deadCount: '',
disposalMeasures: '',
expectRecoverTime: '',
injuredCount: '',
investedFunds: '',
investedMachinery: '',
investedManpower: '',
remark: '',
siteDescription: '',
strandedPersonCount: '',
strandedVehicleCount: '',
totalLossAmount: ''
},
lossList: [],
fileList: []
})
disposalMeasureValue.value = ''
}
//
const submit = () => {
if (validate()) {
emit('submit', getFormData())
} }
} }
const handleSubmit = async () => { const handleSubmit = async () => {
//
if (!validate()) { if (!validate()) {
return return
} }
try { try {
//
//
const submitData = {
...formData
//
}
const res = await request({ const res = await request({
url: '/snow-ops-platform/event/addOrUpdate', url: '/snow-ops-platform/water-damage/addOrUpdate',
method: 'post', method: 'post',
data: getFormData() data: submitData
}) })
if (res?.code === '00000') { if (res?.code === '00000') {
ElMessage.success('提交成功') ElMessage.success('提交成功')
emit('refresh')
emit("refresh")
} else { } else {
ElMessage.error(res?.message || '提交失败') ElMessage.error(res.message)
} }
} catch (error) { } catch (error) {
ElMessage.error('提交失败,请重试') ElMessage.error('提交失败,请重试')
console.error('提交失败:', error) console.error('提交失败:', error)
} finally {
} }
} }
//
defineExpose({ defineExpose({
validate, validate,
initFormData, initFormData,
getFormData, getFormData,
calibrateTime resetForm,
calibrateTime,
}) })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.ice-disaster-pc { .water-disaster-pc {
background-color: #f5f7fa; background-color: #f5f7fa;
height: 100%; height: 100%;
.info-card { .form-card {
margin-bottom: 20px;
border-radius: 8px; border-radius: 8px;
:deep(.el-card__header) {
padding: 16px 20px;
border-bottom: 1px solid #ebeef5;
background: #fafafa;
}
.card-header { .card-header {
.card-title {
font-size: 16px; font-size: 16px;
font-weight: 600; font-weight: 600;
color: #303133; color: #303133;
} border-left: 4px solid #409eff;
padding-left: 12px;
} }
} }
:deep(.el-form-item) { ::v-deep .el-form-item {
margin-bottom: 22px; margin-bottom: 22px;
} }
// :deep(.el-input-group__append) { ::v-deep .el-input-group__append {
// padding: 0 10px; padding: 0 10px;
// }
.upload-wrapper {
width: 100%;
} }
.upload-tip { ::v-deep .el-input-number {
margin-top: 8px; width: 300px;
color: #909399;
font-size: 12px; .el-input-group__append {
line-height: 1.6; padding: 0 10px;
}
}
::v-deep .el-radio-group {
.el-radio {
margin-right: 20px;
}
} }
} }
</style> </style>

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="page-container"> <div class="web-detail-container">
<div class="content-container" v-if="detailData"> <div class="content-container">
<div class="left-panel"> <div class="left-panel">
<!-- 基本信息卡片 --> <!-- 基本信息卡片 -->
<el-card class="info-card" shadow="never"> <el-card class="info-card" shadow="never">
@ -20,13 +20,13 @@
<el-col :span="8"> <el-col :span="8">
<div class="info-item"> <div class="info-item">
<span class="info-label">所属服务站</span> <span class="info-label">所属服务站</span>
<span class="info-value">{{ detailData.event?.stationName || '-' }}</span> <span class="info-value">{{}}</span>
</div> </div>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<div class="info-item"> <div class="info-item">
<span class="info-label">线路编号</span> <span class="info-label">线路编号</span>
<span class="info-value">{{ detailData.routeNo || detailData.event?.routeNo || '-' }}</span> <span class="info-value">{{}}</span>
</div> </div>
</el-col> </el-col>
</el-row> </el-row>
@ -34,66 +34,22 @@
<el-col :span="8"> <el-col :span="8">
<div class="info-item"> <div class="info-item">
<span class="info-label">发现时间</span> <span class="info-label">发现时间</span>
<span class="info-value">{{ detailData.occurTime || '-' }}</span> <span class="info-value">冰雪事件</span>
</div> </div>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<div class="info-item"> <div class="info-item">
<span class="info-label">路况位置</span> <span class="info-label">路况位置</span>
<span class="info-value">{{ detailData.occurLocation || '-' }}</span> <span class="info-value">{{}}</span>
</div> </div>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<div class="info-item"> <div class="info-item">
<span class="info-label">发生地点</span> <span class="info-label">发生地点</span>
<span class="info-value">{{ detailData.event?.occurLocation || '-' }}</span> <span class="info-value">{{}}</span>
</div> </div>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="20" class="info-row">
<div class="stake-panel">
<el-icon class="stake-point-icon">
<LocationFilled />
</el-icon>
<div class="info-item">
<span class="info-label">起点桩号</span>
<span class="info-value">{{ formatStakeNo(detailData.event?.startStakeNo) }}</span>
</div>
<div class="info-item">
<span class="info-label">纬度</span>
<span class="info-value">{{ formatValue(detailData.event?.startStakeLat ?? detailData.event?.startStakeLatitude) }}</span>
</div>
<div class="info-item">
<span class="info-label">经度</span>
<span class="info-value">{{ formatValue(detailData.event?.startStakeLng ?? detailData.event?.startStakeLongitude) }}</span>
</div>
</div>
<div class="stake-center">
<div class="info-item stake-mileage-item">
<span class="info-label">受灾里程</span>
<span class="info-value">{{ formatMileage(detailData.event?.disasterMileage) }}</span>
</div>
<div class="stake-mileage-line"></div>
</div>
<div class="stake-panel">
<el-icon class="stake-point-icon">
<LocationFilled />
</el-icon>
<div class="info-item">
<span class="info-label">止点桩号</span>
<span class="info-value">{{ formatStakeNo(detailData.event?.endStakeNo) }}</span>
</div>
<div class="info-item">
<span class="info-label">纬度</span>
<span class="info-value">{{ formatValue(detailData.event?.endStakeLat ?? detailData.event?.endStakeLatitude) }}</span>
</div>
<div class="info-item">
<span class="info-label">经度</span>
<span class="info-value">{{ formatValue(detailData.event?.endStakeLng ?? detailData.event?.endStakeLongitude) }}</span>
</div>
</div>
</el-row>
</el-card> </el-card>
<!-- 填报情况 --> <!-- 填报情况 -->
<el-card class="info-card" shadow="never"> <el-card class="info-card" shadow="never">
@ -102,94 +58,41 @@
<span class="card-title">填报情况</span> <span class="card-title">填报情况</span>
</div> </div>
</template> </template>
<div v-if="hasReportData">
<div v-for="(report, index) in allReports" :key="'report' + index" class="report-section">
<div class="report-header">
<span class="report-title">{{ getReportTitle(index) }}</span>
<span class="report-meta">时间{{ formatValue(report.createTime) }}</span>
</div>
<div class="content-wrapper">
<div class="basic-info-wrapper">
<div class="info-list">
<div class="info-item">
<span class="info-label">处理措施</span>
<span class="info-value">{{ formatDisposalMeasures(report.disposalMeasures) }}</span>
</div>
<div class="info-item">
<span class="info-label">预计恢复时间</span>
<span class="info-value">{{ formatValue(report.expectRecoverTime) }}</span>
</div>
<div class="info-item">
<span class="info-label">实际恢复时间</span>
<span class="info-value">{{ formatValue(report.actualRecoverTime) }}</span>
</div>
<div class="info-item">
<span class="info-label">填报人</span>
<span class="info-value">{{ formatValue(report.reporterName || report.reportUserName || report.createByName) }}</span>
</div>
<div class="info-item">
<span class="info-label">联系电话</span>
<span class="info-value">{{ formatValue(report.reporterPhone || report.phone || report.reportPhone || report.contactPhone) }}</span>
</div>
<div class="info-item" v-for="(item, index) in report.materialUsageList" :key="index">
<span class="info-label">{{item.materialName}}</span>
<span class="info-value">{{ getMaterialUsageText(item) }}</span>
</div>
<div class="info-item">
<span class="info-label">投入资金</span>
<span class="info-value">{{ formatUnitValue(report.inputFunds ?? report.material?.inputFunds ?? report.investedFunds, '万元') }}</span>
</div>
<div class="info-item">
<span class="info-label">投入人力</span>
<span class="info-value">{{ formatUnitValue(report.inputManpower ?? report.material?.inputManpower ?? report.investedManpower, '人次') }}</span>
</div>
<div class="info-item">
<span class="info-label">投入设备</span>
<span class="info-value">{{ formatUnitValue(report.inputEquipment ?? report.material?.inputEquipment ?? report.investedMachinery, '台') }}</span>
</div>
<div class="info-item">
<span class="info-label">有无车辆滞留</span>
<span class="info-value">{{ getHasStrandedVehiclesText(report) }}</span>
</div>
<div class="info-item">
<span class="info-label">滞留车辆</span>
<span class="info-value">{{ formatUnitValue(report.strandedVehicleCount ?? report.traffic?.strandedVehicleCount, '辆') }}</span>
</div>
<div class="info-item">
<span class="info-label">现场情况描述</span>
<span class="info-value">{{ formatValue(report.siteDescription) }}</span>
</div>
</div>
<div class="file-list">
<FileUpload v-model="report.fileList" :readonly="!isEdit" />
</div>
</div>
</div>
</div>
</div>
<el-empty v-else description="暂无填报情况" :image-size="100" />
</el-card> </el-card>
</div> </div>
<div class="right-panel" v-if="isEdit"> <!-- <div class="right-panel" v-if="isEdit">
<ContinueReport ref="continueReport" @refresh="getDisasterDetail" /> <ContinueReport ref="continueReport" @refresh="getDisasterDetail" />
</div> </div> -->
</div> </div>
</div> </div>
</template> </template>
<script setup> <script setup>
import { onMounted, ref, computed, nextTick } from 'vue' import { onMounted, ref, computed } from 'vue'
import { useRoute } from 'vue-router' import { useRouter, useRoute } from 'vue-router'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { LocationFilled } from '@element-plus/icons-vue' import { ArrowLeft, Picture, VideoCamera } from '@element-plus/icons-vue'
import { request } from '@shared/utils/request'
import ContinueReport from './IceDisasterContinueReportPC.vue' import ContinueReport from './IceDisasterContinueReportPC.vue'
import { request } from '@shared/utils/request'
import FileUpload from '@/component/FileUpload/FileUpload.vue' import FileUpload from '@/component/FileUpload/FileUpload.vue'
const router = useRouter()
const route = useRoute() const route = useRoute()
// //
const detailData = ref(null) const detailData = ref({
event: null,
report: [],
fileList: [],
lossList: [],
occurLocation: '',
occurTime: '',
roadConditionType: '',
routeNo: ''
})
//
const eventStatus = ref(0)
// //
const isEdit = computed(() => { const isEdit = computed(() => {
@ -198,25 +101,19 @@ const isEdit = computed(() => {
const continueReport = ref(null) const continueReport = ref(null)
const formatValue = (value) => {
return value || value === 0 ? value : '-'
}
const formatStakeNo = (value) => {
if (!value && value !== 0) return '-'
const text = String(value).trim()
if (!text) return '-'
return /^k/i.test(text) ? text.toUpperCase() : `K${text}`
}
const formatMileage = (value) => {
if (!value && value !== 0) return '-'
return `${value}公里`
}
// + // +
const allReports = computed(() => { const allReports = computed(() => {
return detailData.value.report || [] 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()
}) })
// //
@ -224,39 +121,6 @@ const hasReportData = computed(() => {
return allReports.value.length > 0 return allReports.value.length > 0
}) })
const getReportTitle = (index) => {
const reportLength = allReports.value.length
return index === reportLength - 1 ? '首报' : `续报${reportLength - 1 - index}`
}
const formatDisposalMeasures = (value) => {
if (!value) return '-'
return String(value)
.split(/[,]/)
.map((item) => item.trim())
.filter(Boolean)
.join('、')
}
const formatUnitValue = (value, unit) => {
if (value === null || value === undefined || value === '') return '-'
return `${value}${unit}`
}
const getMaterialUsageText = (item) => {
return item.usageAmount + ' ' + item.materialUnit
}
const getHasStrandedVehiclesText = (report) => {
const value = report?.hasStrandedVehicles ?? report?.traffic?.hasStrandedVehicles
if (value === 1 || value === true || value === '1' || value === '是' || value === '有') return '有'
if (value === 0 || value === false || value === '0' || value === '否' || value === '无') return '无'
const count = report?.strandedVehicleCount ?? report?.traffic?.strandedVehicleCount
if (count === null || count === undefined || count === '') return '-'
return Number(count) > 0 ? '有' : '无'
}
// //
const getDisasterDetail = async () => { const getDisasterDetail = async () => {
const id = route.query.id const id = route.query.id
@ -273,27 +137,27 @@ const getDisasterDetail = async () => {
if (result?.data) { if (result?.data) {
const data = result.data const data = result.data
console.log('🚀 ~ getDisasterDetail ~ data:', data)
detailData.value = { detailData.value = {
event: data.event || null, event: data.event || null,
report: data.reportList?.reverse(), report: data.report || [],
fileList: data.fileList || [], fileList: data.fileList || [],
lossList: data.lossList || [], lossList: data.lossList || [],
occurLocation: data.occurLocation || data.event?.roadConditionLocation || '', occurLocation: data.occurLocation || '',
occurTime: data.occurTime || data.event?.occurTime || '', occurTime: data.occurTime || '',
roadConditionType: data.roadConditionType || '', roadConditionType: data.roadConditionType || '',
routeNo: data.routeNo || data.event?.routeNo || '' routeNo: data.routeNo || ''
} }
eventStatus.value = data.eventStatus || 0
if (isEdit.value) { if (isEdit.value) {
const newFormData = { const newFormData = {
...data, ...data,
lossList: null,
report: {}, report: {},
yhzMaterialList: [], fileList: null
fileList: []
} }
nextTick(()=>{
continueReport.value?.initFormData(newFormData) continueReport.value?.initFormData(newFormData)
})
} }
} else { } else {
ElMessage.warning(result.message || '获取详情失败') ElMessage.warning(result.message || '获取详情失败')
@ -304,13 +168,18 @@ const getDisasterDetail = async () => {
} }
} }
//
const handleClickBack = () => {
router.push('/disasterManagement')
}
onMounted(() => { onMounted(() => {
getDisasterDetail() getDisasterDetail()
}) })
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.page-container { .web-detail-container {
padding: 20px; padding: 20px;
background: #f5f7fa; background: #f5f7fa;
height: 100%; height: 100%;
@ -318,6 +187,27 @@ onMounted(() => {
padding-bottom: 100px; padding-bottom: 100px;
} }
.page-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding: 0 20px;
.header-left {
display: flex;
align-items: center;
gap: 16px;
.page-title {
margin: 0;
font-size: 20px;
font-weight: 600;
color: #303133;
}
}
}
.info-card { .info-card {
margin-bottom: 20px; margin-bottom: 20px;
border-radius: 8px; border-radius: 8px;
@ -337,41 +227,6 @@ onMounted(() => {
} }
} }
.stake-panel {
padding: 8px 12px 4px;
}
.stake-center {
padding: 18px 12px 4px;
}
.stake-point-icon {
display: flex;
align-items: center;
justify-content: center;
width: 50px;
height: 50px;
margin: 0 auto 18px;
color: #409eff;
font-size: 40px;
}
.stake-mileage-item {
margin-bottom: 10px;
justify-content: center;
&.info-item .info-value {
flex: initial;
}
}
.stake-mileage-line {
width: 200px;
height: 2px;
margin: 0 4px;
background: #2f3136;
}
.info-row { .info-row {
margin-bottom: 16px; margin-bottom: 16px;
@ -389,6 +244,10 @@ onMounted(() => {
margin-top: 10px; margin-top: 10px;
} }
&.margin {
margin-top: 10px;
}
.info-label { .info-label {
white-space: nowrap; white-space: nowrap;
flex-shrink: 0; flex-shrink: 0;
@ -436,37 +295,88 @@ onMounted(() => {
} }
} }
.attachment-wrapper {
margin-top: 12px;
padding-top: 8px;
border-top: 1px dashed #ebeef5;
.attachment-item {
.attachment-list {
display: flex;
flex-wrap: wrap;
gap: 16px;
.attachment-link {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 6px 12px;
background: #f5f7fa;
border-radius: 4px;
cursor: pointer;
&:hover {
background: #ecf5ff;
color: #409eff;
}
.file-name {
font-size: 13px;
max-width: 200px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
}
}
.footer-buttons {
position: fixed;
bottom: 0;
left: 0;
right: 0;
display: flex;
justify-content: center;
padding: 16px 24px;
background: #fff;
box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.08);
z-index: 100;
.footer-btn {
width: 200px;
height: 44px;
font-size: 16px;
border-radius: 22px;
}
}
.content-container { .content-container {
display: flex; display: flex;
.left-panel { .left-panel {
flex: 1; flex: 1;
margin-right: 10px; margin-right: 10px;
} }
.right-panel { .right-panel {
width: 400px; width: 300px;
} }
} }
.content-wrapper { .content-wrapper {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
.basic-info-wrapper { .basic-info-wrapper {
display: flex; display: flex;
align-items: flex-start;
gap: 24px;
} }
.detal-info-wrapper {
margin-top: 10px;
border-top: 1px solid #efefef;
padding-top: 10px;
}
.info-list { .info-list {
flex: 1; flex: 1;
overflow: hidden; overflow: hidden;
} }
.file-list { .file-list {
width: 260px;
flex-shrink: 0;
} }
</style> </style>

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="disaster-form-page"> <div class="disaster-form-page">
<el-form ref="formRef" :model="formData" :rules="formRules" class="disaster-form" @submit.prevent> <el-form ref="formRef" :model="formData" :rules="formRules" label-width="120px" class="disaster-form" @submit.prevent>
<el-card class="form-section" shadow="never"> <el-card class="form-section" shadow="never">
<template #header> <template #header>
<div class="section-header"> <div class="section-header">
@ -11,18 +11,18 @@
<BlockItem title="填报人员信息"> <BlockItem title="填报人员信息">
<el-row :gutter="24"> <el-row :gutter="24">
<el-col :span="8"> <el-col :span="8">
<el-form-item label="填报单位" prop="event.reportUnit"> <el-form-item label="填报单位" prop="event.reporterUnit">
<el-input v-model="formData.event.reportUnit" disabled /> <el-input v-model="formData.event.reporterUnit" disabled />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="联系人员" prop="event.reporterName"> <el-form-item label="联系人员" prop="event.contactPerson">
<el-input v-model="formData.event.reporterName" placeholder="请填写" /> <el-input v-model="formData.event.contactPerson" placeholder="请填写" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="联系电话" prop="event.reporterPhone"> <el-form-item label="联系电话" prop="event.contactPhone">
<el-input v-model="formData.event.reporterPhone" maxlength="11" placeholder="请填写" /> <el-input v-model="formData.event.contactPhone" maxlength="11" placeholder="请填写" />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@ -97,13 +97,13 @@
<el-row :gutter="24"> <el-row :gutter="24">
<el-col :span="8"> <el-col :span="8">
<el-form-item label="起点桩经度" prop="event.startStakeLng"> <el-form-item label="起点桩经度" prop="event.startStakeLongitude">
<NumberInput v-model="formData.event.startStakeLng" :precision="6" placeholder="请填写" /> <el-input v-model="formData.event.startStakeLongitude" placeholder="请填写" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="起点桩纬度" prop="event.startStakeLat"> <el-form-item label="起点桩纬度" prop="event.startStakeLatitude">
<NumberInput v-model="formData.event.startStakeLat" :precision="6" placeholder="请填写" /> <el-input v-model="formData.event.startStakeLatitude" placeholder="请填写" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
@ -117,20 +117,20 @@
<el-row :gutter="24"> <el-row :gutter="24">
<el-col :span="8"> <el-col :span="8">
<el-form-item label="止点桩经度" prop="event.endStakeLng"> <el-form-item label="止点桩经度" prop="event.endStakeLongitude">
<NumberInput v-model="formData.event.endStakeLng" :precision="6" placeholder="请填写" /> <el-input v-model="formData.event.endStakeLongitude" placeholder="请填写" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="止点桩纬度" prop="event.endStakeLat"> <el-form-item label="止点桩纬度" prop="event.endStakeLatitude">
<NumberInput v-model="formData.event.endStakeLat" :precision="6" placeholder="请填写" /> <el-input v-model="formData.event.endStakeLatitude" placeholder="请填写" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="受灾里程" prop="event.disasterMileage"> <el-form-item label="受灾里程" prop="event.disasterMileage">
<NumberInput v-model="formData.event.disasterMileage" :precision="2" placeholder="请填写"> <el-input v-model="formData.event.disasterMileage" placeholder="请填写">
<template #append>公里</template> <template #append>公里</template>
</NumberInput> </el-input>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@ -179,41 +179,49 @@
<el-row :gutter="24"> <el-row :gutter="24">
<el-col :span="8"> <el-col :span="8">
<el-form-item label="投入人力" prop="report.inputManpower"> <el-form-item label="投入人力" prop="material.inputManpower">
<NumberInput v-model="formData.report.inputManpower" :precision="0" placeholder="请填写" style="width: 100%"> <el-input-number v-model="formData.material.inputManpower" :min="0" :step="1" :controls="false" placeholder="请填写" style="width: 100%">
<template #append>人次</template> <template #suffix>
</NumberInput> <span class="unit-text">人次</span>
</template>
</el-input-number>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="投入资金" prop="report.inputFunds"> <el-form-item label="投入资金" prop="material.inputFunds">
<NumberInput v-model="formData.report.inputFunds" :precision="2" placeholder="请填写" style="width: 100%"> <el-input-number v-model="formData.material.inputFunds" :min="0" :precision="2" :controls="false" placeholder="请填写" style="width: 100%">
<template #append>万元</template> <template #suffix>
</NumberInput> <span class="unit-text">万元</span>
</template>
</el-input-number>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="投入设备" prop="report.inputEquipment"> <el-form-item label="投入设备" prop="material.inputEquipment">
<NumberInput v-model="formData.report.inputEquipment" :precision="1" placeholder="请填写" style="width: 100%"> <el-input-number v-model="formData.material.inputEquipment" :min="0" :precision="1" :controls="false" placeholder="请填写" style="width: 100%">
<template #append>台班</template> <template #suffix>
</NumberInput> <span class="unit-text">台班</span>
</template>
</el-input-number>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="24"> <el-row :gutter="24">
<el-col :span="8"> <el-col :span="8">
<el-form-item label="有无滞留车辆" prop="report.hasStrandedVehicles"> <el-form-item label="有无滞留车辆" prop="traffic.hasStrandedVehicles">
<el-select v-model="formData.report.hasStrandedVehicles" placeholder="请选择" style="width: 100%" @change="handleHasStrandedVehiclesChange"> <el-select v-model="formData.traffic.hasStrandedVehicles" placeholder="请选择" style="width: 100%" @change="handleHasStrandedVehiclesChange">
<el-option v-for="option in strandedVehicleOptions" :key="option.value" :label="option.label" :value="option.value" /> <el-option v-for="option in strandedVehicleOptions" :key="option.value" :label="option.label" :value="option.value" />
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="滞留车辆" prop="report.strandedVehicleCount"> <el-form-item label="滞留车辆" prop="traffic.strandedVehicleCount">
<NumberInput v-model="formData.report.strandedVehicleCount" :precision="0" placeholder="请填写" style="width: 100%"> <el-input-number v-model="formData.traffic.strandedVehicleCount" :min="0" :step="1" :controls="false" placeholder="请填写" style="width: 100%">
<template #append></template> <template #suffix>
</NumberInput> <span class="unit-text"></span>
</template>
</el-input-number>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@ -251,7 +259,6 @@
import { LocationFilled } from '@element-plus/icons-vue' import { LocationFilled } from '@element-plus/icons-vue'
import BlockItem from '@/component/BlockItem.vue' import BlockItem from '@/component/BlockItem.vue'
import FileUpload from '@/component/FileUpload/FileUpload.vue' import FileUpload from '@/component/FileUpload/FileUpload.vue'
import NumberInput from '@/component/NumberInput/NumberInput.vue'
import RoadRoutesSelect from '../components/RoadRoutesSelect.vue' import RoadRoutesSelect from '../components/RoadRoutesSelect.vue'
import YHZSelect from '../components/YHZSelect.vue' import YHZSelect from '../components/YHZSelect.vue'
import MaterialList from '../components/MaterialList.vue' import MaterialList from '../components/MaterialList.vue'

View File

@ -11,49 +11,36 @@ const createDefaultFormData = () => ({
occurTime: '', occurTime: '',
routeNo: '', routeNo: '',
event: { event: {
actualRecoverTime: '', contactPerson: '',
contactPhone: '',
disasterMileage: null, disasterMileage: null,
disposalMeasures: '',
district: '', district: '',
endStakeLat: null, endStakeLatitude: null,
endStakeLng: null, endStakeLongitude: null,
endStakeNo: '', endStakeNo: '',
expectRecoverTime: '',
id: null,
occurLocation: '', occurLocation: '',
occurTime: '', reporterUnit: DEFAULT_REPORTER_UNIT,
reporterName: '',
reporterPhone: '',
reportTime: '',
reportUnit: DEFAULT_REPORTER_UNIT,
roadConditionLocation: '',
routeNo: '',
routeType: '',
serviceStationId: '', serviceStationId: '',
startStakeLat: null, startStakeLatitude: null,
startStakeLng: null, startStakeLongitude: null,
startStakeNo: '' startStakeNo: ''
}, },
material: {
inputEquipment: null,
inputFunds: null,
inputManpower: null
},
report: { report: {
actualRecoverTime: '', actualRecoverTime: '',
antiSlipSand: null,
disposalMeasures: '', disposalMeasures: '',
expectRecoverTime: '', expectRecoverTime: '',
siteDescription: ''
},
traffic: {
hasStrandedVehicles: null, hasStrandedVehicles: null,
industrialSalt: null,
inputEquipment: null,
inputFunds: null,
inputManpower: null,
reporterName: '',
reporterPhone: '',
reportTime: '',
sandbags: null,
siteDescription: '',
strandedVehicleCount: null strandedVehicleCount: null
}, },
fileList: [], fileList: []
lossList: [],
yhzMaterialList: []
}) })
const mergeFormData = (source = {}) => { const mergeFormData = (source = {}) => {
@ -65,18 +52,24 @@ const mergeFormData = (source = {}) => {
...defaults.event, ...defaults.event,
...(source.event || {}) ...(source.event || {})
}, },
material: {
...defaults.material,
...(source.material || {})
},
report: { report: {
...defaults.report, ...defaults.report,
...(source.report || {}) ...(source.report || {})
},
traffic: {
...defaults.traffic,
...(source.traffic || {})
} }
} }
merged.fileList = Array.isArray(source.fileList) ? source.fileList : defaults.fileList merged.fileList = Array.isArray(source.fileList) ? source.fileList : defaults.fileList
merged.lossList = Array.isArray(source.lossList) ? source.lossList : defaults.lossList
merged.yhzMaterialList = Array.isArray(source.yhzMaterialList) ? source.yhzMaterialList : defaults.yhzMaterialList
if (!merged.event.reportUnit) { if (!merged.event.reporterUnit) {
merged.event.reportUnit = DEFAULT_REPORTER_UNIT merged.event.reporterUnit = DEFAULT_REPORTER_UNIT
} }
return merged return merged
@ -134,8 +127,8 @@ export const useIceDisasterReport = () => {
}) })
const formRules = { const formRules = {
'event.reporterName': [{ required: true, message: '请输入联系人员', trigger: 'blur' }], 'event.contactPerson': [{ required: true, message: '请输入联系人员', trigger: 'blur' }],
'event.reporterPhone': [ 'event.contactPhone': [
{ required: true, message: '请输入联系电话', trigger: 'blur' }, { required: true, message: '请输入联系电话', trigger: 'blur' },
{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的联系电话', trigger: 'blur' } { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的联系电话', trigger: 'blur' }
], ],
@ -146,11 +139,11 @@ export const useIceDisasterReport = () => {
'event.occurLocation': [{ required: true, message: '请输入发生地点', trigger: 'blur' }], 'event.occurLocation': [{ required: true, message: '请输入发生地点', trigger: 'blur' }],
occurLocation: [{ required: true, message: '请选择路况位置', trigger: 'blur' }], occurLocation: [{ required: true, message: '请选择路况位置', trigger: 'blur' }],
'event.startStakeNo': [{ required: true, message: '请输入起点桩号', trigger: 'blur' }], 'event.startStakeNo': [{ required: true, message: '请输入起点桩号', trigger: 'blur' }],
'event.startStakeLng': [{ required: true, message: '请输入起点桩经度', trigger: 'blur' }], 'event.startStakeLongitude': [{ required: true, message: '请输入起点桩经度', trigger: 'blur' }],
'event.startStakeLat': [{ required: true, message: '请输入起点桩纬度', trigger: 'blur' }], 'event.startStakeLatitude': [{ required: true, message: '请输入起点桩纬度', trigger: 'blur' }],
'event.endStakeNo': [{ required: true, message: '请输入止点桩号', trigger: 'blur' }], 'event.endStakeNo': [{ required: true, message: '请输入止点桩号', trigger: 'blur' }],
'event.endStakeLng': [{ required: true, message: '请输入止点桩经度', trigger: 'blur' }], 'event.endStakeLongitude': [{ required: true, message: '请输入止点桩经度', trigger: 'blur' }],
'event.endStakeLat': [{ required: true, message: '请输入止点桩纬度', trigger: 'blur' }], 'event.endStakeLatitude': [{ required: true, message: '请输入止点桩纬度', trigger: 'blur' }],
'event.disasterMileage': [{ required: true, message: '请输入受灾里程', trigger: 'blur' }], 'event.disasterMileage': [{ required: true, message: '请输入受灾里程', trigger: 'blur' }],
'report.disposalMeasures': [{ required: true, message: '请选择处理措施', trigger: 'change' }], 'report.disposalMeasures': [{ required: true, message: '请选择处理措施', trigger: 'change' }],
'report.siteDescription': [{ required: true, message: '请输入现场情况描述', trigger: 'blur' }], 'report.siteDescription': [{ required: true, message: '请输入现场情况描述', trigger: 'blur' }],
@ -179,14 +172,13 @@ export const useIceDisasterReport = () => {
} }
const handleDistrictChange = () => { const handleDistrictChange = () => {
// 暂时不处理区县变化 formData.routeNo = ''
// formData.routeNo = '' formData.event.startStakeNo = ''
// formData.event.startStakeNo = '' formData.event.endStakeNo = ''
// formData.event.endStakeNo = '' formData.event.startStakeLongitude = null
// formData.event.startStakeLng = null formData.event.startStakeLatitude = null
// formData.event.startStakeLat = null formData.event.endStakeLongitude = null
// formData.event.endStakeLng = null formData.event.endStakeLatitude = null
// formData.event.endStakeLat = null
} }
const handleRouteNoChange = (item = {}) => { const handleRouteNoChange = (item = {}) => {
@ -197,52 +189,28 @@ export const useIceDisasterReport = () => {
const startPoint = parsePointValue(item.startPoint ?? item.startpoint) const startPoint = parsePointValue(item.startPoint ?? item.startpoint)
const endPoint = parsePointValue(item.endPoint ?? item.endpoint) const endPoint = parsePointValue(item.endPoint ?? item.endpoint)
formData.event.startStakeLng = startPoint.longitude formData.event.startStakeLongitude = startPoint.longitude
formData.event.startStakeLat = startPoint.latitude formData.event.startStakeLatitude = startPoint.latitude
formData.event.endStakeLng = endPoint.longitude formData.event.endStakeLongitude = endPoint.longitude
formData.event.endStakeLat = endPoint.latitude formData.event.endStakeLatitude = endPoint.latitude
} }
const handleHasStrandedVehiclesChange = (value) => { const handleHasStrandedVehiclesChange = (value) => {
if (value !== 1) { if (value !== 1) {
formData.report.strandedVehicleCount = null formData.traffic.strandedVehicleCount = null
} }
} }
const getCurrentTime = () => {
const currentDate = new Date()
const year = currentDate.getFullYear()
const month = String(currentDate.getMonth() + 1).padStart(2, '0')
const day = String(currentDate.getDate()).padStart(2, '0')
const hours = String(currentDate.getHours()).padStart(2, '0')
const minutes = String(currentDate.getMinutes()).padStart(2, '0')
const seconds = String(currentDate.getSeconds()).padStart(2, '0')
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
}
const buildSubmitData = () => { const buildSubmitData = () => {
const payload = mergeFormData(formData) const payload = mergeFormData(formData)
const reportTime = payload.report.reportTime || payload.event.reportTime || getCurrentTime()
payload.event.routeNo = payload.routeNo payload.event.routeNo = payload.routeNo
payload.event.occurTime = payload.occurTime payload.event.occurTime = payload.occurTime
payload.event.reportTime = reportTime
payload.event.reportUnit = payload.event.reportUnit || DEFAULT_REPORTER_UNIT
payload.event.disposalMeasures = payload.report.disposalMeasures
payload.event.expectRecoverTime = payload.report.expectRecoverTime
payload.event.actualRecoverTime = payload.report.actualRecoverTime || null
payload.event.roadConditionLocation = payload.occurLocation
payload.event.routeType = filterForm.routeType
payload.event.eventType = eventType.value payload.event.eventType = eventType.value
payload.event.roadType = filterForm.routeType
payload.report.reporterName = payload.report.reporterName || payload.event.reporterName payload.event.roadConditionLocation = payload.occurLocation
payload.report.reporterPhone = payload.report.reporterPhone || payload.event.reporterPhone if (payload.traffic.hasStrandedVehicles !== 1) {
payload.report.reportTime = reportTime payload.traffic.strandedVehicleCount = null
if (payload.report.hasStrandedVehicles !== 1) {
payload.report.strandedVehicleCount = null
} }
return payload return payload
} }
@ -304,42 +272,22 @@ export const useIceDisasterReport = () => {
if (result?.data) { if (result?.data) {
const data = result.data const data = result.data
const baseReport = data.report || data.reportList?.[data.reportList.length - 1] || {}
filterForm.routeType = data.event?.routeType || data.event?.roadType || filterForm.routeType
initFormData({ initFormData({
occurLocation: data.occurLocation || data.event?.roadConditionLocation || '', occurLocation: data.occurLocation || data.event?.roadConditionLocation || '',
occurTime: data.occurTime || data.event?.occurTime || '', occurTime: data.occurTime || data.event?.occurTime || '',
routeNo: data.routeNo || data.event?.routeNo || '', routeNo: data.routeNo || data.event?.routeNo || '',
event: { event: {
...(data.event || {}), ...(data.event || {})
reporterName: data.event?.reporterName || data.event?.contactPerson || '', },
reporterPhone: data.event?.reporterPhone || data.event?.contactPhone || '', material: {
reportUnit: data.event?.reportUnit || data.event?.reporterUnit || DEFAULT_REPORTER_UNIT, ...(data.material || {})
startStakeLat: data.event?.startStakeLat ?? data.event?.startStakeLatitude ?? null,
startStakeLng: data.event?.startStakeLng ?? data.event?.startStakeLongitude ?? null,
endStakeLat: data.event?.endStakeLat ?? data.event?.endStakeLatitude ?? null,
endStakeLng: data.event?.endStakeLng ?? data.event?.endStakeLongitude ?? null
}, },
report: { report: {
...baseReport, ...(data.report || {})
disposalMeasures: baseReport.disposalMeasures || data.event?.disposalMeasures || '',
expectRecoverTime: baseReport.expectRecoverTime || data.event?.expectRecoverTime || '',
actualRecoverTime: baseReport.actualRecoverTime || data.event?.actualRecoverTime || '',
inputEquipment: baseReport.inputEquipment ?? data.material?.inputEquipment ?? baseReport.investedMachinery ?? null,
inputFunds: baseReport.inputFunds ?? data.material?.inputFunds ?? baseReport.investedFunds ?? null,
inputManpower: baseReport.inputManpower ?? data.material?.inputManpower ?? baseReport.investedManpower ?? null,
hasStrandedVehicles: baseReport.hasStrandedVehicles ?? data.traffic?.hasStrandedVehicles ?? null,
strandedVehicleCount: baseReport.strandedVehicleCount ?? data.traffic?.strandedVehicleCount ?? null,
industrialSalt: baseReport.industrialSalt ?? null,
antiSlipSand: baseReport.antiSlipSand ?? null,
sandbags: baseReport.sandbags ?? null,
reporterName: baseReport.reporterName || data.event?.reporterName || data.event?.contactPerson || '',
reporterPhone: baseReport.reporterPhone || data.event?.reporterPhone || data.event?.contactPhone || '',
reportTime: baseReport.reportTime || data.event?.reportTime || ''
}, },
fileList: data.fileList || [], traffic: {
lossList: data.lossList || [], ...(data.traffic || {})
yhzMaterialList: data.yhzMaterialList || baseReport.yhzMaterialList || [] }
}) })
} else { } else {
ElMessage.warning(result?.message || '获取详情失败') ElMessage.warning(result?.message || '获取详情失败')

View File

@ -1,16 +1,13 @@
<template> <template>
<div class="water-disaster-pc"> <div class="water-disaster-pc">
<!-- 合并后的单个卡片 --> <!-- 合并后的单个卡片 -->
<el-card class="info-card" shadow="never"> <el-card class="form-card" shadow="never">
<template #header> <div slot="header" class="card-header">
<div class="card-header"> <span>续报信息</span>
<span class="card-title">续报信息</span>
</div> </div>
</template>
<!-- 所有表单项合并到一个区域每行一个 --> <!-- 所有表单项合并到一个区域每行一个 -->
<el-form :model="formData" > <el-form :model="formData" label-width="120px" size="small">
<BlockItem title="处置情况">
<!-- 处置措施 --> <!-- 处置措施 -->
<el-form-item label="处置措施"> <el-form-item label="处置措施">
<el-select v-model="formData.report.disposalMeasures"> <el-select v-model="formData.report.disposalMeasures">
@ -27,7 +24,7 @@
v-model="formData.report.expectRecoverTime" v-model="formData.report.expectRecoverTime"
type="datetime" type="datetime"
placeholder="请选择时间" placeholder="请选择时间"
value-format="YYYY-MM-DD HH:mm:ss" value-format="yyyy-MM-dd HH:mm"
:picker-options="pickerOptions" :picker-options="pickerOptions"
style="width: 100%" style="width: 100%"
/> />
@ -39,98 +36,95 @@
v-model="formData.report.actualRecoverTime" v-model="formData.report.actualRecoverTime"
type="datetime" type="datetime"
placeholder="请选择时间" placeholder="请选择时间"
value-format="YYYY-MM-DD HH:mm:ss" value-format="yyyy-MM-dd HH:mm"
:picker-options="pickerOptions" :picker-options="pickerOptions"
style="width: 100%" style="width: 100%"
/> />
</el-form-item> </el-form-item>
</BlockItem>
<BlockItem title="实施情况"> </BlockItem>
<!-- 受伤人员 --> <!-- 受伤人员 -->
<el-form-item label="受伤人员"> <el-form-item label="受伤人员">
<NumberInput v-model="formData.report.injuredCount" :precision="0" placeholder="请填写" style="width: 300px"> <el-input-number v-model="formData.report.injuredCount" :min="0" :controls="false" placeholder="请填写" style="width: 300px">
<template #append></template> <template slot="append"></template>
</NumberInput> </el-input-number>
</el-form-item> </el-form-item>
<!-- 死亡人员 --> <!-- 死亡人员 -->
<el-form-item label="死亡人员"> <el-form-item label="死亡人员">
<NumberInput v-model="formData.report.deadCount" :precision="0" placeholder="请填写" style="width: 300px"> <el-input-number v-model="formData.report.deadCount" :min="0" :controls="false" placeholder="请填写" style="width: 300px">
<template #append></template> <template slot="append"></template>
</NumberInput> </el-input-number>
</el-form-item> </el-form-item>
<!-- 滞留人员 --> <!-- 滞留人员 -->
<el-form-item label="滞留人员"> <el-form-item label="滞留人员">
<NumberInput v-model="formData.report.strandedPersonCount" :precision="0" placeholder="请填写" style="width: 300px"> <el-input-number v-model="formData.report.strandedPersonCount" :min="0" :controls="false" placeholder="请填写" style="width: 300px">
<template #append></template> <template slot="append"></template>
</NumberInput> </el-input-number>
</el-form-item> </el-form-item>
<!-- 损坏车辆 --> <!-- 损坏车辆 -->
<el-form-item label="损坏车辆"> <el-form-item label="损坏车辆">
<NumberInput v-model="formData.report.damagedVehicleCount" :precision="0" placeholder="请填写" style="width: 300px"> <el-input-number v-model="formData.report.damagedVehicleCount" :min="0" :controls="false" placeholder="请填写" style="width: 300px">
<template #append></template> <template slot="append"></template>
</NumberInput> </el-input-number>
</el-form-item> </el-form-item>
<!-- 滞留车辆 --> <!-- 滞留车辆 -->
<el-form-item label="滞留车辆"> <el-form-item label="滞留车辆">
<NumberInput v-model="formData.report.strandedVehicleCount" :precision="0" placeholder="请填写" style="width: 300px"> <el-input-number v-model="formData.report.strandedVehicleCount" :min="0" :controls="false" placeholder="请填写" style="width: 300px">
<template #append></template> <template slot="append"></template>
</NumberInput> </el-input-number>
</el-form-item> </el-form-item>
<!-- 损失列表组件 --> <!-- 损失列表组件 -->
<loss-list :col-span="24" v-model="formData.lossList" /> <loss-list :col-span="24" v-model="formData.lossList" />
<!-- 已投机械 -->
<el-form-item label="投入机械">
<NumberInput v-model="formData.report.investedMachinery" :precision="1" placeholder="请填写" style="width: 300px">
<template #append>/</template>
</NumberInput>
</el-form-item>
<!-- 投入人力 -->
<el-form-item label="投入人力">
<NumberInput v-model="formData.report.investedManpower" :precision="0" placeholder="请填写" style="width: 300px">
<template #append>人次</template>
</NumberInput>
</el-form-item>
<!-- 投入资金 -->
<el-form-item label="投入资金">
<NumberInput v-model="formData.report.investedFunds" :precision="2" placeholder="请填写" style="width: 300px">
<template #append>万元</template>
</NumberInput>
</el-form-item>
<!-- 处理情况 --> <!-- 处理情况 -->
<el-form-item label="处理情况"> <el-form-item label="处理情况">
<el-input v-model="formData.report.remark" type="textarea" :rows="2" placeholder="请填写(选填)" /> <el-input v-model="formData.report.remark" type="textarea" :rows="2" placeholder="请填写(选填)" style="width: 60%" />
</el-form-item> </el-form-item>
<!-- 损失总金额 --> <!-- 损失总金额 -->
<el-form-item label="损失总金额"> <el-form-item label="损失总金额">
<NumberInput v-model="formData.report.totalLossAmount" :precision="2" placeholder="请填写(选填)" style="width: 300px"> <el-input v-model="formData.report.totalLossAmount" placeholder="请填写(选填)" style="width: 300px">
<template #append>万元</template> <template slot="append">万元</template>
</NumberInput> </el-input>
</el-form-item>
<!-- 已投机械 -->
<el-form-item label="已投机械">
<el-input v-model="formData.report.investedMachinery" placeholder="请填写" style="width: 300px">
<template slot="append">/</template>
</el-input>
</el-form-item>
<!-- 投入人力 -->
<el-form-item label="投入人力">
<el-input-number v-model="formData.report.investedManpower" :min="0" :controls="false" placeholder="请填写" style="width: 300px">
<template slot="append">人次</template>
</el-input-number>
</el-form-item>
<!-- 投入资金 -->
<el-form-item label="投入资金">
<el-input v-model="formData.report.investedFunds" placeholder="请填写" style="width: 300px">
<template slot="append">万元</template>
</el-input>
</el-form-item> </el-form-item>
<!-- 现场描述 --> <!-- 现场描述 -->
<el-form-item label="现场情况描述"> <el-form-item label="现场描述">
<el-input v-model="formData.report.siteDescription" type="textarea" :rows="2" placeholder="请填写" /> <el-input v-model="formData.report.siteDescription" type="textarea" :rows="2" placeholder="请填写" style="width: 60%" />
</el-form-item> </el-form-item>
<!-- 是否需要恢复重建 --> <!-- 是否需要恢复重建 -->
<!-- <el-form-item label="是否需要恢复重建"> <el-form-item label="是否需要恢复重建">
<el-radio-group v-model="formData.event.needsRecovery"> <el-radio-group v-model="formData.event.needsRecovery">
<el-radio :label="true"></el-radio> <el-radio :label="true"></el-radio>
<el-radio :label="false"></el-radio> <el-radio :label="false"></el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> --> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary" @click="handleSubmit">追加记录</el-button> <el-button type="primary" @click="handleSubmit">追加记录</el-button>
@ -144,8 +138,6 @@
import { ref, reactive, watch, computed } from 'vue' import { ref, reactive, watch, computed } from 'vue'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { request } from '@shared/utils/request' import { request } from '@shared/utils/request'
import BlockItem from '@/component/BlockItem.vue'
import NumberInput from '@/component/NumberInput/NumberInput.vue'
import LossList from '../WaterDisasterReport/WaterDisasterLossListPC.vue' import LossList from '../WaterDisasterReport/WaterDisasterLossListPC.vue'
// Props // Props
@ -376,7 +368,7 @@ const handleSubmit = async () => {
if (res?.code === '00000') { if (res?.code === '00000') {
ElMessage.success('提交成功') ElMessage.success('提交成功')
emit('refresh') emit("refresh")
} else { } else {
ElMessage.error(res.message) ElMessage.error(res.message)
} }
@ -384,6 +376,7 @@ const handleSubmit = async () => {
ElMessage.error('提交失败,请重试') ElMessage.error('提交失败,请重试')
console.error('提交失败:', error) console.error('提交失败:', error)
} finally { } finally {
} }
} }
@ -393,7 +386,7 @@ defineExpose({
initFormData, initFormData,
getFormData, getFormData,
resetForm, resetForm,
calibrateTime calibrateTime,
}) })
</script> </script>
@ -402,22 +395,15 @@ defineExpose({
background-color: #f5f7fa; background-color: #f5f7fa;
height: 100%; height: 100%;
.info-card { .form-card {
margin-bottom: 20px;
border-radius: 8px; border-radius: 8px;
:deep(.el-card__header) {
padding: 16px 20px;
border-bottom: 1px solid #ebeef5;
background: #fafafa;
}
.card-header { .card-header {
.card-title {
font-size: 16px; font-size: 16px;
font-weight: 600; font-weight: 600;
color: #303133; color: #303133;
} border-left: 4px solid #409eff;
padding-left: 12px;
} }
} }
@ -429,6 +415,14 @@ defineExpose({
padding: 0 10px; padding: 0 10px;
} }
::v-deep .el-input-number {
width: 300px;
.el-input-group__append {
padding: 0 10px;
}
}
::v-deep .el-radio-group { ::v-deep .el-radio-group {
.el-radio { .el-radio {
margin-right: 20px; margin-right: 20px;

View File

@ -1,6 +1,7 @@
<template> <template>
<div class="web-detail-container"> <div class="web-detail-container">
<div class="content-container" v-if="detailData">
<div class="content-container">
<div class="left-panel"> <div class="left-panel">
<!-- 基本信息卡片 --> <!-- 基本信息卡片 -->
<el-card class="info-card" shadow="never"> <el-card class="info-card" shadow="never">
@ -10,100 +11,122 @@
</div> </div>
</template> </template>
<div class="base-info-grid"> <el-row :gutter="20" class="info-row">
<div class="base-info-column"> <el-col :span="8">
<div class="info-item"> <div class="info-item">
<span class="info-label">事件类型</span> <span class="info-label">事件类型</span>
<span class="info-value">水毁事件</span> <span class="info-value">水毁事件</span>
</div> </div>
</el-col>
<el-col :span="8">
<div class="info-item"> <div class="info-item">
<span class="info-label">路况类别</span> <span class="info-label">路况类别</span>
<span class="info-value">{{ detailData.roadConditionType || '-' }}</span> <span class="info-value">{{ detailData.roadConditionType || '-' }}</span>
</div> </div>
</el-col>
<el-col :span="8">
<div class="info-item"> <div class="info-item">
<span class="info-label">是否阻断</span> <span class="info-label">是否阻断</span>
<span class="info-value">{{ formatBooleanValue(detailData.event?.isBlocked) }}</span> <span class="info-value">{{ detailData.event?.isBlocked ? '是' : '否' }}</span>
</div>
<div class="info-item">
<span class="info-label">路况位置</span>
<span class="info-value">{{ detailData.occurLocation || '-' }}</span>
</div>
<div class="info-item">
<span class="info-label">所属区县</span>
<span class="info-value">{{ detailData.event?.district || '-' }}</span>
</div>
<div class="info-item">
<span class="info-label">起点桩经度</span>
<span class="info-value">{{ detailData.event?.startStakeLongitude || '-' }}</span>
</div>
<div class="info-item">
<span class="info-label">止点桩经度</span>
<span class="info-value">{{ detailData.event?.endStakeLongitude || '-' }}</span>
</div>
<div class="info-item">
<span class="info-label">是否需要恢复重建</span>
<span class="info-value">{{ formatBooleanValue(detailData.event?.needsRecovery) }}</span>
</div>
</div> </div>
</el-col>
</el-row>
<div class="base-info-column"> <el-row :gutter="20" class="info-row">
<div class="info-item"> <el-col :span="8">
<span class="info-label">填报站点</span>
<span class="info-value">{{ detailData.stationName || '-' }}</span>
</div>
<div class="info-item"> <div class="info-item">
<span class="info-label">抢险进度</span> <span class="info-label">抢险进度</span>
<span class="info-value">{{ detailData.event?.repairProgress || '-' }}</span> <span class="info-value">{{ detailData.event?.repairProgress || '-' }}</span>
</div> </div>
<div class="info-item"> </el-col>
<span class="info-label">地点路线</span> <el-col :span="8">
<span class="info-value">{{ detailData.routeNo }}</span>
</div>
<div class="info-item">
<span class="info-label">阻断点小地名</span>
<span class="info-value">{{ detailData.event?.blockedPointName || '-' }}</span>
</div>
<div class="info-item">
<span class="info-label">起点桩号</span>
<span class="info-value">{{ detailData.event?.startStakeNo || '-' }}</span>
</div>
<div class="info-item">
<span class="info-label">止点桩号</span>
<span class="info-value">{{ detailData.event?.endStakeNo || '-' }}</span>
</div>
<div class="info-item">
<span class="info-label">受灾里程</span>
<span class="info-value">{{ formatUnitValue(detailData.event?.blockedMileage, '公里') }}</span>
</div>
<div class="info-item">
<span class="info-label">恢复重建预估费用万元</span>
<span class="info-value">{{ detailData.event?.estimatedRecoveryCost ?? '-' }}</span>
</div>
</div>
<div class="base-info-column">
<div class="info-item">
<span class="info-label">发生时间</span>
<span class="info-value">{{ detailData.occurTime || '-' }}</span>
</div>
<div class="info-item"> <div class="info-item">
<span class="info-label">处理措施</span> <span class="info-label">处理措施</span>
<span class="info-value">{{ getBaseDisposalMeasures() }}</span> <span class="info-value">{{ getBaseDisposalMeasures() }}</span>
</div> </div>
</el-col>
<el-col :span="8">
<div class="info-item"> <div class="info-item">
<span class="info-label">水毁处数</span> <span class="info-label">水毁处数</span>
<span class="info-value">{{ detailData.event?.damageCount ?? '-' }}</span> <span class="info-value">{{ detailData.event?.damageCount || 0 }}</span>
</div> </div>
</el-col>
</el-row>
<el-row :gutter="20" class="info-row">
<el-col :span="8">
<div class="info-item"> <div class="info-item">
<span class="info-label">起点桩纬度</span> <span class="info-label">阻断里程</span>
<span class="info-value">{{ detailData.event?.startStakeLatitude || '-' }}</span> <span class="info-value">{{ detailData.event?.blockedMileage ? detailData.event.blockedMileage + '公里' : '-' }}</span>
</div> </div>
</el-col>
</el-row>
<el-row :gutter="20" class="info-row">
<el-col :span="8">
<div class="info-item"> <div class="info-item">
<span class="info-label">止点桩纬度</span> <span class="info-label">地点路线</span>
<span class="info-value">{{ detailData.event?.endStakeLatitude || '-' }}</span> <span class="info-value">{{ detailData.occurLocation || '-' }}</span>
</div> </div>
</el-col>
<el-col :span="8">
<div class="info-item">
<span class="info-label">起点桩号</span>
<span class="info-value">{{ detailData.event?.startStakeNo || '-' }}</span>
</div> </div>
</el-col>
<el-col :span="8">
<div class="info-item">
<span class="info-label">止点桩号</span>
<span class="info-value">{{ detailData.event?.endStakeNo || '-' }}</span>
</div> </div>
</el-col>
</el-row>
<el-row :gutter="20" class="info-row">
<el-col :span="8">
<div class="info-item">
<span class="info-label">路况位置</span>
<span class="info-value">{{ detailData.event?.blockedPointName || detailData.occurLocation || '-' }}</span>
</div>
</el-col>
<el-col :span="8">
<div class="info-item">
<span class="info-label">阻断点小地名</span>
<span class="info-value">{{ detailData.event?.blockedPointName || '-' }}</span>
</div>
</el-col>
</el-row>
<el-row :gutter="20" class="info-row">
<el-col :span="8">
<div class="info-item">
<span class="info-label">所属区县</span>
<span class="info-value">{{ detailData.event?.district || '-' }}</span>
</div>
</el-col>
<el-col :span="8">
<div class="info-item">
<span class="info-label">发生时间</span>
<span class="info-value">{{ detailData.occurTime || '-' }}</span>
</div>
</el-col>
</el-row>
<el-row :gutter="20" class="info-row">
<el-col :span="8">
<div class="info-item">
<span class="info-label">是否恢复重建</span>
<span class="info-value">{{ detailData.event?.needsRecovery ? '是' : '否' }}</span>
</div>
</el-col>
<el-col :span="16" v-if="detailData.event?.needsRecovery">
<div class="info-item">
<span class="info-label">恢复重建预估费用</span>
<span class="info-value">{{ detailData.event?.estimatedRecoveryCost ? detailData.event.estimatedRecoveryCost + '万元' : '-' }}</span>
</div>
</el-col>
</el-row>
</el-card> </el-card>
<!-- 填报信息卡片 --> <!-- 填报信息卡片 -->
@ -162,19 +185,19 @@
<el-col :span="8"> <el-col :span="8">
<div class="info-item margin"> <div class="info-item margin">
<span class="info-label">投入机械</span> <span class="info-label">投入机械</span>
<span class="info-value">{{ report.investedMachinery ? report.investedMachinery + '台/班' : '-' }}</span> <span class="info-value">{{ report.investedMachinery ? report.investedMachinery + '台/班' : '-'}}</span>
</div> </div>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<div class="info-item margin"> <div class="info-item margin">
<span class="info-label">投入人力</span> <span class="info-label">投入人力</span>
<span class="info-value">{{ report.investedManpower ? report.investedManpower + '人次' : '-' }}</span> <span class="info-value">{{ report.investedManpower ? report.investedManpower + '人次' : '-'}}</span>
</div> </div>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<div class="info-item margin"> <div class="info-item margin">
<span class="info-label">投入资金</span> <span class="info-label">投入资金</span>
<span class="info-value">{{ report.investedFunds ? report.investedFunds + '万元' : '-' }}</span> <span class="info-value">{{ report.investedFunds ? report.investedFunds + '万元' : '-'}}</span>
</div> </div>
</el-col> </el-col>
</el-row> </el-row>
@ -190,6 +213,10 @@
<el-empty v-else description="暂无填报信息" :image-size="100" /> <el-empty v-else description="暂无填报信息" :image-size="100" />
</el-card> </el-card>
<!-- 底部按钮 -->
<!-- <div class="footer-buttons">
<el-button type="primary" size="large" @click="handleContinueReport" class="footer-btn"> 续报 </el-button>
</div> -->
</div> </div>
<div class="right-panel" v-if="isEdit"> <div class="right-panel" v-if="isEdit">
<ContinueReport ref="continueReport" @refresh="getDisasterDetail" /> <ContinueReport ref="continueReport" @refresh="getDisasterDetail" />
@ -199,19 +226,33 @@
</template> </template>
<script setup> <script setup>
import { onMounted, ref, computed, nextTick } from 'vue' import { onMounted, ref, computed } from 'vue'
import { useRoute } from 'vue-router' import { useRouter, useRoute } from 'vue-router'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { ArrowLeft, Picture, VideoCamera } from '@element-plus/icons-vue'
import ContinueReport from './WaterDisasterContinueReportPC.vue' import ContinueReport from './WaterDisasterContinueReportPC.vue'
import { request } from '@shared/utils/request' import { request } from '@shared/utils/request'
import LossListDetail from './WaterDisasterLossListDetailPC.vue' import LossListDetail from './WaterDisasterLossListDetailPC.vue'
import FileUpload from '@/component/FileUpload/FileUpload.vue' import FileUpload from '@/component/FileUpload/FileUpload.vue'
import mockData from '../WaterDisasterReport/waterMockJson.json' import mockData from '../WaterDisasterReport/waterMockJson.json'
const router = useRouter()
const route = useRoute() const route = useRoute()
// //
const detailData = ref(null) const detailData = ref({
event: null,
report: [],
fileList: [],
lossList: [],
occurLocation: '',
occurTime: '',
roadConditionType: '',
routeNo: ''
})
//
const eventStatus = ref(0)
// //
const isEdit = computed(() => { const isEdit = computed(() => {
@ -223,7 +264,7 @@ const continueReport = ref(null)
// + // +
const allReports = computed(() => { const allReports = computed(() => {
const reports = const reports =
detailData.value?.report?.map((item, index) => { detailData.value.report?.map((item, index) => {
if (index === detailData.value.report.length - 1) { if (index === detailData.value.report.length - 1) {
item.title = '首报' item.title = '首报'
} else { } else {
@ -246,17 +287,6 @@ const getBaseDisposalMeasures = () => {
return formatDisposalMeasures(firstItem.disposalMeasures || '') || '-' return formatDisposalMeasures(firstItem.disposalMeasures || '') || '-'
} }
const formatBooleanValue = (value) => {
if (value === true || value === 1 || value === '1') return '是'
if (value === false || value === 0 || value === '0') return '否'
return '-'
}
const formatUnitValue = (value, unit) => {
if (value === null || value === undefined || value === '') return '-'
return `${value}${unit}`
}
// //
const formatDisposalMeasures = (measures) => { const formatDisposalMeasures = (measures) => {
if (!measures) return '' if (!measures) return ''
@ -272,6 +302,27 @@ const formatDisposalMeasures = (measures) => {
.join('、') .join('、')
} }
//
const getLossDescription = (report) => {
const lossList = report?.lossList
if (!lossList || lossList.length === 0) return '-'
const totalVolume = lossList.reduce((sum, loss) => {
const volume = (loss.length || 0) * (loss.width || 0) * (loss.height || 0)
return sum + volume
}, 0)
const totalAmount = lossList.reduce((sum, loss) => sum + (loss.totalAmount || 0), 0)
return `${totalVolume}方,共损失${totalAmount}万元`
}
//
const getVehicleStrandedText = (report) => {
const count = report?.strandedVehicleCount || 0
return count > 0 ? `有车滞留,共${count}` : '无车滞留'
}
// //
const getDisasterDetail = async () => { const getDisasterDetail = async () => {
const id = route.query.id const id = route.query.id
@ -289,6 +340,7 @@ const getDisasterDetail = async () => {
if (result?.data) { if (result?.data) {
const data = result.data const data = result.data
console.log('🚀 ~ getDisasterDetail ~ data:', data)
detailData.value = { detailData.value = {
event: data.event || null, event: data.event || null,
report: data.report || [], report: data.report || [],
@ -297,9 +349,9 @@ const getDisasterDetail = async () => {
occurLocation: data.occurLocation || '', occurLocation: data.occurLocation || '',
occurTime: data.occurTime || '', occurTime: data.occurTime || '',
roadConditionType: data.roadConditionType || '', roadConditionType: data.roadConditionType || '',
routeNo: data.routeNo || '', routeNo: data.routeNo || ''
routeName: data.routeName || ''
} }
eventStatus.value = data.eventStatus || 0
if (isEdit.value) { if (isEdit.value) {
const newFormData = { const newFormData = {
@ -308,9 +360,7 @@ const getDisasterDetail = async () => {
report: route.query.mock ? mockData.report : {}, report: route.query.mock ? mockData.report : {},
fileList: null fileList: null
} }
nextTick(() => {
continueReport.value?.initFormData(newFormData) continueReport.value?.initFormData(newFormData)
})
} }
} else { } else {
ElMessage.warning(result.message || '获取详情失败') ElMessage.warning(result.message || '获取详情失败')
@ -321,6 +371,11 @@ const getDisasterDetail = async () => {
} }
} }
//
const handleClickBack = () => {
router.push('/disasterManagement')
}
onMounted(() => { onMounted(() => {
getDisasterDetail() getDisasterDetail()
}) })
@ -335,6 +390,27 @@ onMounted(() => {
padding-bottom: 100px; padding-bottom: 100px;
} }
.page-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding: 0 20px;
.header-left {
display: flex;
align-items: center;
gap: 16px;
.page-title {
margin: 0;
font-size: 20px;
font-weight: 600;
color: #303133;
}
}
}
.info-card { .info-card {
margin-bottom: 20px; margin-bottom: 20px;
border-radius: 8px; border-radius: 8px;
@ -354,10 +430,12 @@ onMounted(() => {
} }
} }
.base-info-grid { .info-row {
display: grid; margin-bottom: 16px;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 24px; &:last-child {
margin-bottom: 0;
}
} }
.info-item { .info-item {
@ -388,10 +466,6 @@ onMounted(() => {
} }
} }
.base-info-column {
min-width: 0;
}
.report-section { .report-section {
margin-bottom: 32px; margin-bottom: 32px;
padding-bottom: 24px; padding-bottom: 24px;
@ -424,6 +498,62 @@ onMounted(() => {
} }
} }
.attachment-wrapper {
margin-top: 12px;
padding-top: 8px;
border-top: 1px dashed #ebeef5;
.attachment-item {
.attachment-list {
display: flex;
flex-wrap: wrap;
gap: 16px;
.attachment-link {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 6px 12px;
background: #f5f7fa;
border-radius: 4px;
cursor: pointer;
&:hover {
background: #ecf5ff;
color: #409eff;
}
.file-name {
font-size: 13px;
max-width: 200px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
}
}
.footer-buttons {
position: fixed;
bottom: 0;
left: 0;
right: 0;
display: flex;
justify-content: center;
padding: 16px 24px;
background: #fff;
box-shadow: 0 -2px 12px rgba(0, 0, 0, 0.08);
z-index: 100;
.footer-btn {
width: 200px;
height: 44px;
font-size: 16px;
border-radius: 22px;
}
}
.content-container { .content-container {
display: flex; display: flex;
.left-panel { .left-panel {
@ -431,7 +561,7 @@ onMounted(() => {
margin-right: 10px; margin-right: 10px;
} }
.right-panel { .right-panel {
width: 400px; width: 300px;
} }
} }
.content-wrapper { .content-wrapper {
@ -451,5 +581,6 @@ onMounted(() => {
overflow: hidden; overflow: hidden;
} }
.file-list { .file-list {
} }
</style> </style>

View File

@ -3,9 +3,11 @@
<template v-for="(item, index) in configs" :key="index"> <template v-for="(item, index) in configs" :key="index">
<el-col :span="colSpan"> <el-col :span="colSpan">
<el-form-item :label="item.lossTypeName"> <el-form-item :label="item.lossTypeName">
<NumberInput :model-value="getValue(item)" :precision="2" @update:model-value="(value) => changeValue(item, value)"> <el-input :modelValue="getValue(item)" @update:modelValue="(event) => changeValue(item, event)">
<template #append>{{ item.unit }}</template> <template #suffix>
</NumberInput> <span>{{ item.unit }}</span>
</template>
</el-input>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="24" v-if="item.lossTypeCode == 'OTHER_LOSS'"> <el-col :span="24" v-if="item.lossTypeCode == 'OTHER_LOSS'">
@ -18,10 +20,12 @@
</template> </template>
<script setup> <script setup>
import { ref, onMounted } from 'vue' import { ref, computed, onMounted, watch } from 'vue'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { Delete, Plus } from '@element-plus/icons-vue'
import { request } from '@shared/utils/request' import { request } from '@shared/utils/request'
import NumberInput from '@/component/NumberInput/NumberInput.vue'
const emit = defineEmits(['update:modelValue'])
const props = defineProps({ const props = defineProps({
modelValue: { modelValue: {
@ -64,9 +68,9 @@ const getLossDict = async () => {
} }
} }
const changeValue = (config, value) => { const changeValue = (config, event) => {
const item = getValueItem(config) const item = getValueItem(config)
item.totalAmount = value item.totalAmount = event
} }
onMounted(async () => { onMounted(async () => {
@ -77,5 +81,88 @@ onMounted(async () => {
<style scoped lang="scss"> <style scoped lang="scss">
.loss-list-pc { .loss-list-pc {
width: 100%; width: 100%;
.loss-table {
margin-bottom: 16px;
:deep(.el-table) {
.amount-cell {
display: flex;
align-items: center;
gap: 8px;
.unit-text {
color: #909399;
font-size: 14px;
white-space: nowrap;
}
}
}
}
.add-button-wrapper {
display: flex;
justify-content: flex-start;
}
.calculate-form {
padding: 8px 0;
:deep(.el-form-item) {
margin-bottom: 20px;
}
}
.calculation-preview {
background-color: #f5f7fa;
border-radius: 8px;
padding: 16px;
margin-top: 16px;
.preview-item {
display: flex;
justify-content: space-between;
align-items: center;
.preview-label {
color: #606266;
font-size: 14px;
}
.preview-value {
color: #f56c6c;
font-size: 16px;
font-weight: 500;
}
}
}
.loss-picker-content {
max-height: 400px;
overflow-y: auto;
padding: 8px 0;
.loss-radio-group {
display: flex;
flex-direction: column;
gap: 12px;
width: 100%;
.loss-radio-item {
margin: 0;
padding: 10px 12px;
border-radius: 6px;
width: 100%;
box-sizing: border-box;
:deep(.el-radio__label) {
width: calc(100% - 22px);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
}
} }
</style> </style>

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="disaster-form-page"> <div class="disaster-form-page">
<el-form ref="formRef" :model="formData" :rules="formRules" class="disaster-form" @submit.prevent> <el-form ref="formRef" :model="formData" :rules="formRules" label-width="120px" class="disaster-form" @submit.prevent>
<el-card class="form-section" shadow="never"> <el-card class="form-section" shadow="never">
<template #header> <template #header>
<div class="section-header"> <div class="section-header">
@ -76,16 +76,16 @@
<el-row :gutter="24"> <el-row :gutter="24">
<el-col :span="8"> <el-col :span="8">
<el-form-item label="受灾里程" prop="event.blockedMileage"> <el-form-item label="受灾里程" prop="event.blockedMileage">
<NumberInput v-model="formData.event.blockedMileage" :precision="2" placeholder="请填写"> <el-input v-model="formData.event.blockedMileage" placeholder="请填写">
<template #append>公里</template> <template #append>公里</template>
</NumberInput> </el-input>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="水毁处数" prop="event.damageCount"> <el-form-item label="水毁处数" prop="event.damageCount">
<NumberInput v-model="formData.event.damageCount" :precision="0" placeholder="请填写"> <el-input v-model="formData.event.damageCount" placeholder="请填写">
<template #append></template> <template #append></template>
</NumberInput> </el-input>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@ -139,12 +139,12 @@
<el-row :gutter="24"> <el-row :gutter="24">
<el-col :span="8"> <el-col :span="8">
<el-form-item label="起点桩经度" prop="event.startStakeLongitude"> <el-form-item label="起点桩经度" prop="event.startStakeLongitude">
<NumberInput v-model="formData.event.startStakeLongitude" :precision="6" placeholder="请填写" /> <el-input v-model="formData.event.startStakeLongitude" placeholder="请填写" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="起点桩纬度" prop="event.startStakeLatitude"> <el-form-item label="起点桩纬度" prop="event.startStakeLatitude">
<NumberInput v-model="formData.event.startStakeLatitude" :precision="6" placeholder="请填写" /> <el-input v-model="formData.event.startStakeLatitude" placeholder="请填写" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
@ -159,12 +159,12 @@
<el-row :gutter="24"> <el-row :gutter="24">
<el-col :span="8"> <el-col :span="8">
<el-form-item label="止点桩经度" prop="event.endStakeLongitude"> <el-form-item label="止点桩经度" prop="event.endStakeLongitude">
<NumberInput v-model="formData.event.endStakeLongitude" :precision="6" placeholder="请填写" /> <el-input v-model="formData.event.endStakeLongitude" placeholder="请填写" />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="止点桩纬度" prop="event.endStakeLatitude"> <el-form-item label="止点桩纬度" prop="event.endStakeLatitude">
<NumberInput v-model="formData.event.endStakeLatitude" :precision="6" placeholder="请填写" /> <el-input v-model="formData.event.endStakeLatitude" placeholder="请填写" />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@ -212,23 +212,29 @@
<el-row :gutter="24"> <el-row :gutter="24">
<el-col :span="8"> <el-col :span="8">
<el-form-item label="受伤人员" prop="report.injuredCount"> <el-form-item label="受伤人员" prop="report.injuredCount">
<NumberInput v-model="formData.report.injuredCount" :precision="0" style="width: 100%"> <el-input-number v-model="formData.report.injuredCount" :min="0" :step="1" style="width: 100%">
<template #append></template> <template #suffix>
</NumberInput> <span class="unit-text"></span>
</template>
</el-input-number>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="死亡人员" prop="report.deadCount"> <el-form-item label="死亡人员" prop="report.deadCount">
<NumberInput v-model="formData.report.deadCount" :precision="0" style="width: 100%"> <el-input-number v-model="formData.report.deadCount" :min="0" :step="1" style="width: 100%">
<template #append></template> <template #suffix>
</NumberInput> <span class="unit-text"></span>
</template>
</el-input-number>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="滞留人员" prop="report.strandedPersonCount"> <el-form-item label="滞留人员" prop="report.strandedPersonCount">
<NumberInput v-model="formData.report.strandedPersonCount" :precision="0" style="width: 100%"> <el-input-number v-model="formData.report.strandedPersonCount" :min="0" :step="1" style="width: 100%">
<template #append></template> <template #suffix>
</NumberInput> <span class="unit-text"></span>
</template>
</el-input-number>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@ -236,16 +242,20 @@
<el-row :gutter="24"> <el-row :gutter="24">
<el-col :span="8"> <el-col :span="8">
<el-form-item label="损坏车辆" prop="report.damagedVehicleCount"> <el-form-item label="损坏车辆" prop="report.damagedVehicleCount">
<NumberInput v-model="formData.report.damagedVehicleCount" :precision="0" style="width: 100%"> <el-input-number v-model="formData.report.damagedVehicleCount" :min="0" :step="1" style="width: 100%">
<template #append></template> <template #suffix>
</NumberInput> <span class="unit-text"></span>
</template>
</el-input-number>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="滞留车辆" prop="report.strandedVehicleCount"> <el-form-item label="滞留车辆" prop="report.strandedVehicleCount">
<NumberInput v-model="formData.report.strandedVehicleCount" :precision="0" style="width: 100%"> <el-input-number v-model="formData.report.strandedVehicleCount" :min="0" :step="1" style="width: 100%">
<template #append></template> <template #suffix>
</NumberInput> <span class="unit-text"></span>
</template>
</el-input-number>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@ -257,23 +267,25 @@
<el-row :gutter="24"> <el-row :gutter="24">
<el-col :span="8"> <el-col :span="8">
<el-form-item label="投入机械" prop="report.investedMachinery"> <el-form-item label="投入机械" prop="report.investedMachinery">
<NumberInput v-model="formData.report.investedMachinery" :precision="1" placeholder="请填写"> <el-input v-model="formData.report.investedMachinery" placeholder="请填写">
<template #append>/</template> <template #append>/</template>
</NumberInput> </el-input>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="投入人力" prop="report.investedManpower"> <el-form-item label="投入人力" prop="report.investedManpower">
<NumberInput v-model="formData.report.investedManpower" :precision="0" style="width: 100%"> <el-input-number v-model="formData.report.investedManpower" :min="0" :step="1" style="width: 100%">
<template #append>人次</template> <template #suffix>
</NumberInput> <span class="unit-text">人次</span>
</template>
</el-input-number>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="投入资金" prop="report.investedFunds"> <el-form-item label="投入资金" prop="report.investedFunds">
<NumberInput v-model="formData.report.investedFunds" :precision="2" placeholder="请填写"> <el-input v-model="formData.report.investedFunds" placeholder="请填写">
<template #append>万元</template> <template #append>万元</template>
</NumberInput> </el-input>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@ -306,9 +318,9 @@
</el-col> </el-col>
<el-col v-if="showEstimatedRecoveryCost" :span="8"> <el-col v-if="showEstimatedRecoveryCost" :span="8">
<el-form-item label="恢复重建预估费用" prop="event.estimatedRecoveryCost"> <el-form-item label="恢复重建预估费用" prop="event.estimatedRecoveryCost">
<NumberInput v-model="formData.event.estimatedRecoveryCost" :precision="2" placeholder="请填写"> <el-input v-model="formData.event.estimatedRecoveryCost" placeholder="请填写">
<template #append>万元</template> <template #append>万元</template>
</NumberInput> </el-input>
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
@ -327,7 +339,6 @@
import { LocationFilled } from '@element-plus/icons-vue' import { LocationFilled } from '@element-plus/icons-vue'
import BlockItem from '@/component/BlockItem.vue' import BlockItem from '@/component/BlockItem.vue'
import FileUpload from '@/component/FileUpload/FileUpload.vue' import FileUpload from '@/component/FileUpload/FileUpload.vue'
import NumberInput from '@/component/NumberInput/NumberInput.vue'
import RoadRoutesSelect from '../components/RoadRoutesSelect.vue' import RoadRoutesSelect from '../components/RoadRoutesSelect.vue'
import YHZSelect from '../components/YHZSelect.vue' import YHZSelect from '../components/YHZSelect.vue'
import LossList from './WaterDisasterLossListPC.vue' import LossList from './WaterDisasterLossListPC.vue'

View File

@ -0,0 +1,742 @@
<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>
<BlockItem title="填报人员信息">
<el-row :gutter="24">
<!-- 填报单位 -->
<el-col :span="8">
<el-form-item label="填报单位" prop="event.reporterUnit">
<el-input v-model="formData.event.reporterUnit" placeholder="请填写" />
</el-form-item>
</el-col>
<!-- 联系人 -->
<el-col :span="8">
<el-form-item label="联系人员" prop="event.contactPerson">
<el-input v-model="formData.event.contactPerson" placeholder="请填写" />
</el-form-item>
</el-col>
<!-- 联系电话 -->
<el-col :span="8">
<el-form-item label="联系电话" prop="event.contactPhone">
<el-input v-model="formData.event.contactPhone" placeholder="请填写" />
</el-form-item>
</el-col>
</el-row>
</BlockItem>
<BlockItem title="路况事件信息">
<el-row :gutter="24">
<el-col :span="8">
<el-form-item label="事件类型">
<el-select v-model="eventType" placeholder="请选择" style="width: 100%" @change="handleEventTypeChange">
<el-option v-for="(option, idx) in options['eventType']" :label="option.label" :value="option.value" :key="idx" />
</el-select>
</el-form-item>
</el-col>
<!-- 路况类别 -->
<el-col :span="8">
<el-form-item label="路况类别" prop="roadConditionType">
<el-select v-model="formData.roadConditionType" placeholder="请选择" style="width: 100%">
<el-option v-for="(option, idx) in options['waterRoadConditionType']" :label="option.label" :value="option.value" :key="idx" />
</el-select>
</el-form-item>
</el-col>
<!-- 是否阻断 -->
<el-col :span="8">
<el-form-item label="是否阻断" prop="event.isBlocked">
<el-select v-model="formData.event.isBlocked" placeholder="请选择" style="width: 100%">
<el-option v-for="(option, idx) in options['yesNoBool']" :label="option.label" :value="option.value" :key="idx" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<!-- 抢险进度 -->
<el-col :span="8">
<el-form-item label="抢险进度" prop="event.repairProgress">
<el-select v-model="formData.event.repairProgress" placeholder="请选择" style="width: 100%">
<el-option v-for="(option, idx) in options['repairProgress']" :label="option.label" :value="option.value" :key="idx" />
</el-select>
</el-form-item>
</el-col>
<!-- 处理措施-->
<el-col :span="8">
<el-form-item label="处理措施" prop="report.disposalMeasures">
<el-select v-model="formData.report.disposalMeasures" placeholder="请选择" style="width: 100%">
<el-option v-for="(option, idx) in options['disposalMeasures']" :label="option.label" :value="option.value" :key="idx" />
</el-select>
</el-form-item>
</el-col>
<!-- 水毁处数 -->
<el-col :span="8">
<el-form-item label="水毁处数" prop="event.damageCount">
<el-input-number v-model="formData.event.damageCount" :min="0" :step="1" style="width: 100%" placeholder="请填写">
<template #suffix>
<span class="unit-text"></span>
</template>
</el-input-number>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<!-- 阻断里程 -->
<el-col :span="8">
<el-form-item label="阻断里程" prop="event.blockedMileage">
<el-input-number v-model="formData.event.blockedMileage" :min="0" :precision="3" style="width: 100%" placeholder="请填写">
<template #suffix>
<span class="unit-text">公里</span>
</template>
</el-input-number>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<!-- 发生时间 -->
<el-col :span="8">
<el-form-item label="发生时间" prop="occurTime">
<el-date-picker v-model="formData.occurTime" 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="report.expectRecoverTime">
<el-date-picker v-model="formData.report.expectRecoverTime" type="datetime" placeholder="请选择时间" style="width: 100%" value-format="YYYY-MM-DD HH:mm:ss" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<!-- 现场描述 -->
<el-col :span="16">
<el-form-item label="现场描述(绕行方案)" prop="report.siteDescription">
<el-input v-model="formData.report.siteDescription" type="textarea" :rows="2" placeholder="请填写" />
</el-form-item>
</el-col>
</el-row>
</BlockItem>
<BlockItem title="位置信息">
<el-row :gutter="24">
<!-- 路线类型 -->
<el-col :span="8">
<el-form-item label="路线类型">
<el-select v-model="filterForm.routeType" placeholder="请选择" style="width: 100%">
<el-option v-for="(option, idx) in options['roadType']" :label="option.label" :value="option.value" :key="idx" />
</el-select>
</el-form-item>
</el-col>
<!-- 所属区县 -->
<el-col :span="8">
<el-form-item label="所属区县" prop="event.district">
<el-select v-model="formData.event.district" placeholder="请选择" style="width: 100%" @change="handleDistrictChange">
<el-option v-for="(option, idx) in options['area']" :label="option.label" :value="option.value" :key="idx" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="8">
<el-form-item label="地点路线" prop="routeNo">
<RoadRoutesSelect v-model="formData.routeNo" @change="handleRouteNoChange" :extra-params="{ xzdj: filterForm.routeType, qxid: formData.event.district }" />
</el-form-item>
</el-col>
<!-- 起点桩号 -->
<el-col :span="8">
<el-form-item label="起点桩号(K)" prop="event.startStakeNo">
<el-input v-model="formData.event.startStakeNo" placeholder="请填写">
<template #append>K</template>
</el-input>
</el-form-item>
</el-col>
<!-- 止点桩号 -->
<el-col :span="8">
<el-form-item label="止点桩号(K)" prop="event.endStakeNo">
<el-input v-model="formData.event.endStakeNo" placeholder="请填写">
<template #append>K</template>
</el-input>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<!-- 路况位置 -->
<el-col :span="8">
<el-form-item label="路况位置" prop="occurLocation">
<el-input v-model="formData.occurLocation" placeholder="请填写" />
</el-form-item>
</el-col>
<!-- 阻断点小地名 -->
<el-col :span="8">
<el-form-item label="阻断点小地名" prop="event.blockedPointName">
<el-input v-model="formData.event.blockedPointName" placeholder="请填写" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<!-- 经度 -->
<el-col :span="8">
<el-form-item label="经度" prop="event.longitude">
<el-input v-model="formData.event.longitude" placeholder="经度"> </el-input>
</el-form-item>
</el-col>
<!-- 纬度 -->
<el-col :span="8">
<el-form-item label="纬度" prop="event.latitude">
<el-input v-model="formData.event.latitude" placeholder="纬度"> </el-input>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="8">
<el-form-item label="图片上传" prop="fileList">
<FileUpload type="image" :limit="9" v-model="formData.fileList" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="视频上传" prop="fileList">
<FileUpload type="video" :limit="9" v-model="formData.fileList" />
</el-form-item>
</el-col>
</el-row>
</BlockItem>
</el-card>
<el-card class="form-section" shadow="never">
<template #header>
<div class="section-header">
<span class="section-title">灾毁损失</span>
</div>
</template>
<BlockItem title="路况事件信息">
<el-row :gutter="24">
<!-- 受伤人员 -->
<el-col :span="8">
<el-form-item label="受伤人员" prop="report.injuredCount">
<el-input-number v-model="formData.report.injuredCount" :min="0" :step="1" style="width: 100%">
<template #suffix>
<span class="unit-text"></span>
</template>
</el-input-number>
</el-form-item>
</el-col>
<!-- 死亡人员 -->
<el-col :span="8">
<el-form-item label="死亡人员" prop="report.deadCount">
<el-input-number v-model="formData.report.deadCount" :min="0" :step="1" style="width: 100%">
<template #suffix>
<span class="unit-text"></span>
</template>
</el-input-number>
</el-form-item>
</el-col>
<!-- 滞留人员 -->
<el-col :span="8">
<el-form-item label="滞留人员" prop="report.strandedPersonCount">
<el-input-number v-model="formData.report.strandedPersonCount" :min="0" :step="1" style="width: 100%">
<template #suffix>
<span class="unit-text"></span>
</template>
</el-input-number>
</el-form-item>
</el-col>
<!-- 损坏车辆 -->
<el-col :span="8">
<el-form-item label="损坏车辆" prop="report.damagedVehicleCount">
<el-input-number v-model="formData.report.damagedVehicleCount" :min="0" :step="1" style="width: 100%">
<template #suffix>
<span class="unit-text"></span>
</template>
</el-input-number>
</el-form-item>
</el-col>
<!-- 滞留车辆 -->
<el-col :span="8">
<el-form-item label="滞留车辆" prop="report.strandedVehicleCount">
<el-input-number v-model="formData.report.strandedVehicleCount" :min="0" :step="1" style="width: 100%">
<template #suffix>
<span class="unit-text"></span>
</template>
</el-input-number>
</el-form-item>
</el-col>
</el-row>
</BlockItem>
<BlockItem title="道路损失及其他">
<LossList v-model:model-value="formData.report.lossList" />
<el-row :gutter="24">
<!-- 投入机械 -->
<el-col :span="8">
<el-form-item label="投入机械" prop="report.investedMachinery">
<el-input-number v-model="formData.report.investedMachinery" :min="0" :precision="1" style="width: 100%" placeholder="请填写">
<template #suffix>
<span class="unit-text">/</span>
</template>
</el-input-number>
</el-form-item>
</el-col>
<!-- 投入人力 -->
<el-col :span="8">
<el-form-item label="投入人力" prop="report.investedManpower">
<el-input-number v-model="formData.report.investedManpower" :min="0" :step="1" style="width: 100%" placeholder="请填写">
<template #suffix>
<span class="unit-text">人次</span>
</template>
</el-input-number>
</el-form-item>
</el-col>
<!-- 投入资金 -->
<el-col :span="8">
<el-form-item label="投入资金" prop="report.investedFunds">
<el-input-number v-model="formData.report.investedFunds" :min="0" :precision="2" style="width: 100%" placeholder="请填写">
<template #suffix>
<span class="unit-text">万元</span>
</template>
</el-input-number>
</el-form-item>
</el-col>
</el-row>
</BlockItem>
<BlockItem title="恢复重建预估费用">
<el-row :gutter="24">
<!-- 是否需要恢复重建 -->
<el-col :span="8">
<el-form-item label="是否需要恢复重建" prop="event.needsRecovery">
<el-select v-model="formData.event.needsRecovery" placeholder="请选择" style="width: 100%">
<el-option v-for="(option, idx) in options['yesNoBool']" :label="option.label" :value="option.value" :key="idx" />
</el-select>
</el-form-item>
</el-col>
<!-- 恢复重建预估费用 -->
<el-col :span="8" v-if="formData?.event.needsRecovery">
<el-form-item label="恢复重建预估费用" prop="event.estimatedRecoveryCost">
<el-input-number v-model="formData.event.estimatedRecoveryCost" :min="0" :precision="2" style="width: 100%" placeholder="请填写">
<template #suffix>
<span class="unit-text">万元</span>
</template>
</el-input-number>
</el-form-item>
</el-col>
</el-row>
</BlockItem>
</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, watch, onMounted } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { ElMessage } from 'element-plus'
import { Plus, Upload } from '@element-plus/icons-vue'
import mockData from './waterMockJson.json'
import { request } from '@/utils/request'
import LossList from './WaterDisasterLossListPC.vue'
import BlockItem from '@/component/BlockItem.vue'
import FileUpload from '@/component/FileUpload/FileUpload.vue'
import { useOptions } from '@shared/composables/useOptions'
import RoadRoutesSelect from '../components/RoadRoutesSelect.vue'
const router = useRouter()
const route = useRoute()
const { options, getAreaOptions } = useOptions()
const formRef = ref(null)
const submitting = ref(false)
//
const isContinue = computed(() => route.query.isContinue === 'true')
//
const disposalMeasuresArray = ref([])
//
const imageFileList = ref([])
const videoFileList = ref([])
const eventType = ref('水毁事件')
const filterForm = reactive({
routeType: ''
})
const formData = reactive({
//
occurLocation: null, // /
occurTime: null, //
roadConditionType: null, //
routeNo: null, // 线
// event
event: {
blockedMileage: null, //
blockedPointName: null, //
contactPerson: null, //
contactPhone: null, //
damageCount: null, //
district: null, //
endStakeNo: null, //
estimatedRecoveryCost: null, //
inspectionMileage: null, //
isBlocked: null, //
needsRecovery: null, //
repairProgress: null, //
reporterUnit: null, //
startStakeNo: null //
},
// report
report: {
actualRecoverTime: null, //
damagedVehicleCount: null, //
deadCount: null, //
disposalMeasures: null, //
expectRecoverTime: null, //
injuredCount: null, //
investedFunds: null, //
investedMachinery: null, //
investedManpower: null, //
remark: null, // /
siteDescription: null, //
strandedPersonCount: null, //
strandedVehicleCount: null, //
totalLossAmount: null //
},
// lossList
lossList: [],
// fileList
fileList: []
})
const handleEventTypeChange = () => {
router.replace({ path: '/iceDisasterReport' })
}
// report.disposalMeasures
watch(
disposalMeasuresArray,
(newVal) => {
formData.report.disposalMeasures = newVal.length ? newVal.join(',') : null
},
{ deep: true }
)
// fileList
watch(
imageFileList,
() => {
syncFileList()
},
{ deep: true }
)
// fileList
watch(
videoFileList,
() => {
syncFileList()
},
{ deep: true }
)
// fileList
const syncFileList = () => {
formData.fileList = [
...imageFileList.value.map((f) => ({
fileName: f.name || '',
fileSize: f.size || 0,
fileType: 1, // 1-
fileUrl: f.url || f.content || ''
})),
...videoFileList.value.map((f) => ({
fileName: f.name || '',
fileSize: f.size || 0,
fileType: 2, // 2-
fileUrl: f.url || f.content || ''
}))
]
}
// report.disposalMeasures
watch(
() => formData.report.disposalMeasures,
(newVal) => {
if (newVal && typeof newVal === 'string') {
disposalMeasuresArray.value = newVal.split(',').filter(Boolean)
} else {
disposalMeasuresArray.value = []
}
},
{ immediate: true }
)
//
const formRules = {
roadConditionType: [{ required: true, message: '请选择路况类别', trigger: 'change' }],
'event.isBlocked': [{ required: true, message: '请选择是否阻断', trigger: 'change' }],
'event.repairProgress': [{ required: true, message: '请选择抢险进度', trigger: 'change' }],
'report.disposalMeasures': [{ required: true, message: '请选择处置措施', trigger: 'change' }],
'event.damageCount': [{ required: true, message: '请输入水毁处数', trigger: 'blur' }],
'event.blockedMileage': [{ required: true, message: '请输入阻断里程', trigger: 'blur' }],
occurTime: [{ required: true, message: '请选择发生时间', trigger: 'change' }],
'report.expectRecoverTime': [{ required: true, message: '请输入预计恢复时间', trigger: 'blur' }],
routeNo: [{ required: true, message: '请输入线路编号', trigger: 'blur' }],
'event.startStakeNo': [{ required: true, message: '请输入起点桩号', trigger: 'blur' }],
'event.endStakeNo': [{ required: true, message: '请输入止点桩号', trigger: 'blur' }],
occurLocation: [{ required: true, message: '请输入路况位置', trigger: 'blur' }],
'event.blockedPointName': [{ required: true, message: '请输入阻断点小地名', trigger: 'blur' }],
'event.longitude': [{ required: true, message: '请输入经度', trigger: 'blur' }],
'event.latitude': [{ required: true, message: '请输入纬度', trigger: 'blur' }],
'event.needsRecovery': [{ required: true, message: '请选择是否需要恢复重建', trigger: 'change' }],
'event.estimatedRecoveryCost': [{ required: true, message: '请输入恢复重建预估费用', trigger: 'blur' }]
// 'event.reporterUnit': [{ required: true, message: '', trigger: 'blur' }],
// 'event.contactPerson': [{ required: true, message: '', trigger: 'blur' }],
// 'event.contactPhone': [
// { required: true, message: '', trigger: 'blur' },
// { pattern: /^1[3-9]\d{9}$/, 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 isLt20M = file.size / 1024 / 1024 < 20
if (!isLt20M) {
ElMessage.error('视频大小不能超过 20MB!')
return false
}
return false
}
//
const previewDialogVisible = ref(false)
const previewImageUrl = ref('')
const handlePicturePreview = (file) => {
previewImageUrl.value = file.url
previewDialogVisible.value = true
}
const handlePictureRemove = (file, fileList) => {
imageFileList.value = fileList
}
//
const handleBack = () => {
router.back()
}
// /
const initFormData = (data) => {
Object.assign(formData, data)
}
const handleDistrictChange = () => {
formData.routeNo = null
}
const handleRouteNoChange = (item) => {
formData.event.startStakeNo = item.startStakeNo
formData.event.endStakeNo = item.endStakeNo
}
//
const getFormData = () => {
return { ...formData }
}
//
const validate = async () => {
if (!formRef.value) return false
try {
await formRef.value.validate()
return true
} catch (error) {
ElMessage.warning('请完善表单信息')
return false
}
}
//
const handleSubmit = async () => {
//
if (!(await validate())) {
return
}
submitting.value = true
try {
//
//
const submitData = {
...formData
//
}
const res = await request({
url: '/snow-ops-platform/water-damage/addOrUpdate',
method: 'post',
data: submitData
})
if (res?.code === '00000') {
ElMessage.success('提交成功')
} else {
ElMessage.error(res.message)
}
//
setTimeout(() => {
router.replace('/disasterManagement')
}, 1000)
} catch (error) {
ElMessage.error('提交失败,请重试')
console.error('提交失败:', error)
} finally {
submitting.value = false
}
}
//
const loadEditData = async () => {
if (route.query.mock) {
initFormData(mockData)
} else {
initFormData({})
}
}
onMounted(() => {
//
getAreaOptions()
loadEditData()
})
//
defineExpose({
validate,
initFormData,
getFormData
})
</script>
<style scoped lang="scss">
.disaster-form-page {
padding: 20px;
background-color: #f5f7fa;
height: 100%;
overflow: auto;
.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-text {
color: #909399;
font-size: 12px;
}
.upload-tip {
font-size: 12px;
color: #909399;
margin-top: 8px;
}
.video-preview {
margin-top: 12px;
}
.form-actions {
display: flex;
justify-content: center;
gap: 16px;
padding: 20px 0 40px;
}
}
}
</style>

View File

@ -1,13 +1,13 @@
<template> <template>
<el-row class="material-list-pc"> <el-row class="material-list-pc" :gutter="24">
<template v-for="(item, index) in configs" :key="index"> <template v-for="(item, index) in configs" :key="index">
<el-col :span="colSpan"> <el-col :span="colSpan">
<el-form-item :label="item.wzmc"> <el-form-item :label="item.wzmc">
<NumberInput :model-value="getValue(item)" :precision="2" :placeholder="`余额: ${item.ye} `" @update:model-value="(value) => changeValue(item, value)"> <el-input :modelValue="getValue(item)" :placeholder="`余额: ${item.ye} `" @update:modelValue="(event) => changeValue(item, event)">
<template #append> <template #suffix>
{{ item.dw }} <span>{{ item.dw }}</span>
</template> </template>
</NumberInput> </el-input>
</el-form-item> </el-form-item>
</el-col> </el-col>
</template> </template>
@ -15,9 +15,10 @@
</template> </template>
<script setup> <script setup>
import { ref, onMounted, watch } from 'vue' import { ref, computed, onMounted, watch } from 'vue'
import { ElMessage } from 'element-plus'
import { Delete, Plus } from '@element-plus/icons-vue'
import { request } from '@shared/utils/request' import { request } from '@shared/utils/request'
import NumberInput from '@/component/NumberInput/NumberInput.vue'
const emit = defineEmits(['update:modelValue']) const emit = defineEmits(['update:modelValue'])
@ -36,17 +37,14 @@ const props = defineProps({
} }
}) })
watch( watch(()=> props.yhzId, ()=> {
() => props.yhzId,
() => {
emit('update:modelValue', []) emit('update:modelValue', [])
getDict() getDict()
} })
)
const getValue = (config) => { const getValue = (config) => {
const item = getValueItem(config) const item = getValueItem(config)
return item?.usageAmount || null return item?.usageAmount || 0
} }
const getValueItem = (config) => { const getValueItem = (config) => {
@ -69,7 +67,7 @@ const configs = ref([])
// //
const getDict = async () => { const getDict = async () => {
if (!props.yhzId) return [] if(!props.yhzId) return []
try { try {
const res = await request({ const res = await request({
url: `/snow-ops-platform/yjwz/list?yhzid=${props.yhzId}&pageNum=1&pageSize=9999`, url: `/snow-ops-platform/yjwz/list?yhzid=${props.yhzId}&pageNum=1&pageSize=9999`,
@ -80,14 +78,93 @@ const getDict = async () => {
console.error('获取物质列表失败:', error) console.error('获取物质列表失败:', error)
} }
} }
onMounted(() => {
getDict()
})
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.material-list-pc { .material-list-pc {
width: 100%; width: 100%;
.loss-table {
margin-bottom: 16px;
:deep(.el-table) {
.amount-cell {
display: flex;
align-items: center;
gap: 8px;
.unit-text {
color: #909399;
font-size: 14px;
white-space: nowrap;
}
}
}
}
.add-button-wrapper {
display: flex;
justify-content: flex-start;
}
.calculate-form {
padding: 8px 0;
:deep(.el-form-item) {
margin-bottom: 20px;
}
}
.calculation-preview {
background-color: #f5f7fa;
border-radius: 8px;
padding: 16px;
margin-top: 16px;
.preview-item {
display: flex;
justify-content: space-between;
align-items: center;
.preview-label {
color: #606266;
font-size: 14px;
}
.preview-value {
color: #f56c6c;
font-size: 16px;
font-weight: 500;
}
}
}
.loss-picker-content {
max-height: 400px;
overflow-y: auto;
padding: 8px 0;
.loss-radio-group {
display: flex;
flex-direction: column;
gap: 12px;
width: 100%;
.loss-radio-item {
margin: 0;
padding: 10px 12px;
border-radius: 6px;
width: 100%;
box-sizing: border-box;
:deep(.el-radio__label) {
width: calc(100% - 22px);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
}
} }
</style> </style>

View File

@ -50,7 +50,6 @@ export function useOptions() {
// 冰灾 处理措施 // 冰灾 处理措施
options.value['iceDisposalMeasures'] = [ options.value['iceDisposalMeasures'] = [
{ label: '正常通行', value: '正常通行' },
{ label: '封闭交通', value: '封闭交通' }, { label: '封闭交通', value: '封闭交通' },
{ label: '限速通行', value: '限速通行' }, { label: '限速通行', value: '限速通行' },
] ]