Procházet zdrojové kódy

feat: 预警信息联动应急事件

bxy před 5 měsíci
rodič
revize
a239b8c9bc

+ 2 - 0
src/types/disaster-warning/index.ts

@@ -38,6 +38,8 @@ export interface WarningInfoDetailResponse
   extends BasicDetailResponse,
     Omit<WarningInfoListResponse, 'effectState' | 'isPush' | 'pushTime'> {
   source: string;
+  isEmergency: number;
+  eventType?: string;
 }
 
 export interface DefenseNoticeDetailResponse

+ 6 - 0
src/views/disaster/constant/index.ts

@@ -8,6 +8,12 @@ export enum IS_PUSH {
   PUSH,
 }
 
+// 是否启动应急事件
+export enum IS_EMERGENCY {
+  NOT_EMERGENCY = 0,
+  EMERGENCY,
+}
+
 // 生效状态
 export enum ACTIVE_STATUS {
   INACTIVE = 0,

+ 4 - 0
src/views/disaster/disaster-warning/PageWarningInfoItem.vue

@@ -54,6 +54,8 @@
       warnTime: formData.warnTime,
       source: formData.source,
       content: formData.content,
+      isEmergency: formData.isEmergency,
+      eventType: formData.eventType,
       isPush: formData.isPush,
       userGroupList: formData.isPush ? formData.userGroupList : [],
     };
@@ -67,6 +69,8 @@
       warnTime: formData.warnTime,
       source: formData.source,
       content: formData.content,
+      isEmergency: formData.isEmergency,
+      eventType: formData.eventType,
       isPush: formData.isPush,
       userGroupList: formData.isPush ? formData.userGroupList : [],
     };

+ 77 - 5
src/views/disaster/disaster-warning/src/components/CreateWarningInfoItem.vue

@@ -21,6 +21,22 @@
           />
         </el-select>
       </template>
+      <template #isEmergency>
+        <el-radio-group v-model="ruleFormData.isEmergency">
+          <el-radio :value="IS_EMERGENCY.EMERGENCY">是</el-radio>
+          <el-radio :value="IS_EMERGENCY.NOT_EMERGENCY">否</el-radio>
+        </el-radio-group>
+      </template>
+      <template #eventType>
+        <el-select v-model="ruleFormData.eventType" placeholder="请选择应急事件类型" filterable>
+          <el-option
+            v-for="item in emergencyEventDice"
+            :key="item.itemCode"
+            :label="item.itemValue"
+            :value="item.itemValue"
+          />
+        </el-select>
+      </template>
       <template #isPush>
         <el-radio-group v-model="ruleFormData.isPush">
           <el-radio :value="IS_PUSH.PUSH">是</el-radio>
@@ -29,8 +45,8 @@
         <SelectGroup
           v-if="ruleFormData.isPush"
           ref="selectGroupRef"
-          :userGroupList="ruleFormData.userGroupList || []"
-          @userGroupListChange="handleUserGroupListChange"
+          :user-group-list="ruleFormData.userGroupList || []"
+          @user-group-list-change="handleUserGroupListChange"
         />
       </template>
     </BasicForm>
@@ -38,27 +54,79 @@
 </template>
 
 <script setup lang="ts">
-  import { onMounted, ref } from 'vue';
+  import { onMounted, ref, watch } from 'vue';
   import BasicForm from '@/components/BasicForm.vue';
   import SelectGroup from '@/components/PersonGroup/SelectGroup.vue';
   import { useFormConfigHook } from '@/hooks/useFormConfigHook';
   import { useUserInfoHook } from '@/views/disaster/hooks';
   import { useDisasterWarningHook } from '../hook';
+  import { useEmergencyProcedureHook } from '@/views/emergency/emergency-procedure/hooks';
   import type { WarningInfoRuleForm } from '../type';
   import { WARNING_INFO_FROM_CONFIG, WARNING_INFO_FROM_DATA, WARNING_INFO_FROM_RULES } from '../config';
-  import { IS_PUSH } from '@/views/disaster/constant';
+  import { IS_PUSH, IS_EMERGENCY } from '@/views/disaster/constant';
 
   const { realname } = useUserInfoHook();
   const basicFormRef = ref<InstanceType<typeof BasicForm>>();
   const selectGroupRef = ref<InstanceType<typeof SelectGroup>>();
 
   const { warningTypeDice, disasterLevelDice, getWarningInfoDict, getDisasterLevelDict } = useDisasterWarningHook();
+  const { emergencyEventDice, getEmergencyEventDict } = useEmergencyProcedureHook();
 
   const { ruleFormConfig, ruleFormData, formRules, cloneRuleFormData, beforeRouteLeave } =
     useFormConfigHook<WarningInfoRuleForm>(WARNING_INFO_FROM_CONFIG, WARNING_INFO_FROM_DATA, WARNING_INFO_FROM_RULES);
 
+  // 应急事件类型配置
+  const EVENT_TYPE_PROP = 'eventType';
+  const initialFormConfig = [...ruleFormConfig.value];
+  const eventTypeIndex = initialFormConfig.findIndex((item) => item.prop === EVENT_TYPE_PROP);
+  const eventTypeConfig = eventTypeIndex > -1 ? initialFormConfig[eventTypeIndex] : null;
+  const eventTypeRules = formRules[EVENT_TYPE_PROP];
+
+  // 如果应急事件未启动,则默认启动应急事件
+  if (ruleFormData.isEmergency === undefined || ruleFormData.isEmergency === null) {
+    ruleFormData.isEmergency = IS_EMERGENCY.EMERGENCY;
+  }
+
+  watch(
+    () => ruleFormData.isEmergency,
+    (value) => {
+      const isEmergencyOpen = value === IS_EMERGENCY.EMERGENCY;
+
+      // 如果应急事件未启动,则清空应急事件类型
+      if (!isEmergencyOpen) {
+        if (ruleFormData.eventType) {
+          ruleFormData.eventType = '';
+        }
+        // 如果应急事件类型配置存在,则删除应急事件类型配置
+        if (eventTypeConfig && ruleFormConfig.value.some((item) => item.prop === EVENT_TYPE_PROP)) {
+          const withoutEventType = ruleFormConfig.value.filter((item) => item.prop !== EVENT_TYPE_PROP);
+          ruleFormConfig.value = withoutEventType;
+        }
+        // 如果应急事件类型规则存在,则删除应急事件类型规则
+        if (formRules[EVENT_TYPE_PROP]) {
+          delete formRules[EVENT_TYPE_PROP];
+        }
+        return;
+      }
+
+      // 如果应急事件已启动,则添加应急事件类型配置
+      if (eventTypeConfig && !ruleFormConfig.value.some((item) => item.prop === EVENT_TYPE_PROP)) {
+        const newConfig = [...ruleFormConfig.value];
+        const insertIndex =
+          eventTypeIndex > -1 && eventTypeIndex <= newConfig.length ? eventTypeIndex : newConfig.length;
+        newConfig.splice(insertIndex, 0, eventTypeConfig);
+        ruleFormConfig.value = newConfig;
+      }
+
+      if (eventTypeRules) {
+        formRules[EVENT_TYPE_PROP] = eventTypeRules;
+      }
+    },
+    { immediate: true },
+  );
+
   const handleUserGroupListChange = (userGroupList: number[]) => {
-    ruleFormData.userGroupList = userGroupList;
+    ruleFormData.userGroupList = userGroupList ?? [];
   };
 
   const handleValidate = async () => {
@@ -74,6 +142,9 @@
     if (!ruleFormData.isPush) {
       ruleFormData.userGroupList = [];
     }
+    if (ruleFormData.isEmergency !== IS_EMERGENCY.EMERGENCY) {
+      ruleFormData.eventType = '';
+    }
     cloneRuleFormData();
     return ruleFormData;
   };
@@ -85,6 +156,7 @@
   onMounted(() => {
     getWarningInfoDict();
     getDisasterLevelDict();
+    getEmergencyEventDict();
     ruleFormData.realname = realname;
     cloneRuleFormData();
     beforeRouteLeave();

+ 69 - 5
src/views/disaster/disaster-warning/src/components/EditWarningInfoItem.vue

@@ -21,6 +21,22 @@
           />
         </el-select>
       </template>
+      <template #isEmergency>
+        <el-radio-group v-model="ruleFormData.isEmergency">
+          <el-radio :value="IS_EMERGENCY.EMERGENCY">是</el-radio>
+          <el-radio :value="IS_EMERGENCY.NOT_EMERGENCY">否</el-radio>
+        </el-radio-group>
+      </template>
+      <template #eventType>
+        <el-select v-model="ruleFormData.eventType" placeholder="请选择应急事件类型" filterable>
+          <el-option
+            v-for="item in emergencyEventDice"
+            :key="item.itemCode"
+            :label="item.itemValue"
+            :value="item.itemValue"
+          />
+        </el-select>
+      </template>
       <template #isPush>
         <el-radio-group v-model="ruleFormData.isPush">
           <el-radio :value="IS_PUSH.PUSH">是</el-radio>
@@ -29,8 +45,8 @@
         <SelectGroup
           v-if="ruleFormData.isPush"
           ref="selectGroupRef"
-          :userGroupList="ruleFormData.userGroupList || []"
-          @userGroupListChange="handleUserGroupListChange"
+          :user-group-list="ruleFormData.userGroupList || []"
+          @user-group-list-change="handleUserGroupListChange"
         />
       </template>
     </BasicForm>
@@ -38,15 +54,16 @@
 </template>
 
 <script setup lang="ts">
-  import { onMounted, ref } from 'vue';
+  import { onMounted, ref, watch } from 'vue';
   import BasicForm from '@/components/BasicForm.vue';
   import SelectGroup from '@/components/PersonGroup/SelectGroup.vue';
   import { useFormConfigHook } from '@/hooks/useFormConfigHook';
   import { useDisasterWarningHook } from '../hook';
+  import { useEmergencyProcedureHook } from '@/views/emergency/emergency-procedure/hooks';
   import type { WarningInfoRuleForm } from '../type';
   import { getWarningInfoDetail } from '@/api/disaster-warning';
   import { WARNING_INFO_FROM_CONFIG, WARNING_INFO_FROM_DATA, WARNING_INFO_FROM_RULES } from '../config';
-  import { IS_PUSH } from '@/views/disaster/constant';
+  import { IS_PUSH, IS_EMERGENCY } from '@/views/disaster/constant';
 
   const props = defineProps<{
     id: number;
@@ -56,10 +73,50 @@
   const selectGroupRef = ref<InstanceType<typeof SelectGroup>>();
 
   const { warningTypeDice, disasterLevelDice, getWarningInfoDict, getDisasterLevelDict } = useDisasterWarningHook();
+  const { emergencyEventDice, getEmergencyEventDict } = useEmergencyProcedureHook();
 
   const { ruleFormConfig, ruleFormData, formRules, cloneRuleFormData, beforeRouteLeave } =
     useFormConfigHook<WarningInfoRuleForm>(WARNING_INFO_FROM_CONFIG, WARNING_INFO_FROM_DATA, WARNING_INFO_FROM_RULES);
 
+  const EVENT_TYPE_PROP = 'eventType';
+  const initialFormConfig = [...ruleFormConfig.value];
+  const eventTypeIndex = initialFormConfig.findIndex((item) => item.prop === EVENT_TYPE_PROP);
+  const eventTypeConfig = eventTypeIndex > -1 ? initialFormConfig[eventTypeIndex] : null;
+  const eventTypeRules = formRules[EVENT_TYPE_PROP];
+
+  watch(
+    () => ruleFormData.isEmergency,
+    (value) => {
+      const isEmergencyOpen = value === IS_EMERGENCY.EMERGENCY;
+
+      if (!isEmergencyOpen) {
+        if (ruleFormData.eventType) {
+          ruleFormData.eventType = '';
+        }
+        if (eventTypeConfig && ruleFormConfig.value.some((item) => item.prop === EVENT_TYPE_PROP)) {
+          ruleFormConfig.value = ruleFormConfig.value.filter((item) => item.prop !== EVENT_TYPE_PROP);
+        }
+        if (formRules[EVENT_TYPE_PROP]) {
+          delete formRules[EVENT_TYPE_PROP];
+        }
+        return;
+      }
+
+      if (eventTypeConfig && !ruleFormConfig.value.some((item) => item.prop === EVENT_TYPE_PROP)) {
+        const newConfig = [...ruleFormConfig.value];
+        const insertIndex =
+          eventTypeIndex > -1 && eventTypeIndex <= newConfig.length ? eventTypeIndex : newConfig.length;
+        newConfig.splice(insertIndex, 0, eventTypeConfig);
+        ruleFormConfig.value = newConfig;
+      }
+
+      if (eventTypeRules) {
+        formRules[EVENT_TYPE_PROP] = eventTypeRules;
+      }
+    },
+    { immediate: true },
+  );
+
   const handleUserGroupListChange = (userGroupList: number[]) => {
     ruleFormData.userGroupList = userGroupList;
   };
@@ -68,8 +125,11 @@
     const res = await getWarningInfoDetail(props.id);
     for (const key in res) {
       if (key in ruleFormData) {
+        if (key === 'userGroupList') {
+          ruleFormData.userGroupList = JSON.parse(res.userGroupList as unknown as string);
+          continue;
+        }
         ruleFormData[key] = res[key as keyof typeof res];
-        ruleFormData.userGroupList = JSON.parse(res.userGroupList as unknown as string);
       }
     }
     cloneRuleFormData();
@@ -88,6 +148,9 @@
     if (!ruleFormData.isPush) {
       ruleFormData.userGroupList = [];
     }
+    if (ruleFormData.isEmergency !== IS_EMERGENCY.EMERGENCY) {
+      ruleFormData.eventType = '';
+    }
     cloneRuleFormData();
     return ruleFormData;
   };
@@ -100,6 +163,7 @@
     getWarningInfoDetailData();
     getWarningInfoDict();
     getDisasterLevelDict();
+    getEmergencyEventDict();
     beforeRouteLeave();
   });
 </script>

+ 27 - 5
src/views/disaster/disaster-warning/src/components/ViewWarningInfoItem.vue

@@ -14,31 +14,55 @@
       <p class="info-item">
         信息来源:<span class="info-content">{{ warningInfoDetail?.source }}</span>
       </p>
+      <p class="info-item">
+        启动应急事件:<span class="info-content">{{ getEmergencyStatusLabel }}</span>
+      </p>
+      <p v-if="warningInfoDetail?.isEmergency === IS_EMERGENCY.EMERGENCY" class="info-item">
+        应急事件类型:<span class="info-content">{{ emergencyEventLabel }}</span>
+      </p>
     </div>
   </header>
-  <section class="divider" />
+  <section class="divider"></section>
   <section class="content">
+    <!-- eslint-disable-next-line vue/no-v-html -->
     <div v-html="warningInfoDetail?.content"></div>
   </section>
 </template>
 
 <script setup lang="ts">
-  import { ref, onMounted } from 'vue';
+  import { ref, onMounted, computed } from 'vue';
   import { useDisasterWarningHook } from '../hook';
   import type { WarningInfoDetailResponse } from '@/types/disaster-warning';
   import { getWarningInfoDetail } from '@/api/disaster-warning';
+  import { useEmergencyProcedureHook } from '@/views/emergency/emergency-procedure/hooks';
+  import { IS_EMERGENCY } from '@/views/disaster/constant';
 
   const props = defineProps<{
     id: number;
   }>();
 
   const { getWarningInfoDict, getWarningType, getDisasterLevelDict, getDisasterLevel } = useDisasterWarningHook();
+  const { emergencyEventDice, getEmergencyEventDict } = useEmergencyProcedureHook();
 
   const warningInfoDetail = ref<WarningInfoDetailResponse>();
 
+  const getEmergencyStatusLabel = computed(() => {
+    if (!warningInfoDetail.value) return '-';
+    return warningInfoDetail.value.isEmergency === IS_EMERGENCY.EMERGENCY ? '是' : '否';
+  });
+
+  const emergencyEventLabel = computed(() => {
+    if (!warningInfoDetail.value || warningInfoDetail.value.isEmergency !== IS_EMERGENCY.EMERGENCY) {
+      return '-';
+    }
+    const eventType = warningInfoDetail.value.eventType || '';
+    return eventType || emergencyEventDice.value.find((item) => item.itemValue === eventType)?.itemValue || '-';
+  });
+
   onMounted(() => {
     getWarningInfoDict();
     getDisasterLevelDict();
+    getEmergencyEventDict();
     getWarningInfoDetail(props.id).then((res) => {
       warningInfoDetail.value = res;
     });
@@ -54,8 +78,6 @@
   }
   .info-item {
     width: 50%;
-    &:nth-child(1) {
-      margin-bottom: 16px;
-    }
+    margin-bottom: 16px;
   }
 </style>

+ 17 - 1
src/views/disaster/disaster-warning/src/config/form.ts

@@ -2,6 +2,8 @@
  * 灾害预警信息表单配置
  */
 import type { FormConfig } from '@/types/basic-form';
+import { IS_EMERGENCY } from '@/views/disaster/constant';
+
 // 通用表单信息
 const BASIC_FROM_CONFIG = {
   DISASTER_LEVEL: {
@@ -62,9 +64,19 @@ export const WARNING_INFO_FROM_CONFIG: FormConfig[] = [
     componentProps: {
       placeholder: '请输入发布内容',
       type: 'textarea',
-      rows: 5
+      rows: 5,
     },
   },
+  {
+    label: '启动应急事件:',
+    prop: 'isEmergency',
+    slot: 'isEmergency',
+  },
+  {
+    label: '应急事件类型:',
+    prop: 'eventType',
+    slot: 'eventType',
+  },
   BASIC_FROM_CONFIG.IS_PUSH,
   BASIC_FROM_CONFIG.CREATE_USER,
 ];
@@ -123,6 +135,8 @@ export const WARNING_INFO_FROM_DATA = {
   ...BASIC_FROM_DATA,
   warnTime: '',
   source: '',
+  isEmergency: IS_EMERGENCY.EMERGENCY,
+  eventType: '',
 };
 
 // 防御通知表单数据
@@ -153,6 +167,8 @@ export const WARNING_INFO_FROM_RULES = {
   ...BASIC_FROM_RULES,
   warnTime: [{ required: true, message: '请选择预警时间', trigger: 'change' }],
   source: [{ required: true, message: '请输入信息来源', trigger: 'blur' }],
+  isEmergency: [{ required: true, message: '请选择是否启动应急事件', trigger: 'change' }],
+  eventType: [{ required: true, message: '请选择应急事件类型', trigger: 'change' }],
 };
 
 // 防御通知表单规则