772 lines
23 KiB
Vue
Raw Normal View History

2026-04-07 17:01:46 +08:00
<template>
<div class="water-disaster">
<!-- 基本信息 -->
2026-04-08 16:01:04 +08:00
<PanelItem title="基本信息" v-if="!isContinue">
2026-04-07 17:01:46 +08:00
<van-form>
<!-- 路况类别 -->
2026-04-15 10:44:57 +08:00
<BasePicker v-model="formData.roadConditionType" :options="options['waterRoadConditionType']" label="路况类别" placeholder="请选择" />
2026-04-07 17:01:46 +08:00
2026-04-08 11:12:41 +08:00
<!-- 是否阻断 (event.isBlocked) -->
2026-04-20 11:28:23 +08:00
<BasePicker v-model="formData.event.isBlocked" :options="options['yesOrNoBool']" label="是否阻断" placeholder="请选择" />
2026-04-07 17:01:46 +08:00
2026-04-10 11:38:24 +08:00
<!-- 抢险进度 (event.repairProgress) -->
2026-04-15 09:08:41 +08:00
<BasePicker v-model="formData.event.repairProgress" :options="options['repairProgress']" label="抢险进度" placeholder="请选择" />
2026-04-07 17:01:46 +08:00
2026-04-08 11:12:41 +08:00
<!-- 水毁处数 (event.damageCount) -->
<van-field v-model="formData.event.damageCount" label="水毁处数" placeholder="请填写" type="number" />
2026-04-07 17:01:46 +08:00
2026-04-08 11:12:41 +08:00
<!-- 阻断里程 (event.blockedMileage) -->
<van-field v-model="formData.event.blockedMileage" label="阻断里程" placeholder="请填写" type="digit">
2026-04-07 17:01:46 +08:00
<template #button>
<span class="field-unit">公里</span>
</template>
</van-field>
2026-04-08 11:12:41 +08:00
<!-- 发生时间 (顶层 occurTime) -->
2026-04-07 17:01:46 +08:00
<BaseDatePicker v-model="formData.occurTime" label="发生时间" placeholder="请选择时间" :columnsType="['year', 'month', 'day', 'hour', 'minute']" />
<div class="calibrate-time-btn" @click="calibrateTime">
<van-icon name="replay" />
<span>校准时间</span>
</div>
2026-04-08 11:12:41 +08:00
<!-- 线路编号 (顶层 routeNo) -->
2026-04-15 09:08:41 +08:00
<RoadRoutesPicker v-model="formData.routeNo" label="线路编号" placeholder="请线路" @change="handleRouteNoChange" />
2026-04-07 17:01:46 +08:00
2026-04-08 11:12:41 +08:00
<!-- 起点桩号 (event.startStakeNo) -->
<van-field v-model="formData.event.startStakeNo" label="起点桩号(K)" placeholder="请填写" />
2026-04-07 17:01:46 +08:00
2026-04-08 11:12:41 +08:00
<!-- 止点桩号 (event.endStakeNo) -->
<van-field v-model="formData.event.endStakeNo" label="止点桩号(K)" placeholder="请填写" />
2026-04-07 17:01:46 +08:00
2026-04-15 09:08:41 +08:00
<van-field v-model="formData.event.longitude" label="经度" placeholder="请填写" />
<van-field v-model="formData.event.latitude" label="纬度" placeholder="请填写" />
2026-04-09 09:35:05 +08:00
<!-- 路况位置 (occurLocation) -->
2026-04-08 11:12:41 +08:00
<van-field v-model="formData.occurLocation" label="路况位置" placeholder="请填写" />
2026-04-07 17:01:46 +08:00
2026-04-08 11:12:41 +08:00
<!-- 阻断点小地名 (event.blockedPointName) -->
<van-field v-model="formData.event.blockedPointName" label="阻断点小地名" placeholder="请填写" />
2026-04-07 17:01:46 +08:00
</van-form>
</PanelItem>
2026-04-08 11:12:41 +08:00
<!-- 处置情况 (report) -->
2026-04-07 17:01:46 +08:00
<PanelItem title="处置情况">
<div class="disposal-measures">
<span class="measures-label">处置措施</span>
<div class="measures-options">
2026-04-15 09:08:41 +08:00
<van-row gutter="10">
<van-col v-for="(item, index) in options['disposalMeasures']" :span="24 / options['disposalMeasures'].length" :key="index">
<van-button block plain :type="item.value === formData.report.disposalMeasures ? 'primary' : 'default'" @click="formData.report.disposalMeasures = item.value">
{{ item.label }}
</van-button>
</van-col>
</van-row>
2026-04-07 17:01:46 +08:00
</div>
</div>
2026-04-08 11:12:41 +08:00
<!-- 预计恢复时间 (report.expectRecoverTime) -->
<BaseDatePicker v-model="formData.report.expectRecoverTime" label="预计恢复时间" placeholder="请选择时间" :min-date="minDate" :max-date="maxDate" type="datetime" />
2026-04-07 17:01:46 +08:00
2026-04-08 11:12:41 +08:00
<!-- 实际恢复时间 (report.actualRecoverTime) -->
<BaseDatePicker v-model="formData.report.actualRecoverTime" label="实际恢复时间" placeholder="请选择时间" :min-date="minDate" :max-date="maxDate" type="datetime" />
2026-04-07 17:01:46 +08:00
</PanelItem>
2026-04-08 11:12:41 +08:00
<!-- 人员车辆 (report) -->
2026-04-07 17:01:46 +08:00
<PanelItem title="人员车辆">
<van-form>
2026-04-08 11:12:41 +08:00
<van-field v-model="formData.report.injuredCount" label="受伤人员" placeholder="请填写" type="number">
2026-04-07 17:01:46 +08:00
<template #button>
2026-04-08 11:12:41 +08:00
<span class="field-unit"></span>
2026-04-07 17:01:46 +08:00
</template>
</van-field>
2026-04-08 11:12:41 +08:00
<van-field v-model="formData.report.deadCount" label="死亡人员" placeholder="请填写" type="number">
2026-04-07 17:01:46 +08:00
<template #button>
2026-04-08 11:12:41 +08:00
<span class="field-unit"></span>
2026-04-07 17:01:46 +08:00
</template>
</van-field>
2026-04-08 11:12:41 +08:00
<van-field v-model="formData.report.strandedPersonCount" label="滞留人员" placeholder="请填写" type="number">
2026-04-07 17:01:46 +08:00
<template #button>
2026-04-08 11:12:41 +08:00
<span class="field-unit"></span>
2026-04-07 17:01:46 +08:00
</template>
</van-field>
2026-04-08 11:12:41 +08:00
<van-field v-model="formData.report.damagedVehicleCount" label="损坏车辆" placeholder="请填写" type="number">
2026-04-07 17:01:46 +08:00
<template #button>
<span class="field-unit"></span>
</template>
</van-field>
2026-04-08 11:12:41 +08:00
<van-field v-model="formData.report.strandedVehicleCount" label="滞留车辆" placeholder="请填写" type="number">
2026-04-07 17:01:46 +08:00
<template #button>
<span class="field-unit"></span>
</template>
</van-field>
</van-form>
</PanelItem>
2026-04-08 11:12:41 +08:00
<!-- 灾毁损失 (lossList) -->
2026-04-07 17:01:46 +08:00
<PanelItem title="灾毁损失">
2026-04-08 09:21:47 +08:00
<LossList v-model="formData.lossList" />
2026-04-08 11:12:41 +08:00
<van-field v-model="formData.report.remark" label="处理情况" placeholder="请填写(选填)" />
<van-field v-model="formData.report.totalLossAmount" label="损失总金额" placeholder="请填写(选填)" type="digit">
2026-04-07 17:01:46 +08:00
<template #button>
<span class="field-unit">万元</span>
</template>
</van-field>
</PanelItem>
2026-04-08 11:12:41 +08:00
<!-- 投入资源 (report) -->
2026-04-07 17:01:46 +08:00
<PanelItem>
2026-04-15 10:44:57 +08:00
<van-field v-model="formData.report.investedMachinery" label="投入机械" placeholder="请填写" type="digit">
2026-04-07 17:01:46 +08:00
<template #button>
<span class="field-unit">/</span>
</template>
</van-field>
2026-04-15 10:44:57 +08:00
<van-field v-model="formData.report.investedManpower" label="投入人力" placeholder="请填写" type="number">
2026-04-07 17:01:46 +08:00
<template #button>
<span class="field-unit">人次</span>
</template>
</van-field>
2026-04-15 10:44:57 +08:00
<van-field v-model="formData.report.investedFunds" label="投入资金" placeholder="请填写" type="digit">
2026-04-07 17:01:46 +08:00
<template #button>
<span class="field-unit">万元</span>
</template>
</van-field>
2026-04-08 11:12:41 +08:00
<van-field v-model="formData.report.siteDescription" label="现场描述" placeholder="请填写" type="textarea" rows="2" autosize />
2026-04-10 11:38:24 +08:00
<van-field label="附件" center>
<template #input>
2026-04-15 09:08:41 +08:00
<van-uploader accept="video/*,image/*" :modelValue="getFileList()" :after-read="afterRead" multiple :max-count="7" @delete="removeFile" />
2026-04-10 11:38:24 +08:00
</template>
</van-field>
2026-04-07 17:01:46 +08:00
</PanelItem>
2026-04-15 09:08:41 +08:00
<PanelItem v-if="!isContinue || (isContinue && !detail?.event.needsRecovery)">
2026-04-08 11:12:41 +08:00
<!-- 是否需要恢复重建 (event.needsRecovery) -->
2026-04-20 11:28:23 +08:00
<BasePicker v-model="formData.event.needsRecovery" :options="options['yesOrNoBool']" label="是否需要恢复重建" placeholder="请选择" />
2026-04-08 11:12:41 +08:00
<!-- 恢复重建预估费用 (event.estimatedRecoveryCost) -->
2026-04-15 09:08:41 +08:00
<van-field v-model="formData.event.estimatedRecoveryCost" v-if="formData?.event.needsRecovery" label="恢复重建预估费用" placeholder="请填写" type="digit">
2026-04-08 11:12:41 +08:00
<template #button>
<span class="field-unit">万元</span>
</template>
</van-field>
</PanelItem>
2026-04-15 09:08:41 +08:00
<!-- 提交按钮 -->
<van-button type="primary" class="footer-btn" @click="handleSubmit" :loading="submitting"> 提交 </van-button>
2026-04-07 17:01:46 +08:00
</div>
</template>
<script setup>
2026-04-15 09:08:41 +08:00
import { ref, computed, watch, onMounted } from 'vue'
2026-04-10 11:38:24 +08:00
import { showToast, showFailToast, showLoadingToast } from 'vant'
2026-04-07 17:01:46 +08:00
import PanelItem from '@/components/PanelItem.vue'
import BasePicker from '@/components/BasePicker.vue'
import BaseDatePicker from '@/components/BaseDatePicker.vue'
2026-04-15 09:08:41 +08:00
import RoadRoutesPicker from '../RoadRoutesPicker.vue'
2026-04-20 11:51:52 +08:00
import LossList from './components/LossList.vue'
2026-04-08 16:01:04 +08:00
import { useRouter, useRoute } from 'vue-router'
2026-04-10 11:38:24 +08:00
import { request } from '@shared/utils/request'
2026-04-15 09:08:41 +08:00
import { useOptions } from '@shared/composables/useOptions'
2026-04-07 17:01:46 +08:00
2026-04-08 16:01:04 +08:00
const route = useRoute()
2026-04-15 09:08:41 +08:00
const { options } = useOptions()
2026-04-08 16:01:04 +08:00
// 是否为续报
const isContinue = computed(() => route.query.isContinue)
2026-04-07 17:01:46 +08:00
2026-04-10 14:55:19 +08:00
// 表单数据 - 按 Request 接口结构定义,使用 ref 包装
const formData = ref({
2026-04-08 11:12:41 +08:00
// 顶层字段
occurLocation: '', // 发生地点
2026-04-15 09:08:41 +08:00
occurTime: null, // 发生时间
2026-04-08 11:12:41 +08:00
roadConditionType: '', // 路况类别
routeNo: '', // 线路编号
// event 对象
event: {
blockedMileage: '', // 阻断里程
blockedPointName: '', // 阻断点小地名
contactPerson: '', // 联系人
contactPhone: '', // 联系电话
damageCount: '', // 水毁处数
district: '', // 上报区县
endStakeNo: '', // 止点桩号
estimatedRecoveryCost: '', // 恢复重建预估费用
isBlocked: '', // 是否阻断
needsRecovery: '', // 是否需要恢复重建
2026-04-10 11:38:24 +08:00
repairProgress: '', // 抢险进度
2026-04-08 11:12:41 +08:00
reporterUnit: '', // 填报单位
startStakeNo: '' // 起点桩号
},
// report 对象
report: {
actualRecoverTime: '', // 实际恢复时间
damagedVehicleCount: '', // 损坏车辆
deadCount: '', // 死亡人员
2026-04-09 09:35:05 +08:00
disposalMeasures: '', // 处置措施(单个值,不再用逗号分隔)
2026-04-08 11:12:41 +08:00
expectRecoverTime: '', // 预计恢复时间
injuredCount: '', // 受伤人员
investedFunds: '', // 已投资金
investedMachinery: '', // 已投机械
investedManpower: '', // 已投人力
remark: '', // 处理情况/备注
siteDescription: '', // 现场描述
strandedPersonCount: '', // 滞留人员
strandedVehicleCount: '', // 滞留车辆
totalLossAmount: '' // 损失总金额
},
// lossList 数组
lossList: [],
// fileList 数组
fileList: []
2026-04-07 17:01:46 +08:00
})
2026-04-10 14:55:19 +08:00
const getFileList = () => {
const fileList = formData.value.fileList?.map((item) => {
return {
url: item.fileUrl,
name: item.fileName
}
})
return fileList
}
2026-04-15 09:08:41 +08:00
const submitting = ref(false)
2026-04-07 17:01:46 +08:00
// 时间选择器范围
const minDate = new Date(2020, 0, 1)
const maxDate = new Date(2030, 11, 31)
2026-04-08 11:12:41 +08:00
const initFormData = (newVal) => {
if (newVal && Object.keys(newVal).length > 0) {
2026-04-10 14:55:19 +08:00
// 深度合并数据 - 直接替换整个对象
formData.value = {
2026-04-08 11:12:41 +08:00
occurLocation: newVal.occurLocation || '',
2026-04-15 09:08:41 +08:00
occurTime: newVal.occurTime || formatTime(),
2026-04-08 11:12:41 +08:00
roadConditionType: newVal.roadConditionType || '',
routeNo: newVal.routeNo || '',
2026-04-10 14:55:19 +08:00
event: { ...formData.value.event, ...(newVal.event || {}) },
report: { ...formData.value.report, ...(newVal.report || {}) },
2026-04-08 11:12:41 +08:00
lossList: newVal.lossList || [],
fileList: newVal.fileList || []
2026-04-10 14:55:19 +08:00
}
2026-04-08 11:12:41 +08:00
}
}
2026-04-07 17:01:46 +08:00
// 校准时间
const calibrateTime = () => {
const now = new Date()
const formatted = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')} ${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}`
2026-04-10 14:55:19 +08:00
formData.value.occurTime = formatted
2026-04-07 17:01:46 +08:00
showToast('时间已校准为当前时间')
}
// 图片上传处理
const afterImageRead = (file) => {
console.log('图片上传:', file)
}
const onOversize = () => {
showFailToast('图片大小不能超过500KB')
}
const afterVideoRead = (file) => {
console.log('视频上传:', file)
}
const onVideoOversize = () => {
showFailToast('视频大小不能超过20MB')
}
2026-04-10 11:38:24 +08:00
const isImageFile = (file) => {
// 根据url后缀判断
const imageExtensions = /\.(jpg|jpeg|png|gif|webp|bmp|svg)$/i
if (file.fileUrl && imageExtensions.test(file.fileUrl)) return true
// 根据文件类型判断
if (file.type && file.type.startsWith('image/')) return true
return false
}
const isVideoFile = (file) => {
// 根据url后缀判断
const videoExtensions = /\.(mp4|avi|mov|wmv|flv|mkv)$/i
if (file.fileUrl && videoExtensions.test(file.fileUrl)) return true
}
2026-04-17 18:16:31 +08:00
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 }
}
2026-04-15 09:08:41 +08:00
const handleRouteNoChange = (item) => {
2026-04-17 18:16:31 +08:00
formData.routeNo = item.routeCode
formData.event.startStakeNo = item.startStakeNo
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
2026-04-15 09:08:41 +08:00
}
2026-04-10 11:38:24 +08:00
/**
* 判断图片是否可以上传
* @param {File} file - 图片文件
* @returns {boolean} 是否允许上传
*/
const isValidImage = (file) => {
// 校验文件类型
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png'
if (!isJpgOrPng) {
showFailToast('只能上传 JPG/PNG 格式的图片!')
return false
}
// 校验文件大小500KB = 500 * 1024 bytes
const isLt500k = file.size / 1024 < 500
if (!isLt500k) {
showFailToast(`图片大小不能超过 500KB当前大小${(file.size / 1024).toFixed(2)}KB`)
return false
}
return true
}
/**
* 判断视频是否可以上传
* @param {File} file - 视频文件
* @returns {boolean} 是否允许上传
*/
const isValidVideo = (file) => {
// 校验文件类型
const allowedTypes = ['video/mp4', 'video/quicktime', 'video/x-msvideo', 'video/webm']
const isValidType = allowedTypes.includes(file.type)
if (!isValidType) {
showFailToast('请上传有效的视频文件MP4、MOV、AVI、WEBM格式')
return false
}
// 校验文件大小50MB = 50 * 1024 * 1024 bytes
const maxSize = 50 * 1024 * 1024
const isValidSize = file.size <= maxSize
if (!isValidSize) {
showFailToast(`视频大小不能超过 50MB当前大小${(file.size / 1024 / 1024).toFixed(2)}MB`)
return false
}
return true
}
/**
2026-04-10 14:55:19 +08:00
* 统一的上传前校验
2026-04-10 11:38:24 +08:00
* @param {File} file - 上传的文件
* @returns {boolean} 是否允许上传
*/
const checkFile = (file) => {
// 判断是否为图片
if (file.type.startsWith('image/')) {
2026-04-15 09:08:41 +08:00
const imageCount = formData.value.fileList?.filter((item) => item.fileType === 1).length
if (imageCount == 6) {
showFailToast('只能上传六张图片!')
return false
}
2026-04-10 11:38:24 +08:00
return isValidImage(file)
}
// 判断是否为视频
if (file.type.startsWith('video/')) {
2026-04-15 09:08:41 +08:00
const videoCount = formData.value.fileList?.filter((item) => item.fileType === 2).length
if (videoCount == 1) {
showFailToast('只能上传一个视频文件!')
return false
}
2026-04-10 11:38:24 +08:00
return isValidVideo(file)
}
showFailToast('只支持图片和视频文件!')
return false
}
const afterRead = async (options) => {
const file = options.file
2026-04-10 14:55:19 +08:00
if (!checkFile(file)) return
2026-04-10 11:38:24 +08:00
const toast = showLoadingToast({
message: '上传中...',
forbidClick: true,
duration: 0 // 设置为0表示不会自动关闭
})
try {
2026-04-10 14:55:19 +08:00
const uploadFormData = new FormData()
uploadFormData.append('file', file)
2026-04-10 11:38:24 +08:00
const res = await request({
url: '/snow-ops-platform/file/upload',
method: 'post',
2026-04-10 14:55:19 +08:00
data: uploadFormData
2026-04-10 11:38:24 +08:00
})
toast.close()
if (res.code === '00000') {
const name = file.name
const url = res.data
2026-04-17 18:16:31 +08:00
const type = isImageFile({ fileUrl: url }) ? 1 : isVideoFile({ fileUrl: url }) ? 2 : 3
2026-04-10 11:38:24 +08:00
const fileData = {
fileName: name,
fileUrl: url,
fileType: type,
fileSize: file.size
}
2026-04-10 14:55:19 +08:00
if (!formData.value.fileList) formData.value.fileList = []
formData.value.fileList.push(fileData)
2026-04-10 11:38:24 +08:00
} else {
throw new Error(res.message)
}
} catch (error) {
toast.close()
showToast({
type: 'fail',
message: error.message
})
}
}
2026-04-10 14:55:19 +08:00
const removeFile = (file, index) => {
// 删除文件
formData.value.fileList.splice(index, 1)
}
2026-04-15 09:08:41 +08:00
// 简单的空值判断
const isEmpty = (value) => {
return value === null || value === undefined || value === ''
}
2026-04-07 17:01:46 +08:00
const validate = () => {
2026-04-15 09:08:41 +08:00
if (isEmpty(formData.value.roadConditionType)) {
showToast('请选择路况类别')
return false
}
if (isEmpty(formData.value.event?.isBlocked)) {
showToast('请选择是否阻断')
return false
}
if (isEmpty(formData.value.event?.repairProgress)) {
showToast('请选择抢险进度')
return false
}
if (isEmpty(formData.value.report?.disposalMeasures)) {
showToast('请选择处置措施')
return false
}
if (isEmpty(formData.value.event?.damageCount)) {
showToast('请输入水毁处数')
return false
}
if (isEmpty(formData.value.event?.blockedMileage)) {
showToast('请输入阻断里程')
return false
}
if (isEmpty(formData.value.occurTime)) {
showToast('请选择发生时间')
return false
}
if (isEmpty(formData.value.report?.expectRecoverTime)) {
showToast('请输入预计恢复时间')
return false
}
if (isEmpty(formData.value.routeNo)) {
showToast('请输入线路编号')
return false
}
if (isEmpty(formData.value.event?.startStakeNo)) {
showToast('请输入起点桩号')
return false
}
if (isEmpty(formData.value.event?.endStakeNo)) {
showToast('请输入止点桩号')
return false
}
if (isEmpty(formData.value.occurLocation)) {
showToast('请输入路况位置')
return false
}
if (isEmpty(formData.value.event?.blockedPointName)) {
showToast('请输入阻断点小地名')
return false
}
if (isEmpty(formData.value.event?.longitude)) {
showToast('请输入经度')
2026-04-07 17:01:46 +08:00
return false
}
2026-04-15 09:08:41 +08:00
if (isEmpty(formData.value.event?.latitude)) {
showToast('请输入纬度')
return false
}
if (isEmpty(formData.value.event?.needsRecovery)) {
showToast('请选择是否需要恢复重建')
return false
}
if (formData.value.event?.needsRecovery && isEmpty(formData.value.event?.estimatedRecoveryCost)) {
showToast('请输入恢复重建预估费用')
2026-04-07 17:01:46 +08:00
return false
}
return true
}
2026-04-10 14:55:19 +08:00
// 获取表单数据 - 返回 formData.value 的副本
2026-04-07 17:01:46 +08:00
const getFormData = () => {
2026-04-10 14:55:19 +08:00
return { ...formData.value }
2026-04-07 17:01:46 +08:00
}
2026-04-15 09:08:41 +08:00
// 提交表单
const handleSubmit = async () => {
// 验证表单
if (!validate()) return
submitting.value = true
try {
// 获取表单数据
let formData = getFormData()
// 添加事件类型和站点信息
const submitData = {
...formData
// 可以在这里添加站点信息等其他数据
}
const res = await request({
url: '/snow-ops-platform/water-damage/addOrUpdate',
method: 'post',
data: submitData
})
if (res?.code === '00000') {
showSuccessToast('提交成功')
let isRebuilded = false
if (isContinue && detail.value.event.needsRecovery) {
// 如果之前已经进行了项目重建的流程,后续不再进行该流程
isRebuilded = true
}
if (!isRebuilded && submitData.event.needsRecovery) {
router.replace({
name: 'RebuildAdd',
params: {
data: res.data.id
}
})
} else {
// 提交成功后返回列表页
setTimeout(() => {
router.replace('/disasterManagement')
}, 500)
}
} else {
showFailToast(res.message)
}
} catch (error) {
showFailToast('提交失败,请重试')
console.error('提交失败:', error)
} finally {
submitting.value = false
}
}
const detail = ref(null)
// 获取灾毁详情
const getDisasterDetail = async () => {
const id = route.query.id
if (!id) {
return
}
try {
const result = await request({
url: `/snow-ops-platform/water-damage/getById`,
method: 'get',
params: { id }
})
if (result?.data) {
// 接口返回 Data 结构
const data = result.data
detail.value = result.data
const newFormData = {
...data,
lossList: null,
2026-04-20 11:28:23 +08:00
report: {},
2026-04-15 09:08:41 +08:00
fileList: null
}
initFormData(newFormData)
} else {
showToast(result.message || '获取详情失败')
}
} catch (error) {
console.error('获取灾毁详情失败:', error)
showToast('获取详情失败,请稍后重试')
}
}
// 日期格式化
const formatTime = (date = new Date()) => {
const pad = (n) => n.toString().padStart(2, '0')
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ` + `${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`
}
onMounted(() => {
formData.value.occurTime = formatTime()
if (route.query.id) {
getDisasterDetail()
} else {
2026-04-20 11:28:23 +08:00
initFormData({})
2026-04-15 09:08:41 +08:00
}
})
2026-04-07 17:01:46 +08:00
// 暴露方法给父组件
defineExpose({
validate,
2026-04-08 11:12:41 +08:00
initFormData,
2026-04-07 17:01:46 +08:00
getFormData
})
</script>
<style lang="scss" scoped>
.water-disaster {
.coordinate-row {
display: flex;
gap: 8px;
.coordinate-field {
flex: 1;
}
}
.calibrate-time-btn,
.calibrate-coord-btn {
display: inline-flex;
align-items: center;
gap: 4px;
font-size: 12px;
color: #1989fa;
margin: 8px 0 8px 12px;
padding: 4px 8px;
background: #f0f7ff;
border-radius: 20px;
cursor: pointer;
width: fit-content;
}
.field-unit {
color: #969799;
font-size: 14px;
margin-left: 4px;
}
.disposal-measures {
margin-bottom: 16px;
.measures-label {
font-size: 14px;
color: #323233;
display: block;
margin-bottom: 8px;
}
.measures-options {
2026-04-09 09:35:05 +08:00
:deep(.van-radio-group) {
2026-04-07 17:01:46 +08:00
display: flex;
flex-wrap: wrap;
gap: 16px;
}
2026-04-09 09:35:05 +08:00
:deep(.van-radio) {
2026-04-07 17:01:46 +08:00
margin-right: 0;
}
}
}
.attachment-tip {
font-size: 12px;
color: #969799;
margin-bottom: 12px;
}
.upload-area {
display: flex;
gap: 16px;
flex-wrap: wrap;
.upload-btn {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 80px;
height: 80px;
background: #f8f9fa;
border: 1px dashed #dcdee0;
border-radius: 8px;
gap: 4px;
font-size: 12px;
color: #969799;
cursor: pointer;
}
}
.video-preview {
margin-top: 12px;
}
:deep(.van-field__label) {
2026-04-08 11:12:41 +08:00
width: 110px;
2026-04-07 17:01:46 +08:00
}
}
2026-04-15 09:08:41 +08:00
.footer-btn {
position: fixed;
bottom: 15px;
left: 50%;
transform: translateX(-50%);
width: calc(100% - 32px);
max-width: 340px;
border-radius: 48px;
height: 48px;
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
cursor: pointer;
z-index: 10;
&:active {
opacity: 0.9;
transform: translateX(-50%) scale(0.98);
}
}
</style>