Просмотр исходного кода

Merge branch 'dev-wyf' into 'dev'

演练执行

See merge request product-group-fe/sfy-safety-group/sfy-safety!139
yunfeng wu 9 месяцев назад
Родитель
Сommit
3cbe30fa26

+ 21 - 5
src/api/emergency-drill/emergency-drill.ts

@@ -38,15 +38,31 @@ export const createEmergencyDrillPlan = (params: CreateEmergencyDrillRuleForm) =
 
 export const saveEmergencyDrillExecute = (params: ExecuteDrillPlanRuleForm) => {
   return http.request({
-    url: '/emergencyDrill/saveEmergencyDrillPlan',
+    url: '/emergencyDrill/executeEmergencyDrillPlan',
     method: 'post',
     data: {
-      id: params.id,
+      drillPlanId: params.drillPlanId,
       drillTime: params.drillTime,
       drillLocation: params.drillLocation,
       personInChargeId: params.personInChargeId,
       drillDeptIdList: params.drillDeptIdList ? '[' + params.drillDeptIdList?.join(',') + ']' : null,
-      drillScript: params.drillScript || null,
+      drillScript: params.drillScript,
+      saveOrSubmit: 0,
+    },
+  });
+};
+export const submitEmergencyDrillExecute = (params: ExecuteDrillPlanRuleForm) => {
+  return http.request({
+    url: '/emergencyDrill/executeEmergencyDrillPlan',
+    method: 'post',
+    data: {
+      drillPlanId: params.drillPlanId,
+      drillTime: params.drillTime,
+      drillLocation: params.drillLocation,
+      personInChargeId: params.personInChargeId,
+      drillDeptIdList: params.drillDeptIdList ? '[' + params.drillDeptIdList?.join(',') + ']' : null,
+      drillScript: params.drillScript,
+      saveOrSubmit: 1,
     },
   });
 };
@@ -84,8 +100,8 @@ export const queryEmergencyPlanDetail = (id) => {
   return http.request<any>({
     url: `/emergencyPlan/queryEmergencyPlanDetail?emergencyPlanId=${id}`,
     method: 'get',
-  })
-}
+  });
+};
 /**
  * 查询演练会签列表
  */

+ 1 - 0
src/views/disaster/components/UploadFiles.vue

@@ -194,6 +194,7 @@
       fileList.value.splice(index, 1);
     }
     ElMessage.success('文件删除成功');
+    emit('uploadSuccess', fileList.value);
   };
 
   const removeAllFiles = () => {

+ 12 - 2
src/views/emergency/emergency-drill/PageDrillPlanItem.vue

@@ -60,6 +60,8 @@
         return defineAsyncComponent(() => import('./components/DrillPlanExecuteItem.vue'));
       case 'record':
         return defineAsyncComponent(() => import('./components/DrillPlanRecordItem.vue'));
+      default:
+        return '';
     }
   });
 
@@ -83,8 +85,16 @@
     }
   };
 
-  const executeSave = async () => {};
-  const executeSubmit = async () => {};
+  const executeSave = async () => {
+    formLoading.value = true;
+    await dynamicComponentRef.value.executeSaveOrSubmit('save');
+    formLoading.value = false;
+  };
+  const executeSubmit = async () => {
+    formLoading.value = true;
+    await dynamicComponentRef.value.executeSaveOrSubmit('submit');
+    formLoading.value = false;
+  };
 
   const recordSave = async () => {};
   const recordSubmit = async () => {};

+ 6 - 2
src/views/emergency/emergency-drill/PageDrillPlanList.vue

@@ -30,9 +30,13 @@
               <ActionButton
                 v-if="scope.row.status > 0 && scope.row.status <= 3"
                 text="演练执行"
-                @click=""
+                @click="handleToExecute(scope.row.id)"
+              ></ActionButton>
+              <ActionButton
+                v-else-if="scope.row.status < 6"
+                text="演练记录"
+                @click="handleToRecord(scope.row.id)"
               ></ActionButton>
-              <ActionButton v-else-if="scope.row.status < 6" text="演练记录" @click=""></ActionButton>
               <ActionButton
                 text="删除"
                 :popconfirm="{

+ 6 - 1
src/views/emergency/emergency-drill/components/DrillPlanCreateItem.vue

@@ -43,7 +43,12 @@
         </el-select>
       </template>
       <template #approvalTemplateId>
-        <el-select v-model="ruleFormData.approvalTemplateId" placeholder="请选择审批流程" class="custom-select">
+        <el-select
+          v-model="ruleFormData.approvalTemplateId"
+          placeholder="请选择审批流程"
+          class="custom-select"
+          filterable
+        >
           <el-option v-for="item in allApprovals" :key="item.id" :label="item.templateName" :value="item.id" />
         </el-select>
       </template>

+ 98 - 5
src/views/emergency/emergency-drill/components/DrillPlanExecuteForm.vue

@@ -1,7 +1,25 @@
 <template>
   <div>
     <BasicForm ref="basicFormRef" :formData="ruleFormData" :formRules="formRules" :formConfig="ruleFormConfig">
-      <template #personInChargeId> </template>
+      <template #personInChargeName>
+        <el-select
+          v-model="ruleFormData.personInChargeName"
+          placeholder="请输入负责人姓名"
+          value-key="id"
+          filterable
+          remote
+          :remote-method="remoteMethod"
+          :loading="loading"
+          @change="selectKeeper"
+        >
+          <el-option
+            v-for="item in userOptions"
+            :key="item.id"
+            :label="`${item.realname}(${item.username})${item.deptName}`"
+            :value="item"
+          />
+        </el-select>
+      </template>
       <template #drillDeptIdList>
         <el-cascader
           v-model="ruleFormData.drillDeptIdList"
@@ -15,7 +33,19 @@
         >
         </el-cascader>
       </template>
-      <template #drillScript> </template>
+      <template #drillScript>
+        <UploadFiles
+          ref="uploadFilesRef"
+          label="上传材料"
+          :fileList="unformatAttachment(props.drillData.drillScript)"
+          @uploadSuccess="
+            (files) => {
+              fileList = files;
+              ruleFormData.drillScript = files;
+            }
+          "
+        />
+      </template>
     </BasicForm>
   </div>
 </template>
@@ -33,8 +63,12 @@
   } from '../configs/plan/form';
   import { DeptTree } from '@/types/dept/type';
   import { getAllDepartments } from '@/api/auth/dept';
+  import type { QueryUserInfoByUserNameRes } from '@/types/person-group/type';
+  import { queryUserInfoByUserName } from '@/api/system/person-group';
+  import UploadFiles from '@/views/disaster/components/UploadFiles.vue';
 
   const props = defineProps<{
+    insCode: string;
     drillData: DrillPlanItemDetail;
   }>();
 
@@ -45,15 +79,16 @@
       DRILL_EXECUTE_FORM_CONFIG,
       props.drillData
         ? {
-            id: props.drillData.id,
+            drillPlanId: props.drillData.id,
             drillTime: props.drillData.drillTime,
             drillLocation: props.drillData.drillLocation,
             personInChargeId: props.drillData.personInChargeId,
-            drillDeptIdList: undefined,
+            personInChargeName: props.drillData.personInChargeName,
+            drillDeptIdList: stringToArray(props.drillData.drillDeptIdList),
             drillScript: props.drillData.drillScript,
           }
         : DRILL_EXECUTE_FORM_DATA,
-      props.drillData.drillScope === 'institute_level' ? INS_DRILL_EXECUTE_FORM_RULES : DEP_DRILL_EXECUTE_FORM_RULES,
+      props.drillData.drillScope === props.insCode ? INS_DRILL_EXECUTE_FORM_RULES : DEP_DRILL_EXECUTE_FORM_RULES,
     );
 
   const cascaderProp = { multiple: true, expandTrigger: 'hover', emitPath: false, value: 'id', label: 'deptName' };
@@ -64,9 +99,67 @@
     deptTree.value = result;
   };
 
+  const userOptions = ref<QueryUserInfoByUserNameRes[]>([]);
+  const loading = ref<boolean>(false);
+
+  const fileList = ref();
+  fileList.value = unformatAttachment(props.drillData.drillScript);
+
+  const remoteMethod = async (query: string) => {
+    if (!query) {
+      userOptions.value = [];
+      return;
+    }
+    loading.value = true;
+    userOptions.value = await queryUserInfoByUserName(query);
+    loading.value = false;
+  };
+
   onMounted(() => {
     loadDeptTreeData();
   });
+
+  const handleValidate = async () => {
+    if (!basicFormRef.value) return;
+    const validateResult = await basicFormRef.value.validateForm();
+    return validateResult;
+  };
+
+  const handleClearValidate = () => {
+    if (!basicFormRef.value) return;
+    basicFormRef.value.clearValidate();
+  };
+
+  function getFormData() {
+    return ruleFormData;
+  }
+
+  defineExpose({
+    handleValidate,
+    handleClearValidate,
+    getFormData,
+  });
+
+  function selectKeeper(value) {
+    if (!value) return;
+    ruleFormData.personInChargeId = value.id;
+    ruleFormData.personInChargeName = value.realname;
+  }
+
+  function stringToArray(str?: string): number[] | undefined {
+    if (!str) return undefined;
+    // 去除字符串中的方括号
+    const trimmed = str.replace(/\[|\]/g, '');
+    // 将剩余部分转换为数字并放入数组
+    return [Number(trimmed)];
+  }
+
+  function unformatAttachment(file?: string) {
+    if (!file) return undefined;
+    const fileData = JSON.parse(file);
+    console.log(fileData);
+    return [fileData];
+  }
 </script>
 
 <style scoped></style>

+ 82 - 4
src/views/emergency/emergency-drill/components/DrillPlanExecuteItem.vue

@@ -12,7 +12,13 @@
     </div>
     <div>
       <div class="name">演练实施</div>
-      <DrillPlanExecuteForm v-if="drillData" :drill-data="drillData" />
+      <DrillPlanExecuteForm
+        v-if="drillData"
+        ref="drillPlanExecuteFormRef"
+        :ins-code="drillScopeDice[0].itemCode"
+        :drill-data="drillData"
+        style="margin-top: 20px"
+      />
     </div>
   </div>
 </template>
@@ -23,8 +29,18 @@
   import { DrillPlanItemDetail } from '../types';
   import { DRILL_VIEW_CONTENT } from '../constants';
   import DrillPlanExecuteForm from './DrillPlanExecuteForm.vue';
-  import { queryEmergencyDrillPlanDetail, queryEmergencyPlanDetail } from '@/api/emergency-drill/emergency-drill';
+  import {
+    queryEmergencyDrillPlanDetail,
+    queryEmergencyPlanDetail,
+    saveEmergencyDrillExecute,
+    submitEmergencyDrillExecute,
+  } from '@/api/emergency-drill/emergency-drill';
   import { getAllApproval } from '@/api/approval/approval';
+  import type { FileItem } from '@/views/disaster/types';
+  import { uploadFileApi, UPLOAD_BIZ_TYPE } from '@/api/minio';
+  import { useEmergencyDrillHook } from '../hook';
+
+  const { drillScopeDice, getDrillScopeDict } = useEmergencyDrillHook();
 
   const route = useRoute();
   const id = route.query.id;
@@ -39,8 +55,10 @@
         ? drillData.value.responsibleDeptNameList!.replace(/^\[|\]$/g, '')
         : undefined;
 
-      const emergencyPlan = await queryEmergencyPlanDetail(drillData.value.emergencyPlanId);
-      drillData.value.emergencyPlanFile = emergencyPlan.planName + emergencyPlan.appendix;
+      if (drillData.value.emergencyPlanId) {
+        const emergencyPlan = await queryEmergencyPlanDetail(drillData.value.emergencyPlanId);
+        drillData.value.emergencyPlanFile = emergencyPlan.planName + emergencyPlan.appendix;
+      }
 
       const allApprovals = await getAllApproval();
       drillData.value.approvalTemplateName = allApprovals.find(
@@ -51,9 +69,69 @@
     }
   }
 
+  const drillPlanExecuteFormRef = ref();
+
+  const formatAttachmentList = async (data: FileItem[]) => {
+    if (!data || data.length === 0) return null;
+    const file = data[0];
+    if (!file.file) return file;
+    const fileName = file.fileName;
+    const res = await uploadFileApi({ bizType: UPLOAD_BIZ_TYPE.ATTACHMENT, fileName, file: file.file });
+    const fileType = file.fileType;
+    const fileSize = file.fileSize;
+    const fileId = file.fileId;
+    const fileUrl = res.url;
+    return {
+      fileName,
+      fileType,
+      fileSize,
+      fileUrl,
+      fileId,
+    };
+  };
+
+  async function executeSaveOrSubmit(mode: string) {
+    if (!drillPlanExecuteFormRef.value) return;
+    // drillPlanExecuteFormRef.value.handleClearValidate();
+    if (mode === 'submit') {
+      const res = await drillPlanExecuteFormRef.value.handleValidate();
+      if (!res) return;
+    }
+
+    const formData = drillPlanExecuteFormRef.value.getFormData();
+    let attachmentListRes;
+    if (typeof formData.drillScript === 'string') {
+      attachmentListRes = formData.drillScript;
+    } else if (!formData.drillScript || formData.drillScript.length === 0) {
+      attachmentListRes = null;
+    } else {
+      attachmentListRes = JSON.stringify(await formatAttachmentList(formData.drillScript));
+    }
+
+    const executeParams = {
+      drillPlanId: formData.drillPlanId,
+      drillTime: formData.drillTime,
+      drillLocation: formData.drillLocation,
+      personInChargeId: formData.personInChargeId,
+      drillDeptIdList: formData.drillDeptIdList,
+      drillScript: attachmentListRes,
+    };
+
+    if (mode === 'save') {
+      await saveEmergencyDrillExecute(executeParams);
+    } else {
+      await submitEmergencyDrillExecute(executeParams);
+    }
+  }
+
   onMounted(() => {
+    getDrillScopeDict();
     getDrillData();
   });
+
+  defineExpose({
+    executeSaveOrSubmit,
+  });
 </script>
 
 <style scoped>

+ 4 - 2
src/views/emergency/emergency-drill/components/DrillPlanViewActivities.vue

@@ -55,8 +55,10 @@
         ? drillData.value.responsibleDeptNameList!.replace(/^\[|\]$/g, '')
         : undefined;
 
-      const emergencyPlan = await queryEmergencyPlanDetail(drillData.value.emergencyPlanId);
-      drillData.value.emergencyPlanFile = emergencyPlan.planName + emergencyPlan.appendix;
+      if (drillData.value.emergencyPlanId) {
+        const emergencyPlan = await queryEmergencyPlanDetail(drillData.value.emergencyPlanId);
+        drillData.value.emergencyPlanFile = emergencyPlan.planName + emergencyPlan.appendix;
+      }
 
       const allApprovals = await getAllApproval();
       drillData.value.approvalTemplateName = allApprovals.find(

+ 5 - 5
src/views/emergency/emergency-drill/configs/plan/form.ts

@@ -126,9 +126,9 @@ export const DRILL_EXECUTE_FORM_CONFIG = [
     componentProps: { placeholder: '请输入演练地点' },
   },
   {
-    prop: 'personInChargeId',
+    prop: 'personInChargeName',
     label: '负责人:',
-    slot: 'personInChargeId',
+    slot: 'personInChargeName',
   },
   {
     prop: 'drillDeptIdList',
@@ -145,7 +145,7 @@ export const DRILL_EXECUTE_FORM_CONFIG = [
 export const INS_DRILL_EXECUTE_FORM_RULES = {
   drillTime: [{ required: true, message: '请选择演练时间', trigger: 'change' }],
   drillLocation: [{ required: true, message: '请输入演练地点', trigger: 'blur' }],
-  personInChargeId: [{ required: true, message: '请选择演练负责人', trigger: 'change' }],
+  personInChargeName: [{ required: true, message: '请选择演练负责人', trigger: 'change' }],
   drillDeptIdList: [{ required: true, message: '请选择演练部门', trigger: 'change' }],
   drillScript: [{ required: true, message: '请上传演练脚本', trigger: 'change' }],
 };
@@ -153,13 +153,13 @@ export const INS_DRILL_EXECUTE_FORM_RULES = {
 export const DEP_DRILL_EXECUTE_FORM_RULES = {
   drillTime: [{ required: true, message: '请选择演练时间', trigger: 'change' }],
   drillLocation: [{ required: true, message: '请输入演练地点', trigger: 'blur' }],
-  personInChargeId: [{ required: true, message: '请选择演练负责人', trigger: 'change' }],
+  personInChargeName: [{ required: true, message: '请选择演练负责人', trigger: 'change' }],
 };
 
 export const DRILL_EXECUTE_FORM_DATA = {
   drillTime: undefined,
   drillLocation: '',
-  personInChargeId: undefined,
+  personInChargeName: undefined,
   drillDeptIdList: undefined,
   drillScript: undefined,
 };

+ 2 - 1
src/views/emergency/emergency-drill/types.ts

@@ -177,13 +177,14 @@ export interface DrillPlanRecord {
 }
 
 export interface ExecuteDrillPlanRuleForm {
-  id?: number;
+  drillPlanId?: number;
   /*演练时间 */
   drillTime?: string;
   /*演练地点 */
   drillLocation?: string;
   /*演练负责人id */
   personInChargeId?: number;
+  personInChargeName?: string;
   /*演练部门id列表 */
   drillDeptIdList?: number[];
   /*演练脚本 */

+ 1 - 1
src/views/system/approval/PageApproval.vue

@@ -62,7 +62,7 @@
   };
   const handleCurrentChange = (value: number) => {
     pagination.pageNumber = value;
-    tabelQuery.value.pageSize = value;
+    tabelQuery.value.pageNumber = value;
     getTabelData();
   };
 

+ 1 - 1
src/views/system/approval/PageApprovalNode.vue

@@ -19,7 +19,7 @@
           <el-button type="primary" @click="handleEditApproval">保存</el-button>
         </div>
         <div class="approval-node-container__title">审批流程设置</div>
-        <div class="approval-node-container__button" style="">
+        <div class="approval-node-container__button">
           <el-button type="primary" @click="handleCreateApprovalNode" :icon="Plus">添加审批节点</el-button>
         </div>
         <div style="flex-grow: 1">