Преглед изворни кода

差一个审批跑完主流程

chauncey пре 9 месеци
родитељ
комит
2b1557a465

+ 63 - 1
src/api/emergency-plan/index.ts

@@ -1,5 +1,12 @@
 import { http } from '@/utils/http/axios';
 import { http } from '@/utils/http/axios';
-import type { PlanEmergencyListQuery, PlanEmergencyListResponse } from '@/types/emergency-plan';
+import type {
+  PlanEmergencyListQuery,
+  PlanEmergencyListResponse,
+  AddEmergencyPlanParam,
+  ApprovalProcessParam,
+  PlanApprovalListQuery,
+  PlanApprovalListResponse,
+} from '@/types/emergency-plan';
 import type { QueryPageRequest, QueryPageResponse } from '@/types/basic-query';
 import type { QueryPageRequest, QueryPageResponse } from '@/types/basic-query';
 
 
 /**
 /**
@@ -13,6 +20,17 @@ export const getEmergencyPlanList = (data: QueryPageRequest<PlanEmergencyListQue
   });
   });
 };
 };
 
 
+/**
+ * 创建应急预案
+ */
+export const createEmergencyPlan = (data: AddEmergencyPlanParam) => {
+  return http.request({
+    url: '/emergencyPlan/saveEmergencyPlan',
+    method: 'post',
+    data,
+  });
+};
+
 /**
 /**
  * 删除应急预案
  * 删除应急预案
  */
  */
@@ -22,3 +40,47 @@ export const deleteEmergencyPlan = (emergencyPlanId: number) => {
     method: 'delete',
     method: 'delete',
   });
   });
 };
 };
+
+/**
+ * 查询应急预案详情
+ */
+export const queryEmergencyPlan = (emergencyPlanId: number) => {
+  return http.request({
+    url: '/emergencyPlan/queryEmergencyPlanDetail',
+    method: 'get',
+    params: { emergencyPlanId },
+  });
+};
+
+/**
+ * 更新应急预案详情
+ */
+export const editEmergencyPlan = (data: AddEmergencyPlanParam & { id: number }) => {
+  return http.request({
+    url: '/emergencyPlan/updateEmergencyPlan',
+    method: 'post',
+    data,
+  });
+};
+
+/**
+ * 提交审批流程
+ */
+export const submitApproval = (data: ApprovalProcessParam) => {
+  return http.request({
+    url: '/emergencyPlan/saveApprovalProcess',
+    method: 'post',
+    data,
+  });
+};
+
+/**
+ * 查询预案审批列表
+ */
+export const getEmergencyApprovalList = (data: QueryPageRequest<PlanApprovalListQuery>) => {
+    return http.request<QueryPageResponse<PlanApprovalListResponse>>({
+      url: '/emergencyPlan/queryEmergencyPlanApprovalPage',
+      method: 'post',
+      data,
+    });
+};

+ 38 - 9
src/types/emergency-plan/index.ts

@@ -6,22 +6,51 @@ export interface PlanEmergencyListQuery {
   status?: number;
   status?: number;
 }
 }
 
 
-export interface PlanEmergencyListResponse {
-  id: number;
-  planName: string;
-  planType: string;
-  enentType: string;
-  deptId: number;
-  status: number;
+export interface PlanApprovalListQuery {
+  approvalStatus?: number;
 }
 }
 
 
-export interface AddEmergencyPlanForm {
+interface BasicListResponse {
+  id: number;
   planName: string;
   planName: string;
   planType: string;
   planType: string;
   eventType: string;
   eventType: string;
-  deptId: string;
+  deptId: number | null;
   deptName: string;
   deptName: string;
+}
+
+export interface PlanEmergencyListResponse extends BasicListResponse {
+  status: number;
+}
+
+export interface PlanApprovalListResponse extends BasicListResponse {
+  approvalStatus: number;
+  appendix: string;
+  approvalDescription: string;
+  createdByName: string;
+  createdAt: string;
+  approvalOrder: number;
+}
+
+export interface AddEmergencyPlanForm extends Omit<PlanEmergencyListResponse, 'id' | 'status'> {
   approvalTemplateId: string;
   approvalTemplateId: string;
   uploadFile: FileItem[];
   uploadFile: FileItem[];
   appendix: string;
   appendix: string;
 }
 }
+
+export interface EditEmergencyPlaneForm extends AddEmergencyPlanForm {
+  planTypeName: string;
+  eventTypeName: string;
+  approvalTemplateName: string;
+}
+
+export interface AddEmergencyPlanParam extends Omit<AddEmergencyPlanForm, 'uploadFile' | 'approvalTemplateName'> {}
+
+export interface ApprovalProcessParam {
+  planId: number;
+  approvalDescription: string;
+  approvalInfoList: {
+    approvalOrder: number;
+    approverIdList: number[];
+  }[];
+}

+ 134 - 3
src/views/emergency/emergency-plan/PageApproval.vue

@@ -1,7 +1,138 @@
 <template>
 <template>
-  <div> this is page approval page </div>
+  <div class="safety-platform-container">
+    <div class="safety-platform-container__header">
+      <div class="breadcrumb-title">预案审批</div>
+    </div>
+    <div class="safety-platform-container__main">
+      <div class="search-table-container">
+        <header class="disaster-precaution__header">
+          <BasicSearch
+            :searchConfig="EMERGENCY_PLAN_APPROVAL_SEARCH_CONFIG"
+            :searchData="searchData"
+            @update:searchData="handleSearch"
+          />
+        </header>
+        <BasicTable
+          :tableData="tableData"
+          :tableConfig="tableConfig"
+          @update:pageSize="handleSizeChange"
+          @update:pageNumber="handleCurrentChange"
+        >
+          <template #planType="scope">
+            <span>{{ getPlanType(scope.row.planType) }}</span>
+          </template>
+          <template #eventType="scope">
+            <span>{{ getEmergencyEvent(scope.row.eventType) }}</span>
+          </template>
+          <template #approvalStatus="scope">
+            <span>{{ getEmergencyPlanApproStatusLabel(scope.row.status) }}</span>
+          </template>
+          <template #appendix="scope">
+            <span class="appendix" v-if="scope.row.appendix" @click="handlePreviewScript(scope.row.appendix)">
+              预览
+            </span>
+            <span v-else>--</span>
+          </template>
+          <template #action="scope">
+            <div class="action-container--div">
+              <ActionButton text="审批" @click="handleApproval(scope.row.id, scope.row.approvalOrder)" />
+            </div>
+          </template>
+        </BasicTable>
+      </div>
+    </div>
+    <PreviewOnline ref="previewOnlineRef" />
+  </div>
+  <BasicDialog ref="basicDialogRef" title="审批">
+  </BasicDialog>
 </template>
 </template>
 
 
-<script setup lang="ts"></script>
+<script setup lang="ts">
+  import { ref, reactive, onMounted } from 'vue';
+  import { ElMessage } from 'element-plus';
+  import BasicSearch from '@/components/BasicSearch.vue';
+  import BasicTable from '@/components/BasicTable.vue';
+  import BasicDialog from '@/components/BasicDialog.vue';
+  import ActionButton from '@/components/ActionButton.vue';
+  import PreviewOnline from '@/views/disaster/components/PreviewOnline.vue';
+  import useTableConfig from '@/hooks/useTableConfigHook';
+  import { useEmergencyHook } from '../src/hoos';
+  import { useEmergencyPlanHook } from './src/hook';
+  import type { QueryPageRequest } from '@/types/basic-query';
+  import type { PlanApprovalListQuery, PlanApprovalListResponse } from '@/types/emergency-plan';
+  import { getEmergencyApprovalList } from '@/api/emergency-plan';
+  import {
+    EMERGENCY_PLAN_APPROVAL_SEARCH_CONFIG,
+    EMERGENCY_PLAN_APPROVAL_TABLE_OPTIONS,
+    EMERGENCY_PLAN_APPROVAL_TABLE_COLUMNS,
+  } from './src/config';
+  import { FILE_TYPE_ICON } from '@/views/disaster/constant';
 
 
-<style lang="scss" scoped></style>
+  const { tableConfig, pagination } = useTableConfig(
+    EMERGENCY_PLAN_APPROVAL_TABLE_COLUMNS,
+    EMERGENCY_PLAN_APPROVAL_TABLE_OPTIONS,
+  );
+  const { getEmergencyEventDict, getEmergencyEvent } = useEmergencyHook();
+  const { getPlanTypeDict, getPlanType, getEmergencyPlanApproStatusLabel } = useEmergencyPlanHook();
+  let planApprovalListQuery: QueryPageRequest<PlanApprovalListQuery> = {
+    pageNumber: pagination.pageNumber,
+    pageSize: pagination.pageSize,
+    queryParam: {},
+  };
+  const tableData = ref<PlanApprovalListResponse[]>([]);
+  const searchData = reactive({
+    approvalStatus: null,
+  });
+  const previewOnlineRef = ref<InstanceType<typeof PreviewOnline>>();
+  const basicDialogRef = ref<InstanceType<typeof BasicDialog>>();
+  const handleSearch = () => {
+    planApprovalListQuery.queryParam = {};
+    if (searchData.approvalStatus) {
+      planApprovalListQuery.queryParam.approvalStatus = searchData.approvalStatus;
+    }
+    getTableData();
+  };
+  const getTableData = async () => {
+    tableConfig.loading = true;
+    const res = await getEmergencyApprovalList(planApprovalListQuery);
+    tableData.value = res.records;
+    pagination.total = res.totalRow;
+    tableConfig.loading = false;
+  };
+  const handleSizeChange = (value: number) => {
+    pagination.pageSize = value;
+    planApprovalListQuery.pageSize = value;
+    getTableData();
+  };
+  const handleCurrentChange = (value: number) => {
+    pagination.pageNumber = value;
+    planApprovalListQuery.pageNumber = value;
+    getTableData();
+  };
+  const handlePreviewScript = (appendix: string) => {
+    const file = JSON.parse(appendix)[0];
+    previewOnlineRef.value?.open(file.fileUrl, file.fileType as keyof typeof FILE_TYPE_ICON);
+  };
+  const currentId = ref<number>();
+  const currentOrder = ref<number>();
+  const handleApproval = (id: number, approvalOrder: number) => {
+    currentId.value = id;
+    currentOrder.value = approvalOrder;
+    basicDialogRef.value?.openDialog();
+  };
+  onMounted(() => {
+    getPlanTypeDict();
+    getEmergencyEventDict();
+    getTableData();
+  });
+</script>
+
+<style scoped lang="scss">
+  @use '@/styles/page-details-layout.scss' as *;
+  @use '@/styles/page-main-layout.scss' as *;
+  @use '@/styles/basic-table-action.scss' as *;
+  .appendix {
+    cursor: pointer;
+    color: $primary-color;
+  }
+</style>

+ 2 - 1
src/views/emergency/emergency-plan/PageManagement.vue

@@ -130,7 +130,7 @@
     if (searchData.eventType) {
     if (searchData.eventType) {
       planManagementListQuery.queryParam.eventType = searchData.eventType;
       planManagementListQuery.queryParam.eventType = searchData.eventType;
     }
     }
-    if (searchData.status) {
+    if (searchData.status !== null) {
       planManagementListQuery.queryParam.status = searchData.status;
       planManagementListQuery.queryParam.status = searchData.status;
     }
     }
     getTableData();
     getTableData();
@@ -175,6 +175,7 @@
       name: defaultName,
       name: defaultName,
       query: {
       query: {
         id,
         id,
+        type: 'view'
       },
       },
     });
     });
   };
   };

+ 149 - 7
src/views/emergency/emergency-plan/PageManagementDetail.vue

@@ -7,26 +7,94 @@
     <main class="safety-platform-container__main">
     <main class="safety-platform-container__main">
       <component ref="dynamicComponentRef" :is="dynamicComponent" :id="id" />
       <component ref="dynamicComponentRef" :is="dynamicComponent" :id="id" />
     </main>
     </main>
-    <footer class="safety-platform-container__footer">
+    <footer class="safety-platform-container__footer" v-if="type !== 'view'">
       <el-button @click="router.back()">取消</el-button>
       <el-button @click="router.back()">取消</el-button>
       <el-button type="primary" @click="handleSubmit">提交</el-button>
       <el-button type="primary" @click="handleSubmit">提交</el-button>
     </footer>
     </footer>
   </div>
   </div>
+  <BasicDialog ref="basicDialogRef" title="提交审批" @refresh="closeDialog">
+    <template #form>
+      <div class="form">
+        <el-form ref="approvalFormRef" :model="approvalForm">
+          <el-form-item label="审批描述:" label-position="top">
+            <el-input v-model="approvalForm.description" placeholder="请输入审批描述" type="textarea" />
+          </el-form-item>
+          <div class="form-item">
+            <span>审批流程:</span>
+            <template v-for="item in approvalNodeList" :key="item.id">
+              <el-form-item
+                :label="`第${item.approvalOrder}步:${item.nodeDescription}(${APPROVAL_TYPE_MAP[item.approvalType]})`"
+                label-position="top"
+                :prop="item.approverType !== APPROVER_TYPE.FIX ? `approvers.${item.id}` : ''"
+                :rules="{ required: true, message: '请选择审批人员', trigger: 'change' }"
+              >
+                <el-input
+                  v-if="item.approverType === APPROVER_TYPE.FIX"
+                  :model-value="item.approverInfoList.map((info) => info.approverName).join(',')"
+                  disabled
+                ></el-input>
+                <el-select
+                  v-else
+                  v-model="approvalForm.approvers[item.id]"
+                  placeholder="请选择审批人员"
+                  value-key="id"
+                  filterable
+                  remote
+                  collapse-tags
+                  collapse-tags-tooltip
+                  :max-collapse-tags="2"
+                  :remote-method="remoteMethod"
+                  :loading="loading"
+                  multiple
+                >
+                  <el-option
+                    v-for="option in userOptions"
+                    :key="option.id"
+                    :label="`${option.realname}(${option.username})${option.deptName}`"
+                    :value="option.id"
+                  />
+                </el-select>
+              </el-form-item>
+            </template>
+          </div>
+        </el-form>
+      </div>
+    </template>
+    <template #footer>
+      <el-button type="primary" @click="handleSubmitApproval">提交</el-button>
+      <el-button @click="basicDialogRef.closeDialog">取消</el-button>
+    </template>
+  </BasicDialog>
 </template>
 </template>
 
 
 <script setup lang="ts">
 <script setup lang="ts">
   import { useRoute, useRouter } from 'vue-router';
   import { useRoute, useRouter } from 'vue-router';
-  import { ref, computed, defineAsyncComponent } from 'vue';
+  import { ref, computed, defineAsyncComponent, reactive } from 'vue';
+  import { ElMessage } from 'element-plus';
+  import BasicDialog from '@/components/BasicDialog.vue';
+  import { useEmergencySuppliesHook } from '@/views/emergency/emergency-supplies/src/hook';
   import type { FileItem } from '@/views/disaster/types';
   import type { FileItem } from '@/views/disaster/types';
   import type { AddEmergencyPlanForm } from '@/types/emergency-plan';
   import type { AddEmergencyPlanForm } from '@/types/emergency-plan';
+  import type { ApprovalNodeInstanceType } from '@/views/system/approval/types';
   import { uploadFileApi, UPLOAD_BIZ_TYPE } from '@/api/minio';
   import { uploadFileApi, UPLOAD_BIZ_TYPE } from '@/api/minio';
-  import { ElMessage } from 'element-plus';
+  import { createEmergencyPlan, editEmergencyPlan,submitApproval } from '@/api/emergency-plan';
+  import { getApprovalNodeInstanceList } from '@/api/approval/approval';
+  import { APPROVAL_TYPE_MAP, APPROVER_TYPE } from './src/constant';
 
 
   const route = useRoute();
   const route = useRoute();
   const router = useRouter();
   const router = useRouter();
   const type = String(route.query.type);
   const type = String(route.query.type);
   const id = Number(route.query.id);
   const id = Number(route.query.id);
+  const planId = ref<number>();
+  const approvalFormRef = ref();
+  const approvalForm = reactive({
+    description: '',
+    approvers: {} as Record<number, any[]>,
+  });
+
+  const approvalNodeList = ref<ApprovalNodeInstanceType[]>([]);
   const dynamicComponentRef = ref();
   const dynamicComponentRef = ref();
+  const basicDialogRef = ref();
   const headerTitle = computed(() => {
   const headerTitle = computed(() => {
     const title = '应急预案';
     const title = '应急预案';
     if (type === 'add') {
     if (type === 'add') {
@@ -44,6 +112,7 @@
     }
     }
     return defineAsyncComponent(() => import('./src/components/ViewManagementDetail.vue'));
     return defineAsyncComponent(() => import('./src/components/ViewManagementDetail.vue'));
   });
   });
+  const { userOptions, loading, remoteMethod } = useEmergencySuppliesHook();
   const formatAttachmentList = async (file: FileItem) => {
   const formatAttachmentList = async (file: FileItem) => {
     if (!file.file) return file;
     if (!file.file) return file;
     const fileName = file.fileName;
     const fileName = file.fileName;
@@ -71,9 +140,29 @@
       deptId: formData.deptId,
       deptId: formData.deptId,
       deptName: formData.deptName,
       deptName: formData.deptName,
       approvalTemplateId: formData.approvalTemplateId,
       approvalTemplateId: formData.approvalTemplateId,
-      appendix: attachmentListRes,
+      appendix: JSON.stringify(attachmentListRes),
+    };
+    return await createEmergencyPlan(createParam);
+  };
+  const editPlanManagementItemFunc = async (formData: AddEmergencyPlanForm) => {
+    const attachmentListRes: FileItem[] = await Promise.all(
+      formData.uploadFile.map((item) => formatAttachmentList(item)),
+    );
+    const editParam = {
+      id,
+      planName: formData.planName,
+      planType: formData.planType,
+      eventType: formData.eventType,
+      deptId: formData.deptId,
+      deptName: formData.deptName,
+      approvalTemplateId: formData.approvalTemplateId,
+      appendix: JSON.stringify(attachmentListRes),
     };
     };
-    console.log(createParam);
+    await editEmergencyPlan(editParam);
+  };
+  const getApprovalNode = async (id: number) => {
+    const res = await getApprovalNodeInstanceList(id);
+    approvalNodeList.value = res.approvalNodeInfoList || [];
   };
   };
   const handleSubmit = async () => {
   const handleSubmit = async () => {
     if (!dynamicComponentRef.value) return;
     if (!dynamicComponentRef.value) return;
@@ -82,14 +171,67 @@
     if (!res) return;
     if (!res) return;
     const data = dynamicComponentRef.value.getFormData();
     const data = dynamicComponentRef.value.getFormData();
     if (type === 'add') {
     if (type === 'add') {
-      await createPlanManagementItemFunc(data);
+      const res = await createPlanManagementItemFunc(data);
+      planId.value = res;
+    } else {
+      await editPlanManagementItemFunc(data);
+      planId.value = id;
     }
     }
     ElMessage.success(`${message}成功`);
     ElMessage.success(`${message}成功`);
-    // router.back();
+    getApprovalNode(data.approvalTemplateId);
+    basicDialogRef.value.openDialog();
+  };
+
+  const refreshForm = () => {
+    approvalFormRef.value?.resetFields();
+    approvalForm.description = '';
+  };
+
+  const closeDialog = () => {
+    refreshForm();
+    basicDialogRef.value.closeDialog();
+  };
+
+  const handleSubmitApproval = () => {
+    approvalFormRef.value.validate(async(valid: boolean) => {
+      if (valid) {
+        // 构造后端需要的数据格式
+        const approvalData = {
+          planId: planId.value!,
+          approvalDescription: approvalForm.description,
+          approvalInfoList: approvalNodeList.value.map((node) => {
+            let approverIdList: number[] = [];
+            if (node.approverType === APPROVER_TYPE.FIX) {
+              approverIdList = node.approverInfoList.map((info) => info.approverId);
+            } else if (approvalForm.approvers[node.id]) {
+              approverIdList = approvalForm.approvers[node.id];
+            }
+            return {
+              approvalOrder: node.approvalOrder,
+              approverIdList,
+            };
+          }),
+        };
+        await submitApproval(approvalData);
+        ElMessage.success('提交成功');
+        basicDialogRef.value.closeDialog();
+        router.back();
+      }
+    });
   };
   };
 </script>
 </script>
 
 
 <style scoped lang="scss">
 <style scoped lang="scss">
   @use '@/styles/page-details-layout.scss' as *;
   @use '@/styles/page-details-layout.scss' as *;
   @use './src/styles/info-common.scss' as *;
   @use './src/styles/info-common.scss' as *;
+  .form {
+    display: flex;
+    flex-direction: column;
+    gap: 40px;
+  }
+  .form-item {
+    display: flex;
+    flex-direction: column;
+    gap: 8px;
+  }
 </style>
 </style>

+ 25 - 14
src/views/emergency/emergency-plan/src/components/EditManagementDetail.vue

@@ -2,7 +2,12 @@
   <div class="emergency-plan-container">
   <div class="emergency-plan-container">
     <BasicForm ref="formRef" :formData="ruleFormData" :formConfig="ruleFormConfig">
     <BasicForm ref="formRef" :formData="ruleFormData" :formConfig="ruleFormConfig">
       <template #appendix>
       <template #appendix>
-        <UploadFiles label="上传附件" :maxCount="1" @uploadSuccess="handleUploadSuccess" />
+        <UploadFiles
+          label="上传附件"
+          :maxCount="1"
+          @uploadSuccess="handleUploadSuccess"
+          :fileList="ruleFormData.uploadFile"
+        />
       </template>
       </template>
     </BasicForm>
     </BasicForm>
   </div>
   </div>
@@ -15,23 +20,32 @@
   import { useFormConfigHook } from '@/hooks/useFormConfigHook';
   import { useFormConfigHook } from '@/hooks/useFormConfigHook';
   import { useEmergencyHook } from '@/views/emergency/src/hoos';
   import { useEmergencyHook } from '@/views/emergency/src/hoos';
   import { useEmergencyPlanHook } from '../hook';
   import { useEmergencyPlanHook } from '../hook';
-  import type { AddEmergencyPlanForm } from '@/types/emergency-plan';
+  import type { EditEmergencyPlaneForm } from '@/types/emergency-plan';
   import type { FileItem } from '@/views/disaster/types';
   import type { FileItem } from '@/views/disaster/types';
-  import { PLAN_MANAGEMENT_FORM_CONFIG_EDIT, PLAN_MANAGEMENT_FORM_DATA } from '../config';
+  import { queryEmergencyPlan } from '@/api/emergency-plan';
+  import { PLAN_MANAGEMENT_FORM_CONFIG_EDIT, PLAN_MANAGEMENT_FORM_DATA_EDIT } from '../config';
 
 
   const formRef = ref();
   const formRef = ref();
-  const { ruleFormConfig, ruleFormData, cloneRuleFormData, beforeRouteLeave } = useFormConfigHook<AddEmergencyPlanForm>(
+  const props = defineProps<{
+    id: number;
+  }>();
+  const { ruleFormConfig, ruleFormData } = useFormConfigHook<EditEmergencyPlaneForm>(
     PLAN_MANAGEMENT_FORM_CONFIG_EDIT,
     PLAN_MANAGEMENT_FORM_CONFIG_EDIT,
-    PLAN_MANAGEMENT_FORM_DATA,
+    PLAN_MANAGEMENT_FORM_DATA_EDIT,
   );
   );
 
 
-  const { getEmergencyEventDict, getEmergencyEvent, getDeptTreeData, getApprovalList } = useEmergencyHook();
+  const { getEmergencyEventDict, getEmergencyEvent, getApprovalList, approvalList } = useEmergencyHook();
   const { getPlanTypeDict, getPlanType } = useEmergencyPlanHook();
   const { getPlanTypeDict, getPlanType } = useEmergencyPlanHook();
-  const getPlanDetail = () => {
-    ruleFormData.planName = '测试';
-    ruleFormData.planType = getPlanType('comprehensive_contingency') || '';
-    ruleFormData.eventType = getEmergencyEvent('flood_typhoon_prevention') || '';
-    cloneRuleFormData();
+  const getPlanDetail = async () => {
+    const res = await queryEmergencyPlan(props.id);
+    for (const key in res) {
+      ruleFormData[key] = res[key as keyof typeof res];
+      ruleFormData.planTypeName = getPlanType(res.planType) || '';
+      ruleFormData.eventTypeName = getEmergencyEvent(res.eventType) || '';
+      ruleFormData.approvalTemplateName =
+        approvalList.value?.find((item) => item.id === res.approvalTemplateId)?.templateName || '';
+      ruleFormData.uploadFile = JSON.parse(res.appendix);
+    }
   };
   };
   const handleUploadSuccess = (fileList: FileItem[]) => {
   const handleUploadSuccess = (fileList: FileItem[]) => {
     ruleFormData.uploadFile = fileList;
     ruleFormData.uploadFile = fileList;
@@ -42,16 +56,13 @@
     return validateResult;
     return validateResult;
   };
   };
   const getFormData = () => {
   const getFormData = () => {
-    cloneRuleFormData();
     return ruleFormData;
     return ruleFormData;
   };
   };
   onMounted(async () => {
   onMounted(async () => {
     await getPlanTypeDict();
     await getPlanTypeDict();
     await getEmergencyEventDict();
     await getEmergencyEventDict();
-    await getDeptTreeData();
     await getApprovalList();
     await getApprovalList();
     getPlanDetail();
     getPlanDetail();
-    beforeRouteLeave();
   });
   });
   defineExpose({
   defineExpose({
     handleValidate,
     handleValidate,

+ 65 - 6
src/views/emergency/emergency-plan/src/components/ViewManagementDetail.vue

@@ -1,13 +1,72 @@
 <template>
 <template>
-    <div>
-
-    </div>
+  <div class="emergency-plan-container">
+    <BasicForm ref="formRef" :formData="ruleFormData" :formConfig="ruleFormConfig">
+      <template #appendix>
+        <div class="appendix-container" v-if="ruleFormData.uploadFile.length">
+          <div class="appendix-item" v-for="item in ruleFormData.uploadFile" :key="item.fileId">
+            <div class="appendix-item-name" @click="handlePreviewScript(item.fileUrl, item.fileType)">
+              {{ item.fileName }}
+            </div>
+          </div>
+        </div>
+        <div v-else style="color: rgba(0, 0, 0, 0.65)">暂无预案文件</div>
+      </template>
+    </BasicForm>
+    <PreviewOnline ref="previewOnlineRef" />
+  </div>
 </template>
 </template>
 
 
 <script setup lang="ts">
 <script setup lang="ts">
+  import { ref, onMounted } from 'vue';
+  import BasicForm from '@/components/BasicForm.vue';
+  import PreviewOnline from '@/views/disaster/components/PreviewOnline.vue';
+  import { useFormConfigHook } from '@/hooks/useFormConfigHook';
+  import { useEmergencyHook } from '@/views/emergency/src/hoos';
+  import { useEmergencyPlanHook } from '../hook';
+  import type { EditEmergencyPlaneForm } from '@/types/emergency-plan';
+  import { queryEmergencyPlan } from '@/api/emergency-plan';
+  import { PLAN_MANAGEMENT_FORM_CONFIG_EDIT, PLAN_MANAGEMENT_FORM_DATA_EDIT } from '../config';
+  import { FILE_TYPE_ICON } from '@/views/disaster/constant';
 
 
-</script>
+  const formRef = ref();
+  const previewOnlineRef = ref<InstanceType<typeof PreviewOnline>>();
+  const props = defineProps<{
+    id: number;
+  }>();
+  const { ruleFormConfig, ruleFormData } = useFormConfigHook<EditEmergencyPlaneForm>(
+    PLAN_MANAGEMENT_FORM_CONFIG_EDIT,
+    PLAN_MANAGEMENT_FORM_DATA_EDIT,
+  );
 
 
-<style scoped lang="scss">
+  const { getEmergencyEventDict, getEmergencyEvent, getApprovalList, approvalList } = useEmergencyHook();
+  const { getPlanTypeDict, getPlanType } = useEmergencyPlanHook();
+  const getPlanDetail = async () => {
+    const res = await queryEmergencyPlan(props.id);
+    for (const key in res) {
+      ruleFormData[key] = res[key as keyof typeof res];
+      ruleFormData.planTypeName = getPlanType(res.planType) || '';
+      ruleFormData.eventTypeName = getEmergencyEvent(res.eventType) || '';
+      ruleFormData.approvalTemplateName =
+        approvalList.value?.find((item) => item.id === res.approvalTemplateId)?.templateName || '';
+      ruleFormData.uploadFile = JSON.parse(res.appendix);
+    }
+  };
+  const handlePreviewScript = (url: string | undefined, type: string) => {
+    if (!url) return;
+    previewOnlineRef.value?.open(url, type as keyof typeof FILE_TYPE_ICON);
+  };
+  onMounted(async () => {
+    await getPlanTypeDict();
+    await getEmergencyEventDict();
+    await getApprovalList();
+    getPlanDetail();
+  });
+</script>
 
 
-</style>
+<style lang="scss" scoped>
+  @use '../styles/info.scss' as *;
+  .appendix-item-name {
+    cursor: pointer;
+    color: $primary-color;
+  }
+</style>

+ 15 - 6
src/views/emergency/emergency-plan/src/config/form.ts

@@ -54,7 +54,7 @@ export const PLAN_MANAGEMENT_FORM_CONFIG_EDIT: FormConfig[] = [
   },
   },
   {
   {
     label: '预案类型:',
     label: '预案类型:',
-    prop: 'planType',
+    prop: 'planTypeName',
     component: 'ElInput',
     component: 'ElInput',
     componentProps: {
     componentProps: {
       placeholder: '请输入预案类型',
       placeholder: '请输入预案类型',
@@ -63,7 +63,7 @@ export const PLAN_MANAGEMENT_FORM_CONFIG_EDIT: FormConfig[] = [
   },
   },
   {
   {
     label: '事件类型:',
     label: '事件类型:',
-    prop: 'eventType',
+    prop: 'eventTypeName',
     component: 'ElInput',
     component: 'ElInput',
     componentProps: {
     componentProps: {
       placeholder: '请输入事件类型',
       placeholder: '请输入事件类型',
@@ -72,7 +72,7 @@ export const PLAN_MANAGEMENT_FORM_CONFIG_EDIT: FormConfig[] = [
   },
   },
   {
   {
     label: '制定部门:',
     label: '制定部门:',
-    prop: 'deptId',
+    prop: 'deptName',
     component: 'ElInput',
     component: 'ElInput',
     componentProps: {
     componentProps: {
       placeholder: '请输入制定部门',
       placeholder: '请输入制定部门',
@@ -81,7 +81,7 @@ export const PLAN_MANAGEMENT_FORM_CONFIG_EDIT: FormConfig[] = [
   },
   },
   {
   {
     label: '审批流程:',
     label: '审批流程:',
-    prop: 'approvalTemplateId',
+    prop: 'approvalTemplateName',
     component: 'ElInput',
     component: 'ElInput',
     componentProps: {
     componentProps: {
       placeholder: '请输入审批流程',
       placeholder: '请输入审批流程',
@@ -92,17 +92,26 @@ export const PLAN_MANAGEMENT_FORM_CONFIG_EDIT: FormConfig[] = [
 ];
 ];
 
 
 // 盘点任务表单数据
 // 盘点任务表单数据
-export const PLAN_MANAGEMENT_FORM_DATA = {
+const BASE_FORM_DATA = {
   planName: '',
   planName: '',
   planType: '',
   planType: '',
   eventType: '',
   eventType: '',
-  deptId: '',
+  deptId: null,
   deptName: '',
   deptName: '',
   approvalTemplateId: '',
   approvalTemplateId: '',
   appendix: '',
   appendix: '',
   uploadFile: [],
   uploadFile: [],
 };
 };
 
 
+export const PLAN_MANAGEMENT_FORM_DATA = { ...BASE_FORM_DATA };
+
+export const PLAN_MANAGEMENT_FORM_DATA_EDIT = {
+  ...BASE_FORM_DATA,
+  planTypeName: '',
+  eventTypeName: '',
+  approvalTemplateName: '',
+};
+
 // 盘点任务表单规则
 // 盘点任务表单规则
 export const PLAN_MANAGEMENT_FORM_RULES = {
 export const PLAN_MANAGEMENT_FORM_RULES = {
   planName: [{ required: true, message: '请输入预案名称', trigger: 'blur' }],
   planName: [{ required: true, message: '请输入预案名称', trigger: 'blur' }],

+ 8 - 1
src/views/emergency/emergency-plan/src/config/index.ts

@@ -1,15 +1,18 @@
-import { EMERGENCY_PLAN_MANAGEMENT_SEARCH_CONFIG } from './search';
+import { EMERGENCY_PLAN_MANAGEMENT_SEARCH_CONFIG, EMERGENCY_PLAN_APPROVAL_SEARCH_CONFIG } from './search';
 import {
 import {
   EMERGENCY_PLAN_MANAGEMENT_TABLE_OPTIONS,
   EMERGENCY_PLAN_MANAGEMENT_TABLE_OPTIONS,
   EMERGENCY_PLAN_MANAGEMENT_TABLE_COLUMNS,
   EMERGENCY_PLAN_MANAGEMENT_TABLE_COLUMNS,
   TABLE_MAX_HEIGHT_DEFAULT,
   TABLE_MAX_HEIGHT_DEFAULT,
   TABLE_MAX_HEIGHT_PERMISSION,
   TABLE_MAX_HEIGHT_PERMISSION,
+  EMERGENCY_PLAN_APPROVAL_TABLE_OPTIONS,
+  EMERGENCY_PLAN_APPROVAL_TABLE_COLUMNS,
 } from './table';
 } from './table';
 import {
 import {
   PLAN_MANAGEMENT_FORM_CONFIG,
   PLAN_MANAGEMENT_FORM_CONFIG,
   PLAN_MANAGEMENT_FORM_DATA,
   PLAN_MANAGEMENT_FORM_DATA,
   PLAN_MANAGEMENT_FORM_RULES,
   PLAN_MANAGEMENT_FORM_RULES,
   PLAN_MANAGEMENT_FORM_CONFIG_EDIT,
   PLAN_MANAGEMENT_FORM_CONFIG_EDIT,
+  PLAN_MANAGEMENT_FORM_DATA_EDIT,
 } from './form';
 } from './form';
 export {
 export {
   EMERGENCY_PLAN_MANAGEMENT_SEARCH_CONFIG,
   EMERGENCY_PLAN_MANAGEMENT_SEARCH_CONFIG,
@@ -21,4 +24,8 @@ export {
   PLAN_MANAGEMENT_FORM_CONFIG_EDIT,
   PLAN_MANAGEMENT_FORM_CONFIG_EDIT,
   PLAN_MANAGEMENT_FORM_DATA,
   PLAN_MANAGEMENT_FORM_DATA,
   PLAN_MANAGEMENT_FORM_RULES,
   PLAN_MANAGEMENT_FORM_RULES,
+  PLAN_MANAGEMENT_FORM_DATA_EDIT,
+  EMERGENCY_PLAN_APPROVAL_SEARCH_CONFIG,
+  EMERGENCY_PLAN_APPROVAL_TABLE_OPTIONS,
+  EMERGENCY_PLAN_APPROVAL_TABLE_COLUMNS,
 };
 };

+ 13 - 1
src/views/emergency/emergency-plan/src/config/search.ts

@@ -1,5 +1,5 @@
 import type { SearchConfig } from '@/types/basic-search';
 import type { SearchConfig } from '@/types/basic-search';
-import { EMERGENCY_PLAN_STATUS_OPTIONS } from '../constant';
+import { EMERGENCY_PLAN_STATUS_OPTIONS, APPROVAL_STATUS_OPTIONS } from '../constant';
 
 
 export const EMERGENCY_PLAN_MANAGEMENT_SEARCH_CONFIG: SearchConfig[] = [
 export const EMERGENCY_PLAN_MANAGEMENT_SEARCH_CONFIG: SearchConfig[] = [
   {
   {
@@ -31,3 +31,15 @@ export const EMERGENCY_PLAN_MANAGEMENT_SEARCH_CONFIG: SearchConfig[] = [
     },
     },
   },
   },
 ];
 ];
+
+export const EMERGENCY_PLAN_APPROVAL_SEARCH_CONFIG: SearchConfig[] = [
+  {
+    label: '状态:',
+    prop: 'approvalStatus',
+    component: 'ElSelect',
+    selectOptions: APPROVAL_STATUS_OPTIONS,
+    componentProps: {
+      placeholder: '请输入预案名称',
+    },
+  },
+];

+ 42 - 2
src/views/emergency/emergency-plan/src/config/table.ts

@@ -12,7 +12,7 @@ const BASIC_TABLE_COLUMNS = {
     label: '序号',
     label: '序号',
     type: 'index',
     type: 'index',
     width: '80px',
     width: '80px',
-    align: 'center'
+    align: 'center',
   },
   },
   PLAN_NAME: {
   PLAN_NAME: {
     label: '预案名称',
     label: '预案名称',
@@ -31,7 +31,7 @@ const BASIC_TABLE_COLUMNS = {
   },
   },
   DEPT_NAME: {
   DEPT_NAME: {
     label: '制定部门',
     label: '制定部门',
-    prop: 'deptId',
+    prop: 'deptName',
     minWidth: '120px',
     minWidth: '120px',
   },
   },
   ACTION: {
   ACTION: {
@@ -49,6 +49,11 @@ export const EMERGENCY_PLAN_MANAGEMENT_TABLE_OPTIONS = {
   ...TABLE_OPTIONS,
   ...TABLE_OPTIONS,
 };
 };
 
 
+export const EMERGENCY_PLAN_APPROVAL_TABLE_OPTIONS = {
+  ...TABLE_OPTIONS,
+  maxHeight: 'calc(70vh - 50px)',
+};
+
 export const EMERGENCY_PLAN_MANAGEMENT_TABLE_COLUMNS: TableColumnProps[] = [
 export const EMERGENCY_PLAN_MANAGEMENT_TABLE_COLUMNS: TableColumnProps[] = [
   BASIC_TABLE_COLUMNS.INDEX,
   BASIC_TABLE_COLUMNS.INDEX,
   BASIC_TABLE_COLUMNS.PLAN_NAME,
   BASIC_TABLE_COLUMNS.PLAN_NAME,
@@ -62,3 +67,38 @@ export const EMERGENCY_PLAN_MANAGEMENT_TABLE_COLUMNS: TableColumnProps[] = [
   },
   },
   BASIC_TABLE_COLUMNS.ACTION,
   BASIC_TABLE_COLUMNS.ACTION,
 ];
 ];
+
+export const EMERGENCY_PLAN_APPROVAL_TABLE_COLUMNS: TableColumnProps[] = [
+  BASIC_TABLE_COLUMNS.INDEX,
+  BASIC_TABLE_COLUMNS.PLAN_NAME,
+  BASIC_TABLE_COLUMNS.PLAN_TYPE,
+  BASIC_TABLE_COLUMNS.ENENT_TYPE,
+  BASIC_TABLE_COLUMNS.DEPT_NAME,
+  {
+    label: '审批状态',
+    slot: 'approvalStatus',
+    minWidth: '120px',
+  },
+  {
+    label: '公示文件',
+    slot: 'appendix',
+    width: '120px',
+    align: 'center'
+  },
+  {
+    label: '预案审批描述',
+    prop: 'approvalDescription',
+    minWidth: '120px',
+  },
+  {
+    label: '提交人',
+    prop: 'createdByName',
+    minWidth: '120px',
+  },
+  {
+    label: '提交时间',
+    prop: 'createdAt',
+    minWidth: '200px'
+  },
+  BASIC_TABLE_COLUMNS.ACTION,
+];

+ 71 - 6
src/views/emergency/emergency-plan/src/constant.ts

@@ -1,14 +1,79 @@
+export enum EMERGENCY_PLAN_STATUS {
+  UNAPPROVED = 0,
+  APPROVAL_IN_PROGRESS,
+  RETURNED,
+  PUBLISHED,
+}
+
+export const EMERGENCY_PLAN_STATUS_MAP = {
+  [EMERGENCY_PLAN_STATUS.UNAPPROVED]: '未审批',
+  [EMERGENCY_PLAN_STATUS.APPROVAL_IN_PROGRESS]: '预案审批中',
+  [EMERGENCY_PLAN_STATUS.RETURNED]: '预案已退回',
+  [EMERGENCY_PLAN_STATUS.PUBLISHED]: '已公示',
+};
+
 export const EMERGENCY_PLAN_STATUS_OPTIONS = [
 export const EMERGENCY_PLAN_STATUS_OPTIONS = [
   {
   {
-    label: '预案审批中',
-    value: 1,
+    label: EMERGENCY_PLAN_STATUS_MAP[EMERGENCY_PLAN_STATUS.UNAPPROVED],
+    value: EMERGENCY_PLAN_STATUS.UNAPPROVED,
   },
   },
   {
   {
-    label: '预案已退回',
-    value: 2,
+    label: EMERGENCY_PLAN_STATUS_MAP[EMERGENCY_PLAN_STATUS.APPROVAL_IN_PROGRESS],
+    value: EMERGENCY_PLAN_STATUS.APPROVAL_IN_PROGRESS,
   },
   },
   {
   {
-    label: '已公式',
-    value: 3,
+    label: EMERGENCY_PLAN_STATUS_MAP[EMERGENCY_PLAN_STATUS.RETURNED],
+    value: EMERGENCY_PLAN_STATUS.RETURNED,
+  },
+  {
+    label: EMERGENCY_PLAN_STATUS_MAP[EMERGENCY_PLAN_STATUS.PUBLISHED],
+    value: EMERGENCY_PLAN_STATUS.PUBLISHED,
   },
   },
 ];
 ];
+
+export enum APPROVAL_TYPE {
+  COUNTER_SIGN = 0,
+  ORDINARY_SIGN,
+}
+
+export const APPROVAL_TYPE_MAP = {
+  [APPROVAL_TYPE.COUNTER_SIGN]: '会签',
+  [APPROVAL_TYPE.ORDINARY_SIGN]: '或签',
+};
+
+export enum APPROVER_TYPE{
+  FIX = 0,
+  CUSTOM,
+}
+
+export const APPROVER_TYPE_MAP = {
+  [APPROVER_TYPE.FIX]: '固定',
+  [APPROVER_TYPE.CUSTOM]: '自选',
+};
+
+export enum APPROVAL_STATUS {
+  PENDING = 1,
+  APPROVED,
+  REJECTED,
+}
+
+export const APPROVAL_STATUS_MAP = {
+  [APPROVAL_STATUS.PENDING]: '待审批',
+  [APPROVAL_STATUS.APPROVED]: '已审批',
+  [APPROVAL_STATUS.REJECTED]: '退回',
+};
+
+export const APPROVAL_STATUS_OPTIONS = [
+  {
+    label: APPROVAL_STATUS_MAP[APPROVAL_STATUS.PENDING],
+    value: APPROVAL_STATUS.PENDING,
+  },
+  {
+    label: APPROVAL_STATUS_MAP[APPROVAL_STATUS.APPROVED],
+    value: APPROVAL_STATUS.APPROVED,
+  },
+  {
+    label: APPROVAL_STATUS_MAP[APPROVAL_STATUS.REJECTED],
+    value: APPROVAL_STATUS.REJECTED,
+  },
+];

+ 6 - 2
src/views/emergency/emergency-plan/src/hook.ts

@@ -5,7 +5,7 @@ import { ref } from 'vue';
 import type { SysDictDataDetail } from '@/api/dict';
 import type { SysDictDataDetail } from '@/api/dict';
 import { queryDictTypeDetail } from '@/api/dict';
 import { queryDictTypeDetail } from '@/api/dict';
 import { DICT_CODE } from '@/constant/dict';
 import { DICT_CODE } from '@/constant/dict';
-import { EMERGENCY_PLAN_STATUS_OPTIONS } from './constant';
+import { EMERGENCY_PLAN_STATUS_OPTIONS, APPROVAL_STATUS_OPTIONS } from './constant';
 export const useEmergencyPlanHook = () => {
 export const useEmergencyPlanHook = () => {
   // 预案类型
   // 预案类型
   const planTypeDice = ref<SysDictDataDetail[]>([]);
   const planTypeDice = ref<SysDictDataDetail[]>([]);
@@ -18,11 +18,15 @@ export const useEmergencyPlanHook = () => {
   };
   };
   const getEmergencyPlanStatusLabel = (status: number) => {
   const getEmergencyPlanStatusLabel = (status: number) => {
     return EMERGENCY_PLAN_STATUS_OPTIONS.find((item) => item.value === status)?.label;
     return EMERGENCY_PLAN_STATUS_OPTIONS.find((item) => item.value === status)?.label;
-  }
+  };
+  const getEmergencyPlanApproStatusLabel = (status: number) => {
+    return APPROVAL_STATUS_OPTIONS.find((item) => item.value === status)?.label;
+  };
   return {
   return {
     planTypeDice,
     planTypeDice,
     getPlanTypeDict,
     getPlanTypeDict,
     getPlanType,
     getPlanType,
     getEmergencyPlanStatusLabel,
     getEmergencyPlanStatusLabel,
+    getEmergencyPlanApproStatusLabel,
   };
   };
 };
 };