360 lines
9.6 KiB
Vue
360 lines
9.6 KiB
Vue
<template>
|
|
<div class="disaster-report">
|
|
<!-- 基本信息 -->
|
|
<PanelItem title="基本信息" v-if="!isContinue">
|
|
<!-- 发生时间 (顶层 occurTime) -->
|
|
<BaseDatePicker
|
|
v-model="formData.event.occurTime"
|
|
label="发生时间"
|
|
placeholder="请选择时间"
|
|
:columnsType="['year', 'month', 'day', 'hour', 'minute']"
|
|
/>
|
|
<!-- 校准时间 -->
|
|
<div class="calibrate-time-btn" @click="calibrateTime(true)">
|
|
<van-icon name="replay" />
|
|
<span>校准时间</span>
|
|
</div>
|
|
|
|
<!-- 线路编号 (顶层 routeNo) -->
|
|
<RoadRoutesPicker
|
|
v-model="formData.event.routeNo"
|
|
label="线路编号"
|
|
placeholder="请线路"
|
|
@change="handleRouteNoChange"
|
|
/>
|
|
|
|
<!-- 发生地点 (occurLocation) -->
|
|
<van-field v-model="formData.event.occurLocation" label="发生地点" placeholder="请填写" />
|
|
|
|
<!-- 起点桩号 (event.startStakeNo) -->
|
|
<van-field v-model="formData.event.startStakeNo" label="起点桩号(K)" placeholder="请填写" />
|
|
|
|
<!-- 止点桩号 (event.endStakeNo) -->
|
|
<van-field v-model="formData.event.endStakeNo" label="止点桩号(K)" placeholder="请填写" />
|
|
|
|
<!-- 受灾里程 (event.disasterMileage) -->
|
|
<van-field
|
|
v-model="formData.event.disasterMileage"
|
|
label="受灾里程"
|
|
placeholder="请填写"
|
|
type="digit"
|
|
>
|
|
<template #button>
|
|
<span class="field-unit">公里</span>
|
|
</template>
|
|
</van-field>
|
|
</PanelItem>
|
|
|
|
<PanelItem title="处置情况">
|
|
<van-field label="处置措施" label-align="top">
|
|
<template #input>
|
|
<van-row :gutter="5">
|
|
<van-col
|
|
v-for="(item, index) in options['iceDisposalMeasures']"
|
|
:span="8"
|
|
: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>
|
|
</template>
|
|
</van-field>
|
|
|
|
<BaseDatePicker
|
|
v-model="formData.report.expectRecoverTime"
|
|
label="预计恢复时间"
|
|
placeholder="请选择时间"
|
|
:min-date="minDate"
|
|
:max-date="maxDate"
|
|
type="datetime"
|
|
/>
|
|
</PanelItem>
|
|
|
|
<PanelItem title="实施情况">
|
|
<van-field
|
|
v-model="formData.report.inputManpower"
|
|
label="投入人力"
|
|
placeholder="请填写"
|
|
type="number"
|
|
>
|
|
<template #button>
|
|
<span class="field-unit">人次</span>
|
|
</template>
|
|
</van-field>
|
|
<van-field
|
|
v-model="formData.report.inputFunds"
|
|
label="投入资金"
|
|
placeholder="请填写"
|
|
type="digit"
|
|
>
|
|
<template #button>
|
|
<span class="field-unit">万元</span>
|
|
</template>
|
|
</van-field>
|
|
<van-field
|
|
v-model="formData.report.inputEquipment"
|
|
label="投入设备"
|
|
placeholder="请填写"
|
|
type="digit"
|
|
>
|
|
<template #button>
|
|
<span class="field-unit">台/班</span>
|
|
</template>
|
|
</van-field>
|
|
<!-- 物资选择 -->
|
|
<MaterialPicker v-model="formData.yhzMaterialList" />
|
|
|
|
<BasePicker
|
|
v-model="formData.report.hasStrandedVehicles"
|
|
:options="options['haveOrNot']"
|
|
label="有无车辆滞留"
|
|
placeholder="请选择"
|
|
/>
|
|
|
|
<van-field
|
|
v-if="formData.report.hasStrandedVehicles === 1"
|
|
v-model="formData.report.strandedVehicleCount"
|
|
type="number"
|
|
label="滞留车辆数"
|
|
center
|
|
placeholder="请填写"
|
|
/>
|
|
|
|
<BaseDatePicker
|
|
v-model="formData.report.actualRecoverTime"
|
|
label="实际恢复时间"
|
|
placeholder="请选择时间"
|
|
:min-date="minDate"
|
|
:max-date="maxDate"
|
|
type="datetime"
|
|
/>
|
|
<!-- 文件上传 -->
|
|
<DisasterFileUpload label="附件上传" v-model="formData.fileList" />
|
|
</PanelItem>
|
|
|
|
<!-- 提交按钮 -->
|
|
<van-button type="primary" class="footer-btn" @click="handleSubmit" :loading="submitting">
|
|
提交
|
|
</van-button>
|
|
</div>
|
|
</template>
|
|
<script setup>
|
|
import { ref, computed, onMounted } from 'vue';
|
|
import PanelItem from '@/components/PanelItem.vue';
|
|
import BasePicker from '@/components/BasePicker.vue';
|
|
import BaseDatePicker from '@/components/BaseDatePicker.vue';
|
|
import RoadRoutesPicker from '../components/RoadRoutesPicker.vue';
|
|
import MaterialPicker from '../components/MaterialPicker.vue';
|
|
import { useRoute } from 'vue-router';
|
|
import { request } from '@shared/utils/request';
|
|
import { useOptions } from '@shared/composables/useOptions';
|
|
import DisasterFileUpload from '../components/DisasterFileUpload.vue';
|
|
import { showToast, showFailToast, showLoadingToast, showSuccessToast } from 'vant';
|
|
import { formatDate } from '@shared/utils';
|
|
|
|
const route = useRoute();
|
|
const { options } = useOptions();
|
|
|
|
// 是否为续报
|
|
const isContinue = computed(() => route.query.isContinue);
|
|
|
|
const minDate = new Date();
|
|
const maxDate = new Date(2050, 11, 31);
|
|
|
|
const formData = ref({
|
|
event: {},
|
|
report: {},
|
|
fileList: [],
|
|
yhzMaterialList: [],
|
|
});
|
|
|
|
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 = {}) => {
|
|
formData.event.routeNo = item.routeCode;
|
|
formData.event.startStakeNo = item.startStakeNo;
|
|
formData.event.endStakeNo = item.endStakeNo;
|
|
|
|
const startPoint = parsePointValue(item.startPoint ?? item.startpoint);
|
|
const endPoint = parsePointValue(item.endPoint ?? item.endpoint);
|
|
|
|
formData.event.startStakeLng = startPoint.longitude;
|
|
formData.event.startStakeLat = startPoint.latitude;
|
|
formData.event.endStakeLng = endPoint.longitude;
|
|
formData.event.endStakeLat = endPoint.latitude;
|
|
};
|
|
|
|
const calibrateTime = isShowToast => {
|
|
formData.value.event.occurTime = formatDate(Date.now());
|
|
if (isShowToast) showToast('时间已校准为当前时间');
|
|
};
|
|
|
|
const validate = () => {
|
|
return true;
|
|
};
|
|
|
|
const submitting = ref(false);
|
|
const handleSubmit = async () => {
|
|
// 验证表单
|
|
if (!validate()) return;
|
|
|
|
submitting.value = true;
|
|
try {
|
|
// 添加事件类型和站点信息
|
|
const submitData = {
|
|
...formData.value,
|
|
// 可以在这里添加站点信息等其他数据
|
|
};
|
|
|
|
let apiUrl = formData.id ? '/snow-ops-platform/event/dispose' : '/snow-ops-platform/event/report'
|
|
const res = await request({
|
|
url: apiUrl,
|
|
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(() => {
|
|
if (isContinue) router.go(-1);
|
|
else router.replace('/disasterManagement');
|
|
}, 500);
|
|
}
|
|
} else {
|
|
showFailToast(res.message);
|
|
}
|
|
} catch (error) {
|
|
showFailToast('提交失败,请重试');
|
|
console.error('提交失败:', error);
|
|
} finally {
|
|
submitting.value = false;
|
|
}
|
|
};
|
|
const detailData = ref(null);
|
|
const getDisasterDetail = async () => {
|
|
const id = route.query.id;
|
|
if (!id) {
|
|
ElMessage.warning('缺少灾毁ID');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const result = await request({
|
|
url: `/snow-ops-platform/event/getById`,
|
|
method: 'get',
|
|
params: {
|
|
id,
|
|
},
|
|
});
|
|
|
|
if (result?.data) {
|
|
const data = result.data;
|
|
data.reportList = undefined;
|
|
data.report = {};
|
|
data.yhzMaterialList = [];
|
|
data.fileList = [];
|
|
detailData.value = data;
|
|
formData.value = data;
|
|
} else {
|
|
ElMessage.warning(result.message || '获取详情失败');
|
|
}
|
|
} catch (error) {
|
|
console.error('获取灾毁详情失败:', error);
|
|
ElMessage.error('获取详情失败,请稍后重试');
|
|
}
|
|
};
|
|
|
|
onMounted(() => {
|
|
calibrateTime();
|
|
|
|
if (isContinue.value) {
|
|
getDisasterDetail();
|
|
}
|
|
});
|
|
</script>
|
|
<style scoped lang="scss">
|
|
.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;
|
|
}
|
|
.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>
|