Bläddra i källkod

feat:新增员工上报隐患管理审批流程

sunqijun 1 månad sedan
förälder
incheckning
1719a0fce0

+ 7 - 0
src/api/production-safety/index.ts

@@ -126,6 +126,13 @@ export function queryEmployeeHazardReportById(id: number) {
   });
 }
 
+// 获取templateID
+export function queryTemplateID() {
+  return http.request({
+    url: `/employeeHazardReport/queryReportHazardApprovalFlowId`,
+    method: 'get',
+  });
+}
 // 查看员工上报隐患列表(不分页)
 export function queryEmployeeHazardReportList(params?: QueryEmployeeHazardReportReq) {
   return http.request<EmployeeHazardReportDTO[]>({

+ 179 - 28
src/views/production-safety/hiddenTroubleInvestigationAndGovernance/employeeReportHiddenTroubleManagement/components/employeeReportHiddenTroubleManagementDetail.vue

@@ -13,7 +13,6 @@
         <UploadFiles
           v-if="!isViewMode"
           label="上传文件"
-          :maxCount="1"
           :file-list="attachmentFileList" 
           :disabled="isViewMode"
           :allow-all-file-types="true"
@@ -73,28 +72,94 @@
     </el-button>
     <el-button v-if="isApproveMode" type="primary" @click="handleApproveClick">审核</el-button>
   </footer>
+
+  <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>
 
 <script setup lang="ts">
-  import { computed, onMounted, ref } from 'vue';
+  import { computed, onMounted, ref, reactive } from 'vue';
   import { useRoute, useRouter } from 'vue-router';
   import { ElMessage } from 'element-plus';
   import BasicForm from '@/components/BasicForm.vue';
   import UploadFiles from '@/components/UploadFiles/UploadFiles.vue';
   import type { FileItem } from '@/components/UploadFiles/types';
+  import type { ApprovalNodeInstanceType } from '@/views/system/approval/types';
   import { formatAttachmentList } from '@/components/UploadFiles/utils';
   import { useFormConfigHook } from '@/hooks/useFormConfigHook';
+  import { useEmergencySuppliesHook } from '@/views/emergency/emergency-supplies/src/hook';
   import { ACADEMY_FILE_FORM_CONFIG, ACADEMY_FILE_FORM_DATA, ACADEMY_FILE_FORM_RULES } from '../configs/form';
   import {
     queryHiddenDangerById,
     approveEmployeeHazardReport,
     saveEmployeeHazardReport,
     updateEmployeeHazardReport,
+    queryTemplateID,
     type ApproveEmployeeHazardReportReq,
   } from '@/api/production-safety';
+  import {
+    type PersonalProtectiveEquipmentPurchaseApply,
+    type PurchaseApplyItem,
+    type PpePurchaseApplyDetail,
+    type SavePpePurchaseApplyReq,
+    type ApprovalInfoItem,
+  } from '@/api/production-safety/personal-protective-equipment-purchase-apply';
+  import { APPROVAL_TYPE_MAP, APPROVER_TYPE } from '../configs/constant';
   import PreviewOnline from '@/views/disaster/components/PreviewOnline.vue';
   import { downloadFile } from '@/views/disaster/utils';
-
+  import BasicDialog from '@/components/BasicDialog.vue';
+  import { getApprovalNodeInstanceList } from '@/api/approval/approval';
   const router = useRouter();
   const route = useRoute();
 
@@ -123,6 +188,7 @@
     ACADEMY_FILE_FORM_DATA,
     ACADEMY_FILE_FORM_RULES,
   );
+  const { userOptions, loading, remoteMethod } = useEmergencySuppliesHook();
 
   const formConfig = computed(() =>
     isCreateOrEditMode.value
@@ -132,10 +198,19 @@
         }))
       : ruleFormConfig.value,
   );
-
+  const approvalNodeList = ref<ApprovalNodeInstanceType[]>([]);
+  const basicDialogRef = ref();
+  const approvalFormRef = ref();
   const basicFormRef = ref<InstanceType<typeof BasicForm>>();
   const previewOnlineRef = ref<InstanceType<typeof PreviewOnline>>();
 
+  const approvalForm = reactive({
+    description: '',
+    approvers: {} as Record<number, any[]>,
+  });
+  const closeDialog = () => {
+    basicDialogRef.value.closeDialog();
+  };
   /** 上报时间格式化为 YYYY-MM-DD(详情展示用) */
   function formatReportTimeToDate(reportTime: string | undefined): string {
     if (!reportTime || !String(reportTime).trim()) return '';
@@ -164,7 +239,10 @@
       return [];
     }
   }
-
+  const getApprovalNode = async (id: number) => {
+    const res = await getApprovalNodeInstanceList(id);
+    approvalNodeList.value = res.approvalNodeInfoList || [];
+  };
   const attachmentFileList = computed(() => convertAttachmentJsonToFileItems(ruleFormData.attachment || ''));
 
   async function handleAttachmentUploadSuccess(files: FileItem[]) {
@@ -181,7 +259,7 @@
         }))
         .filter((x) => x.url);
       ruleFormData.attachment = JSON.stringify(jsonArr);
-    } catch (e) {
+    } catch (e:any) {
       console.error('附件上传失败:', e);
       ElMessage.error(e?.message || e?.data || '附件上传失败,请重试');
     }
@@ -214,13 +292,14 @@
         ruleFormData.reporterJobNo = res.reporterJobNo || '';
         ruleFormData.reporterMobile = res.reporterMobile || '';
         ruleFormData.attachment = res.attachment || '';
-        ruleFormData.reportTime = res.reportTime || '';
+        // ruleFormData.reportTime = res.reportTime || '';
+        console.log(ruleFormData.reportTime)
         // 设置审核表单的隐患ID
         approveForm.value.hazardId = res.id;
         approveForm.value.approvalOrder = res.approvalOrder ?? 0;
       }
       cloneRuleFormData();
-    } catch (e) {
+    } catch (e:any) {
       console.error('获取隐患上报详情失败:', e);
       ElMessage.error(e?.message || e?.data || '获取详情失败');
     }
@@ -263,58 +342,130 @@
       ElMessage.success('审核成功');
       approveDialogVisible.value = false;
       router.back();
-    } catch (e) {
+    } catch (e: any) {
       console.error('审核失败:', e);
       ElMessage.error(e?.message || e?.data || '审核失败,请重试');
     }
   };
-
+  // 获取TemplateID
+  const templateInfo = ref()
+  const fetchTemplateID = async ()=>{
+    templateInfo.value =  await queryTemplateID()
+  }
   const handleValidate = async () => {
     if (!basicFormRef.value) return false;
     return await basicFormRef.value.validateForm();
   };
-
+  const params = ref()
   const handleSubmit = async () => {
-    const ok = await handleValidate();
-    if (!ok) return;
+    // const ok = await handleValidate();
+    // if (!ok) return;
     try {
-      const payload = {
+        console.log(ruleFormData, '提交参数')
+      params.value = {
         categoryId: ruleFormData.categoryId ?? 0,
         hazardDesc: ruleFormData.hazardDesc || '',
         location: ruleFormData.location || '',
         reportTime: ruleFormData.reportTime || '',
-        sourceType: ruleFormData.sourceType ?? 1,
+        sourceTypeName: ruleFormData.sourceTypeName,
+        sourceType: Number(ruleFormData.sourceTypeName) ?? 1,
         taskSource: ruleFormData.taskSource || '',
         reporterName: ruleFormData.reporterName || '',
         reporterJobNo: ruleFormData.reporterJobNo || '',
         reporterMobile: ruleFormData.reporterMobile || '',
         attachment: ruleFormData.attachment ? JSON.parse(ruleFormData.attachment) : '',
       };
-      if (
-        operate.value === 'employee-report-hidden-trouble-create' ||
-        operate.value === 'hidden-trouble-review-create'
-      ) {
-        await saveEmployeeHazardReport(payload);
-        ElMessage.success('提交成功');
-      } else if (currentId.value) {
-        await updateEmployeeHazardReport({ id: currentId.value, ...payload });
-        ElMessage.success('保存成功');
-      }
-      router.back();
-    } catch (e) {
+      basicDialogRef.value.openDialog();
+      await getApprovalNode(templateInfo.value);
+    //   if (
+    //     operate.value === 'employee-report-hidden-trouble-create' ||
+    //     operate.value === 'hidden-trouble-review-create'
+    //   ) {
+    //     await saveEmployeeHazardReport(payload);
+    //     ElMessage.success('提交成功');
+    //   } else if (currentId.value) {
+    //     await updateEmployeeHazardReport({ id: currentId.value, ...payload });
+    //     ElMessage.success('保存成功');
+    //   }
+    //   router.back();
+    } catch (e:any) {
       console.error('提交失败:', e);
       ElMessage.error(e?.message || e?.data || '提交失败,请重试');
     }
   };
 
+  // 提交流程
+
+  const handleSubmitApproval = () => {
+    
+    approvalFormRef.value.validate(async (valid: boolean) => {
+      if (valid) {
+        const approvalInfoList: ApprovalInfoItem[] = approvalNodeList.value.map((node) => {
+          let approverIds: number[] = [];
+          if (node.approverType === APPROVER_TYPE.FIX) {
+            approverIds = node.approverInfoList.map((info) => info.approverId);
+          } else {
+            approverIds = approvalForm.approvers[node.id] || [];
+          }
+          return {
+            approvalOrder: node.approvalOrder,
+            approverIdList: approverIds,
+          };
+        });
+
+        const payload = {
+          templateId: templateInfo.value,
+          approvalDescription: approvalForm.description,
+          approvalInfoList,
+          ...params.value,
+        };
+        console.log(payload)
+        await saveEmployeeHazardReport(payload);
+        ElMessage.success('提交成功');
+        // if(isCreateMode.value){
+          
+        // }else{
+        //   const payload = buildSubmitPayload({
+        //     approvalInfoList,
+        //     approvalDescription: '',
+        //     templateId: form.approvalTemplateId,
+        //   });
+        //   await doSubmit(payload);
+        // }
+        basicDialogRef.value.closeDialog();
+        router.back();
+      }
+    });
+  };
+
+//   const handleSubmitApproval = async ()=>{
+//     try {
+//        if (
+//         operate.value === 'employee-report-hidden-trouble-create' ||
+//         operate.value === 'hidden-trouble-review-create'
+//       ) {
+//         await saveEmployeeHazardReport(params.value);
+//         ElMessage.success('提交成功');
+//       } else if (currentId.value) {
+//         await updateEmployeeHazardReport({ id: currentId.value, ...params.value });
+//         ElMessage.success('保存成功');
+//       }
+//       router.back();
+//     } catch (e:any) {
+//       console.error('提交失败:', e);
+//       ElMessage.error(e?.message || e?.data || '提交失败,请重试');
+//     }
+//   }
+
   const previewOnline = (url: string | undefined, type) => {
     if (url) {
-      previewOnlineRef.value?.open(url, type);
+      previewOnlineRef.value?.open(url, 'image/*');
     }
   };
 
   onMounted(() => {
     cloneRuleFormData();
+    fetchTemplateID()
     if (currentId.value) {
       getDetail();
     }

+ 85 - 0
src/views/production-safety/hiddenTroubleInvestigationAndGovernance/employeeReportHiddenTroubleManagement/configs/constant.ts

@@ -0,0 +1,85 @@
+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 = [
+  {
+    label: EMERGENCY_PLAN_STATUS_MAP[EMERGENCY_PLAN_STATUS.UNAPPROVED],
+    value: EMERGENCY_PLAN_STATUS.UNAPPROVED,
+  },
+  {
+    label: EMERGENCY_PLAN_STATUS_MAP[EMERGENCY_PLAN_STATUS.APPROVAL_IN_PROGRESS],
+    value: EMERGENCY_PLAN_STATUS.APPROVAL_IN_PROGRESS,
+  },
+  {
+    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,
+  OHTER,
+}
+
+export const APPROVAL_STATUS_MAP = {
+  [APPROVAL_STATUS.PENDING]: '待审批',
+  [APPROVAL_STATUS.APPROVED]: '已审批',
+  [APPROVAL_STATUS.REJECTED]: '退回',
+  [APPROVAL_STATUS.OHTER]: '他人已审批',
+};
+
+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,
+  },
+  {
+    label: APPROVAL_STATUS_MAP[APPROVAL_STATUS.OHTER],
+    value: APPROVAL_STATUS.OHTER,
+  },
+];

+ 37 - 6
src/views/production-safety/hiddenTroubleInvestigationAndGovernance/employeeReportHiddenTroubleManagement/configs/form.ts

@@ -1,5 +1,16 @@
+/*
+ * @Author: liuJie
+ * @Date: 2026-03-22 16:06:38
+ * @LastEditors: liuJie
+ * @LastEditTime: 2026-04-01 12:08:03
+ * @Describe: file describe
+ */
 import { FormConfig } from '@/types/basic-form';
-
+const sourceTypeNameOptions = [
+    {label: '员工提交', value: '1'},
+    {label: '供应商提交', value: '2'},
+    {label: '第三方提交', value: '3'},
+]
 // 员工上报隐患管理表单配置(详情页,所有字段禁用)
 export const ACADEMY_FILE_FORM_CONFIG: FormConfig[] = [
   {
@@ -23,20 +34,26 @@ export const ACADEMY_FILE_FORM_CONFIG: FormConfig[] = [
   {
     prop: 'reportTime',
     label: '上报时间:',
-    component: 'ElInput',
+    component: 'ElDatePicker',
     componentProps: {
-      placeholder: '上报时间',
+      placeholder: '请选择上报时间',
+      type: 'datetime',
+      format: 'YYYY-MM-DD HH:mm',
+      dateFormat: 'MMM DD, YYYY',
+      timeFormat: 'HH:mm',
+      valueFormat: 'YYYY-MM-DD HH:mm',
       disabled: true,
     },
   },
   {
     prop: 'sourceTypeName',
     label: '提交类型:',
-    component: 'ElInput',
+    component: 'ElSelect',
     componentProps: {
       placeholder: '提交类型',
       disabled: true,
     },
+     selectOptions: sourceTypeNameOptions,
   },
   {
     prop: 'reporterName',
@@ -78,7 +95,7 @@ export const ACADEMY_FILE_FORM_DATA = {
   reportTime: '',
   sourceTypeName: '',
   sourceType: 1 as number, // 提交类型:1-员工
-  taskSource: '',
+  taskSource: '员工上报',
   categoryId: 0 as number,
   reporterName: '',
   reporterJobNo: '',
@@ -86,4 +103,18 @@ export const ACADEMY_FILE_FORM_DATA = {
   attachment: '',
 };
 
-export const ACADEMY_FILE_FORM_RULES = {};
+export const ACADEMY_FILE_FORM_RULES = {
+    hazardDesc:  [{ required: true, message: '请输入隐患问题描述', trigger: 'blur' }],
+    location: [{ required: true, message: '请输入隐患问题描述', trigger: 'blur' }],
+    reportTime: [{ required: true, message: '请选择上报时间', trigger: 'change' }],
+    sourceTypeName: [{ required: true, message: '请选择提交类型', trigger: 'change' }],
+    reporterName: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
+    reporterJobNo: [{ required: true, message: '请输入工号', trigger: 'blur' }],
+    reporterMobile: [
+      { required: true, message: '请输入联系电话', trigger: 'blur' },
+      { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号', trigger: 'blur' }
+    ],
+    attachment: [
+      { required: true, message: '请上传附件', trigger: 'change' }
+    ]
+};

+ 1 - 1
src/views/production-safety/hiddenTroubleInvestigationAndGovernance/employeeReportHiddenTroubleManagement/employeeReportHiddenTroubleManagement.vue

@@ -7,7 +7,7 @@
       <div class="search-table-container">
         <header>
           <div style="position: relative">
-            <!-- <el-button type="primary" :icon="Plus" class="search-table-container--button" @click="handleCreate"> 新增 </el-button> -->
+            <el-button type="primary" :icon="Plus" class="search-table-container--button" @click="handleCreate"> 新增 </el-button>
             <el-button plain class="search-table-container--button" @click="handleImport"> 导入 </el-button>
           </div>