瀏覽代碼

完成静态数据 灾害预警通知

chauncey 11 月之前
父節點
當前提交
303e607db1

+ 48 - 12
src/views/disaster/components/PushObject.vue

@@ -2,18 +2,31 @@
   <div class="push-object-container">
     <el-form :model="ruleForm" ref="ruleFormRef">
       <el-form-item>
-        <el-radio-group v-model="ruleForm.recipientType">
+        <el-radio-group v-model="ruleForm.recipientType" @change="emits('recipientTypeChange', ruleForm.recipientType)">
           <el-radio :value="1">分组</el-radio>
           <el-radio :value="2">自定义</el-radio>
         </el-radio-group>
       </el-form-item>
       <div class="userList" v-if="ruleForm.recipientType === 1">
-        <el-form-item label="选择分组" prop="userGroupList" :rules="[{ required: true, message: '请选择分组' }]">
-          <el-select v-model="ruleForm.userGroupList" multiple placeholder="请选择分组" filterable>
+        <el-form-item
+          label="选择分组"
+          prop="userGroupList"
+          :rules="[{ required: true, message: '请选择分组' }]"
+          class="user-group-list"
+        >
+          <el-select
+            v-model="ruleForm.userGroupList"
+            multiple
+            placeholder="请选择分组"
+            filterable
+            @change="emits('userGroupListChange', ruleForm.userGroupList)"
+          >
             <el-option v-for="item in groupOptions" :key="item.id" :value="item.id" :label="item.name" />
           </el-select>
+          <span @click="showGroupInfo" v-if="ruleForm.userGroupList.length > 0" class="group-info-span">
+            人员详情
+          </span>
         </el-form-item>
-        <span @click="showGroupInfo"> 人员详情 </span>
       </div>
       <div class="userList" v-else-if="ruleForm.recipientType === 2">
         <el-form-item label="选择人员" prop="customUserList" :rules="[{ required: true, message: '请选择人员' }]">
@@ -64,16 +77,23 @@
   import type { GroupOptionType, TreeNodeData } from '../types';
   import type { UserInfo, UserGroupInfo } from '@/types/push-object';
   import { queryUserGroupDetailByIds } from '@/api/push-object';
+  import type { FormInstance } from 'element-plus';
   const props = defineProps<{
     recipientType: number | null;
     userGroupList: number[];
     customUserList: UserInfo[];
   }>();
+  const emits = defineEmits<{
+    (e: 'recipientTypeChange', recipientType: number | null): void;
+    (e: 'userGroupListChange', userGroupList: number[]): void;
+    (e: 'customUserListChange', customUserList: UserInfo[]): void;
+  }>();
   interface RuleForm {
-    recipientType: number;
+    recipientType: number | null;
     userGroupList: number[];
     customUserList: UserInfo[];
   }
+  const ruleFormRef = ref<FormInstance>();
   const groupOptions = ref<GroupOptionType[]>([
     {
       id: 1,
@@ -114,11 +134,22 @@
       };
     });
     userOptions.value = ruleForm.customUserList;
+    emits('customUserListChange', ruleForm.customUserList);
   };
+  const validateForm = () => {
+    return new Promise((resolve) => {
+      ruleFormRef.value?.validate((valid) => {
+        resolve(valid);
+      });
+    });
+  };
+  defineExpose({
+    validateForm,
+  });
   watch(
     [() => props.recipientType, () => props.userGroupList, () => props.customUserList],
     ([newRecipientType, newUserGroupList, newCustomUserList]) => {
-      ruleForm.recipientType = newRecipientType ?? 1;
+      ruleForm.recipientType = newRecipientType ?? null;
       ruleForm.userGroupList = newUserGroupList ?? [];
       ruleForm.customUserList = newCustomUserList ?? [];
       userOptions.value = ruleForm.customUserList;
@@ -139,11 +170,16 @@
   .userList {
     width: 100%;
     padding: 12cpx 0 0 12cpx;
-    span {
-      cursor: pointer;
-      font-size: 10cpx;
-      color: $primary-color;
-      margin-left: 80px;
-    }
+  }
+  .user-group-list {
+    position: relative;
+  }
+  .group-info-span {
+    position: absolute;
+    left: 0;
+    bottom: -30px;
+    cursor: pointer;
+    font-size: 10cpx;
+    color: $primary-color;
   }
 </style>

+ 14 - 4
src/views/disaster/disaster-warning/PageDefenseNoticeItem.vue

@@ -5,17 +5,17 @@
       <span class="disaster-precaution-container__title">{{ headerTitle }}</span>
     </header>
     <main class="disaster-precaution-container__main">
-      <component :is="dynamicComponent" :id="id" />
+      <component :is="dynamicComponent" :id="id" ref="dynamicComponentRef" />
     </main>
     <footer class="disaster-precaution-container__footer" v-if="operate">
-      <el-button>取消</el-button>
-      <el-button type="primary">提交</el-button>
+      <el-button @click="router.back()">取消</el-button>
+      <el-button type="primary" @click="submit">提交</el-button>
     </footer>
   </div>
 </template>
 
 <script lang="ts" setup>
-  import { computed, defineAsyncComponent } from 'vue';
+  import { ref, computed, defineAsyncComponent } from 'vue';
   import { useRoute, useRouter } from 'vue-router';
   import BackIcon from 'assets/svg/back.svg';
   const router = useRouter();
@@ -40,6 +40,16 @@
       return defineAsyncComponent(() => import('./src/components/ViewDefenseNoticeItem.vue'));
     }
   });
+  const dynamicComponentRef = ref();
+  const submit = async () => {
+    if (!dynamicComponentRef.value) return;
+    const res = await dynamicComponentRef.value.handleValidate();
+    if (res) {
+      console.log('提交');
+    } else {
+      console.log('不提交');
+    }
+  };
 </script>
 
 <style lang="scss" scoped>

+ 47 - 3
src/views/disaster/disaster-warning/src/components/CreateDefenseNoticeItem.vue

@@ -10,7 +10,16 @@
               <el-radio :value="true">是</el-radio>
               <el-radio :value="false">否</el-radio>
             </el-radio-group>
-            <PushObject v-if="ruleForm.isPush" />
+            <PushObject
+              v-if="ruleForm.isPush"
+              ref="pushObjectRef"
+              :recipientType="ruleForm.recipientType"
+              :userGroupList="ruleForm.userGroupList"
+              :customUserList="ruleForm.customUserList"
+              @recipientTypeChange="handleRecipientTypeChange"
+              @userGroupListChange="handleUserGroupListChange"
+              @customUserListChange="handleCustomUserListChange"
+            />
           </div>
         </template>
 
@@ -28,11 +37,46 @@
 </template>
 
 <script setup lang="ts">
+  import { onMounted, ref } from 'vue';
   import PushObject from '@/views/disaster/components/PushObject.vue';
   import Upload from '@/views/disaster/components/Upload.vue';
   import { useDefenseNoticeFormHook } from '@/views/disaster/disaster-warning/src/useFormHook';
-
-  const { formConfig, ruleFormRef, ruleForm, rules } = useDefenseNoticeFormHook();
+  import type { UserInfo } from '@/types/push-object';
+  const {
+    formConfig,
+    ruleFormRef,
+    ruleForm,
+    rules,
+    validateForm,
+    handleUploadSuccess,
+    beforeRouteLeave,
+    cloneRuleForm,
+  } = useDefenseNoticeFormHook();
+  const handleRecipientTypeChange = (recipientType: number | null) => {
+    ruleForm.recipientType = recipientType;
+  };
+  const handleUserGroupListChange = (userGroupList: number[]) => {
+    ruleForm.userGroupList = userGroupList;
+  };
+  const handleCustomUserListChange = (customUserList: UserInfo[]) => {
+    ruleForm.customUserList = customUserList;
+  };
+  const pushObjectRef = ref<InstanceType<typeof PushObject>[]>([]);
+  const handleValidate = async () => {
+    if (!pushObjectRef.value) return false;
+    const results = await Promise.all(pushObjectRef.value.map((item) => item.validateForm()));
+    const allValid = results.every((res) => res === true);
+    const res = await validateForm();
+    return allValid && res;
+  };
+  defineExpose({
+    handleValidate,
+  });
+  onMounted(() => {
+    ruleForm.createUser = 'XXX';
+    cloneRuleForm();
+    beforeRouteLeave();
+  });
 </script>
 
 <style scoped lang="scss">

+ 37 - 2
src/views/disaster/disaster-warning/src/components/EditDefenseNoticeItem.vue

@@ -20,6 +20,9 @@
               :recipientType="ruleForm.recipientType"
               :userGroupList="ruleForm.userGroupList"
               :customUserList="ruleForm.customUserList"
+              @recipientTypeChange="handleRecipientTypeChange"
+              @userGroupListChange="handleUserGroupListChange"
+              @customUserListChange="handleCustomUserListChange"
             />
           </div>
         </template>
@@ -38,17 +41,36 @@
 </template>
 
 <script setup lang="ts">
-  import { onMounted } from 'vue';
+  import { onMounted, ref } from 'vue';
   import PushObject from '@/views/disaster/components/PushObject.vue';
   import Upload from '@/views/disaster/components/Upload.vue';
   import { useDefenseNoticeFormHook } from '@/views/disaster/disaster-warning/src/useFormHook';
   import { getDefenseNoticeDetail } from '@/api/disaster-warning';
+  import type { UserInfo } from '@/types/push-object';
 
   const props = defineProps<{
     id: number;
   }>();
 
-  const { formConfig, ruleFormRef, ruleForm, rules, handleUploadSuccess } = useDefenseNoticeFormHook();
+  const {
+    formConfig,
+    ruleFormRef,
+    ruleForm,
+    rules,
+    validateForm,
+    handleUploadSuccess,
+    beforeRouteLeave,
+    cloneRuleForm,
+  } = useDefenseNoticeFormHook();
+  const handleRecipientTypeChange = (recipientType: number | null) => {
+    ruleForm.recipientType = recipientType;
+  };
+  const handleUserGroupListChange = (userGroupList: number[]) => {
+    ruleForm.userGroupList = userGroupList;
+  };
+  const handleCustomUserListChange = (customUserList: UserInfo[]) => {
+    ruleForm.customUserList = customUserList;
+  };
   const getDefenseNoticeDetailData = async () => {
     const res = await getDefenseNoticeDetail(props.id);
     ruleForm.createUser = res.createUser;
@@ -61,9 +83,22 @@
     ruleForm.recipientType = res.recipientType ?? null;
     ruleForm.userGroupList = res.userGroupList ?? [];
     ruleForm.customUserList = res.customUserList ?? [];
+    cloneRuleForm();
   };
+  const pushObjectRef = ref<InstanceType<typeof PushObject>[]>([]);
+  const handleValidate = async () => {
+    if (!pushObjectRef.value) return false;
+    const results = await Promise.all(pushObjectRef.value.map((item) => item.validateForm()));
+    const allValid = results.every((res) => res === true);
+    const res = await validateForm();
+    return allValid && res;
+  };
+  defineExpose({
+    handleValidate,
+  });
   onMounted(() => {
     getDefenseNoticeDetailData();
+    beforeRouteLeave();
   });
 </script>
 

+ 15 - 0
src/views/disaster/disaster-warning/src/type.ts

@@ -0,0 +1,15 @@
+import type { DefenseNoticeAttachment } from '@/types/disaster-warning';
+import type { UserInfo } from '@/types/push-object';
+export interface RuleForm {
+  disasterType: string;
+  disasterLevel: string;
+  noticeTitle: string;
+  noticeContent: string;
+  noticeAttachment: DefenseNoticeAttachment[];
+  isPush: boolean | null;
+  recipientType: number | null;
+  userGroupList: number[];
+  customUserList: UserInfo[];
+  createUser: string;
+  [key: string]: any; // 添加索引签名
+}

+ 40 - 17
src/views/disaster/disaster-warning/src/useFormHook.ts

@@ -3,25 +3,13 @@
  */
 import { ref, reactive } from 'vue';
 import type { FormInstance, FormRules } from 'element-plus';
-import { cloneDeep } from 'lodash-es';
+import { cloneDeep, isEqual } from 'lodash-es';
 import { DISASTER_TYPE, DISASTER_LEVEL } from '@/views/disaster/constant';
 import type { FileItem } from '@/views/disaster/types';
-import type { DefenseNoticeAttachment } from '@/types/disaster-warning';
-import type { UserInfo } from '@/types/push-object';
+import type { RuleForm } from './type';
+import { onBeforeRouteLeave } from 'vue-router';
+import { ElMessageBox } from 'element-plus';
 export const useDefenseNoticeFormHook = () => {
-  interface RuleForm {
-    disasterType: string;
-    disasterLevel: string;
-    noticeTitle: string;
-    noticeContent: string;
-    noticeAttachment: DefenseNoticeAttachment[];
-    isPush: boolean | null;
-    recipientType: number | null;
-    userGroupList: number[];
-    customUserList: UserInfo[];
-    createUser: string;
-    [key: string]: any; // 添加索引签名
-  }
   const formConfig = [
     {
       label: '灾害类型',
@@ -99,8 +87,9 @@ export const useDefenseNoticeFormHook = () => {
     customUserList: [],
     createUser: '',
   });
+  const initRuleForm = ref<RuleForm>();
   const cloneRuleForm = () => {
-    return cloneDeep(ruleForm);
+    initRuleForm.value = cloneDeep(ruleForm);
   };
   const rules = reactive<FormRules<RuleForm>>({
     disasterType: [{ required: true, message: '请选择灾害类型', trigger: 'change' }],
@@ -128,8 +117,40 @@ export const useDefenseNoticeFormHook = () => {
     noticeAttachment: [{ required: true, message: '请上传通知附件', trigger: 'change' }],
     isPush: [{ required: true, message: '请选择是否推送', trigger: 'change' }],
   });
+  const validateForm = () => {
+    return new Promise((resolve) => {
+      ruleFormRef.value?.validate((valid: boolean) => {
+        resolve(valid);
+      });
+    });
+  };
+  const hasFormChanged = () => {
+    return !isEqual(initRuleForm.value, ruleForm);
+  };
+  const beforeRouteLeave = () => {
+    onBeforeRouteLeave((to, from, next) => {
+      const res = hasFormChanged();
+      if (!res) {
+        next();
+        return;
+      }
+      setTimeout(() => {
+        ElMessageBox.confirm('当前页面存在修改,是否确认离开当前页面?', '提示', {
+          confirmButtonText: '确认',
+          cancelButtonText: '取消',
+        })
+          .then(() => {
+            next();
+          })
+          .catch(() => {
+            next(false);
+          });
+      }, 200);
+    });
+  };
   const handleUploadSuccess = (fileList: FileItem[]) => {
     ruleForm.noticeAttachment = fileList;
+    ruleFormRef.value?.validateField('noticeAttachment');
   };
   return {
     formConfig,
@@ -137,6 +158,8 @@ export const useDefenseNoticeFormHook = () => {
     ruleForm,
     rules,
     cloneRuleForm,
+    validateForm,
+    beforeRouteLeave,
     handleUploadSuccess,
   };
 };