Merge branch 'dev' of http://222.212.85.86:8222/bdzl2/bxztApp into dev
This commit is contained in:
commit
5e90481aaa
@ -190,7 +190,6 @@ const formData = ref({
|
|||||||
district: '', // 上报区县
|
district: '', // 上报区县
|
||||||
endStakeNo: '', // 止点桩号
|
endStakeNo: '', // 止点桩号
|
||||||
estimatedRecoveryCost: '', // 恢复重建预估费用
|
estimatedRecoveryCost: '', // 恢复重建预估费用
|
||||||
inspectionMileage: '', // 巡查里程
|
|
||||||
isBlocked: '', // 是否阻断
|
isBlocked: '', // 是否阻断
|
||||||
needsRecovery: '', // 是否需要恢复重建
|
needsRecovery: '', // 是否需要恢复重建
|
||||||
repairProgress: '', // 抢险进度
|
repairProgress: '', // 抢险进度
|
||||||
|
|||||||
@ -102,12 +102,6 @@
|
|||||||
<span class="info-value">{{ detailData.event?.district || '-' }}</span>
|
<span class="info-value">{{ detailData.event?.district || '-' }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 巡查里程 -->
|
|
||||||
<div class="info-row">
|
|
||||||
<span class="info-label">巡查里程:</span>
|
|
||||||
<span class="info-value">{{ detailData.event?.inspectionMileage ? detailData.event.inspectionMileage + '公里' : '-' }}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 是否恢复重建 -->
|
<!-- 是否恢复重建 -->
|
||||||
<div class="info-row">
|
<div class="info-row">
|
||||||
<span class="info-label">是否恢复重建:</span>
|
<span class="info-label">是否恢复重建:</span>
|
||||||
|
|||||||
@ -12,7 +12,6 @@
|
|||||||
"district": "武侯区",
|
"district": "武侯区",
|
||||||
"endStakeNo": "K2251+200",
|
"endStakeNo": "K2251+200",
|
||||||
"estimatedRecoveryCost": 120.5,
|
"estimatedRecoveryCost": 120.5,
|
||||||
"inspectionMileage": 25.6,
|
|
||||||
"isBlocked": true,
|
"isBlocked": true,
|
||||||
"needsRecovery": true,
|
"needsRecovery": true,
|
||||||
"repairProgress": "抢险中",
|
"repairProgress": "抢险中",
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, watch, ref, provide } from 'vue'
|
import { onMounted, watch, ref, provide, computed } from 'vue'
|
||||||
import DynamicFormItem from './DynamicFormItem.vue'
|
import DynamicFormItem from './DynamicFormItem.vue'
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
configList: {
|
configList: {
|
||||||
|
|||||||
@ -46,7 +46,7 @@ export default () => {
|
|||||||
const firstMenuItem = menuList.value[0]?.children?.[0];
|
const firstMenuItem = menuList.value[0]?.children?.[0];
|
||||||
if (firstMenuItem) {
|
if (firstMenuItem) {
|
||||||
// 注释掉进入页面点击第一项的逻辑 后续记得打开
|
// 注释掉进入页面点击第一项的逻辑 后续记得打开
|
||||||
// handleMenuClick(firstMenuItem);
|
handleMenuClick(firstMenuItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, { immediate: true });
|
}, { immediate: true });
|
||||||
|
|||||||
5
packages/screen/src/directive/index.js
Normal file
5
packages/screen/src/directive/index.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import hasPermi from './permission/hasPermi'
|
||||||
|
|
||||||
|
export default function directive(app){
|
||||||
|
app.directive('hasPermi', hasPermi)
|
||||||
|
}
|
||||||
27
packages/screen/src/directive/permission/hasPermi.js
Normal file
27
packages/screen/src/directive/permission/hasPermi.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/**
|
||||||
|
* v-hasPermi 操作权限处理
|
||||||
|
* Copyright (c) 2019 ruoyi
|
||||||
|
*/
|
||||||
|
import useUserStore from '@flightweb/store/modules/user'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
mounted(el, binding, vnode) {
|
||||||
|
const { value } = binding
|
||||||
|
const all_permission = "*:*:*"
|
||||||
|
const permissions = useUserStore().permissions
|
||||||
|
|
||||||
|
if (value && value instanceof Array && value.length > 0) {
|
||||||
|
const permissionFlag = value
|
||||||
|
|
||||||
|
const hasPermissions = permissions.some(permission => {
|
||||||
|
return all_permission === permission || permissionFlag.includes(permission)
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!hasPermissions) {
|
||||||
|
el.parentNode && el.parentNode.removeChild(el)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error(`请设置操作权限标签值`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -190,6 +190,17 @@ const routes = [
|
|||||||
parentRoute: 'warningManagement3'
|
parentRoute: 'warningManagement3'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/messageManagement',
|
||||||
|
name: 'messageManagement',
|
||||||
|
component: () => import('../views/WarningManagement/law/messageManagement/index.vue'),
|
||||||
|
meta: {
|
||||||
|
title: '消息推送设置',
|
||||||
|
breadcrumb: true,
|
||||||
|
parentRoute: 'warningManagement3'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
// 项目管理 - 区县
|
// 项目管理 - 区县
|
||||||
{
|
{
|
||||||
|
|||||||
13
packages/screen/src/store/userStore.js
Normal file
13
packages/screen/src/store/userStore.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { defineStore } from 'pinia'
|
||||||
|
|
||||||
|
export const useUserStore = defineStore('user', {
|
||||||
|
state: {
|
||||||
|
|
||||||
|
},
|
||||||
|
getters: {
|
||||||
|
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
|
||||||
|
}
|
||||||
|
})
|
||||||
@ -166,7 +166,6 @@ const formData = reactive({
|
|||||||
district: '',
|
district: '',
|
||||||
endStakeNo: '',
|
endStakeNo: '',
|
||||||
estimatedRecoveryCost: '',
|
estimatedRecoveryCost: '',
|
||||||
inspectionMileage: '',
|
|
||||||
isBlocked: '',
|
isBlocked: '',
|
||||||
needsRecovery: '',
|
needsRecovery: '',
|
||||||
repairProgress: '',
|
repairProgress: '',
|
||||||
@ -325,7 +324,6 @@ const resetForm = () => {
|
|||||||
district: '',
|
district: '',
|
||||||
endStakeNo: '',
|
endStakeNo: '',
|
||||||
estimatedRecoveryCost: '',
|
estimatedRecoveryCost: '',
|
||||||
inspectionMileage: '',
|
|
||||||
isBlocked: '',
|
isBlocked: '',
|
||||||
needsRecovery: '',
|
needsRecovery: '',
|
||||||
repairProgress: '',
|
repairProgress: '',
|
||||||
|
|||||||
@ -1,9 +1,64 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="web-detail-container">
|
<div class="web-detail-container">
|
||||||
|
|
||||||
<div class="content-container">
|
<div class="content-container">
|
||||||
<div class="left-panel">
|
<div class="left-panel">
|
||||||
<DynamicDetail v-model="detailData" :config-list="detailConfig" />
|
<!-- 基本信息卡片 -->
|
||||||
|
<el-card class="info-card" shadow="never">
|
||||||
|
<template #header>
|
||||||
|
<div class="card-header">
|
||||||
|
<span class="card-title">基本信息</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<el-row :gutter="20" class="info-row">
|
||||||
|
<el-col :span="8">
|
||||||
|
<div class="info-item">
|
||||||
|
<span class="info-label">事件类型:</span>
|
||||||
|
<span class="info-value">冰雪事件</span>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<div class="info-item">
|
||||||
|
<span class="info-label">所属服务站:</span>
|
||||||
|
<span class="info-value">{{}}</span>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<div class="info-item">
|
||||||
|
<span class="info-label">线路编号:</span>
|
||||||
|
<span class="info-value">{{}}</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">冰雪事件</span>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<div class="info-item">
|
||||||
|
<span class="info-label">路况位置:</span>
|
||||||
|
<span class="info-value">{{}}</span>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<div class="info-item">
|
||||||
|
<span class="info-label">发生地点:</span>
|
||||||
|
<span class="info-value">{{}}</span>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-card>
|
||||||
|
<!-- 填报情况 -->
|
||||||
|
<el-card class="info-card" shadow="never">
|
||||||
|
<template #header>
|
||||||
|
<div class="card-header">
|
||||||
|
<span class="card-title">填报情况</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</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" />
|
||||||
@ -20,8 +75,6 @@ import { ArrowLeft, Picture, VideoCamera } from '@element-plus/icons-vue'
|
|||||||
import ContinueReport from './IceDisasterContinueReportPC.vue'
|
import ContinueReport from './IceDisasterContinueReportPC.vue'
|
||||||
import { request } from '@shared/utils/request'
|
import { request } from '@shared/utils/request'
|
||||||
import FileUpload from '@/component/FileUpload/FileUpload.vue'
|
import FileUpload from '@/component/FileUpload/FileUpload.vue'
|
||||||
import detailConfig from './detailConfig'
|
|
||||||
import DynamicDetail from '@/component/DynamicDetail/DynamicDetail.vue'
|
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
@ -68,7 +121,6 @@ const hasReportData = computed(() => {
|
|||||||
return allReports.value.length > 0
|
return allReports.value.length > 0
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
// 获取灾毁详情
|
// 获取灾毁详情
|
||||||
const getDisasterDetail = async () => {
|
const getDisasterDetail = async () => {
|
||||||
const id = route.query.id
|
const id = route.query.id
|
||||||
@ -80,7 +132,7 @@ const getDisasterDetail = async () => {
|
|||||||
try {
|
try {
|
||||||
const result = await request({
|
const result = await request({
|
||||||
url: `/snow-ops-platform/event/getById?id=${route.query.id}`,
|
url: `/snow-ops-platform/event/getById?id=${route.query.id}`,
|
||||||
method: 'get',
|
method: 'get'
|
||||||
})
|
})
|
||||||
|
|
||||||
if (result?.data) {
|
if (result?.data) {
|
||||||
|
|||||||
@ -1,111 +0,0 @@
|
|||||||
export default [
|
|
||||||
{
|
|
||||||
type: 'card',
|
|
||||||
label: '基础信息',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
type: 'row',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
span: 8,
|
|
||||||
label: '事件类型',
|
|
||||||
value: '冰雪事件',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
span: 8,
|
|
||||||
label: '路况类别',
|
|
||||||
prop: 'event.routeNo'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
span: 8,
|
|
||||||
label: '处理措施',
|
|
||||||
prop: 'event.disposalMeasures'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'row',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
span: 8,
|
|
||||||
label: '地点路线',
|
|
||||||
prop: 'event.occurLocation'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
span: 8,
|
|
||||||
label: '起点桩号',
|
|
||||||
prop: 'event.startStakeNo'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
span: 8,
|
|
||||||
label: '止点桩号',
|
|
||||||
prop: 'event.endStakeNo'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'row',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
span: 8,
|
|
||||||
label: '路况位置',
|
|
||||||
prop: 'event.occurLocation'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
span: 8,
|
|
||||||
label: '阻断点小地名',
|
|
||||||
prop: 'event.occurLocation'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
span: 8,
|
|
||||||
label: '地点路线',
|
|
||||||
prop: 'event.occurLocation'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'row',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
span: 24,
|
|
||||||
label: '受灾里程',
|
|
||||||
prop: 'event.disasterMileage'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'row',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
span: 8,
|
|
||||||
label: '所属区县',
|
|
||||||
prop: 'event.district'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
span: 8,
|
|
||||||
label: '发现时间',
|
|
||||||
prop: 'event.occurTime'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'row',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
span: 8,
|
|
||||||
label: '是否需要恢复重建',
|
|
||||||
prop: 'event.actualRecoverTime'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
show: (formData) => {
|
|
||||||
return formData.event?.actualRecoverTime
|
|
||||||
},
|
|
||||||
span: 8,
|
|
||||||
label: '恢复重建预估费用(万元)',
|
|
||||||
prop: 'event.estimatedRecoveryCost'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
@ -1,83 +1,50 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="disaster-form-page">
|
<div class="disaster-form-page">
|
||||||
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="140px" 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">
|
||||||
<span class="section-title">基本信息</span>
|
<span class="section-title">基础信息</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<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.reporterUnit">
|
<el-form-item label="填报单位" prop="event.reporterUnit">
|
||||||
<el-input v-model="formData.event.reporterUnit" placeholder="请填写" />
|
<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.contactPerson">
|
<el-form-item label="联系人员" prop="event.contactPerson">
|
||||||
<el-input v-model="formData.event.contactPerson" 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.contactPhone">
|
<el-form-item label="联系电话" prop="event.contactPhone">
|
||||||
<el-input v-model="formData.event.contactPhone" 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>
|
||||||
</BlockItem>
|
</BlockItem>
|
||||||
|
|
||||||
<BlockItem title="路况事件信息">
|
<BlockItem title="路况事件信息">
|
||||||
<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="roadConditionType">
|
|
||||||
<el-select v-model="formData.roadConditionType" placeholder="请选择" style="width: 100%">
|
|
||||||
<el-option v-for="(option, idx) in options['iceRoadConditionType']" :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-row>
|
|
||||||
<el-row :gutter="24">
|
<el-row :gutter="24">
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<el-form-item label="事件类型">
|
<el-form-item label="事件类型">
|
||||||
<el-select v-model="eventType" placeholder="请选择" style="width: 100%" @change="handleEventTypeChange">
|
<el-select v-model="eventType" style="width: 100%" @change="handleEventTypeChange">
|
||||||
<el-option v-for="(option, idx) in options['eventType']" :label="option.label" :value="option.value" :key="idx" />
|
<el-option v-for="(option, idx) in options['eventType']" :key="idx" :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.expectRecoverTime">
|
<el-form-item label="填报站点" prop="event.serviceStationId">
|
||||||
<el-date-picker v-model="formData.report.expectRecoverTime" type="datetime" placeholder="请选择时间" style="width: 100%" value-format="YYYY-MM-DD HH:mm:ss" />
|
<YHZSelect v-model="formData.event.serviceStationId" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
<el-col :span="8">
|
||||||
<el-row :gutter="24"> </el-row>
|
<el-form-item label="发生时间" prop="occurTime">
|
||||||
<el-row :gutter="24">
|
<el-date-picker v-model="formData.occurTime" type="datetime" placeholder="请选择日期时间" style="width: 100%" value-format="YYYY-MM-DD HH:mm:ss" />
|
||||||
<!-- 现场描述 -->
|
|
||||||
<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-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
@ -85,90 +52,85 @@
|
|||||||
|
|
||||||
<BlockItem title="位置信息">
|
<BlockItem title="位置信息">
|
||||||
<el-row :gutter="24">
|
<el-row :gutter="24">
|
||||||
<!-- 路线类型 -->
|
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<el-form-item label="路线类型">
|
<el-form-item label="路线类型">
|
||||||
<el-select v-model="filterForm.routeType" placeholder="请选择" style="width: 100%">
|
<el-input :model-value="routeTypeLabel" readonly />
|
||||||
<el-option v-for="(option, idx) in options['roadType']" :label="option.label" :value="option.value" :key="idx" />
|
|
||||||
</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="event.district">
|
<el-form-item label="所属区县" prop="event.district">
|
||||||
<el-select v-model="formData.event.district" placeholder="请选择" style="width: 100%" @change="handleDistrictChange">
|
<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-option v-for="(option, idx) in options['area']" :key="idx" :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="event.disasterMileage">
|
<el-form-item label="线路编号" prop="routeNo">
|
||||||
<el-input v-model="formData.event.disasterMileage" placeholder="请填写" />
|
<RoadRoutesSelect v-model="formData.routeNo" :extra-params="{ xzdj: filterForm.routeType, qxid: formData.event.district }" @change="handleRouteNoChange" />
|
||||||
</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="routeNo">
|
<el-form-item label="发生地点" prop="event.occurLocation">
|
||||||
<RoadRoutesSelect v-model="formData.routeNo" @change="handleRouteNoChange" :extra-params="{ xzdj: filterForm.routeType, qxid: formData.event.district }" />
|
<el-input v-model="formData.event.occurLocation" placeholder="请填写" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<!-- 起点桩号 -->
|
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<el-form-item label="起点桩号(K)" prop="event.startStakeNo">
|
<el-form-item label="路况位置" prop="occurLocation">
|
||||||
|
<el-input v-model="formData.occurLocation" placeholder="请选择">
|
||||||
|
<template #suffix>
|
||||||
|
<el-icon class="location-icon"><LocationFilled /></el-icon>
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="起点桩号" prop="event.startStakeNo">
|
||||||
<el-input v-model="formData.event.startStakeNo" placeholder="请填写">
|
<el-input v-model="formData.event.startStakeNo" placeholder="请填写">
|
||||||
<template #prepend>K</template>
|
<template #prepend>K</template>
|
||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<!-- 止点桩号 -->
|
</el-row>
|
||||||
|
|
||||||
|
<el-row :gutter="24">
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<el-form-item label="止点桩号(K)" prop="event.endStakeNo">
|
<el-form-item label="起点桩经度" prop="event.startStakeLongitude">
|
||||||
|
<el-input v-model="formData.event.startStakeLongitude" placeholder="请填写" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="起点桩纬度" prop="event.startStakeLatitude">
|
||||||
|
<el-input v-model="formData.event.startStakeLatitude" placeholder="请填写" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="止点桩号" prop="event.endStakeNo">
|
||||||
<el-input v-model="formData.event.endStakeNo" placeholder="请填写">
|
<el-input v-model="formData.event.endStakeNo" placeholder="请填写">
|
||||||
<template #prepend>K</template>
|
<template #prepend>K</template>
|
||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</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-row :gutter="24">
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<el-form-item label="图片上传" prop="fileList">
|
<el-form-item label="止点桩经度" prop="event.endStakeLongitude">
|
||||||
<FileUpload type="image" :limit="9" v-model="formData.fileList" />
|
<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="fileList">
|
<el-form-item label="止点桩纬度" prop="event.endStakeLatitude">
|
||||||
<FileUpload type="video" :limit="9" v-model="formData.fileList" />
|
<el-input v-model="formData.event.endStakeLatitude" placeholder="请填写" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="受灾里程" prop="event.disasterMileage">
|
||||||
|
<el-input v-model="formData.event.disasterMileage" placeholder="请填写">
|
||||||
|
<template #append>公里</template>
|
||||||
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
@ -178,440 +140,151 @@
|
|||||||
<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">
|
||||||
<span class="section-title">灾毁损失</span>
|
<span class="section-title">处置情况</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<BlockItem title="路况事件信息">
|
|
||||||
|
<BlockItem>
|
||||||
<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.disposalMeasures">
|
||||||
<el-input-number v-model="formData.report.injuredCount" :min="0" :step="1" style="width: 100%">
|
<el-select v-model="formData.report.disposalMeasures" placeholder="请选择" style="width: 100%">
|
||||||
<template #suffix>
|
<el-option v-for="(option, idx) in options['iceDisposalMeasures']" :key="idx" :label="option.label" :value="option.value" />
|
||||||
<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-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
<!-- 恢复重建预估费用 -->
|
<el-form-item label="预计恢复时间" prop="report.expectRecoverTime">
|
||||||
<el-col :span="8" v-if="formData?.event.needsRecovery">
|
<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 label="恢复重建预估费用" prop="event.estimatedRecoveryCost">
|
</el-form-item>
|
||||||
<el-input-number v-model="formData.event.estimatedRecoveryCost" :min="0" :precision="2" style="width: 100%" placeholder="请填写">
|
</el-col>
|
||||||
<template #suffix>
|
<el-col :span="8">
|
||||||
<span class="unit-text">万元</span>
|
<el-form-item label="实际预计恢复时间" prop="report.actualRecoverTime">
|
||||||
</template>
|
<el-date-picker v-model="formData.report.actualRecoverTime" type="datetime" placeholder="请选择日期时间" style="width: 100%" value-format="YYYY-MM-DD HH:mm:ss" />
|
||||||
</el-input-number>
|
</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>
|
||||||
|
<MaterialList v-model="formData.yhzMaterialList" :yhzId="formData.event.serviceStationId" />
|
||||||
|
|
||||||
|
<el-row :gutter="24">
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="投入人力" prop="material.inputManpower">
|
||||||
|
<el-input-number v-model="formData.material.inputManpower" :min="0" :step="1" :controls="false" placeholder="请填写" 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="material.inputFunds">
|
||||||
|
<el-input-number v-model="formData.material.inputFunds" :min="0" :precision="2" :controls="false" placeholder="请填写" 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="material.inputEquipment">
|
||||||
|
<el-input-number v-model="formData.material.inputEquipment" :min="0" :precision="1" :controls="false" placeholder="请填写" style="width: 100%">
|
||||||
|
<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="traffic.hasStrandedVehicles">
|
||||||
|
<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-select>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="滞留车辆" prop="traffic.strandedVehicleCount">
|
||||||
|
<el-input-number v-model="formData.traffic.strandedVehicleCount" :min="0" :step="1" :controls="false" placeholder="请填写" style="width: 100%">
|
||||||
|
<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="18">
|
||||||
|
<el-form-item label="现场情况描述" prop="report.siteDescription">
|
||||||
|
<el-input v-model="formData.report.siteDescription" type="textarea" :rows="3" placeholder="请填写" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<el-row :gutter="24">
|
||||||
|
<el-col :span="16">
|
||||||
|
<el-form-item label="附件上传" prop="fileList">
|
||||||
|
<div class="upload-wrapper">
|
||||||
|
<div class="upload-title">图片上传</div>
|
||||||
|
<FileUpload v-model="formData.fileList" type="image" :limit="9" />
|
||||||
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</BlockItem>
|
</BlockItem>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<!-- 提交按钮 -->
|
|
||||||
<div class="form-actions">
|
<div class="form-actions">
|
||||||
<el-button @click="handleBack">取消</el-button>
|
<el-button @click="handleBack">取消</el-button>
|
||||||
<el-button type="primary" @click="handleSubmit" :loading="submitting">提交</el-button>
|
<el-button type="primary" :loading="submitting" @click="handleSubmit">提交</el-button>
|
||||||
</div>
|
</div>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
|
||||||
<!-- 图片预览对话框 -->
|
|
||||||
<el-dialog v-model="previewDialogVisible" title="图片预览" width="600px">
|
|
||||||
<img :src="previewImageUrl" style="width: 100%" alt="预览图片" />
|
|
||||||
</el-dialog>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, reactive, computed, watch, onMounted } from 'vue'
|
import { LocationFilled } from '@element-plus/icons-vue'
|
||||||
import { useRouter, useRoute } from 'vue-router'
|
|
||||||
import { ElMessage } from 'element-plus'
|
|
||||||
import { Plus, Upload } from '@element-plus/icons-vue'
|
|
||||||
import { request } from '@/utils/request'
|
|
||||||
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 { useOptions } from '@shared/composables/useOptions'
|
|
||||||
import RoadRoutesSelect from '../components/RoadRoutesSelect.vue'
|
import RoadRoutesSelect from '../components/RoadRoutesSelect.vue'
|
||||||
|
import YHZSelect from '../components/YHZSelect.vue'
|
||||||
|
import MaterialList from '../components/MaterialList.vue'
|
||||||
|
import { useIceDisasterReport } from './useIceDisasterReport'
|
||||||
|
|
||||||
const router = useRouter()
|
const {
|
||||||
const route = useRoute()
|
eventType,
|
||||||
const { options, getAreaOptions } = useOptions()
|
filterForm,
|
||||||
const formRef = ref(null)
|
formData,
|
||||||
const submitting = ref(false)
|
formRef,
|
||||||
|
formRules,
|
||||||
|
handleBack,
|
||||||
|
handleDistrictChange,
|
||||||
|
handleEventTypeChange,
|
||||||
|
handleRouteNoChange,
|
||||||
|
handleSubmit,
|
||||||
|
initFormData,
|
||||||
|
getFormData,
|
||||||
|
options,
|
||||||
|
routeTypeLabel,
|
||||||
|
strandedVehicleOptions,
|
||||||
|
submitting,
|
||||||
|
handleHasStrandedVehiclesChange,
|
||||||
|
validate
|
||||||
|
} = useIceDisasterReport()
|
||||||
|
|
||||||
// 是否为续报
|
|
||||||
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, // 联系电话
|
|
||||||
district: null, // 上报区县
|
|
||||||
endStakeNo: null, // 止点桩号
|
|
||||||
estimatedRecoveryCost: null, // 恢复重建预估费用
|
|
||||||
inspectionMileage: null, // 巡查里程
|
|
||||||
needsRecovery: null, // 是否需要恢复重建
|
|
||||||
reporterUnit: null, // 填报单位
|
|
||||||
startStakeNo: null, // 起点桩号
|
|
||||||
disasterMileage: 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: '/waterDisasterReport' })
|
|
||||||
}
|
|
||||||
|
|
||||||
// 监听处置措施数组变化,转换为逗号分隔的字符串存到 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' }],
|
|
||||||
'report.disposalMeasures': [{ required: true, message: '请选择处置措施', trigger: 'change' }],
|
|
||||||
'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 () => {
|
|
||||||
initFormData({})
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
// 获取区县下拉列表
|
|
||||||
getAreaOptions()
|
|
||||||
|
|
||||||
loadEditData()
|
|
||||||
})
|
|
||||||
|
|
||||||
// 暴露方法给父组件
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
validate,
|
validate,
|
||||||
initFormData,
|
initFormData,
|
||||||
@ -625,74 +298,65 @@ defineExpose({
|
|||||||
background-color: #f5f7fa;
|
background-color: #f5f7fa;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
.disaster-form {
|
.form-section {
|
||||||
.form-section {
|
margin-bottom: 20px;
|
||||||
margin-bottom: 20px;
|
|
||||||
|
|
||||||
:deep(.el-card__header) {
|
:deep(.el-card__header) {
|
||||||
padding: 12px 20px;
|
padding: 12px 20px;
|
||||||
background-color: #fafafa;
|
background-color: #fafafa;
|
||||||
border-bottom: 1px solid #ebeef5;
|
border-bottom: 1px solid #ebeef5;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.el-card__body) {
|
:deep(.el-card__body) {
|
||||||
padding: 20px;
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.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;
|
||||||
|
border-radius: 2px;
|
||||||
|
background-color: #409eff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.location-icon {
|
||||||
|
color: #909399;
|
||||||
|
}
|
||||||
|
|
||||||
|
.unit-text {
|
||||||
|
color: #606266;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-wrapper {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.upload-title {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
color: #303133;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 16px;
|
||||||
|
padding: 8px 0 32px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -0,0 +1,336 @@
|
|||||||
|
import { computed, onMounted, reactive, ref } from 'vue'
|
||||||
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import { request } from '@/utils/request'
|
||||||
|
import { useOptions } from '@shared/composables/useOptions'
|
||||||
|
|
||||||
|
const DEFAULT_REPORTER_UNIT = '万州区公路中心'
|
||||||
|
|
||||||
|
const createDefaultFormData = () => ({
|
||||||
|
occurLocation: '',
|
||||||
|
occurTime: '',
|
||||||
|
routeNo: '',
|
||||||
|
event: {
|
||||||
|
contactPerson: '',
|
||||||
|
contactPhone: '',
|
||||||
|
disasterMileage: null,
|
||||||
|
district: '',
|
||||||
|
endStakeLatitude: null,
|
||||||
|
endStakeLongitude: null,
|
||||||
|
endStakeNo: '',
|
||||||
|
occurLocation: '',
|
||||||
|
reporterUnit: DEFAULT_REPORTER_UNIT,
|
||||||
|
serviceStationId: '',
|
||||||
|
startStakeLatitude: null,
|
||||||
|
startStakeLongitude: null,
|
||||||
|
startStakeNo: ''
|
||||||
|
},
|
||||||
|
material: {
|
||||||
|
inputEquipment: null,
|
||||||
|
inputFunds: null,
|
||||||
|
inputManpower: null
|
||||||
|
},
|
||||||
|
report: {
|
||||||
|
actualRecoverTime: '',
|
||||||
|
disposalMeasures: '',
|
||||||
|
expectRecoverTime: '',
|
||||||
|
siteDescription: ''
|
||||||
|
},
|
||||||
|
traffic: {
|
||||||
|
hasStrandedVehicles: null,
|
||||||
|
strandedVehicleCount: null
|
||||||
|
},
|
||||||
|
fileList: []
|
||||||
|
})
|
||||||
|
|
||||||
|
const mergeFormData = (source = {}) => {
|
||||||
|
const defaults = createDefaultFormData()
|
||||||
|
const merged = {
|
||||||
|
...defaults,
|
||||||
|
...source,
|
||||||
|
event: {
|
||||||
|
...defaults.event,
|
||||||
|
...(source.event || {})
|
||||||
|
},
|
||||||
|
material: {
|
||||||
|
...defaults.material,
|
||||||
|
...(source.material || {})
|
||||||
|
},
|
||||||
|
report: {
|
||||||
|
...defaults.report,
|
||||||
|
...(source.report || {})
|
||||||
|
},
|
||||||
|
traffic: {
|
||||||
|
...defaults.traffic,
|
||||||
|
...(source.traffic || {})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
merged.fileList = Array.isArray(source.fileList) ? source.fileList : defaults.fileList
|
||||||
|
|
||||||
|
if (!merged.event.reporterUnit) {
|
||||||
|
merged.event.reporterUnit = DEFAULT_REPORTER_UNIT
|
||||||
|
}
|
||||||
|
|
||||||
|
return merged
|
||||||
|
}
|
||||||
|
|
||||||
|
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 }
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useIceDisasterReport = () => {
|
||||||
|
const router = useRouter()
|
||||||
|
const route = useRoute()
|
||||||
|
const { options, getAreaOptions } = useOptions()
|
||||||
|
|
||||||
|
const formRef = ref(null)
|
||||||
|
const submitting = ref(false)
|
||||||
|
const eventType = ref('冰雪事件')
|
||||||
|
const filterForm = reactive({
|
||||||
|
routeType: ''
|
||||||
|
})
|
||||||
|
const formData = reactive(createDefaultFormData())
|
||||||
|
const strandedVehicleOptions = [
|
||||||
|
{ label: '有', value: 1 },
|
||||||
|
{ label: '无', value: 0 }
|
||||||
|
]
|
||||||
|
|
||||||
|
const routeTypeLabel = computed(() => {
|
||||||
|
const matched = options.value.roadType?.find((item) => item.value === filterForm.routeType)
|
||||||
|
return matched?.label || '国省道'
|
||||||
|
})
|
||||||
|
|
||||||
|
const formRules = {
|
||||||
|
'event.contactPerson': [{ required: true, message: '请输入联系人员', trigger: 'blur' }],
|
||||||
|
'event.contactPhone': [
|
||||||
|
{ required: true, message: '请输入联系电话', trigger: 'blur' },
|
||||||
|
{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的联系电话', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
'event.serviceStationId': [{ required: true, message: '请选择填报站点', trigger: 'change' }],
|
||||||
|
occurTime: [{ required: true, message: '请选择发生时间', trigger: 'change' }],
|
||||||
|
'event.district': [{ required: true, message: '请选择所属区县', trigger: 'change' }],
|
||||||
|
routeNo: [{ required: true, message: '请选择线路编号', trigger: 'change' }],
|
||||||
|
'event.occurLocation': [{ required: true, message: '请输入发生地点', trigger: 'blur' }],
|
||||||
|
occurLocation: [{ required: true, message: '请选择路况位置', trigger: 'blur' }],
|
||||||
|
'event.startStakeNo': [{ required: true, message: '请输入起点桩号', trigger: 'blur' }],
|
||||||
|
'event.startStakeLongitude': [{ required: true, message: '请输入起点桩经度', trigger: 'blur' }],
|
||||||
|
'event.startStakeLatitude': [{ required: true, message: '请输入起点桩纬度', trigger: 'blur' }],
|
||||||
|
'event.endStakeNo': [{ required: true, message: '请输入止点桩号', trigger: 'blur' }],
|
||||||
|
'event.endStakeLongitude': [{ required: true, message: '请输入止点桩经度', trigger: 'blur' }],
|
||||||
|
'event.endStakeLatitude': [{ required: true, message: '请输入止点桩纬度', trigger: 'blur' }],
|
||||||
|
'event.disasterMileage': [{ required: true, message: '请输入受灾里程', trigger: 'blur' }],
|
||||||
|
'report.disposalMeasures': [{ required: true, message: '请选择处理措施', trigger: 'change' }],
|
||||||
|
'report.siteDescription': [{ required: true, message: '请输入现场情况描述', trigger: 'blur' }],
|
||||||
|
fileList: [
|
||||||
|
{
|
||||||
|
validator: (_rule, value, callback) => {
|
||||||
|
if (!Array.isArray(value) || value.length === 0) {
|
||||||
|
callback(new Error('请上传附件'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
callback()
|
||||||
|
},
|
||||||
|
trigger: 'change'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
const initFormData = (data = {}) => {
|
||||||
|
Object.assign(formData, mergeFormData(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleEventTypeChange = (value) => {
|
||||||
|
if (value === '水毁事件') {
|
||||||
|
router.replace({ path: '/waterDisasterReport' })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDistrictChange = () => {
|
||||||
|
formData.routeNo = ''
|
||||||
|
formData.event.startStakeNo = ''
|
||||||
|
formData.event.endStakeNo = ''
|
||||||
|
formData.event.startStakeLongitude = null
|
||||||
|
formData.event.startStakeLatitude = null
|
||||||
|
formData.event.endStakeLongitude = null
|
||||||
|
formData.event.endStakeLatitude = null
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleRouteNoChange = (item = {}) => {
|
||||||
|
formData.routeNo = item.routeCode || formData.routeNo
|
||||||
|
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.startStakeLongitude = startPoint.longitude
|
||||||
|
formData.event.startStakeLatitude = startPoint.latitude
|
||||||
|
formData.event.endStakeLongitude = endPoint.longitude
|
||||||
|
formData.event.endStakeLatitude = endPoint.latitude
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleHasStrandedVehiclesChange = (value) => {
|
||||||
|
if (value !== 1) {
|
||||||
|
formData.traffic.strandedVehicleCount = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const buildSubmitData = () => {
|
||||||
|
const payload = mergeFormData(formData)
|
||||||
|
payload.event.routeNo = payload.routeNo
|
||||||
|
payload.event.occurTime = payload.occurTime
|
||||||
|
payload.event.eventType = eventType.value
|
||||||
|
payload.event.roadType = filterForm.routeType
|
||||||
|
payload.event.roadConditionLocation = payload.occurLocation
|
||||||
|
if (payload.traffic.hasStrandedVehicles !== 1) {
|
||||||
|
payload.traffic.strandedVehicleCount = null
|
||||||
|
}
|
||||||
|
return payload
|
||||||
|
}
|
||||||
|
|
||||||
|
const getFormData = () => buildSubmitData()
|
||||||
|
|
||||||
|
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 res = await request({
|
||||||
|
url: '/snow-ops-platform/event/addOrUpdate',
|
||||||
|
method: 'post',
|
||||||
|
data: buildSubmitData()
|
||||||
|
})
|
||||||
|
|
||||||
|
if (res?.code === '00000') {
|
||||||
|
ElMessage.success('提交成功')
|
||||||
|
setTimeout(() => {
|
||||||
|
router.replace('/disasterManagement')
|
||||||
|
}, 500)
|
||||||
|
} else {
|
||||||
|
ElMessage.error(res?.message || '提交失败')
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('提交失败:', error)
|
||||||
|
ElMessage.error('提交失败,请重试')
|
||||||
|
} finally {
|
||||||
|
submitting.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getDisasterDetail = async () => {
|
||||||
|
if (!route.query.id) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await request({
|
||||||
|
url: `/snow-ops-platform/event/getById?id=${route.query.id}`,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
|
||||||
|
if (result?.data) {
|
||||||
|
const data = result.data
|
||||||
|
initFormData({
|
||||||
|
occurLocation: data.occurLocation || data.event?.roadConditionLocation || '',
|
||||||
|
occurTime: data.occurTime || data.event?.occurTime || '',
|
||||||
|
routeNo: data.routeNo || data.event?.routeNo || '',
|
||||||
|
event: {
|
||||||
|
...(data.event || {})
|
||||||
|
},
|
||||||
|
material: {
|
||||||
|
...(data.material || {})
|
||||||
|
},
|
||||||
|
report: {
|
||||||
|
...(data.report || {})
|
||||||
|
},
|
||||||
|
traffic: {
|
||||||
|
...(data.traffic || {})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
ElMessage.warning(result?.message || '获取详情失败')
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取冰雪详情失败:', error)
|
||||||
|
ElMessage.error('获取详情失败,请稍后重试')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleBack = () => {
|
||||||
|
router.back()
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
await getAreaOptions()
|
||||||
|
|
||||||
|
if (route.query.id) {
|
||||||
|
await getDisasterDetail()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
initFormData({})
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
eventType,
|
||||||
|
filterForm,
|
||||||
|
formData,
|
||||||
|
formRef,
|
||||||
|
formRules,
|
||||||
|
handleBack,
|
||||||
|
handleDistrictChange,
|
||||||
|
handleEventTypeChange,
|
||||||
|
handleHasStrandedVehiclesChange,
|
||||||
|
handleRouteNoChange,
|
||||||
|
handleSubmit,
|
||||||
|
initFormData,
|
||||||
|
getFormData,
|
||||||
|
options,
|
||||||
|
routeTypeLabel,
|
||||||
|
strandedVehicleOptions,
|
||||||
|
submitting,
|
||||||
|
validate
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -166,7 +166,6 @@ const formData = reactive({
|
|||||||
district: '',
|
district: '',
|
||||||
endStakeNo: '',
|
endStakeNo: '',
|
||||||
estimatedRecoveryCost: '',
|
estimatedRecoveryCost: '',
|
||||||
inspectionMileage: '',
|
|
||||||
isBlocked: '',
|
isBlocked: '',
|
||||||
needsRecovery: '',
|
needsRecovery: '',
|
||||||
repairProgress: '',
|
repairProgress: '',
|
||||||
@ -317,7 +316,6 @@ const resetForm = () => {
|
|||||||
district: '',
|
district: '',
|
||||||
endStakeNo: '',
|
endStakeNo: '',
|
||||||
estimatedRecoveryCost: '',
|
estimatedRecoveryCost: '',
|
||||||
inspectionMileage: '',
|
|
||||||
isBlocked: '',
|
isBlocked: '',
|
||||||
needsRecovery: '',
|
needsRecovery: '',
|
||||||
repairProgress: '',
|
repairProgress: '',
|
||||||
|
|||||||
@ -68,6 +68,11 @@ const getLossDict = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const changeValue = (config, event) => {
|
||||||
|
const item = getValueItem(config)
|
||||||
|
item.totalAmount = event
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await getLossDict()
|
await getLossDict()
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,32 +1,28 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="disaster-form-page">
|
<div class="disaster-form-page">
|
||||||
<el-form ref="formRef" :model="formData" :rules="formRules" label-width="140px" 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">
|
||||||
<span class="section-title">基本信息</span>
|
<span class="section-title">基础信息</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<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.reporterUnit">
|
<el-form-item label="填报单位" prop="event.reporterUnit">
|
||||||
<el-input v-model="formData.event.reporterUnit" placeholder="请填写" />
|
<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.contactPerson">
|
<el-form-item label="联系人员" prop="event.contactPerson">
|
||||||
<el-input v-model="formData.event.contactPerson" 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.contactPhone">
|
<el-form-item label="联系电话" prop="event.contactPhone">
|
||||||
<el-input v-model="formData.event.contactPhone" 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>
|
||||||
@ -36,87 +32,60 @@
|
|||||||
<el-row :gutter="24">
|
<el-row :gutter="24">
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<el-form-item label="事件类型">
|
<el-form-item label="事件类型">
|
||||||
<el-select v-model="eventType" placeholder="请选择" style="width: 100%" @change="handleEventTypeChange">
|
<el-select v-model="eventType" style="width: 100%" @change="handleEventTypeChange">
|
||||||
<el-option v-for="(option, idx) in options['eventType']" :label="option.label" :value="option.value" :key="idx" />
|
<el-option v-for="(option, idx) in options['eventType']" :key="idx" :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-form-item label="填报站点" prop="event.serviceStationId">
|
||||||
|
<YHZSelect v-model="formData.event.serviceStationId" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<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-row>
|
||||||
|
|
||||||
|
<el-row :gutter="24">
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<el-form-item label="路况类别" prop="roadConditionType">
|
<el-form-item label="路况类别" prop="roadConditionType">
|
||||||
<el-select v-model="formData.roadConditionType" placeholder="请选择" style="width: 100%">
|
<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-option v-for="(option, idx) in options['waterRoadConditionType']" :key="idx" :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-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-col :span="8">
|
||||||
<el-form-item label="抢险进度" prop="event.repairProgress">
|
<el-form-item label="抢险进度" prop="event.repairProgress">
|
||||||
<el-select v-model="formData.event.repairProgress" placeholder="请选择" style="width: 100%">
|
<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-option v-for="(option, idx) in options['repairProgress']" :key="idx" :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.disposalMeasures">
|
<el-form-item label="是否阻断" prop="event.isBlocked">
|
||||||
<el-select v-model="formData.report.disposalMeasures" placeholder="请选择" style="width: 100%">
|
<el-select v-model="formData.event.isBlocked" placeholder="请选择" style="width: 100%">
|
||||||
<el-option v-for="(option, idx) in options['disposalMeasures']" :label="option.label" :value="option.value" :key="idx" />
|
<el-option v-for="(option, idx) in options['yesNoBool']" :key="idx" :label="option.label" :value="option.value" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<!-- 水毁处数 -->
|
</el-row>
|
||||||
|
|
||||||
|
<el-row :gutter="24">
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="受灾里程" prop="event.blockedMileage">
|
||||||
|
<el-input v-model="formData.event.blockedMileage" placeholder="请填写">
|
||||||
|
<template #append>公里</template>
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<el-form-item label="水毁处数" prop="event.damageCount">
|
<el-form-item label="水毁处数" prop="event.damageCount">
|
||||||
<el-input-number v-model="formData.event.damageCount" :min="0" :step="1" style="width: 100%" placeholder="请填写">
|
<el-input v-model="formData.event.damageCount" placeholder="请填写">
|
||||||
<template #suffix>
|
<template #append>处</template>
|
||||||
<span class="unit-text">处</span>
|
</el-input>
|
||||||
</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-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
@ -124,84 +93,78 @@
|
|||||||
|
|
||||||
<BlockItem title="位置信息">
|
<BlockItem title="位置信息">
|
||||||
<el-row :gutter="24">
|
<el-row :gutter="24">
|
||||||
<!-- 路线类型 -->
|
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<el-form-item label="路线类型">
|
<el-form-item label="路线类型">
|
||||||
<el-select v-model="filterForm.routeType" placeholder="请选择" style="width: 100%">
|
<el-input :model-value="routeTypeLabel" readonly />
|
||||||
<el-option v-for="(option, idx) in options['roadType']" :label="option.label" :value="option.value" :key="idx" />
|
|
||||||
</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="event.district">
|
<el-form-item label="所属区县" prop="event.district">
|
||||||
<el-select v-model="formData.event.district" placeholder="请选择" style="width: 100%" @change="handleDistrictChange">
|
<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-option v-for="(option, idx) in options['area']" :key="idx" :label="option.label" :value="option.value" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
|
||||||
<el-row :gutter="24">
|
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<el-form-item label="地点路线" prop="routeNo">
|
<el-form-item label="线路编号" prop="routeNo">
|
||||||
<RoadRoutesSelect v-model="formData.routeNo" @change="handleRouteNoChange" :extra-params="{ xzdj: filterForm.routeType, qxid: formData.event.district }" />
|
<RoadRoutesSelect v-model="formData.routeNo" :extra-params="{ xzdj: filterForm.routeType, qxid: formData.event.district }" @change="handleRouteNoChange" />
|
||||||
</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-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="occurLocation">
|
<el-form-item label="路况位置" prop="occurLocation">
|
||||||
<el-input v-model="formData.occurLocation" placeholder="请填写" />
|
<el-input v-model="formData.occurLocation" placeholder="请选择">
|
||||||
|
<template #suffix>
|
||||||
|
<el-icon class="location-icon"><LocationFilled /></el-icon>
|
||||||
|
</template>
|
||||||
|
</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.blockedPointName">
|
<el-form-item label="阻断点小地名" prop="event.blockedPointName">
|
||||||
<el-input v-model="formData.event.blockedPointName" placeholder="请填写" />
|
<el-input v-model="formData.event.blockedPointName" placeholder="请填写" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
|
||||||
<el-row :gutter="24">
|
|
||||||
<!-- 经度 -->
|
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<el-form-item label="经度" prop="event.longitude">
|
<el-form-item label="起点桩号" prop="event.startStakeNo">
|
||||||
<el-input v-model="formData.event.longitude" placeholder="经度"> </el-input>
|
<el-input v-model="formData.event.startStakeNo" placeholder="请填写">
|
||||||
|
<template #prepend>K</template>
|
||||||
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
<!-- 纬度 -->
|
<el-row :gutter="24">
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<el-form-item label="纬度" prop="event.latitude">
|
<el-form-item label="起点桩经度" prop="event.startStakeLongitude">
|
||||||
<el-input v-model="formData.event.latitude" placeholder="纬度"> </el-input>
|
<el-input v-model="formData.event.startStakeLongitude" placeholder="请填写" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="起点桩纬度" prop="event.startStakeLatitude">
|
||||||
|
<el-input v-model="formData.event.startStakeLatitude" placeholder="请填写" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-form-item label="止点桩号" prop="event.endStakeNo">
|
||||||
|
<el-input v-model="formData.event.endStakeNo" placeholder="请填写">
|
||||||
|
<template #prepend>K</template>
|
||||||
|
</el-input>
|
||||||
</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="fileList">
|
<el-form-item label="止点桩经度" prop="event.endStakeLongitude">
|
||||||
<FileUpload type="image" :limit="9" v-model="formData.fileList" />
|
<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="fileList">
|
<el-form-item label="止点桩纬度" prop="event.endStakeLatitude">
|
||||||
<FileUpload type="video" :limit="9" v-model="formData.fileList" />
|
<el-input v-model="formData.event.endStakeLatitude" placeholder="请填写" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
@ -211,12 +174,42 @@
|
|||||||
<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">
|
||||||
<span class="section-title">灾毁损失</span>
|
<span class="section-title">处置情况</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<BlockItem title="路况事件信息">
|
|
||||||
|
<BlockItem>
|
||||||
|
<el-row :gutter="24">
|
||||||
|
<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']" :key="idx" :label="option.label" :value="option.value" />
|
||||||
|
</el-select>
|
||||||
|
</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-col :span="8">
|
||||||
|
<el-form-item label="实际恢复时间" prop="report.actualRecoverTime">
|
||||||
|
<el-date-picker v-model="formData.report.actualRecoverTime" type="datetime" placeholder="请选择时间" style="width: 100%" value-format="YYYY-MM-DD HH:mm:ss" />
|
||||||
|
</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-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">
|
||||||
<el-input-number v-model="formData.report.injuredCount" :min="0" :step="1" style="width: 100%">
|
<el-input-number v-model="formData.report.injuredCount" :min="0" :step="1" style="width: 100%">
|
||||||
@ -226,8 +219,6 @@
|
|||||||
</el-input-number>
|
</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">
|
||||||
<el-input-number v-model="formData.report.deadCount" :min="0" :step="1" style="width: 100%">
|
<el-input-number v-model="formData.report.deadCount" :min="0" :step="1" style="width: 100%">
|
||||||
@ -237,8 +228,6 @@
|
|||||||
</el-input-number>
|
</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">
|
||||||
<el-input-number v-model="formData.report.strandedPersonCount" :min="0" :step="1" style="width: 100%">
|
<el-input-number v-model="formData.report.strandedPersonCount" :min="0" :step="1" style="width: 100%">
|
||||||
@ -248,8 +237,9 @@
|
|||||||
</el-input-number>
|
</el-input-number>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
<!-- 损坏车辆 -->
|
<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">
|
||||||
<el-input-number v-model="formData.report.damagedVehicleCount" :min="0" :step="1" style="width: 100%">
|
<el-input-number v-model="formData.report.damagedVehicleCount" :min="0" :step="1" style="width: 100%">
|
||||||
@ -259,8 +249,6 @@
|
|||||||
</el-input-number>
|
</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">
|
||||||
<el-input-number v-model="formData.report.strandedVehicleCount" :min="0" :step="1" style="width: 100%">
|
<el-input-number v-model="formData.report.strandedVehicleCount" :min="0" :step="1" style="width: 100%">
|
||||||
@ -272,390 +260,110 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</BlockItem>
|
</BlockItem>
|
||||||
<BlockItem title="道路损失及其他">
|
|
||||||
<LossList v-model:model-value="formData.report.lossList" />
|
<BlockItem title="灾毁损失">
|
||||||
|
<LossList v-model:model-value="formData.lossList" />
|
||||||
|
|
||||||
<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">
|
||||||
<el-input-number v-model="formData.report.investedMachinery" :min="0" :precision="1" style="width: 100%" placeholder="请填写">
|
<el-input v-model="formData.report.investedMachinery" placeholder="请填写">
|
||||||
<template #suffix>
|
<template #append>台/班</template>
|
||||||
<span class="unit-text">台/班</span>
|
</el-input>
|
||||||
</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.investedManpower">
|
<el-form-item label="投入人力" prop="report.investedManpower">
|
||||||
<el-input-number v-model="formData.report.investedManpower" :min="0" :step="1" style="width: 100%" placeholder="请填写">
|
<el-input-number v-model="formData.report.investedManpower" :min="0" :step="1" style="width: 100%">
|
||||||
<template #suffix>
|
<template #suffix>
|
||||||
<span class="unit-text">人次</span>
|
<span class="unit-text">人次</span>
|
||||||
</template>
|
</template>
|
||||||
</el-input-number>
|
</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">
|
||||||
<el-input-number v-model="formData.report.investedFunds" :min="0" :precision="2" style="width: 100%" placeholder="请填写">
|
<el-input v-model="formData.report.investedFunds" placeholder="请填写">
|
||||||
<template #suffix>
|
<template #append>万元</template>
|
||||||
<span class="unit-text">万元</span>
|
</el-input>
|
||||||
</template>
|
</el-form-item>
|
||||||
</el-input-number>
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<el-row :gutter="24">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="现场情况描述" prop="report.siteDescription">
|
||||||
|
<el-input v-model="formData.report.siteDescription" type="textarea" :rows="3" placeholder="请填写" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<el-row :gutter="24">
|
||||||
|
<el-col :span="16">
|
||||||
|
<el-form-item label="附件">
|
||||||
|
<FileUpload v-model="formData.fileList" type="image" :limit="9" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</BlockItem>
|
</BlockItem>
|
||||||
|
|
||||||
<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.needsRecovery">
|
<el-form-item label="是否需要恢复重建" prop="event.needsRecovery">
|
||||||
<el-select v-model="formData.event.needsRecovery" placeholder="请选择" style="width: 100%">
|
<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-option v-for="(option, idx) in options['yesNoBool']" :key="idx" :label="option.label" :value="option.value" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
<el-col v-if="showEstimatedRecoveryCost" :span="8">
|
||||||
<!-- 恢复重建预估费用 -->
|
|
||||||
<el-col :span="8" v-if="formData?.event.needsRecovery">
|
|
||||||
<el-form-item label="恢复重建预估费用" prop="event.estimatedRecoveryCost">
|
<el-form-item label="恢复重建预估费用" prop="event.estimatedRecoveryCost">
|
||||||
<el-input-number v-model="formData.event.estimatedRecoveryCost" :min="0" :precision="2" style="width: 100%" placeholder="请填写">
|
<el-input v-model="formData.event.estimatedRecoveryCost" placeholder="请填写">
|
||||||
<template #suffix>
|
<template #append>万元</template>
|
||||||
<span class="unit-text">万元</span>
|
</el-input>
|
||||||
</template>
|
|
||||||
</el-input-number>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
</BlockItem>
|
</BlockItem>
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
||||||
<!-- 提交按钮 -->
|
|
||||||
<div class="form-actions">
|
<div class="form-actions">
|
||||||
<el-button @click="handleBack">取消</el-button>
|
<el-button @click="handleBack">取消</el-button>
|
||||||
<el-button type="primary" @click="handleSubmit" :loading="submitting">提交</el-button>
|
<el-button type="primary" :loading="submitting" @click="handleSubmit">提交</el-button>
|
||||||
</div>
|
</div>
|
||||||
</el-form>
|
</el-form>
|
||||||
|
|
||||||
<!-- 图片预览对话框 -->
|
|
||||||
<el-dialog v-model="previewDialogVisible" title="图片预览" width="600px">
|
|
||||||
<img :src="previewImageUrl" style="width: 100%" alt="预览图片" />
|
|
||||||
</el-dialog>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, reactive, computed, watch, onMounted } from 'vue'
|
import { LocationFilled } from '@element-plus/icons-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 BlockItem from '@/component/BlockItem.vue'
|
||||||
import FileUpload from '@/component/FileUpload/FileUpload.vue'
|
import FileUpload from '@/component/FileUpload/FileUpload.vue'
|
||||||
import { useOptions } from '@shared/composables/useOptions'
|
|
||||||
import RoadRoutesSelect from '../components/RoadRoutesSelect.vue'
|
import RoadRoutesSelect from '../components/RoadRoutesSelect.vue'
|
||||||
|
import YHZSelect from '../components/YHZSelect.vue'
|
||||||
|
import LossList from './WaterDisasterLossListPC.vue'
|
||||||
|
import { useWaterDisasterReport } from './useWaterDisasterReport'
|
||||||
|
|
||||||
const router = useRouter()
|
const {
|
||||||
const route = useRoute()
|
eventType,
|
||||||
const { options, getAreaOptions } = useOptions()
|
filterForm,
|
||||||
const formRef = ref(null)
|
formData,
|
||||||
const submitting = ref(false)
|
formRef,
|
||||||
|
formRules,
|
||||||
|
handleBack,
|
||||||
|
handleDistrictChange,
|
||||||
|
handleEventTypeChange,
|
||||||
|
handleRouteNoChange,
|
||||||
|
handleSubmit,
|
||||||
|
initFormData,
|
||||||
|
getFormData,
|
||||||
|
options,
|
||||||
|
routeTypeLabel,
|
||||||
|
showEstimatedRecoveryCost,
|
||||||
|
submitting,
|
||||||
|
validate
|
||||||
|
} = useWaterDisasterReport()
|
||||||
|
|
||||||
// 是否为续报
|
|
||||||
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({
|
defineExpose({
|
||||||
validate,
|
validate,
|
||||||
initFormData,
|
initFormData,
|
||||||
@ -669,74 +377,55 @@ defineExpose({
|
|||||||
background-color: #f5f7fa;
|
background-color: #f5f7fa;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
.disaster-form {
|
.form-section {
|
||||||
.form-section {
|
margin-bottom: 20px;
|
||||||
margin-bottom: 20px;
|
|
||||||
|
|
||||||
:deep(.el-card__header) {
|
:deep(.el-card__header) {
|
||||||
padding: 12px 20px;
|
padding: 12px 20px;
|
||||||
background-color: #fafafa;
|
background-color: #fafafa;
|
||||||
border-bottom: 1px solid #ebeef5;
|
border-bottom: 1px solid #ebeef5;
|
||||||
}
|
}
|
||||||
|
|
||||||
:deep(.el-card__body) {
|
:deep(.el-card__body) {
|
||||||
padding: 20px;
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.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;
|
||||||
|
border-radius: 2px;
|
||||||
|
background-color: #409eff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.location-icon {
|
||||||
|
color: #909399;
|
||||||
|
}
|
||||||
|
|
||||||
|
.unit-text {
|
||||||
|
color: #909399;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-actions {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 16px;
|
||||||
|
padding: 8px 0 32px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -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>
|
||||||
@ -0,0 +1,292 @@
|
|||||||
|
import { computed, onMounted, reactive, ref } from 'vue'
|
||||||
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import { request } from '@/utils/request'
|
||||||
|
import { useOptions } from '@shared/composables/useOptions'
|
||||||
|
import mockData from './waterMockJson.json'
|
||||||
|
|
||||||
|
const DEFAULT_REPORTER_UNIT = '万州区公路中心'
|
||||||
|
|
||||||
|
const createDefaultFormData = () => ({
|
||||||
|
occurLocation: '',
|
||||||
|
occurTime: '',
|
||||||
|
roadConditionType: '',
|
||||||
|
routeNo: '',
|
||||||
|
event: {
|
||||||
|
blockedMileage: null,
|
||||||
|
blockedPointName: '',
|
||||||
|
contactPerson: '',
|
||||||
|
contactPhone: '',
|
||||||
|
damageCount: null,
|
||||||
|
district: '',
|
||||||
|
endStakeLatitude: null,
|
||||||
|
endStakeLongitude: null,
|
||||||
|
endStakeNo: '',
|
||||||
|
estimatedRecoveryCost: null,
|
||||||
|
isBlocked: null,
|
||||||
|
latitude: null,
|
||||||
|
longitude: null,
|
||||||
|
needsRecovery: null,
|
||||||
|
repairProgress: '抢险中',
|
||||||
|
reportSite: '',
|
||||||
|
reporterUnit: DEFAULT_REPORTER_UNIT,
|
||||||
|
serviceStationId: '',
|
||||||
|
startStakeLatitude: null,
|
||||||
|
startStakeLongitude: null,
|
||||||
|
startStakeNo: ''
|
||||||
|
},
|
||||||
|
report: {
|
||||||
|
actualRecoverTime: '',
|
||||||
|
damagedVehicleCount: null,
|
||||||
|
deadCount: null,
|
||||||
|
disposalMeasures: '',
|
||||||
|
expectRecoverTime: '',
|
||||||
|
injuredCount: null,
|
||||||
|
investedFunds: null,
|
||||||
|
investedMachinery: null,
|
||||||
|
investedManpower: null,
|
||||||
|
remark: '',
|
||||||
|
siteDescription: '',
|
||||||
|
strandedPersonCount: null,
|
||||||
|
strandedVehicleCount: null,
|
||||||
|
totalLossAmount: null
|
||||||
|
},
|
||||||
|
lossList: [],
|
||||||
|
fileList: []
|
||||||
|
})
|
||||||
|
|
||||||
|
const mergeFormData = (source = {}) => {
|
||||||
|
const defaults = createDefaultFormData()
|
||||||
|
const merged = {
|
||||||
|
...defaults,
|
||||||
|
...source,
|
||||||
|
event: {
|
||||||
|
...defaults.event,
|
||||||
|
...(source.event || {})
|
||||||
|
},
|
||||||
|
report: {
|
||||||
|
...defaults.report,
|
||||||
|
...(source.report || {})
|
||||||
|
},
|
||||||
|
lossList: Array.isArray(source.lossList) ? source.lossList : defaults.lossList,
|
||||||
|
fileList: Array.isArray(source.fileList) ? source.fileList : defaults.fileList
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!merged.event.reporterUnit) {
|
||||||
|
merged.event.reporterUnit = DEFAULT_REPORTER_UNIT
|
||||||
|
}
|
||||||
|
if (!merged.event.repairProgress) {
|
||||||
|
merged.event.repairProgress = '抢险中'
|
||||||
|
}
|
||||||
|
if (!merged.event.serviceStationId && merged.event.reportSite) {
|
||||||
|
merged.event.serviceStationId = merged.event.reportSite
|
||||||
|
}
|
||||||
|
|
||||||
|
return merged
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useWaterDisasterReport = () => {
|
||||||
|
const router = useRouter()
|
||||||
|
const route = useRoute()
|
||||||
|
const { options, getAreaOptions } = useOptions()
|
||||||
|
|
||||||
|
const formRef = ref(null)
|
||||||
|
const submitting = ref(false)
|
||||||
|
const eventType = ref('水毁事件')
|
||||||
|
const filterForm = reactive({
|
||||||
|
routeType: ''
|
||||||
|
})
|
||||||
|
const formData = reactive(createDefaultFormData())
|
||||||
|
|
||||||
|
const routeTypeLabel = computed(() => {
|
||||||
|
const matched = options.value.roadType?.find((item) => item.value === filterForm.routeType)
|
||||||
|
return matched?.label || '国省道'
|
||||||
|
})
|
||||||
|
|
||||||
|
const showEstimatedRecoveryCost = computed(() => formData.event.needsRecovery === true)
|
||||||
|
|
||||||
|
const formRules = {
|
||||||
|
'event.contactPerson': [{ required: true, message: '请输入联系人员', trigger: 'blur' }],
|
||||||
|
'event.contactPhone': [
|
||||||
|
{ required: true, message: '请输入联系电话', trigger: 'blur' },
|
||||||
|
{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的联系电话', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
'event.serviceStationId': [{ required: true, message: '请选择填报站点', trigger: 'change' }],
|
||||||
|
occurTime: [{ required: true, message: '请选择发生时间', trigger: 'change' }],
|
||||||
|
roadConditionType: [{ required: true, message: '请选择路况类别', trigger: 'change' }],
|
||||||
|
'event.repairProgress': [{ required: true, message: '请选择抢险进度', trigger: 'change' }],
|
||||||
|
'event.isBlocked': [{ required: true, message: '请选择是否阻断', trigger: 'change' }],
|
||||||
|
'event.blockedMileage': [{ required: true, message: '请输入受灾里程', trigger: 'blur' }],
|
||||||
|
'event.damageCount': [{ required: true, message: '请输入水毁处数', trigger: 'blur' }],
|
||||||
|
'event.district': [{ required: true, message: '请选择所属区县', trigger: 'change' }],
|
||||||
|
routeNo: [{ required: true, message: '请选择线路编号', trigger: 'change' }],
|
||||||
|
occurLocation: [{ required: true, message: '请输入路况位置', trigger: 'blur' }],
|
||||||
|
'event.blockedPointName': [{ required: true, message: '请输入阻断点小地名', trigger: 'blur' }],
|
||||||
|
'event.startStakeNo': [{ required: true, message: '请输入起点桩号', trigger: 'blur' }],
|
||||||
|
'event.startStakeLongitude': [{ required: true, message: '请输入起点桩经度', trigger: 'blur' }],
|
||||||
|
'event.startStakeLatitude': [{ required: true, message: '请输入起点桩纬度', trigger: 'blur' }],
|
||||||
|
'event.endStakeNo': [{ required: true, message: '请输入止点桩号', trigger: 'blur' }],
|
||||||
|
'event.endStakeLongitude': [{ required: true, message: '请输入止点桩经度', trigger: 'blur' }],
|
||||||
|
'event.endStakeLatitude': [{ required: true, message: '请输入止点桩纬度', trigger: 'blur' }],
|
||||||
|
'report.disposalMeasures': [{ required: true, message: '请选择处置措施', trigger: 'change' }],
|
||||||
|
'report.expectRecoverTime': [{ required: true, message: '请选择预计恢复时间', trigger: 'change' }],
|
||||||
|
'event.needsRecovery': [{ required: true, message: '请选择是否需要恢复重建', trigger: 'change' }],
|
||||||
|
'event.estimatedRecoveryCost': [
|
||||||
|
{
|
||||||
|
validator: (_rule, value, callback) => {
|
||||||
|
if (showEstimatedRecoveryCost.value && (value === '' || value === null || value === undefined)) {
|
||||||
|
callback(new Error('请输入恢复重建预估费用'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
callback()
|
||||||
|
},
|
||||||
|
trigger: 'blur'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
const initFormData = (data = {}) => {
|
||||||
|
Object.assign(formData, mergeFormData(data))
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleEventTypeChange = (value) => {
|
||||||
|
if (value === '冰雪事件') {
|
||||||
|
router.replace({ path: '/iceDisasterReport' })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDistrictChange = () => {
|
||||||
|
// formData.routeNo = ''
|
||||||
|
// formData.occurLocation = ''
|
||||||
|
// formData.event.startStakeNo = ''
|
||||||
|
// formData.event.endStakeNo = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
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.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
|
||||||
|
}
|
||||||
|
|
||||||
|
const buildSubmitData = () => {
|
||||||
|
const payload = mergeFormData(formData)
|
||||||
|
if (!payload.event.reportSite && payload.event.serviceStationId) {
|
||||||
|
payload.event.reportSite = payload.event.serviceStationId
|
||||||
|
}
|
||||||
|
|
||||||
|
return payload
|
||||||
|
}
|
||||||
|
|
||||||
|
const getFormData = () => buildSubmitData()
|
||||||
|
|
||||||
|
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 res = await request({
|
||||||
|
url: '/snow-ops-platform/water-damage/addOrUpdate',
|
||||||
|
method: 'post',
|
||||||
|
data: buildSubmitData()
|
||||||
|
})
|
||||||
|
|
||||||
|
if (res?.code === '00000') {
|
||||||
|
ElMessage.success('提交成功')
|
||||||
|
setTimeout(() => {
|
||||||
|
router.replace('/disasterManagement')
|
||||||
|
}, 500)
|
||||||
|
} else {
|
||||||
|
ElMessage.error(res?.message || '提交失败')
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('提交失败:', error)
|
||||||
|
ElMessage.error('提交失败,请重试')
|
||||||
|
} finally {
|
||||||
|
submitting.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const handleBack = () => {
|
||||||
|
router.back()
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
await getAreaOptions()
|
||||||
|
|
||||||
|
initFormData(route.query.mock ? mockData : {})
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
eventType,
|
||||||
|
filterForm,
|
||||||
|
formData,
|
||||||
|
formRef,
|
||||||
|
formRules,
|
||||||
|
handleBack,
|
||||||
|
handleDistrictChange,
|
||||||
|
handleEventTypeChange,
|
||||||
|
handleRouteNoChange,
|
||||||
|
handleSubmit,
|
||||||
|
initFormData,
|
||||||
|
getFormData,
|
||||||
|
options,
|
||||||
|
routeTypeLabel,
|
||||||
|
showEstimatedRecoveryCost,
|
||||||
|
submitting,
|
||||||
|
validate
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -12,7 +12,6 @@
|
|||||||
"district": "武侯区",
|
"district": "武侯区",
|
||||||
"endStakeNo": "K2251+200",
|
"endStakeNo": "K2251+200",
|
||||||
"estimatedRecoveryCost": 120.5,
|
"estimatedRecoveryCost": 120.5,
|
||||||
"inspectionMileage": 25.6,
|
|
||||||
"isBlocked": true,
|
"isBlocked": true,
|
||||||
"needsRecovery": true,
|
"needsRecovery": true,
|
||||||
"repairProgress": "抢险中",
|
"repairProgress": "抢险中",
|
||||||
|
|||||||
@ -0,0 +1,170 @@
|
|||||||
|
<template>
|
||||||
|
<el-row class="material-list-pc" :gutter="24">
|
||||||
|
<template v-for="(item, index) in configs" :key="index">
|
||||||
|
<el-col :span="colSpan">
|
||||||
|
<el-form-item :label="item.wzmc">
|
||||||
|
<el-input :modelValue="getValue(item)" :placeholder="`余额: ${item.ye} `" @update:modelValue="(event) => changeValue(item, event)">
|
||||||
|
<template #suffix>
|
||||||
|
<span>{{ item.dw }}</span>
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</template>
|
||||||
|
</el-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
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'
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:modelValue'])
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
yhzId: {
|
||||||
|
type: [Number, null, String],
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
modelValue: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
|
},
|
||||||
|
colSpan: {
|
||||||
|
type: Number,
|
||||||
|
default: 8
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(()=> props.yhzId, ()=> {
|
||||||
|
emit('update:modelValue', [])
|
||||||
|
getDict()
|
||||||
|
})
|
||||||
|
|
||||||
|
const getValue = (config) => {
|
||||||
|
const item = getValueItem(config)
|
||||||
|
return item?.usageAmount || 0
|
||||||
|
}
|
||||||
|
|
||||||
|
const getValueItem = (config) => {
|
||||||
|
let item = props.modelValue.find((v) => v.yhzid === config.yhzid)
|
||||||
|
if (item == null) {
|
||||||
|
item = { ...config }
|
||||||
|
props.modelValue.push(item)
|
||||||
|
}
|
||||||
|
return item
|
||||||
|
}
|
||||||
|
|
||||||
|
const changeValue = (item, value) => {
|
||||||
|
const index = props.modelValue.findIndex((v) => v.yhzid === item.yhzid)
|
||||||
|
if (index > -1) {
|
||||||
|
props.modelValue[index].usageAmount = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const configs = ref([])
|
||||||
|
|
||||||
|
// 获取字典
|
||||||
|
const getDict = async () => {
|
||||||
|
if(!props.yhzId) return []
|
||||||
|
try {
|
||||||
|
const res = await request({
|
||||||
|
url: `/snow-ops-platform/yjwz/list?yhzid=${props.yhzId}&pageNum=1&pageSize=9999`,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
configs.value = res.data?.records
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取物质列表失败:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.material-list-pc {
|
||||||
|
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>
|
||||||
@ -6,7 +6,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-input>
|
</el-input>
|
||||||
|
|
||||||
<el-dialog v-model="dialogVisible" :title="dialogTitle" :width="dialogWidth" :append-to-body="true" :modal="true" @close="handleDialogClose">
|
<el-dialog v-model="dialogVisible" :header="dialogTitle" :width="dialogWidth" :append-to-body="true" :modal="true" @close="handleDialogClose">
|
||||||
<div class="dialog-content">
|
<div class="dialog-content">
|
||||||
<div class="title">已选择地点路线:{{ tempSelectedItem?.routeCode }}</div>
|
<div class="title">已选择地点路线:{{ tempSelectedItem?.routeCode }}</div>
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,253 @@
|
|||||||
|
<template>
|
||||||
|
<div class="selector-component">
|
||||||
|
<el-input :modelValue="tempSelectedItem?.mc" :placeholder="placeholder" readonly @click="openDialog">
|
||||||
|
<template #suffix>
|
||||||
|
<el-icon><ArrowDown /></el-icon>
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
|
||||||
|
<el-dialog v-model="dialogVisible" :header="dialogTitle" :width="dialogWidth" :append-to-body="true" :modal="true" @close="handleDialogClose">
|
||||||
|
<div class="dialog-content">
|
||||||
|
<div class="title">已选择养护站:{{ tempSelectedItem?.mc }}</div>
|
||||||
|
|
||||||
|
<el-input v-model="searchKeyword" :placeholder="searchPlaceholder" clearable @input="handleSearch" />
|
||||||
|
|
||||||
|
<el-table :data="dataList" v-loading="loading" height="350" @row-click="handleRowClick" highlight-current-row>
|
||||||
|
<el-table-column prop="mc" label="服务站名称" />
|
||||||
|
<el-table-column prop="qxmc" label="区县名称" />
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<div class="pagination-wrapper" v-if="total > 0">
|
||||||
|
<el-pagination
|
||||||
|
v-model:current-page="currentPage"
|
||||||
|
:page-size="pageSize"
|
||||||
|
:total="total"
|
||||||
|
:page-sizes="pageSizes"
|
||||||
|
layout="prev, pager, next, sizes"
|
||||||
|
@current-change="handlePageChange"
|
||||||
|
@size-change="handleSizeChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, computed, onUnmounted, watch } from 'vue'
|
||||||
|
import { ArrowDown } from '@element-plus/icons-vue'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import { request } from '@shared/utils/request'
|
||||||
|
|
||||||
|
// ==================== Props ====================
|
||||||
|
const props = defineProps({
|
||||||
|
// v-model 绑定的值
|
||||||
|
modelValue: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 占位符文本
|
||||||
|
placeholder: {
|
||||||
|
type: String,
|
||||||
|
default: '请选择'
|
||||||
|
},
|
||||||
|
// 弹窗标题
|
||||||
|
dialogTitle: {
|
||||||
|
type: String,
|
||||||
|
default: '选择地点路线'
|
||||||
|
},
|
||||||
|
// 弹窗宽度
|
||||||
|
dialogWidth: {
|
||||||
|
type: String,
|
||||||
|
default: '500px'
|
||||||
|
},
|
||||||
|
// 搜索框占位符
|
||||||
|
searchPlaceholder: {
|
||||||
|
type: String,
|
||||||
|
default: '请输入关键词搜索'
|
||||||
|
},
|
||||||
|
// 请求接口地址
|
||||||
|
apiUrl: {
|
||||||
|
type: String,
|
||||||
|
default: '/snow-ops-platform/yhz/list'
|
||||||
|
},
|
||||||
|
// 每页大小
|
||||||
|
pageSize: {
|
||||||
|
type: Number,
|
||||||
|
default: 10
|
||||||
|
},
|
||||||
|
// 每页大小选项
|
||||||
|
pageSizes: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [10, 20, 50]
|
||||||
|
},
|
||||||
|
// 额外请求参数
|
||||||
|
extraParams: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({})
|
||||||
|
},
|
||||||
|
// 搜索防抖延迟时间(ms)
|
||||||
|
searchDelay: {
|
||||||
|
type: Number,
|
||||||
|
default: 1000
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:modelValue', 'change'])
|
||||||
|
|
||||||
|
// ==================== 状态 ====================
|
||||||
|
const dialogVisible = ref(false)
|
||||||
|
const searchKeyword = ref('')
|
||||||
|
const dataList = ref([])
|
||||||
|
const loading = ref(false)
|
||||||
|
const currentPage = ref(1)
|
||||||
|
const pageSize = ref(props.pageSize)
|
||||||
|
const total = ref(0)
|
||||||
|
|
||||||
|
// 临时选中的数据(确定前暂存)
|
||||||
|
const tempSelectedItem = ref(null)
|
||||||
|
|
||||||
|
// 防抖定时器
|
||||||
|
let searchTimer = null
|
||||||
|
|
||||||
|
// 已确认选中的值
|
||||||
|
const selectedValue = computed({
|
||||||
|
get: () => props.modelValue,
|
||||||
|
set: (val) => emit('update:modelValue', val)
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(() => props.modelValue, () => {
|
||||||
|
if(props.modelValue != tempSelectedItem.value?.id) {
|
||||||
|
tempSelectedItem.value = null
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// ==================== API 请求 ====================
|
||||||
|
const fetchData = async () => {
|
||||||
|
loading.value = true
|
||||||
|
|
||||||
|
try {
|
||||||
|
const params = {
|
||||||
|
pageNum: currentPage.value,
|
||||||
|
pageSize: pageSize.value,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果有搜索关键词,添加到参数中
|
||||||
|
if (searchKeyword.value) {
|
||||||
|
params.mc = searchKeyword.value
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await request({
|
||||||
|
url: props.apiUrl,
|
||||||
|
method: 'get',
|
||||||
|
params
|
||||||
|
})
|
||||||
|
|
||||||
|
if (response?.code === '00000') {
|
||||||
|
const records = response.data.records || []
|
||||||
|
total.value = response.data.total || 0
|
||||||
|
|
||||||
|
// 统一格式化数据,便于内部使用
|
||||||
|
dataList.value = records
|
||||||
|
} else {
|
||||||
|
ElMessage.error(response.message || '加载失败')
|
||||||
|
dataList.value = []
|
||||||
|
total.value = 0
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('请求失败:', error)
|
||||||
|
ElMessage.error('加载失败,请重试')
|
||||||
|
dataList.value = []
|
||||||
|
total.value = 0
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 带防抖的搜索函数
|
||||||
|
const debouncedSearch = () => {
|
||||||
|
// 清除之前的定时器
|
||||||
|
if (searchTimer) {
|
||||||
|
clearTimeout(searchTimer)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置新的定时器
|
||||||
|
searchTimer = setTimeout(() => {
|
||||||
|
currentPage.value = 1
|
||||||
|
fetchData()
|
||||||
|
}, props.searchDelay)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 事件处理 ====================
|
||||||
|
const openDialog = () => {
|
||||||
|
dialogVisible.value = true
|
||||||
|
// 重置状态
|
||||||
|
searchKeyword.value = tempSelectedItem.value?.mc || ''
|
||||||
|
currentPage.value = 1
|
||||||
|
fetchData()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleDialogClose = () => {
|
||||||
|
dialogVisible.value = false
|
||||||
|
// 关闭弹窗时清除防抖定时器
|
||||||
|
if (searchTimer) {
|
||||||
|
clearTimeout(searchTimer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSearch = () => {
|
||||||
|
// 使用防抖处理搜索
|
||||||
|
debouncedSearch()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handlePageChange = (page) => {
|
||||||
|
currentPage.value = page
|
||||||
|
fetchData()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSizeChange = (size) => {
|
||||||
|
pageSize.value = size
|
||||||
|
currentPage.value = 1
|
||||||
|
fetchData()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleRowClick = (row) => {
|
||||||
|
tempSelectedItem.value = row
|
||||||
|
selectedValue.value = tempSelectedItem.value.id
|
||||||
|
dialogVisible.value = false
|
||||||
|
emit('change', tempSelectedItem.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 清理定时器 ====================
|
||||||
|
onUnmounted(() => {
|
||||||
|
if (searchTimer) {
|
||||||
|
clearTimeout(searchTimer)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.selector-component {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
:deep(.el-input__wrapper) {
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
.el-input__inner {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialog-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
|
||||||
|
.pagination-wrapper {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="detail-container">
|
<div class="detail-container">
|
||||||
<el-form ref="formRef" :model="form" label-position="right" label-width="auto"
|
<el-form ref="formRef" :model="form" label-position="right" label-width="auto"
|
||||||
style="max-height: 60vh; overflow-y: auto; padding-right: 50px" :rules="rules">
|
style="max-height: 60vh; overflow-y: hidden; padding-right: 50px" :rules="rules">
|
||||||
|
|
||||||
<el-form-item label="" prop="schedules">
|
<el-form-item label="" prop="schedules">
|
||||||
<div class="tree-transfer-container">
|
<div class="tree-transfer-container">
|
||||||
@ -11,24 +11,45 @@
|
|||||||
children: 'children',
|
children: 'children',
|
||||||
label: 'orgName'
|
label: 'orgName'
|
||||||
}" node-key="orgId" :expand-on-click-node="false" :default-expand-all="false" highlight-current
|
}" node-key="orgId" :expand-on-click-node="false" :default-expand-all="false" highlight-current
|
||||||
style="height: 400px; overflow-y: auto;"
|
style="height: 100%; overflow-y: auto;" @node-click="handleNodeClick">
|
||||||
@node-click="handleNodeClick">
|
<template #default="{ node: _node }">
|
||||||
<template #default="{ node, data }">
|
|
||||||
<span class="custom-tree-node">
|
<span class="custom-tree-node">
|
||||||
<span>{{ node.label }}</span>
|
<span>{{ _node.label }}</span>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</el-tree>
|
</el-tree>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 中间空白区域 -->
|
<!-- 中间用户列表 -->
|
||||||
<div class="middle-panel">
|
<div class="middle-panel">
|
||||||
<!-- 暂留空,后续使用 -->
|
<div class="panel-title">用户列表</div>
|
||||||
|
<div class="user-list">
|
||||||
|
<div v-for="user in currentUsers" :key="user.userId" class="user-item"
|
||||||
|
:class="{ 'selected': isUserSelected(user) }" @click="toggleUserSelection(user)">
|
||||||
|
<span class="user-name">{{ user.realName || user.nickName || user.account }}</span>
|
||||||
|
<span class="user-position">{{ user.positionName }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 右侧空白区域 -->
|
<!-- 右侧已选择用户 -->
|
||||||
<div class="right-panel">
|
<div class="right-panel">
|
||||||
<!-- 暂留空,后续使用 -->
|
<div class="panel-title">已选择用户 ({{ selectedUsers.length }})</div>
|
||||||
|
<div class="selected-user-list">
|
||||||
|
<div v-for="user in selectedUsers" :key="user.userId" class="selected-user-item">
|
||||||
|
<div class="user-info">
|
||||||
|
<span class="user-name">{{ user.realName || user.nickName || user.account }}</span>
|
||||||
|
<span class="user-position">{{ user.positionName }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="time-picker-container">
|
||||||
|
<el-date-picker v-model="user.timeRange" type="datetimerange" range-separator="至"
|
||||||
|
start-placeholder="开始时间" end-placeholder="结束时间" format="YYYY-MM-DD HH:mm:ss"
|
||||||
|
value-format="YYYY-MM-DD HH:mm:ss" size="small" :shortcuts="dateShortcuts"
|
||||||
|
@change="handleTimeChange(user)" />
|
||||||
|
</div>
|
||||||
|
<el-button type="danger" size="small" icon="Delete" circle @click.stop="removeSelectedUser(user)" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -38,13 +59,31 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, onMounted } from "vue";
|
import { ref, computed, onMounted, watch } from "vue";
|
||||||
import { request } from "@/utils/request";
|
import { request } from "@/utils/request";
|
||||||
import { ElMessage } from 'element-plus';
|
import { ElMessage } from 'element-plus';
|
||||||
|
|
||||||
const formRef = ref(null);
|
const formRef = ref(null);
|
||||||
defineExpose({ formRef });
|
// 获取保存用的用户数据(格式化后的数据)
|
||||||
|
const getFormattedSelectedUsers = () => {
|
||||||
|
return selectedUsers.value.map(user => ({
|
||||||
|
userId: user.userId,
|
||||||
|
userName: user.realName || user.nickName || user.account,
|
||||||
|
orgId: user.orgId,
|
||||||
|
startTime: user.timeRange ? user.timeRange[0] : '',
|
||||||
|
endTime: user.timeRange ? user.timeRange[1] : ''
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 当前显示的用户列表
|
||||||
|
const currentUsers = ref([]);
|
||||||
|
// 已选择的用户列表
|
||||||
|
const selectedUsers = ref([]);
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
formRef,
|
||||||
|
getFormattedSelectedUsers
|
||||||
|
});
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
form: {
|
form: {
|
||||||
type: Object,
|
type: Object,
|
||||||
@ -52,6 +91,13 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 监听已选择用户变化,实时保存到form中
|
||||||
|
watch(selectedUsers, (newSelectedUsers) => {
|
||||||
|
// 格式化数据并保存到form
|
||||||
|
props.form.schedules = getFormattedSelectedUsers();
|
||||||
|
}, { deep: true, immediate: true });
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const rules = computed(() => {
|
const rules = computed(() => {
|
||||||
@ -122,14 +168,14 @@ const buildOrgTree = (orgList) => {
|
|||||||
// 取最后一个ID作为直接父级(排除-1)
|
// 取最后一个ID作为直接父级(排除-1)
|
||||||
const parentIds = pidMatches.filter(id => id !== '-1');
|
const parentIds = pidMatches.filter(id => id !== '-1');
|
||||||
if (parentIds.length > 0) {
|
if (parentIds.length > 0) {
|
||||||
parentId = parseInt(parentIds[parentIds.length - 1]);
|
parentId = parentIds[parentIds.length - 1]; // 保持字符串类型,不转成数字
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 方法2:如果无法从orgPids解析,使用orgParentId
|
// 方法2:如果无法从orgPids解析,使用orgParentId(转换为字符串)
|
||||||
if (parentId === null && org.orgParentId && org.orgParentId !== -1) {
|
if (parentId === null && org.orgParentId && org.orgParentId !== -1) {
|
||||||
parentId = org.orgParentId;
|
parentId = String(org.orgParentId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加到父节点的children中
|
// 添加到父节点的children中
|
||||||
@ -156,15 +202,66 @@ const buildOrgTree = (orgList) => {
|
|||||||
return sortTree(tree);
|
return sortTree(tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 树节点点击事件
|
// 检查用户是否已被选择
|
||||||
const handleNodeClick = (data, node) => {
|
const isUserSelected = (user) => {
|
||||||
// 判断是否为叶子节点(没有子节点)
|
return selectedUsers.value.some(selected => selected.userId === user.userId);
|
||||||
if (!node.childNodes || node.childNodes.length === 0) {
|
};
|
||||||
// 叶子节点,调用获取用户列表方法
|
|
||||||
getUsersByOrgId(data.orgId);
|
// 切换用户选择状态
|
||||||
|
const toggleUserSelection = (user) => {
|
||||||
|
if (isUserSelected(user)) {
|
||||||
|
removeSelectedUser(user);
|
||||||
|
} else {
|
||||||
|
// 添加用户时初始化时间范围和orgId
|
||||||
|
selectedUsers.value.push({
|
||||||
|
...user,
|
||||||
|
orgId: user.orgId, // 确保包含orgId
|
||||||
|
timeRange: null
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 移除已选择的用户
|
||||||
|
const removeSelectedUser = (user) => {
|
||||||
|
const index = selectedUsers.value.findIndex(selected => selected.userId === user.userId);
|
||||||
|
if (index > -1) {
|
||||||
|
selectedUsers.value.splice(index, 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 树节点点击事件
|
||||||
|
const handleNodeClick = async (_data) => {
|
||||||
|
// 获取该组织的用户列表
|
||||||
|
await getUsersByOrgId(_data.orgId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 日期时间范围快捷选项
|
||||||
|
const dateShortcuts = [
|
||||||
|
{
|
||||||
|
text: '今天',
|
||||||
|
value: [new Date(), new Date()],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '明天',
|
||||||
|
value: [
|
||||||
|
new Date(new Date().getTime() + 86400000),
|
||||||
|
new Date(new Date().getTime() + 86400000)
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '最近一周',
|
||||||
|
value: [new Date(), new Date(new Date().getTime() + 604800000)],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
// 处理时间范围变化
|
||||||
|
const handleTimeChange = (user) => {
|
||||||
|
// 时间变化时的处理逻辑可以在这里添加
|
||||||
|
console.log('时间范围变化:', user.userId, user.timeRange);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 根据组织ID查询用户列表
|
// 根据组织ID查询用户列表
|
||||||
const getUsersByOrgId = async (orgId) => {
|
const getUsersByOrgId = async (orgId) => {
|
||||||
try {
|
try {
|
||||||
@ -176,7 +273,8 @@ const getUsersByOrgId = async (orgId) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
if (res.code === '00000') {
|
if (res.code === '00000') {
|
||||||
console.log('@@@@@@用户列表',res.data);
|
currentUsers.value = res.data || [];
|
||||||
|
// console.log('@@@@@', res.data);
|
||||||
} else {
|
} else {
|
||||||
throw new Error(res.message)
|
throw new Error(res.message)
|
||||||
}
|
}
|
||||||
@ -205,6 +303,7 @@ onMounted(() => {
|
|||||||
display: flex;
|
display: flex;
|
||||||
gap: 20px;
|
gap: 20px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
height: 60vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tree-panel {
|
.tree-panel {
|
||||||
@ -213,10 +312,7 @@ onMounted(() => {
|
|||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
}
|
height: 100%;
|
||||||
|
|
||||||
.empty-panel {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.middle-panel {
|
.middle-panel {
|
||||||
@ -225,6 +321,9 @@ onMounted(() => {
|
|||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.right-panel {
|
.right-panel {
|
||||||
@ -233,6 +332,99 @@ onMounted(() => {
|
|||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-title {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #303133;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
padding-bottom: 8px;
|
||||||
|
border-bottom: 1px solid #ebeef5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-list {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-item {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 8px 12px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-item:hover {
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-item.selected {
|
||||||
|
background-color: #409eff;
|
||||||
|
color: white;
|
||||||
|
border-color: #409eff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-name {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-position {
|
||||||
|
font-size: 12px;
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-user-list {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-user-item {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 8px 12px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: #f0f9ff;
|
||||||
|
border: 1px solid #e1f5fe;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-picker-container {
|
||||||
|
flex: 1.2;
|
||||||
|
min-width: 280px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-picker-container :deep(.el-date-editor) {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-width: 120px;
|
||||||
|
flex: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-user-item .user-name {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-user-item .user-position {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #606266;
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-tree-node {
|
.custom-tree-node {
|
||||||
|
|||||||
@ -68,7 +68,7 @@ const pagination = reactive({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// 获取预警列表
|
// 获取值班列表
|
||||||
const getTableData = async (filterData = {}) => {
|
const getTableData = async (filterData = {}) => {
|
||||||
try {
|
try {
|
||||||
// 过滤空字符串属性
|
// 过滤空字符串属性
|
||||||
@ -100,7 +100,28 @@ const getTableData = async (filterData = {}) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 打开发布预警弹窗
|
// 排班提交
|
||||||
|
const addSchedule = async (form) => {
|
||||||
|
try {
|
||||||
|
const res = await request({
|
||||||
|
url: '/snow-ops-platform/law-duty/schedule',
|
||||||
|
method: "POST",
|
||||||
|
data: form
|
||||||
|
})
|
||||||
|
if (res.code === '00000') {
|
||||||
|
ElMessage.success('排班成功');
|
||||||
|
modelVisible.value = false;
|
||||||
|
getTableData(filterData)
|
||||||
|
} else {
|
||||||
|
throw new Error(res.message)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.error('排班失败');
|
||||||
|
console.error('排班失败:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 打开排班弹窗
|
||||||
const openAddDialog = () => {
|
const openAddDialog = () => {
|
||||||
model.title = '立即排班';
|
model.title = '立即排班';
|
||||||
Object.assign(form, INIT_FORM);
|
Object.assign(form, INIT_FORM);
|
||||||
@ -113,7 +134,7 @@ const openAddDialog = () => {
|
|||||||
};
|
};
|
||||||
model.onConfirm = async () => {
|
model.onConfirm = async () => {
|
||||||
await dialogRef?.value?.dynamicComponentRef?.formRef.validate().then(async () => {
|
await dialogRef?.value?.dynamicComponentRef?.formRef.validate().then(async () => {
|
||||||
console.log('@@@@@立即排班', form);
|
await addSchedule(form)
|
||||||
// await publishWarning(form)
|
// await publishWarning(form)
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { h, ref, onMounted, reactive, watch, toRaw, nextTick } from "vue";
|
|||||||
import { request } from "@/utils/request";
|
import { request } from "@/utils/request";
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import AddDialog from "./addDialog.vue";
|
import AddDialog from "./addDialog.vue";
|
||||||
|
import ScheduleDiaog from "../law/dutyManagement/addDialog.vue"
|
||||||
import DetailDrawer from "./detailDrawer.vue";
|
import DetailDrawer from "./detailDrawer.vue";
|
||||||
|
|
||||||
const tableData = ref([]); // 表格数据
|
const tableData = ref([]); // 表格数据
|
||||||
@ -305,6 +306,53 @@ const uploadFile = async (file) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const form2 = reactive({});
|
||||||
|
const INIT_FORM2 = {};
|
||||||
|
|
||||||
|
// 排班提交
|
||||||
|
const addSchedule = async (form) => {
|
||||||
|
try {
|
||||||
|
const res = await request({
|
||||||
|
url: '/snow-ops-platform/law-duty/schedule',
|
||||||
|
method: "POST",
|
||||||
|
data: form
|
||||||
|
})
|
||||||
|
if (res.code === '00000') {
|
||||||
|
ElMessage.success('排班成功');
|
||||||
|
modelVisible.value = false;
|
||||||
|
getTableData(filterData)
|
||||||
|
} else {
|
||||||
|
throw new Error(res.message)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.error('排班失败');
|
||||||
|
console.error('排班失败:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const openScheduleDiaog = () => {
|
||||||
|
model.title = '立即排班';
|
||||||
|
Object.assign(form2, INIT_FORM2);
|
||||||
|
model.props = {
|
||||||
|
form: form2,
|
||||||
|
};
|
||||||
|
model.content = ScheduleDiaog;
|
||||||
|
model.onCancel = () => {
|
||||||
|
modelVisible.value = false;
|
||||||
|
};
|
||||||
|
model.onConfirm = async () => {
|
||||||
|
await dialogRef?.value?.dynamicComponentRef?.formRef.validate().then(async () => {
|
||||||
|
await addSchedule(form)
|
||||||
|
// await publishWarning(form)
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
ElMessage.error('请处理表单中的错误项');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
model.width = "70%"
|
||||||
|
modelVisible.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -324,6 +372,12 @@ export default () => {
|
|||||||
path: '/dutyManagement'
|
path: '/dutyManagement'
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
// 跳转到消息推送设置
|
||||||
|
const gotoMessagePage = () => {
|
||||||
|
router.push({
|
||||||
|
path: '/messageManagement'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getTableData();
|
getTableData();
|
||||||
@ -348,6 +402,7 @@ export default () => {
|
|||||||
columns,
|
columns,
|
||||||
gotoLedgerPage,
|
gotoLedgerPage,
|
||||||
gotoDutyPage,
|
gotoDutyPage,
|
||||||
|
gotoMessagePage,
|
||||||
|
|
||||||
modelVisible,
|
modelVisible,
|
||||||
model,
|
model,
|
||||||
@ -356,6 +411,7 @@ export default () => {
|
|||||||
dialogRef,
|
dialogRef,
|
||||||
drawerRef,
|
drawerRef,
|
||||||
openAddDialog,
|
openAddDialog,
|
||||||
|
openScheduleDiaog,
|
||||||
|
|
||||||
uploadFile,
|
uploadFile,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,8 +15,9 @@
|
|||||||
<el-button type="primary" @click="script.openAddDialog">发布预警</el-button>
|
<el-button type="primary" @click="script.openAddDialog">发布预警</el-button>
|
||||||
<el-button type="primary" @click="triggerFileSelect">上传线下帮扶</el-button>
|
<el-button type="primary" @click="triggerFileSelect">上传线下帮扶</el-button>
|
||||||
<el-button type="primary" @click="script.gotoLedgerPage">线下帮扶台账</el-button>
|
<el-button type="primary" @click="script.gotoLedgerPage">线下帮扶台账</el-button>
|
||||||
<el-button type="primary" @click="">立即排班</el-button>
|
<el-button type="primary" @click="script.openScheduleDiaog">立即排班</el-button>
|
||||||
<el-button type="primary" @click="script.gotoDutyPage">值班管理</el-button>
|
<el-button type="primary" @click="script.gotoDutyPage">值班管理</el-button>
|
||||||
|
<el-button type="primary" @click="script.gotoMessagePage">消息推送设置</el-button>
|
||||||
<el-button type="primary" color="#952DE6" @click="">导出</el-button>
|
<el-button type="primary" color="#952DE6" @click="">导出</el-button>
|
||||||
<input type="file" ref="fileInput" style="display: none" @change="handleFileSelect" accept=".*"></input>
|
<input type="file" ref="fileInput" style="display: none" @change="handleFileSelect" accept=".*"></input>
|
||||||
<!-- <el-button type="primary" @click="script.gotoLedgerPage">驻地台账</el-button> -->
|
<!-- <el-button type="primary" @click="script.gotoLedgerPage">驻地台账</el-button> -->
|
||||||
|
|||||||
@ -0,0 +1,267 @@
|
|||||||
|
<template>
|
||||||
|
<div class="detail-container">
|
||||||
|
<el-form ref="formRef" :model="form" label-position="right" label-width="auto"
|
||||||
|
style="max-height: 60vh; overflow-y: hidden; padding-right: 50px" :rules="rules">
|
||||||
|
|
||||||
|
<el-form-item label="" prop="schedules">
|
||||||
|
<div class="user-select-container">
|
||||||
|
<!-- 左侧用户列表 -->
|
||||||
|
<div class="user-list-panel">
|
||||||
|
<div class="panel-title">用户列表</div>
|
||||||
|
<div class="user-list">
|
||||||
|
<div v-for="user in currentUsers" :key="user.userId" class="user-item"
|
||||||
|
:class="{ 'selected': isUserSelected(user) }" @click="toggleUserSelection(user)">
|
||||||
|
<span class="user-name">{{ user.realName || user.nickName || user.account }}</span>
|
||||||
|
<span class="user-position">{{ user.positionName }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 右侧已选择用户 -->
|
||||||
|
<div class="selected-panel">
|
||||||
|
<div class="panel-title">已选择用户 ({{ selectedUsers.length }})</div>
|
||||||
|
<div class="selected-user-list">
|
||||||
|
<div v-for="user in selectedUsers" :key="user.userId" class="selected-user-item">
|
||||||
|
<div class="user-info">
|
||||||
|
<span class="user-name">{{ user.realName || user.nickName || user.account }}</span>
|
||||||
|
<span class="user-position">{{ user.positionName }}</span>
|
||||||
|
</div>
|
||||||
|
<el-button type="danger" size="small" icon="Delete" circle @click.stop="removeSelectedUser(user)" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
|
||||||
|
</el-form>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, computed, onMounted, watch } from "vue";
|
||||||
|
import { request } from "@/utils/request";
|
||||||
|
import { ElMessage } from 'element-plus';
|
||||||
|
|
||||||
|
const formRef = ref(null);
|
||||||
|
|
||||||
|
// 当前显示的用户列表
|
||||||
|
const currentUsers = ref([]);
|
||||||
|
// 已选择的用户列表
|
||||||
|
const selectedUsers = ref([]);
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
formRef,
|
||||||
|
});
|
||||||
|
const props = defineProps({
|
||||||
|
form: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
orgId: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
orgName: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
const rules = computed(() => {
|
||||||
|
return {
|
||||||
|
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// 检查用户是否已被选择
|
||||||
|
const isUserSelected = (user) => {
|
||||||
|
return selectedUsers.value.some(selected => selected.userId === user.userId);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 切换用户选择状态
|
||||||
|
const toggleUserSelection = (user) => {
|
||||||
|
if (isUserSelected(user)) {
|
||||||
|
removeSelectedUser(user);
|
||||||
|
} else {
|
||||||
|
// 添加用户时初始化时间范围和orgId
|
||||||
|
selectedUsers.value.push({
|
||||||
|
// ...user,
|
||||||
|
// orgId: user.orgId, // 确保包含orgId
|
||||||
|
// timeRange: null
|
||||||
|
...user,
|
||||||
|
orgId: user.orgId,
|
||||||
|
orgName: props.orgName,
|
||||||
|
userId: user.userId,
|
||||||
|
userAccount: user.account,
|
||||||
|
userPhone: user.phone
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 移除已选择的用户
|
||||||
|
const removeSelectedUser = (user) => {
|
||||||
|
const index = selectedUsers.value.findIndex(selected => selected.userId === user.userId);
|
||||||
|
if (index > -1) {
|
||||||
|
selectedUsers.value.splice(index, 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 根据组织ID查询用户列表
|
||||||
|
const getUsersByOrgId = async (orgId) => {
|
||||||
|
// console.log('@@@@@', orgId);
|
||||||
|
try {
|
||||||
|
const res = await request({
|
||||||
|
url: '/snow-ops-platform/user/orgUsers',
|
||||||
|
method: 'GET',
|
||||||
|
params: {
|
||||||
|
orgId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (res.code === '00000') {
|
||||||
|
currentUsers.value = res.data || [];
|
||||||
|
// console.log('@@@@@', res.data);
|
||||||
|
} else {
|
||||||
|
throw new Error(res.message)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.error('获取用户失败');
|
||||||
|
console.error('获取用户失败:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getUsersByOrgId(props.orgId);
|
||||||
|
})
|
||||||
|
|
||||||
|
watch(selectedUsers.value, (val) => {
|
||||||
|
props.form.data = val;
|
||||||
|
}, { deep: true })
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.form-part {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-select-container {
|
||||||
|
display: flex;
|
||||||
|
gap: 20px;
|
||||||
|
width: 100%;
|
||||||
|
height: 60vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-list-panel {
|
||||||
|
flex: 1;
|
||||||
|
border: 1px solid #dcdfe6;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 10px;
|
||||||
|
background-color: #fff;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-panel {
|
||||||
|
flex: 1;
|
||||||
|
border: 1px solid #dcdfe6;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 10px;
|
||||||
|
background-color: #fff;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-list {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-item {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 8px 12px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-item:hover {
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-item.selected {
|
||||||
|
background-color: #409eff;
|
||||||
|
color: white;
|
||||||
|
border-color: #409eff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-name {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-position {
|
||||||
|
font-size: 12px;
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-user-list {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-user-item {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 8px 12px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: #f0f9ff;
|
||||||
|
border: 1px solid #e1f5fe;
|
||||||
|
gap: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-picker-container {
|
||||||
|
flex: 1.2;
|
||||||
|
min-width: 280px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time-picker-container :deep(.el-date-editor) {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
min-width: 120px;
|
||||||
|
flex: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-user-item .user-name {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-user-item .user-position {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #606266;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-tree-node {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 14px;
|
||||||
|
padding-right: 8px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,224 @@
|
|||||||
|
import { h, ref, onMounted, reactive, watch, toRaw, nextTick } from "vue";
|
||||||
|
import { request } from "@/utils/request";
|
||||||
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
|
import AddDialog from "./addDialog.vue";
|
||||||
|
|
||||||
|
const modelVisible = ref(false); // 弹窗状态
|
||||||
|
const drawerVisible = ref(false); // 抽屉状态
|
||||||
|
// 弹窗内容
|
||||||
|
const model = reactive({
|
||||||
|
|
||||||
|
});
|
||||||
|
const form = reactive({
|
||||||
|
|
||||||
|
});
|
||||||
|
const INIT_FORM = {
|
||||||
|
|
||||||
|
};
|
||||||
|
// 抽屉内容
|
||||||
|
const drawer = reactive({
|
||||||
|
title: '',
|
||||||
|
content: null,
|
||||||
|
props: {},
|
||||||
|
onCancel: null,
|
||||||
|
onConfirm: null,
|
||||||
|
direction: 'rtl',
|
||||||
|
size: '50%'
|
||||||
|
});
|
||||||
|
const dialogRef = ref(null); // 弹窗实例
|
||||||
|
const drawerRef = ref(null); // 抽屉实例
|
||||||
|
|
||||||
|
// 消息推送组织列表(固定六个),增加personList存储该组织的人员数组
|
||||||
|
const messageOrgList = ref([
|
||||||
|
{ title: '中心领导', orgName: '中心领导', personList: [] },
|
||||||
|
{ title: '法规处', orgName: '法规处', personList: [] },
|
||||||
|
{ title: '养护处', orgName: '养护处', personList: [] },
|
||||||
|
{ title: '农村公路处', orgName: '农村公路处', personList: [] },
|
||||||
|
{ title: '建设处', orgName: '建设处', personList: [] },
|
||||||
|
{ title: '市公路应急中心/管理段', orgName: '公路管理段', personList: [] },
|
||||||
|
])
|
||||||
|
|
||||||
|
const messagePushPerson = ref([])
|
||||||
|
const userOrgsList = ref([])
|
||||||
|
|
||||||
|
// 查询所有消息推送人员
|
||||||
|
const getAllMessagePushPerson = async () => {
|
||||||
|
try {
|
||||||
|
const res = await request({
|
||||||
|
url: '/snow-ops-platform/messagePushPerson/listAll',
|
||||||
|
method: 'GET',
|
||||||
|
})
|
||||||
|
if (res.code === '00000') {
|
||||||
|
messagePushPerson.value = res.data
|
||||||
|
|
||||||
|
// 按orgId分组填充人员数据到对应组织
|
||||||
|
messageOrgList.value.forEach(org => {
|
||||||
|
org.personList = messagePushPerson.value.filter(person => person.orgId === org.orgId)
|
||||||
|
});
|
||||||
|
|
||||||
|
// console.log('@@@@@@', messageOrgList.value);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
throw new Error(res.message)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.error('获取消息推送人员失败');
|
||||||
|
console.error('获取消息推送人员失败:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 查询所有组织
|
||||||
|
const getUserOrgs = async () => {
|
||||||
|
try {
|
||||||
|
const res = await request({
|
||||||
|
url: '/snow-ops-platform/user/userOrgs',
|
||||||
|
method: 'GET',
|
||||||
|
})
|
||||||
|
if (res.code === '00000') {
|
||||||
|
userOrgsList.value = res.data.data
|
||||||
|
|
||||||
|
// 遍历后端返回的组织数据,与固定组织列表匹配并赋值orgId
|
||||||
|
messageOrgList.value.forEach(fixedOrg => {
|
||||||
|
const matchedOrg = userOrgsList.value.find(org =>
|
||||||
|
org.orgName === fixedOrg.orgName
|
||||||
|
);
|
||||||
|
if (matchedOrg) {
|
||||||
|
fixedOrg.orgId = matchedOrg.orgId;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 在获取到orgId后,立即根据orgId填充对应的人员数据
|
||||||
|
messageOrgList.value.forEach(org => {
|
||||||
|
org.personList = messagePushPerson.value.filter(person => person.orgId === org.orgId)
|
||||||
|
});
|
||||||
|
|
||||||
|
// console.log('@@@@',messageOrgList.value);
|
||||||
|
} else {
|
||||||
|
throw new Error(res.message)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.error('获取组织失败');
|
||||||
|
console.error('获取组织失败:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加消息推送人
|
||||||
|
const handelAdd = async (data) => {
|
||||||
|
try {
|
||||||
|
const loading = ElLoading.service({
|
||||||
|
lock: true,
|
||||||
|
text: '操作中',
|
||||||
|
background: 'rgba(0, 0, 0, 0.7)',
|
||||||
|
})
|
||||||
|
const res = await request({
|
||||||
|
url: '/snow-ops-platform/messagePushPerson/add',
|
||||||
|
method: 'POST',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
loading.close();
|
||||||
|
if (res.code === '00000') {
|
||||||
|
ElMessage.success('添加成功');
|
||||||
|
modelVisible.value = false;
|
||||||
|
await getAllMessagePushPerson();
|
||||||
|
} else {
|
||||||
|
throw new Error(res.message)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
ElMessage.error('添加失败');
|
||||||
|
console.error('添加失败:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 打开添加人员弹窗
|
||||||
|
const openAddDialog = (orgId, orgName) => {
|
||||||
|
model.title = '添加人员';
|
||||||
|
Object.assign(form, INIT_FORM);
|
||||||
|
model.props = {
|
||||||
|
orgId: orgId,
|
||||||
|
orgName: orgName,
|
||||||
|
form: form,
|
||||||
|
};
|
||||||
|
model.content = AddDialog;
|
||||||
|
model.onCancel = () => {
|
||||||
|
modelVisible.value = false;
|
||||||
|
};
|
||||||
|
model.onConfirm = async () => {
|
||||||
|
await dialogRef?.value?.dynamicComponentRef?.formRef.validate().then(async () => {
|
||||||
|
// console.log('@@@@@@form',form);
|
||||||
|
await handelAdd(form.data)
|
||||||
|
// await addSchedule(form)
|
||||||
|
// await publishWarning(form)
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
ElMessage.error('请处理表单中的错误项');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
model.width = "70%"
|
||||||
|
modelVisible.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除消息推送人
|
||||||
|
const deletePushPerson = async (person) => {
|
||||||
|
try {
|
||||||
|
await ElMessageBox.confirm(
|
||||||
|
`确定要删除【${person.realName}】吗?`,
|
||||||
|
'删除确认',
|
||||||
|
{
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning',
|
||||||
|
}
|
||||||
|
)
|
||||||
|
const loading = ElLoading.service({
|
||||||
|
lock: true,
|
||||||
|
text: '操作中',
|
||||||
|
background: 'rgba(0, 0, 0, 0.7)',
|
||||||
|
})
|
||||||
|
const res = await request({
|
||||||
|
url: '/snow-ops-platform/messagePushPerson/deleteByUserId',
|
||||||
|
method: 'POST',
|
||||||
|
data: {
|
||||||
|
userId: person.userId
|
||||||
|
}
|
||||||
|
})
|
||||||
|
loading.close();
|
||||||
|
if (res.code === '00000') {
|
||||||
|
ElMessage.success('删除成功');
|
||||||
|
await getAllMessagePushPerson();
|
||||||
|
} else {
|
||||||
|
throw new Error(res.message)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
if (error !== 'cancel') {
|
||||||
|
ElMessage.error('删除失败');
|
||||||
|
console.error('删除失败:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
await getUserOrgs();
|
||||||
|
await getAllMessagePushPerson();
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
modelVisible,
|
||||||
|
model,
|
||||||
|
drawerVisible,
|
||||||
|
drawer,
|
||||||
|
dialogRef,
|
||||||
|
drawerRef,
|
||||||
|
openAddDialog,
|
||||||
|
deletePushPerson,
|
||||||
|
|
||||||
|
messageOrgList,
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,121 @@
|
|||||||
|
<template>
|
||||||
|
<div class="root">
|
||||||
|
<div class="content-box">
|
||||||
|
<el-card shadow="never" v-for="org in script.messageOrgList.value" class="org-box">
|
||||||
|
<template #header>
|
||||||
|
<div class="card-header">
|
||||||
|
<span>{{ org.title }}</span>
|
||||||
|
<el-button type="primary" size="small" text
|
||||||
|
@click="script.openAddDialog(org.orgId, org.orgName)">添加</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<!-- 人员列表 -->
|
||||||
|
<div class="person-list">
|
||||||
|
<div v-if="org.personList.length === 0" class="empty-text">暂无人员</div>
|
||||||
|
<div v-else class="person-item" v-for="person in org.personList" :key="person.userId">
|
||||||
|
<div class="person-info">
|
||||||
|
<span class="name">{{ person.realName }}</span>
|
||||||
|
<!-- <span class="account">({{ person.userAccount }})</span> -->
|
||||||
|
<span class="phone" v-if="person.userPhone">{{ person.userPhone }}</span>
|
||||||
|
</div>
|
||||||
|
<el-button type="danger" size="small" text @click="script.deletePushPerson(person)">删除</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
<div class="model-box">
|
||||||
|
<MyDialog v-model="script.modelVisible.value" :title="script.model?.title"
|
||||||
|
:dynamicComponent="script.model?.content" :component-props="script.model?.props"
|
||||||
|
:onConfirm="script.model?.onConfirm" :onCancel="script.model?.onCancel" ref="dialogRef"
|
||||||
|
:width="script.model?.width">
|
||||||
|
</MyDialog>
|
||||||
|
<MyDrawer v-model="script.drawerVisible.value" :title="script.drawer?.title"
|
||||||
|
:dynamicComponent="script.drawer?.content" :component-props="script.drawer?.props"
|
||||||
|
:onConfirm="script.drawer?.onConfirm" :onCancel="script.drawer?.onCancel" ref="drawerRef"
|
||||||
|
:direction="script.drawer?.direction" :size="script.drawer?.size">
|
||||||
|
</MyDrawer>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import DynamicTable from "@/component/DynamicTable/index.js";
|
||||||
|
import { Search, ArrowDown } from "@element-plus/icons-vue";
|
||||||
|
import MyDialog from "@/component/MyDialog/index.js";
|
||||||
|
import MyDrawer from "@/component/MyDrawer/index.js";
|
||||||
|
import scriptFn from "./index.js";
|
||||||
|
const script = scriptFn();
|
||||||
|
const { dialogRef, drawerRef } = script;
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.root {
|
||||||
|
height: 100%;
|
||||||
|
padding: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-box {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.org-box {
|
||||||
|
flex: 1;
|
||||||
|
height: 100%;
|
||||||
|
min-width: fit-content;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-header {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
white-space: nowrap;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.person-list {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-text {
|
||||||
|
color: #999;
|
||||||
|
text-align: center;
|
||||||
|
padding: 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.person-item {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 8px 0;
|
||||||
|
border-bottom: 1px solid #f0f0f0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.person-item:last-child {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.person-info {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.name {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account {
|
||||||
|
color: #666;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.phone {
|
||||||
|
color: #666;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -48,6 +48,12 @@ export function useOptions() {
|
|||||||
{ label: '限制通行', value: '限制通行' }
|
{ label: '限制通行', value: '限制通行' }
|
||||||
]
|
]
|
||||||
|
|
||||||
|
// 冰灾 处理措施
|
||||||
|
options.value['iceDisposalMeasures'] = [
|
||||||
|
{ label: '封闭交通', value: '封闭交通' },
|
||||||
|
{ label: '限速通行', value: '限速通行' },
|
||||||
|
]
|
||||||
|
|
||||||
// 路线类型
|
// 路线类型
|
||||||
options.value['roadType'] = [
|
options.value['roadType'] = [
|
||||||
{ label: '国道', value: 'G' },
|
{ label: '国道', value: 'G' },
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user