From c54f37313cfa74e385b384814952b89e4a9aa4f4 Mon Sep 17 00:00:00 2001 From: huangchenhao <123673748@qq.com> Date: Thu, 16 Apr 2026 14:05:24 +0800 Subject: [PATCH 1/5] =?UTF-8?q?feat:=20=E6=8E=92=E7=8F=AD=E6=8F=90?= =?UTF-8?q?=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../law/dutyManagement/addDialog.vue | 240 ++++++++++++++++-- .../law/dutyManagement/index.js | 27 +- .../src/views/WarningManagement/law/index.js | 49 ++++ .../src/views/WarningManagement/law/index.vue | 2 +- 4 files changed, 288 insertions(+), 30 deletions(-) diff --git a/packages/screen/src/views/WarningManagement/law/dutyManagement/addDialog.vue b/packages/screen/src/views/WarningManagement/law/dutyManagement/addDialog.vue index 5d9bb1c..e1f08fd 100644 --- a/packages/screen/src/views/WarningManagement/law/dutyManagement/addDialog.vue +++ b/packages/screen/src/views/WarningManagement/law/dutyManagement/addDialog.vue @@ -11,24 +11,45 @@ children: 'children', label: 'orgName' }" node-key="orgId" :expand-on-click-node="false" :default-expand-all="false" highlight-current - style="height: 400px; overflow-y: auto;" - @node-click="handleNodeClick"> - + + diff --git a/packages/screen/src/views/DisasterManagement/WaterDisasterReport/useWaterDisasterReport.js b/packages/screen/src/views/DisasterManagement/WaterDisasterReport/useWaterDisasterReport.js new file mode 100644 index 0000000..84e36a8 --- /dev/null +++ b/packages/screen/src/views/DisasterManagement/WaterDisasterReport/useWaterDisasterReport.js @@ -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 + } +} diff --git a/packages/screen/src/views/DisasterManagement/WaterDisasterReport/waterMockJson.json b/packages/screen/src/views/DisasterManagement/WaterDisasterReport/waterMockJson.json index b4b555f..a69aea3 100644 --- a/packages/screen/src/views/DisasterManagement/WaterDisasterReport/waterMockJson.json +++ b/packages/screen/src/views/DisasterManagement/WaterDisasterReport/waterMockJson.json @@ -12,7 +12,6 @@ "district": "武侯区", "endStakeNo": "K2251+200", "estimatedRecoveryCost": 120.5, - "inspectionMileage": 25.6, "isBlocked": true, "needsRecovery": true, "repairProgress": "抢险中", diff --git a/packages/screen/src/views/DisasterManagement/components/MaterialList.vue b/packages/screen/src/views/DisasterManagement/components/MaterialList.vue new file mode 100644 index 0000000..429f788 --- /dev/null +++ b/packages/screen/src/views/DisasterManagement/components/MaterialList.vue @@ -0,0 +1,170 @@ + + + + + diff --git a/packages/screen/src/views/DisasterManagement/components/RoadRoutesSelect.vue b/packages/screen/src/views/DisasterManagement/components/RoadRoutesSelect.vue index 9fc1342..030ea7a 100644 --- a/packages/screen/src/views/DisasterManagement/components/RoadRoutesSelect.vue +++ b/packages/screen/src/views/DisasterManagement/components/RoadRoutesSelect.vue @@ -6,7 +6,7 @@ - +
已选择地点路线:{{ tempSelectedItem?.routeCode }}
diff --git a/packages/screen/src/views/DisasterManagement/components/YHZSelect.vue b/packages/screen/src/views/DisasterManagement/components/YHZSelect.vue new file mode 100644 index 0000000..b74bc6c --- /dev/null +++ b/packages/screen/src/views/DisasterManagement/components/YHZSelect.vue @@ -0,0 +1,253 @@ + + + + + \ No newline at end of file diff --git a/packages/shared/composables/useOptions.js b/packages/shared/composables/useOptions.js index d50d0bc..a1a3c09 100644 --- a/packages/shared/composables/useOptions.js +++ b/packages/shared/composables/useOptions.js @@ -48,6 +48,12 @@ export function useOptions() { { label: '限制通行', value: '限制通行' } ] + // 冰灾 处理措施 + options.value['iceDisposalMeasures'] = [ + { label: '封闭交通', value: '封闭交通' }, + { label: '限速通行', value: '限速通行' }, + ] + // 路线类型 options.value['roadType'] = [ { label: '国道', value: 'G' }, From 1a4041cb492cab4308ece8ad92c63be3b6bca73e Mon Sep 17 00:00:00 2001 From: huangchenhao <123673748@qq.com> Date: Fri, 17 Apr 2026 14:37:53 +0800 Subject: [PATCH 5/5] =?UTF-8?q?feat:=20=E6=B6=88=E6=81=AF=E6=8E=A8?= =?UTF-8?q?=E9=80=81=E8=AE=BE=E7=BD=AE=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/screen/src/router/index.js | 11 + .../src/views/WarningManagement/law/index.js | 7 + .../src/views/WarningManagement/law/index.vue | 1 + .../law/messageManagement/addDialog.vue | 267 ++++++++++++++++++ .../law/messageManagement/index.js | 224 +++++++++++++++ .../law/messageManagement/index.vue | 121 ++++++++ 6 files changed, 631 insertions(+) create mode 100644 packages/screen/src/views/WarningManagement/law/messageManagement/addDialog.vue create mode 100644 packages/screen/src/views/WarningManagement/law/messageManagement/index.js create mode 100644 packages/screen/src/views/WarningManagement/law/messageManagement/index.vue diff --git a/packages/screen/src/router/index.js b/packages/screen/src/router/index.js index 13d592b..5992040 100644 --- a/packages/screen/src/router/index.js +++ b/packages/screen/src/router/index.js @@ -190,6 +190,17 @@ const routes = [ parentRoute: 'warningManagement3' } }, + { + path: '/messageManagement', + name: 'messageManagement', + component: () => import('../views/WarningManagement/law/messageManagement/index.vue'), + meta: { + title: '消息推送设置', + breadcrumb: true, + parentRoute: 'warningManagement3' + } + }, + // 项目管理 - 区县 { diff --git a/packages/screen/src/views/WarningManagement/law/index.js b/packages/screen/src/views/WarningManagement/law/index.js index 2f731a6..5453d4b 100644 --- a/packages/screen/src/views/WarningManagement/law/index.js +++ b/packages/screen/src/views/WarningManagement/law/index.js @@ -372,6 +372,12 @@ export default () => { path: '/dutyManagement' }); }; + // 跳转到消息推送设置 + const gotoMessagePage = () => { + router.push({ + path: '/messageManagement' + }); + } onMounted(() => { getTableData(); @@ -396,6 +402,7 @@ export default () => { columns, gotoLedgerPage, gotoDutyPage, + gotoMessagePage, modelVisible, model, diff --git a/packages/screen/src/views/WarningManagement/law/index.vue b/packages/screen/src/views/WarningManagement/law/index.vue index 5bb49f2..1677d54 100644 --- a/packages/screen/src/views/WarningManagement/law/index.vue +++ b/packages/screen/src/views/WarningManagement/law/index.vue @@ -17,6 +17,7 @@ 线下帮扶台账 立即排班 值班管理 + 消息推送设置 导出 diff --git a/packages/screen/src/views/WarningManagement/law/messageManagement/addDialog.vue b/packages/screen/src/views/WarningManagement/law/messageManagement/addDialog.vue new file mode 100644 index 0000000..bac4316 --- /dev/null +++ b/packages/screen/src/views/WarningManagement/law/messageManagement/addDialog.vue @@ -0,0 +1,267 @@ + + + + + \ No newline at end of file diff --git a/packages/screen/src/views/WarningManagement/law/messageManagement/index.js b/packages/screen/src/views/WarningManagement/law/messageManagement/index.js new file mode 100644 index 0000000..bd41e74 --- /dev/null +++ b/packages/screen/src/views/WarningManagement/law/messageManagement/index.js @@ -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, + + } +} \ No newline at end of file diff --git a/packages/screen/src/views/WarningManagement/law/messageManagement/index.vue b/packages/screen/src/views/WarningManagement/law/messageManagement/index.vue new file mode 100644 index 0000000..2920ca2 --- /dev/null +++ b/packages/screen/src/views/WarningManagement/law/messageManagement/index.vue @@ -0,0 +1,121 @@ + + + + + \ No newline at end of file