From 5a20821e32b7be47453e865e24809fa03a712956 Mon Sep 17 00:00:00 2001 From: niedongsheng <605973111@qq.com> Date: Wed, 8 Apr 2026 11:12:41 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B0=B4=E6=AF=81=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E8=81=94=E8=B0=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/mobile/src/components/BasePicker.vue | 2 +- .../DisasterManagement/DisasterManagement.vue | 63 +-- .../DisasterManagement/DisasterReport.vue | 19 +- .../WaterDisaster/LossList.vue | 60 ++- .../WaterDisaster/LossPicker.vue | 47 +++ .../WaterDisaster/WaterDisaster.vue | 372 +++++++++++------- .../waterDisasterFormData.json | 63 +++ 7 files changed, 413 insertions(+), 213 deletions(-) create mode 100644 packages/mobile/src/views/DisasterManagement/WaterDisaster/LossPicker.vue create mode 100644 packages/mobile/src/views/DisasterManagement/waterDisasterFormData.json diff --git a/packages/mobile/src/components/BasePicker.vue b/packages/mobile/src/components/BasePicker.vue index f68b998..68470dd 100644 --- a/packages/mobile/src/components/BasePicker.vue +++ b/packages/mobile/src/components/BasePicker.vue @@ -34,7 +34,7 @@ import { Field, Popup, Picker } from 'vant' const props = defineProps({ // 双向绑定值 (v-model) modelValue: { - type: [String, Number], + type: [String, Number, Boolean], default: null }, // 选项数据,默认格式 [{ label: '显示名', value: '值' }] diff --git a/packages/mobile/src/views/DisasterManagement/DisasterManagement.vue b/packages/mobile/src/views/DisasterManagement/DisasterManagement.vue index bb92888..294d79e 100644 --- a/packages/mobile/src/views/DisasterManagement/DisasterManagement.vue +++ b/packages/mobile/src/views/DisasterManagement/DisasterManagement.vue @@ -34,7 +34,7 @@ - 冰雪填报 + 灾害填报 { loading.value = true try { - // TODO: 替换为实际的后端接口地址 - // const response = await fetch('/api/disaster/list', { - // method: 'POST', - // headers: { - // 'Content-Type': 'application/json' - // }, - // body: JSON.stringify({ - // keyword: keyword.trim(), - // disasterType: disasterType === 'all' ? '' : disasterType - // }) - // }) - // const result = await response.json() - // if (result.code === 200) { - // list.value = result.data - // } else { - // showToast(result.message || '获取数据失败') - // list.value = [] - // } - - // ========== 模拟数据 ========== - await new Promise((resolve) => setTimeout(resolve, 500)) - const mockData = mockDataJSON - - let filteredData = [...mockData] - - if (keyword) { - filteredData = filteredData.filter((item) => - item.title.toLowerCase().includes(keyword.toLowerCase()) - ) - } - - if (disasterType !== 'all') { - filteredData = filteredData.filter((item) => - item.disasterType === disasterType - ) - } - - list.value = filteredData - - if (keyword && filteredData.length === 0) { - emptyText.value = '未搜索到相关灾毁信息' - } else if (disasterType !== 'all' && filteredData.length === 0) { - const typeLabel = disasterTypes.find(t => t.value === disasterType)?.label || disasterType - emptyText.value = `暂无${typeLabel}类型灾毁信息` + const result = await request({ + url: '/snow-ops-platform/water-damage/list', + method: 'get', + params: { + keyword: keyword.trim(), + disasterType: disasterType === 'all' ? '' : disasterType + } + }) + if (result?.data?.records) { + list.value = result.data.records } else { - emptyText.value = '暂无相关灾毁信息' + showToast(result.message || '获取数据失败') + list.value = [] } - // ========== 模拟数据结束 ========== + } catch (error) { console.error('获取灾毁列表失败:', error) showToast('获取数据失败,请稍后重试') diff --git a/packages/mobile/src/views/DisasterManagement/DisasterReport.vue b/packages/mobile/src/views/DisasterManagement/DisasterReport.vue index 8cf4cc7..15c4694 100644 --- a/packages/mobile/src/views/DisasterManagement/DisasterReport.vue +++ b/packages/mobile/src/views/DisasterManagement/DisasterReport.vue @@ -15,7 +15,6 @@ @@ -31,13 +30,15 @@ \ No newline at end of file + diff --git a/packages/mobile/src/views/DisasterManagement/WaterDisaster/LossPicker.vue b/packages/mobile/src/views/DisasterManagement/WaterDisaster/LossPicker.vue new file mode 100644 index 0000000..535a2f8 --- /dev/null +++ b/packages/mobile/src/views/DisasterManagement/WaterDisaster/LossPicker.vue @@ -0,0 +1,47 @@ + + + diff --git a/packages/mobile/src/views/DisasterManagement/WaterDisaster/WaterDisaster.vue b/packages/mobile/src/views/DisasterManagement/WaterDisaster/WaterDisaster.vue index 2c86c31..dd03a70 100644 --- a/packages/mobile/src/views/DisasterManagement/WaterDisaster/WaterDisaster.vue +++ b/packages/mobile/src/views/DisasterManagement/WaterDisaster/WaterDisaster.vue @@ -4,74 +4,74 @@ - + - - + + - - + + - - + + - - + + - +
校准时间
- - + + - - + + - +
- - + +
校准经纬度
- - + + - +
- - + +
校准经纬度
- - + + - - + +
- +
处置措施
- + 半幅封闭 全副封闭 便道通行 @@ -80,37 +80,37 @@
- - + + - - + +
- + - + - + - + - + - + @@ -118,70 +118,69 @@ - + - 添加损失 - - + + + - + - + - + - - - - - + - + + + + + + + + + + @@ -193,54 +192,133 @@ import BasePicker from '@/components/BasePicker.vue' import BaseDatePicker from '@/components/BaseDatePicker.vue' import LossList from './LossList.vue' -// 定义 props -const props = defineProps({ - modelValue: { - type: Object, - default: () => ({}) - } -}) -// 定义 emits -const emit = defineEmits(['update:modelValue', 'submit']) +// 处置措施数组(用于多选框组,需要转换为逗号分隔的字符串) +const disposalMeasuresArray = ref([]) -// 表单数据 +// 附件列表 +const imageFileList = ref([]) +const videoFileList = ref([]) + +// 表单数据 - 按 Request 接口结构定义 const formData = reactive({ - roadCondition: '', - isBlocked: '', - repairProgress: '', - waterDamageCount: '', - blockedMileage: '', - occurTime: '', - lineCode: '', - startPileNo: '', - startLongitude: '', - startLatitude: '', - endPileNo: '', - endLongitude: '', - endLatitude: '', - roadLocation: '', - smallPlaceName: '', - disposalMeasures: [], - estimatedRecoverTime: '', - actualRecoverTime: '', - injuredCount: '', - deathCount: '', - strandedPeople: '', - damagedVehicles: '', - strandedVehicles: '', - collapseLoss: [], - handlingSituation: '', - totalLossAmount: '', - machineryInput: '', - laborInput: '', - fundsInput: '', - siteDescription: '', - imageFiles: [], - videoFile: [], - lossList: [{ value: '' }] + // 顶层字段 + occurLocation: '', // 发生地点 + occurTime: '', // 发生时间 + roadConditionType: '', // 路况类别 + routeNo: '', // 线路编号 + + // event 对象 + event: { + blockedMileage: '', // 阻断里程 + blockedPointName: '', // 阻断点小地名 + contactPerson: '', // 联系人 + contactPhone: '', // 联系电话 + damageCount: '', // 水毁处数 + district: '', // 上报区县 + endStakeLat: '', // 止点纬度 + endStakeLng: '', // 止点经度 + endStakeNo: '', // 止点桩号 + estimatedRecoveryCost: '', // 恢复重建预估费用 + inspectionMileage: '', // 巡查里程 + isBlocked: '', // 是否阻断 + needsRecovery: '', // 是否需要恢复重建 + repairProgress: '', // 抢修进度 + reporterUnit: '', // 填报单位 + startStakeLat: '', // 起点纬度 + startStakeLng: '', // 起点经度 + startStakeNo: '' // 起点桩号 + }, + + // report 对象 + report: { + actualRecoverTime: '', // 实际恢复时间 + damagedVehicleCount: '', // 损坏车辆 + deadCount: '', // 死亡人员 + disposalMeasures: '', // 处置措施(逗号分隔) + expectRecoverTime: '', // 预计恢复时间 + injuredCount: '', // 受伤人员 + investedFunds: '', // 已投资金 + investedMachinery: '', // 已投机械 + investedManpower: '', // 已投人力 + remark: '', // 处理情况/备注 + siteDescription: '', // 现场描述 + strandedPersonCount: '', // 滞留人员 + strandedVehicleCount: '', // 滞留车辆 + totalLossAmount: '' // 损失总金额 + }, + + // lossList 数组 + lossList: [], + + // fileList 数组 + fileList: [] }) +// 监听处置措施数组变化,转换为逗号分隔的字符串存到 report.disposalMeasures +watch( + disposalMeasuresArray, + (newVal) => { + formData.report.disposalMeasures = newVal.join(',') + }, + { deep: true } +) + +// 监听附件变化,同步到 fileList +watch( + imageFileList, + (newVal) => { + // 转换为接口需要的格式 + formData.fileList = [ + ...imageFileList.value.map((f) => ({ + fileName: f.file?.name || '', + fileSize: f.file?.size || 0, + fileType: 1, // 1-图片 + fileUrl: f.content || '' + })), + ...videoFileList.value.map((f) => ({ + fileName: f.file?.name || '', + fileSize: f.file?.size || 0, + fileType: 2, // 2-视频 + fileUrl: f.content || '' + })) + ] + }, + { deep: true } +) + +watch( + videoFileList, + (newVal) => { + formData.fileList = [ + ...imageFileList.value.map((f) => ({ + fileName: f.file?.name || '', + fileSize: f.file?.size || 0, + fileType: 1, + fileUrl: f.content || '' + })), + ...newVal.map((f) => ({ + fileName: f.file?.name || '', + fileSize: f.file?.size || 0, + fileType: 2, + fileUrl: f.content || '' + })) + ] + }, + { deep: true } +) + +// 从 report.disposalMeasures 初始化处置措施数组 +watch( + () => formData.report.disposalMeasures, + (newVal) => { + if (newVal && typeof newVal === 'string') { + disposalMeasuresArray.value = newVal.split(',').filter(Boolean) + } + }, + { immediate: true } +) + // BasePicker 选项数据 const roadConditionOptions = [ { label: '高速公路', value: '高速公路' }, @@ -252,40 +330,45 @@ const roadConditionOptions = [ ] const blockedOptions = [ - { label: '是', value: '是' }, - { label: '否', value: '否' } + { label: '是', value: true }, + { label: '否', value: false } ] const repairProgressOptions = [ - { label: '未开始', value: '未开始' }, - { label: '进行中', value: '进行中' }, - { label: '已抢通', value: '已抢通' }, - { label: '已修复', value: '已修复' } + { label: '未抢修', value: '未抢修' }, + { label: '抢修中', value: '抢修中' }, + { label: '已完成', value: '已完成' }, +] + +const needsRecoveryOptions = [ + { label: '是', value: true }, + { label: '否', value: false } ] // 时间选择器范围 const minDate = new Date(2020, 0, 1) const maxDate = new Date(2030, 11, 31) -// 监听父组件传入的数据 -watch( - () => props.modelValue, - (newVal) => { - if (newVal && Object.keys(newVal).length > 0) { - Object.assign(formData, newVal) - } - }, - { immediate: true, deep: true } -) +const initFormData = (newVal) => { + if (newVal && Object.keys(newVal).length > 0) { + // 深度合并数据 + Object.assign(formData, { + occurLocation: newVal.occurLocation || '', + occurTime: newVal.occurTime || '', + roadConditionType: newVal.roadConditionType || '', + routeNo: newVal.routeNo || '', + event: { ...formData.event, ...(newVal.event || {}) }, + report: { ...formData.report, ...(newVal.report || {}) }, + lossList: newVal.lossList || [], + fileList: newVal.fileList || [] + }) -// 监听表单数据变化,同步到父组件 -watch( - formData, - () => { - emit('update:modelValue', { ...formData }) - }, - { deep: true } -) + // 初始化处置措施数组 + if (newVal.report?.disposalMeasures) { + disposalMeasuresArray.value = newVal.report.disposalMeasures.split(',').filter(Boolean) + } + } +} // 校准时间 const calibrateTime = () => { @@ -297,15 +380,15 @@ const calibrateTime = () => { // 校准起点经纬度 const calibrateStartCoord = () => { - formData.startLongitude = '108.41763025' - formData.startLatitude = '108.41763025' + formData.event.startStakeLng = '108.41763025' + formData.event.startStakeLat = '108.41763025' showToast('起点经纬度已校准') } // 校准止点经纬度 const calibrateEndCoord = () => { - formData.endLongitude = '108.41763025' - formData.endLatitude = '108.41763025' + formData.event.endStakeLng = '108.41763025' + formData.event.endStakeLat = '108.41763025' showToast('止点经纬度已校准') } @@ -332,7 +415,7 @@ const validate = () => { showToast('请填写发生时间') return false } - if (!formData.lineCode) { + if (!formData.routeNo) { showToast('请填写线路编号') return false } @@ -347,6 +430,7 @@ const getFormData = () => { // 暴露方法给父组件 defineExpose({ validate, + initFormData, getFormData }) @@ -433,18 +517,8 @@ defineExpose({ margin-top: 12px; } - .loss-dialog-content { - padding: 8px 16px 16px; - .loss-calc-result { - font-size: 14px; - color: #1989fa; - margin-top: 12px; - text-align: center; - } - } - :deep(.van-field__label) { - width: 90px; + width: 110px; } } diff --git a/packages/mobile/src/views/DisasterManagement/waterDisasterFormData.json b/packages/mobile/src/views/DisasterManagement/waterDisasterFormData.json new file mode 100644 index 0000000..d17fc06 --- /dev/null +++ b/packages/mobile/src/views/DisasterManagement/waterDisasterFormData.json @@ -0,0 +1,63 @@ +{ + "occurLocation": "G108国道 K2250+300处", + "occurTime": "2024-07-15 14:30:00", + "roadConditionType": "国道", + "routeNo": "G108", + "event": { + "blockedMileage": 1.5, + "blockedPointName": "磨盘山隧道口", + "contactPerson": "张明", + "contactPhone": "13812345678", + "damageCount": 3, + "district": "武侯区", + "endStakeLat": "30.658712", + "endStakeLng": "104.082356", + "endStakeNo": "K2251+200", + "estimatedRecoveryCost": 120.5, + "inspectionMileage": 25.6, + "isBlocked": true, + "needsRecovery": true, + "repairProgress": "抢修中", + "reporterUnit": "武侯区交通运输局", + "startStakeLat": "30.652145", + "startStakeLng": "104.075632", + "startStakeNo": "K2250+300" + }, + "report": { + "damagedVehicleCount": 2, + "strandedPersonCount": 12, + "deadCount": 0, + "strandedVehicleCount": 12, + "disposalMeasures": "halfClose,bypass", + "actualRecoverTime": "2024-07-17 12:00:00", + "expectRecoverTime": "2024-07-18 18:00:00", + "injuredCount": 1, + "investedFunds": 35.8, + "investedMachinery": 6, + "investedManpower": 45, + "remark": "已组织抢险队伍进行抢通,便道已修建完成", + "siteDescription": "因持续强降雨导致山体滑坡,掩埋路面约50米,边坡垮塌严重", + "totalLossAmount": 85.6 + }, + "lossList": [ + { + "length": 50, + "width": 8.5, + "height": 2.5, + "unitPrice": 380, + "totalAmount": 38.9, + "lossCategory": "路面损毁", + "remark": "沥青路面严重损坏" + }, + { + "length": 30, + "width": 2.5, + "height": 6, + "unitPrice": 520, + "totalAmount": 23.4, + "lossCategory": "挡墙损毁", + "remark": "浆砌片石挡墙垮塌" + } + ], + "fileList": [] +} \ No newline at end of file