Prechádzať zdrojové kódy

Merge branch 'dev-production-safety' into feat/production-safety

sunqijun 2 mesiacov pred
rodič
commit
341503c25d

+ 40 - 0
src/api/production-safety/responsibility-implementation/index.ts

@@ -820,6 +820,20 @@ export function constructionSafetySaveConstruction(params) {
   });
 }
 
+// /api/dangerWork/submit
+/**
+ * 提交危险作业
+ * @param params - 提交参数,包含作业数据
+ * @returns Promise<void>
+ */
+export function dangerWorkSubmit(params) {
+  return http.request({
+    url: `/dangerWork/submit`,
+    method: 'put',
+    params
+  });
+}
+
 /**
  * 管理端更新施工安全数据
  * @param params - 更新后的施工安全数据(需包含 ID)
@@ -859,6 +873,19 @@ export function constructionSafetySaveApproval(params) {
   });
 }
 
+/**
+ * 管理端分页查询危险作业审批列表
+ * @param params - 查询参数,包含分页参数(pageNum、pageSize)、申请人、申请时间、审批状态等
+ * @returns Promise<QueryPageResponse> 危险作业审批分页结果
+ */
+export function dangerWorkQueryDangerWorkApprovalPage(params) {
+  return http.request({
+    url: `/dangerWork/queryDangerWorkApprovalPage`,
+    method: 'post',
+    params
+  });
+}
+
 /**
  * 分页查询危险作业列表
  * @param params - 查询参数,包含分页参数(pageNum、pageSize)、作业类型、作业状态等
@@ -922,3 +949,16 @@ export function dangerWorkDeleteDangerWork(id) {
   });
 }
 
+/**
+ * 管理端审批危险作业
+ * @param params - 审批参数,包含作业 ID、审批结果、审批意见等
+ * @returns Promise<void>
+ */
+export function dangerWorkSaveApproval(params) {
+  return http.request({
+    url: `/dangerWork/saveApproval`,
+    method: 'post',
+    params
+  });   
+}
+

+ 73 - 2
src/views/production-safety/implement-safety-duty/non-public-list-responsibilities/list.vue

@@ -22,6 +22,30 @@
               <el-option :value="2" label="待确认" />
             </el-select>
           </el-form-item>
+
+          <el-form-item label="安全责任部门">
+            <el-cascader
+              v-model="queryParams.queryParam.safetyResponsibleDepartmentId"
+              style="width: 170px"
+              ref="cascaderRef"
+              :options="firstLevelDepts"
+              :props="cascaderProp"
+              :show-all-levels="false"
+              placeholder="部门名称"
+              filterable
+              @change="handleChangeDept"
+            />
+          </el-form-item>
+          <el-form-item label="安全具体责任人" prop="safetyResponsibleBuilding">
+            <el-select
+              v-model="queryParams.queryParam.safetySpecificPerson"
+              placeholder="请选择"
+              style="width: 170px"
+              filterable
+            >
+              <el-option v-for="item in userOptions" :key="item.value" :label="item.label" :value="item.value" />
+            </el-select>
+          </el-form-item>
         </el-form>
 
         <div>
@@ -147,6 +171,7 @@
     areaCheckListApprove,
     areaCheckListDelete,
     areaCheckListExportArea,
+    queryAvailableUserList,
   } from '@/api/production-safety/responsibility-implementation';
   import urlJoin from 'url-join';
   import { BatchImport } from '@/components/batch-import';
@@ -154,7 +179,8 @@
   import { unformatAttachment } from '@/components/UploadFiles/utils';
   import { downloadFile } from '@/views/disaster/utils';
   import { useGlobSetting } from '@/hooks/setting';
-
+  import { formatDeptTree } from '@/views/disaster/utils/formatDeptTree';
+  import { getAllDepartments } from '@/api/auth/dept';
   const router = useRouter();
   const activeTab = ref(2);
   const queryParams = reactive<any>({
@@ -164,8 +190,19 @@
       type: 2,
       nameFunction: '',
       status: '',
+      safetyResponsibleDepartmentId: [],
+      safetySpecificPerson: '',
     },
   });
+  const cascaderRef = ref<any>(null);
+  const firstLevelDepts = ref<any[]>([]);
+  const cascaderProp = {
+    expandTrigger: 'click',
+    checkStrictly: true,
+    // emitPath: false,
+    value: 'id',
+    label: 'deptName',
+  };
 
   // 批量导入
   const batchImportVisible = ref(false);
@@ -182,6 +219,15 @@
     data: [],
     total: 0,
   });
+  const userOptions = ref<any[]>([]);
+
+  const handleChangeDept = () => {
+    const deptInfo = cascaderRef.value?.getCheckedNodes();
+    if (deptInfo?.[0]) {
+      // queryParams.queryParam.department = deptInfo[0].label;
+      queryParams.queryParam.safetyResponsibleDepartmentId = deptInfo[0].pathValues;
+    }
+  };
   const handleTabChange = (tab) => {
     if (tab === 1) {
       router.push({
@@ -194,6 +240,12 @@
     }
   };
 
+  const getDeptData = () => {
+    getAllDepartments().then((res) => {
+      firstLevelDepts.value = formatDeptTree(res);
+    });
+  };
+
   async function handleDownload() {
     // getQuery();
     try {
@@ -218,6 +270,21 @@
       queryTableList();
     });
   };
+  const handleQueryAvailableUserList = (deptName = '', realname = '') => {
+    queryAvailableUserList({
+      pageNumber: 1,
+      pageSize: 200,
+      queryParam: {
+        deptName,
+        realname,
+      },
+    }).then((res: any) => {
+      userOptions.value = (res.records || []).map((u: any) => ({
+        value: u.userId || u.id,
+        label: u.realname,
+      }));
+    });
+  };
 
   const handleSizeChange = (value) => {};
   const handleCurrentChange = (value) => {
@@ -245,12 +312,16 @@
         ...queryParams.queryParam,
         status: '',
         nameFunction: '',
+        safetyResponsibleDepartmentId: [],
+        safetySpecificPerson: '',
       },
     });
     queryTableList();
   };
 
-  onMounted(() => {
+  onMounted(async () => {
+    await getDeptData();
+    await handleQueryAvailableUserList();
     queryTableList();
   });
 </script>

+ 74 - 1
src/views/production-safety/implement-safety-duty/public-list-responsibilities/list.vue

@@ -22,6 +22,29 @@
               <el-option :value="2" label="待确认" />
             </el-select>
           </el-form-item>
+          <el-form-item label="安全责任部门">
+            <el-cascader
+              v-model="queryParams.queryParam.safetyResponsibleDepartmentId"
+              style="width: 170px"
+              ref="cascaderRef"
+              :options="firstLevelDepts"
+              :props="cascaderProp"
+              :show-all-levels="false"
+              placeholder="部门名称"
+              filterable
+              @change="handleChangeDept"
+            />
+          </el-form-item>
+          <el-form-item label="安全具体责任人" prop="safetyResponsibleBuilding">
+            <el-select
+              v-model="queryParams.queryParam.safetySpecificPerson"
+              placeholder="请选择"
+              style="width: 170px"
+              filterable
+            >
+              <el-option v-for="item in userOptions" :key="item.value" :label="item.label" :value="item.value" />
+            </el-select>
+          </el-form-item>
         </el-form>
 
         <div>
@@ -147,12 +170,15 @@
     areaCheckListApprove,
     areaCheckListDelete,
     areaCheckListExportArea,
+    queryAvailableUserList,
   } from '@/api/production-safety/responsibility-implementation';
   import urlJoin from 'url-join';
   import { BatchImport } from '@/components/batch-import';
 
   import { downloadFile } from '@/views/disaster/utils';
   import { useGlobSetting } from '@/hooks/setting';
+  import { formatDeptTree } from '@/views/disaster/utils/formatDeptTree';
+  import { getAllDepartments } from '@/api/auth/dept';
 
   const router = useRouter();
   const activeTab = ref(1);
@@ -163,9 +189,21 @@
       type: 1,
       nameFunction: '',
       status: '',
+      safetyResponsibleDepartmentId: [],
+      safetySpecificPerson: '',
     },
   });
 
+  const cascaderRef = ref<any>(null);
+  const firstLevelDepts = ref<any[]>([]);
+  const cascaderProp = {
+    expandTrigger: 'click',
+    checkStrictly: true,
+    // emitPath: false,
+    value: 'id',
+    label: 'deptName',
+  };
+
   // 批量导入
   const batchImportVisible = ref(false);
   const { urlPrefix } = useGlobSetting();
@@ -176,11 +214,21 @@
     batchImportVisible.value = false;
     queryTableList();
   };
+  const userOptions = ref<any[]>([]);
 
   const tableData = reactive({
     data: [],
     total: 0,
   });
+
+  const handleChangeDept = () => {
+    const deptInfo = cascaderRef.value?.getCheckedNodes();
+    if (deptInfo?.[0]) {
+      // queryParams.queryParam.department = deptInfo[0].label;
+      queryParams.queryParam.safetyResponsibleDepartmentId = deptInfo[0].pathValues;
+    }
+  };
+
   const handleTabChange = (tab) => {
     if (tab === 1) {
       //todo
@@ -208,6 +256,22 @@
     }
   }
 
+  const handleQueryAvailableUserList = (deptName = '', realname = '') => {
+    queryAvailableUserList({
+      pageNumber: 1,
+      pageSize: 200,
+      queryParam: {
+        deptName,
+        realname,
+      },
+    }).then((res: any) => {
+      userOptions.value = (res.records || []).map((u: any) => ({
+        value: u.userId || u.id,
+        label: u.realname,
+      }));
+    });
+  };
+
   const handleAreaCheckListApprove = (scope, approveType) => {
     areaCheckListApprove({
       id: scope.row.id,
@@ -245,12 +309,21 @@
         ...queryParams.queryParam,
         status: '',
         nameFunction: '',
+        safetyResponsibleDepartmentId: [],
+        safetySpecificPerson: '',
       },
     });
     queryTableList();
   };
 
-  onMounted(() => {
+  const getDeptData = () => {
+    getAllDepartments().then((res) => {
+      firstLevelDepts.value = formatDeptTree(res);
+    });
+  };
+  onMounted(async () => {
+    await getDeptData();
+    await handleQueryAvailableUserList();
     queryTableList();
   });
 </script>

+ 11 - 4
src/views/production-safety/risk-identification-and-control/hazard-approval-manage/add.vue

@@ -428,6 +428,7 @@
   import { dangerWorkSaveDangerWork } from '@/api/production-safety/responsibility-implementation';
   import { formatDeptTree } from '@/views/disaster/utils/formatDeptTree';
   import { getAllDepartments } from '@/api/auth/dept';
+  import { unformatAttachment, formatAttachmentList } from '@/components/UploadFiles/utils';
 
   const router = useRouter();
   const formRef = ref<any>(null);
@@ -607,10 +608,13 @@
       formValue.applicationDepartmentId = deptInfo[0].pathValues;
     }
   };
-  const handleUpload = (objName: string, keyName: string, fileList: any[]) => {
-    const propPath = `${objName}.${keyName}`;
-    listMap[propPath] = fileList;
-    formValue[objName][keyName] = fileList.map((f) => f.response?.url || f.url || f.name).join(',');
+  const handleUpload = async (obj: string, key: string, list: any[]) => {
+    listMap[`${obj}.${key}`] = list;
+
+    if (formValue[obj]) {
+      const formatted = await formatAttachmentList(list);
+      formValue[obj][key] = formatted.length > 0 ? JSON.stringify(formatted) : '';
+    }
   };
 
   const handleSave = () => {
@@ -675,6 +679,9 @@
   @use '@/styles/page-main-layout.scss' as *;
   @use '@/styles/page-details-layout.scss' as *;
   .safety-platform-container {
+    .section-title {
+      margin-bottom: 15px;
+    }
     .section-title-flex {
       display: flex;
       justify-content: space-between;

+ 88 - 164
src/views/production-safety/risk-identification-and-control/hazard-approval-manage/audit.vue

@@ -1,8 +1,9 @@
 <template>
   <div class="safety-platform-container">
     <header class="safety-platform-container__header">
-      <div class="breadcrumb-title"> 危险作业审核 </div>
+      <div class="breadcrumb-title"> 危险作业管理审核 </div>
     </header>
+
     <main class="safety-platform-container__main">
       <div class="search-form">
         <el-form :inline="true">
@@ -59,16 +60,12 @@
           <el-table-column label="申请时间" width="180" prop="createdAt" />
           <el-table-column label="备注" width="180" prop="remark" />
           <el-table-column label="当前节点名称" width="180" prop="nodeDescription" />
-
-          <el-table-column fixed="right" min-width="240" label="操作">
+          <el-table-column fixed="right" min-width="140" label="操作">
             <template #default="scope">
-              <!-- <el-button v-if="scope.row.status === 1" type="primary" link @click="handleSendApproval(scope)"
-                >提交</el-button
-              >
-              <el-button
+              <!-- <el-button
                 type="primary"
                 link
-                @click="$router.push({ name: 'hazardApprovalManageEdit', query: { id: scope.row.id } })"
+                @click="$router.push({ name: 'constructionSafetyManageEdit', query: { id: scope.row.id } })"
                 >编辑</el-button
               > -->
               <el-button
@@ -77,18 +74,14 @@
                 @click="$router.push({ name: 'hazardApprovalManageView', query: { id: scope.row.id } })"
                 >查看</el-button
               >
-              <!-- 
-              <el-popconfirm title="确定要删除吗?" @confirm="handleConfirmDeleteRow(scope)">
-                <template #reference>
-                  <el-button type="primary" link>删除</el-button>
-                </template>
-              </el-popconfirm> -->
 
-              <el-button type="primary" link>审批</el-button>
+              <!-- <el-button type="primary" link @click="handleConfirmDeleteRow(scope)">删除</el-button> -->
+
+              <el-button type="primary" link @click="openApproveDialog(scope)">审核</el-button>
               <!-- <el-button
                 type="primary"
                 link
-                @click="$router.push({ name: 'hazardApprovalManageMonitor', query: { id: scope.row.id } })"
+                @click="$router.push({ name: 'constructionSafetyManageMonitor', query: { id: scope.row.id } })"
                 >视频监控</el-button
               > -->
             </template>
@@ -107,91 +100,57 @@
       </div>
     </main>
   </div>
-  <BasicDialog
-    v-if="approvalVisible"
-    v-model="approvalVisible"
-    ref="basicDialogRef"
-    title="提交审批"
-    @refresh="closeApprovalDialog"
-  >
+  <!-- 审核弹窗 -->
+  <BasicDialog v-model="showApproveDialog" 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-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>
+      <el-form ref="formRef" :model="formData" style="width: 100%">
+        <el-form-item label="审核:" prop="approvalStatus" :rules="[{ required: true, message: '请选择审核状态' }]">
+          <el-radio-group v-model="formData.approvalStatus">
+            <el-radio :value="2">通过</el-radio>
+            <el-radio :value="3">退回</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item
+          v-if="formData.approvalStatus === 3"
+          label="退回原因:"
+          prop="returnReason"
+          :rules="[{ required: true, message: '请输入退回原因' }]"
+        >
+          <el-input v-model="formData.returnReason" placeholder="请输入退回原因" type="textarea" />
+        </el-form-item>
+      </el-form>
     </template>
     <template #footer>
-      <el-button type="primary" @click="handleSubmitApproval">提交</el-button>
-      <el-button @click="approvalVisible = false">取消</el-button>
+      <el-button type="primary" @click="handleApproveSubmit">提交</el-button>
+      <el-button @click="closeDialog">取消</el-button>
     </template>
   </BasicDialog>
 </template>
 <script lang="ts" setup>
   import { onMounted, reactive, ref } from 'vue';
-  import { ElMessage, ElTableColumn } from 'element-plus';
+  import { ElMessage } from 'element-plus';
   import { useRouter } from 'vue-router';
   import {
-    constructionSafetyUpdateApply,
-    dangerWorkQueryPage,
-    dangerWorkDeleteDangerWork,
+    dangerWorkQueryDangerWorkApprovalPage,
+    dangerWorkSaveApproval,
   } from '@/api/production-safety/responsibility-implementation';
-  import BasicDialog from '@/components/BasicDialog.vue';
-  import { getApprovalNodeInstanceList } from '@/api/approval/approval';
-  import { submitReceiptRecordApprovalProcess } from '@/api/receiptRecord';
   import { omit } from 'lodash-es';
-  import { useUserInfoHook } from '@/hooks/useUserInfoHook';
-  import type { ApprovalNodeInstanceType } from '@/views/system/approval/types';
+  import BasicDialog from '@/components/BasicDialog.vue';
 
   import { formatDeptTree } from '@/views/disaster/utils/formatDeptTree';
   import { getAllDepartments } from '@/api/auth/dept';
-  import { APPROVAL_TYPE_MAP, APPROVER_TYPE } from '@/views/emergency/emergency-plan/src/constant';
-  import { useEmergencySuppliesHook } from '@/views/emergency/emergency-supplies/src/hook';
+  import { APPROVAL_STATUS } from '@/views/emergency/emergency-plan/src/constant';
+  import { type ElForm } from 'element-plus';
 
-  const router = useRouter();
-  const { id } = useUserInfoHook();
   const firstLevelDepts = ref<any[]>([]);
-  const approvalVisible = ref(false);
+
+  const showApproveDialog = ref(false);
+  const basicDialogRef = ref<InstanceType<typeof BasicDialog>>();
+  const formRef = ref<InstanceType<typeof ElForm>>();
+  const formData = reactive({
+    approvalStatus: APPROVAL_STATUS.APPROVED,
+    returnReason: '',
+  });
   const cascaderProp = {
     expandTrigger: 'click',
     checkStrictly: true,
@@ -209,8 +168,8 @@
       applicationDepartmentId: [],
     },
   });
+  const currentRow = ref<any>();
   const cascaderRef = ref();
-
   const tableData = reactive({
     data: [],
     total: 0,
@@ -223,22 +182,54 @@
     queryTableList();
   };
 
+  const closeDialog = () => {
+    formRef.value?.resetFields();
+    showApproveDialog.value = false;
+    currentRow.value = null;
+  };
+
+  function openApproveDialog(scope) {
+    currentRow.value = scope.row;
+    showApproveDialog.value = true;
+  }
+
+  function handleApproveSubmit() {
+    formRef.value?.validate(async (valid) => {
+      if (valid) {
+        try {
+          await dangerWorkSaveApproval({
+            approvalOrder: currentRow.value.approvalOrder,
+            approvalStatus: formData.approvalStatus,
+            id: currentRow.value.id,
+            returnReason: formData.returnReason,
+          });
+          ElMessage.success('审核成功');
+          showApproveDialog.value = false;
+          queryTableList();
+        } catch (e) {
+          console.error('审核失败:', e);
+          ElMessage.error('审核失败,请重试');
+        }
+      } else {
+      }
+    });
+  }
+
   const getDeptData = () => {
     getAllDepartments().then((res) => {
       firstLevelDepts.value = formatDeptTree(res);
     });
   };
-  const handleChangeDept = () => {};
-
-  const handleConfirmDeleteRow = (scope) => {
-    dangerWorkDeleteDangerWork(scope.row.id).then(() => {
-      ElMessage.success('删除成功!');
-      queryTableList();
-    });
+  const handleChangeDept = () => {
+    const deptInfo = cascaderRef.value?.getCheckedNodes();
+    if (deptInfo?.[0]) {
+      queryParams.queryParam.department = deptInfo[0].label;
+      queryParams.queryParam.departmentId = deptInfo[0].pathValues;
+    }
   };
 
   const queryTableList = () => {
-    dangerWorkQueryPage({
+    dangerWorkQueryDangerWorkApprovalPage({
       ...queryParams,
       queryParam: {
         ...omit(queryParams.queryParam, 'responsibleDepartmentId'),
@@ -263,73 +254,6 @@
     queryTableList();
   };
 
-  const basicDialogRef = ref<InstanceType<typeof BasicDialog>>();
-  const approvalFormRef = ref();
-  const approvalForm = reactive({
-    description: '',
-    approvers: {} as Record<number, any[]>,
-  });
-
-  const approvalNodeList = ref<ApprovalNodeInstanceType[]>([]);
-  const receiptRecordId = ref<number>();
-
-  const { userOptions, loading, remoteMethod } = useEmergencySuppliesHook();
-
-  const getApprovalNode = async (id: number) => {
-    const res = await getApprovalNodeInstanceList(id);
-    approvalNodeList.value = res.approvalNodeInfoList || [];
-  };
-  const handleSendApproval = async (scope) => {
-    await getApprovalNode(scope.row.templateId);
-    approvalVisible.value = true;
-    receiptRecordId.value = scope.row.id;
-  };
-  const resetApprovalForm = () => {
-    approvalFormRef.value?.resetFields();
-    approvalForm.description = '';
-  };
-
-  const closeApprovalDialog = () => {
-    resetApprovalForm();
-    basicDialogRef.value?.closeDialog();
-  };
-
-  const handleSubmitApproval = () => {
-    approvalFormRef.value?.validate(async (valid: boolean) => {
-      if (!valid) return;
-      if (!receiptRecordId?.value) {
-        ElMessage.error('缺少施工作业记录ID,无法提交审批');
-        return;
-      }
-
-      const approvalData: any = {
-        id: receiptRecordId.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,
-          };
-        }),
-      };
-
-      try {
-        await constructionSafetyUpdateApply(approvalData);
-        ElMessage.success('提交成功');
-        approvalVisible.value = false;
-        queryTableList();
-      } catch (e) {
-        ElMessage.error('提交审批失败,请重试');
-      }
-    });
-  };
-
   onMounted(async () => {
     await getDeptData();
     queryTableList();
@@ -354,6 +278,10 @@
     margin-left: 0;
   }
 
+  :deep(main) {
+    display: flex;
+    flex-direction: column;
+  }
   .search-form {
     min-width: 800px;
     display: flex;
@@ -370,10 +298,6 @@
     :deep(.el-form-item) {
       margin-bottom: 0;
     }
-    :deep(main) {
-      display: flex;
-      flex-direction: column;
-    }
   }
 
   .button-content {

+ 654 - 1
src/views/production-safety/risk-identification-and-control/hazard-approval-manage/edit.vue

@@ -1 +1,654 @@
-<template> xxx </template>
+<template>
+  <div class="safety-platform-container">
+    <header class="safety-platform-container__header">
+      <div class="breadcrumb-title"><BreadcrumbBack /> 编辑危险作业申请</div>
+    </header>
+
+    <main class="safety-platform-container__main">
+      <el-form ref="formRef" :model="formValue" :rules="rules" label-width="160px" label-position="right">
+        <div class="section-title">基础信息</div>
+        <div class="form-grid">
+          <el-form-item label="审批流程" prop="templateId" class="span-full">
+            <el-select v-model="formValue.templateId" placeholder="请选择审批流程" size="large" clearable>
+              <el-option v-for="opt in approvalOptions" :key="opt.id" :label="opt.templateName" :value="opt.id" />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="作业类型" prop="hazardOperationType">
+            <el-select disabled size="large" v-model="formValue.hazardOperationType" class="w-100">
+              <el-option :value="1" label="有限空间作业" />
+              <el-option :value="2" label="高处作业" />
+              <el-option :value="3" label="临时用电" />
+              <el-option :value="4" label="动火作业" />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="申请单位" prop="applicationUnitName"
+            ><el-input size="large" v-model="formValue.applicationUnitName"
+          /></el-form-item>
+          <el-form-item label="申请人" prop="applicantName"
+            ><el-input size="large" v-model="formValue.applicantName"
+          /></el-form-item>
+          <el-form-item label="申请部门" prop="applicationDepartment"
+            ><el-cascader
+              v-model="formValue.applicationDepartmentId"
+              size="large"
+              ref="cascaderRef"
+              :options="firstLevelDepts"
+              :props="cascaderProp"
+              :show-all-levels="false"
+              placeholder="请选择部门名称"
+              filterable
+              @change="handleChangeDept"
+              style="width: 100%"
+          /></el-form-item>
+          <el-form-item label="联系电话" prop="applicantPhone"
+            ><el-input size="large" v-model="formValue.applicantPhone"
+          /></el-form-item>
+          <el-form-item label="备注信息" prop="remark" class="span-full">
+            <el-input size="large" v-model="formValue.remark" type="textarea" :rows="2" placeholder="备注信息..." />
+          </el-form-item>
+        </div>
+
+        <div class="form-line-divider"></div>
+
+        <template v-if="formValue.hazardOperationType === 1">
+          <div class="section-title">有限空间作业详情</div>
+          <div class="form-grid">
+            <el-form-item label="所属单位" prop="space.confinedSpaceUnit"
+              ><el-input size="large" v-model="formValue.space.confinedSpaceUnit"
+            /></el-form-item>
+            <el-form-item label="空间名称" prop="space.confinedSpaceName"
+              ><el-input size="large" v-model="formValue.space.confinedSpaceName"
+            /></el-form-item>
+            <el-form-item label="负责人" prop="space.unitResponsible"
+              ><el-input size="large" v-model="formValue.space.unitResponsible"
+            /></el-form-item>
+            <el-form-item label="监护人" prop="space.supervisor"
+              ><el-input size="large" v-model="formValue.space.supervisor"
+            /></el-form-item>
+            <el-form-item label="作业人" prop="space.operator"
+              ><el-input size="large" v-model="formValue.space.operator" placeholder="多人请用逗号分隔"
+            /></el-form-item>
+            <el-form-item label="其他作业" prop="space.otherSpecialOps"
+              ><el-input size="large" v-model="formValue.space.otherSpecialOps"
+            /></el-form-item>
+            <el-form-item label="开始时间" prop="space.operationStartTime"
+              ><el-date-picker
+                size="large"
+                v-model="formValue.space.operationStartTime"
+                value-format="YYYY-MM-DD"
+                class="w-100"
+            /></el-form-item>
+            <el-form-item label="结束时间" prop="space.operationEndTime"
+              ><el-date-picker
+                size="large"
+                v-model="formValue.space.operationEndTime"
+                value-format="YYYY-MM-DD"
+                class="w-100"
+            /></el-form-item>
+          </div>
+
+          <div class="sub-group-box">
+            <div class="sub-label is-required-manual">环境当前浓度指标 (初始评估)</div>
+            <el-table :data="[formValue.space]" border class="density-table">
+              <el-table-column label="有毒有害物质 (toxicHazardous)">
+                <template #default="scope">
+                  <el-form-item prop="space.toxicHazardous" :rules="r" label-width="0" class="m-0"
+                    ><el-input v-model="scope.row.toxicHazardous"
+                  /></el-form-item>
+                </template>
+              </el-table-column>
+              <el-table-column label="可燃气 (flammable)">
+                <template #default="scope">
+                  <el-form-item prop="space.flammable" :rules="r" label-width="0" class="m-0"
+                    ><el-input v-model="scope.row.flammable"
+                  /></el-form-item>
+                </template>
+              </el-table-column>
+              <el-table-column label="氧含量 (oxygenContent)">
+                <template #default="scope">
+                  <el-form-item prop="space.oxygenContent" :rules="r" label-width="0" class="m-0"
+                    ><el-input v-model="scope.row.oxygenContent"
+                  /></el-form-item>
+                </template>
+              </el-table-column>
+            </el-table>
+          </div>
+
+          <div class="form-grid mt-20">
+            <el-form-item label="作业内容" prop="space.operationContent" class="span-full"
+              ><el-input size="large" v-model="formValue.space.operationContent" type="textarea"
+            /></el-form-item>
+            <el-form-item label="危害辨识" prop="space.hazardIdentification" class="span-full"
+              ><el-input size="large" v-model="formValue.space.hazardIdentification" type="textarea"
+            /></el-form-item>
+            <el-form-item label="作业附件" class="span-full"
+              ><UploadFiles
+                label="上传附件"
+                @upload-success="(l) => handleUpload('space', 'attachment', l)"
+                :fileList="listMap['space.attachment']"
+            /></el-form-item>
+          </div>
+        </template>
+
+        <template v-else-if="formValue.hazardOperationType === 2">
+          <div class="section-title">高处作业详情</div>
+          <div class="form-grid">
+            <el-form-item label="作业地点" prop="highAltitude.operationLocation"
+              ><el-input size="large" v-model="formValue.highAltitude.operationLocation"
+            /></el-form-item>
+            <el-form-item label="作业单位" prop="highAltitude.operationUnit"
+              ><el-input size="large" v-model="formValue.highAltitude.operationUnit"
+            /></el-form-item>
+            <el-form-item label="作业高度(m)" prop="highAltitude.operationHeight"
+              ><el-input-number
+                size="large"
+                v-model="formValue.highAltitude.operationHeight"
+                class="w-100"
+                :controls="false"
+            /></el-form-item>
+            <el-form-item label="作业类别" prop="highAltitude.operationType"
+              ><el-input size="large" v-model="formValue.highAltitude.operationType" placeholder="如:悬挂作业"
+            /></el-form-item>
+            <el-form-item label="作业人姓名" prop="highAltitude.operatorName"
+              ><el-input size="large" v-model="formValue.highAltitude.operatorName"
+            /></el-form-item>
+            <el-form-item label="监护人" prop="highAltitude.supervisor"
+              ><el-input size="large" v-model="formValue.highAltitude.supervisor"
+            /></el-form-item>
+            <el-form-item label="开始时间" prop="highAltitude.operationStartTime"
+              ><el-date-picker
+                size="large"
+                v-model="formValue.highAltitude.operationStartTime"
+                value-format="YYYY-MM-DD"
+                class="w-100"
+            /></el-form-item>
+            <el-form-item label="结束时间" prop="highAltitude.operationEndTime"
+              ><el-date-picker
+                size="large"
+                v-model="formValue.highAltitude.operationEndTime"
+                value-format="YYYY-MM-DD"
+                class="w-100"
+            /></el-form-item>
+            <el-form-item label="作业内容" prop="highAltitude.operationContent" class="span-full"
+              ><el-input size="large" v-model="formValue.highAltitude.operationContent" type="textarea"
+            /></el-form-item>
+            <el-form-item label="危害辨识" prop="highAltitude.hazardIdentification" class="span-full"
+              ><el-input size="large" v-model="formValue.highAltitude.hazardIdentification" type="textarea"
+            /></el-form-item>
+            <el-form-item label="作业附件" class="span-full"
+              ><UploadFiles
+                label="上传附件"
+                @upload-success="(l) => handleUpload('highAltitude', 'attachment', l)"
+                :fileList="listMap['highAltitude.attachment']"
+            /></el-form-item>
+          </div>
+        </template>
+
+        <template v-else-if="formValue.hazardOperationType === 3">
+          <div class="section-title">临时用电详情</div>
+          <div class="form-grid">
+            <el-form-item label="需求部门" prop="electricityList.requestDepartment"
+              ><el-input size="large" v-model="formValue.electricityList.requestDepartment"
+            /></el-form-item>
+            <el-form-item label="用电类型" prop="electricityList.electricityType">
+              <el-select v-model="formValue.electricityList.electricityType" class="w-100">
+                <el-option :value="1" label="长期" /><el-option :value="2" label="临时" />
+              </el-select>
+            </el-form-item>
+            <el-form-item label="责任人" prop="electricityList.contactPerson"
+              ><el-input size="large" v-model="formValue.electricityList.contactPerson"
+            /></el-form-item>
+            <el-form-item label="设备功率" prop="electricityList.equipmentPower"
+              ><el-input size="large" v-model="formValue.electricityList.equipmentPower"
+            /></el-form-item>
+            <el-form-item label="开始时间" prop="electricityList.operationStartTime"
+              ><el-date-picker
+                size="large"
+                v-model="formValue.electricityList.operationStartTime"
+                value-format="YYYY-MM-DD"
+                class="w-100"
+            /></el-form-item>
+            <el-form-item label="结束时间" prop="electricityList.operationEndTime"
+              ><el-date-picker
+                size="large"
+                v-model="formValue.electricityList.operationEndTime"
+                value-format="YYYY-MM-DD"
+                class="w-100"
+            /></el-form-item>
+            <el-form-item label="保护措施" prop="electricityList.safety" class="span-full"
+              ><el-input size="large" v-model="formValue.electricityList.safety"
+            /></el-form-item>
+            <el-form-item label="用电事由" prop="electricityList.reason" class="span-full"
+              ><el-input size="large" v-model="formValue.electricityList.reason" type="textarea"
+            /></el-form-item>
+            <el-form-item label="申请附件" class="span-full"
+              ><UploadFiles
+                label="上传附件"
+                @upload-success="(l) => handleUpload('electricityList', 'attachment', l)"
+                :fileList="listMap['electricityList.attachment']"
+            /></el-form-item>
+          </div>
+        </template>
+
+        <template v-else-if="formValue.hazardOperationType === 4">
+          <div class="section-title">动火作业详情</div>
+          <div class="sub-label">A. 动火任务信息</div>
+          <div class="form-grid">
+            <el-form-item label="动火地点" prop="hot.hotWorkLocation"
+              ><el-input size="large" v-model="formValue.hot.hotWorkLocation"
+            /></el-form-item>
+            <el-form-item label="动火级别" prop="hot.hotWorkLevel">
+              <el-select v-model="formValue.hot.hotWorkLevel" class="w-100">
+                <el-option :value="1" label="一级" /><el-option :value="2" label="二级" /><el-option
+                  :value="3"
+                  label="三级"
+                />
+              </el-select>
+            </el-form-item>
+            <el-form-item label="特殊时段" prop="hot.isSpecialPeriod">
+              <el-radio-group v-model="formValue.hot.isSpecialPeriod">
+                <el-radio :label="1">是 (节假日/重大活动)</el-radio>
+                <el-radio :label="0">否</el-radio>
+              </el-radio-group>
+            </el-form-item>
+            <el-form-item label="动火类型" prop="hot.hotWorkType"
+              ><el-input size="large" v-model="formValue.hot.hotWorkType" placeholder="气焊/电焊/打磨等"
+            /></el-form-item>
+            <el-form-item label="开始时间" prop="hot.hotWorkStart"
+              ><el-date-picker
+                size="large"
+                v-model="formValue.hot.hotWorkStart"
+                value-format="YYYY-MM-DD"
+                class="w-100"
+            /></el-form-item>
+            <el-form-item label="结束时间" prop="hot.hotWorkEnd"
+              ><el-date-picker size="large" v-model="formValue.hot.hotWorkEnd" value-format="YYYY-MM-DD" class="w-100"
+            /></el-form-item>
+            <el-form-item label="动火任务" prop="hot.hotWorkTask" class="span-full"
+              ><el-input size="large" v-model="formValue.hot.hotWorkTask" type="textarea"
+            /></el-form-item>
+            <el-form-item label="危险性分析" prop="hot.hazardAnalysis" class="span-full"
+              ><el-input size="large" v-model="formValue.hot.hazardAnalysis" type="textarea"
+            /></el-form-item>
+          </div>
+
+          <div class="sub-label">B. 责任人信息</div>
+          <div class="form-grid">
+            <el-form-item label="动火作业人员" prop="hot.hotWorkman"
+              ><el-input size="large" v-model="formValue.hot.hotWorkman"
+            /></el-form-item>
+            <el-form-item label="动火人电话" prop="hot.hotWorkContact"
+              ><el-input size="large" v-model="formValue.hot.hotWorkContact"
+            /></el-form-item>
+            <el-form-item label="施工单位监护人" prop="hot.constructionSupervisor"
+              ><el-input size="large" v-model="formValue.hot.constructionSupervisor"
+            /></el-form-item>
+            <el-form-item label="监护人电话" prop="hot.supervisorContact"
+              ><el-input size="large" v-model="formValue.hot.supervisorContact"
+            /></el-form-item>
+            <el-form-item label="现场负责人" prop="hot.constructionSiteLeader"
+              ><el-input size="large" v-model="formValue.hot.constructionSiteLeader"
+            /></el-form-item>
+            <el-form-item label="教育人" prop="hot.constructionEducator"
+              ><el-input size="large" v-model="formValue.hot.constructionEducator"
+            /></el-form-item>
+            <el-form-item label="申请部门监护人" prop="hot.hotWorkSupervisor"
+              ><el-input size="large" v-model="formValue.hot.hotWorkSupervisor"
+            /></el-form-item>
+            <el-form-item label="部门监护电话" prop="hot.supervisorNumber"
+              ><el-input size="large" v-model="formValue.hot.supervisorNumber"
+            /></el-form-item>
+          </div>
+
+          <div class="sub-label">C. 防护措施与附件</div>
+          <div class="form-grid">
+            <el-form-item label="安全防护措施" prop="hot.fireSafetyMeasures" class="span-full"
+              ><el-input size="large" v-model="formValue.hot.fireSafetyMeasures" type="textarea"
+            /></el-form-item>
+            <el-form-item label="现场检查情况" prop="hot.supervisorMeasures" class="span-full"
+              ><el-input size="large" v-model="formValue.hot.supervisorMeasures" type="textarea"
+            /></el-form-item>
+
+            <el-form-item label="动火现场照片"
+              ><UploadFiles
+                label="上传附件"
+                @upload-success="(l) => handleUpload('hot', 'photos', l)"
+                :fileList="listMap['hot.photos']"
+            /></el-form-item>
+            <el-form-item label="身份证复印件"
+              ><UploadFiles
+                label="上传附件"
+                @upload-success="(l) => handleUpload('hot', 'idCard', l)"
+                :fileList="listMap['hot.idCard']"
+            /></el-form-item>
+            <el-form-item label="特种作业证"
+              ><UploadFiles
+                label="上传附件"
+                @upload-success="(l) => handleUpload('hot', 'optionCard', l)"
+                :fileList="listMap['hot.optionCard']"
+            /></el-form-item>
+            <el-form-item label="安全教育记录"
+              ><UploadFiles
+                label="上传附件"
+                @upload-success="(l) => handleUpload('hot', 'safetyEducationPlan', l)"
+                :fileList="listMap['hot.safetyEducationPlan']"
+            /></el-form-item>
+            <el-form-item label="施工方案"
+              ><UploadFiles
+                label="上传附件"
+                @upload-success="(l) => handleUpload('hot', 'constructionPlan', l)"
+                :fileList="listMap['hot.constructionPlan']"
+            /></el-form-item>
+            <el-form-item label="准备工作照片"
+              ><UploadFiles
+                label="上传附件"
+                @upload-success="(l) => handleUpload('hot', 'preparationPhotos', l)"
+                :fileList="listMap['hot.preparationPhotos']"
+            /></el-form-item>
+            <el-form-item label="管理协议"
+              ><UploadFiles
+                label="上传附件"
+                @upload-success="(l) => handleUpload('hot', 'safetyManagementAgreement', l)"
+                :fileList="listMap['hot.safetyManagementAgreement']"
+            /></el-form-item>
+          </div>
+        </template>
+
+        <div class="form-line-divider"></div>
+
+        <div class="section-title-flex">
+          <span class="is-required-manual">安全措施清单</span>
+          <el-button type="primary" @click="addRow('measure')">+ 新增措施</el-button>
+        </div>
+        <el-table :data="formValue.measure" border class="mb-20">
+          <el-table-column label="序号" prop="serialNumber" width="100" align="center" />
+          <el-table-column label="措施内容"
+            ><template #default="scope"><el-input v-model="scope.row.safetyMeasure" /></template
+          ></el-table-column>
+          <el-table-column label="确认人" width="200"
+            ><template #default="scope"><el-input v-model="scope.row.confirmer" /></template
+          ></el-table-column>
+          <el-table-column label="操作" width="80" align="center">
+            <template #default="scope"
+              ><el-button type="primary" link @click="removeRow('measure', scope.$index)">删除</el-button></template
+            >
+          </el-table-column>
+        </el-table>
+
+        <div class="section-title-flex">
+          <span class="is-required-manual">危害分析记录</span>
+          <el-button type="primary" @click="addRow('analysis')">+ 新增记录</el-button>
+        </div>
+        <el-table :data="formValue.analysis" border>
+          <el-table-column label="检测部位"
+            ><template #default="scope"><el-input v-model="scope.row.analysisPosition" /></template
+          ></el-table-column>
+          <el-table-column label="有毒物质及浓度"
+            ><template #default="scope"><el-input v-model="scope.row.toxicSubstance" /></template
+          ></el-table-column>
+          <el-table-column label="可燃气及浓度"
+            ><template #default="scope"><el-input v-model="scope.row.flammableGas" /></template
+          ></el-table-column>
+          <el-table-column label="氧含量"
+            ><template #default="scope"><el-input v-model="scope.row.oxygenContent" /></template
+          ></el-table-column>
+          <el-table-column label="检测人" width="130"
+            ><template #default="scope"><el-input v-model="scope.row.analyst" /></template
+          ></el-table-column>
+          <el-table-column label="检测时间" width="220"
+            ><template #default="scope">
+              <el-date-picker
+                v-model="scope.row.analysisTime"
+                value-format="YYYY-MM-DD"
+                style="width: 100%"
+              /> </template
+          ></el-table-column>
+          <el-table-column label="操作" width="80" align="center">
+            <template #default="scope"
+              ><el-button type="primary" link @click="removeRow('analysis', scope.$index)">删除</el-button></template
+            >
+          </el-table-column>
+        </el-table>
+      </el-form>
+    </main>
+
+    <footer class="safety-platform-container__footer">
+      <el-button size="large" @click="router.back()">取 消</el-button>
+      <el-button type="primary" size="large" :loading="loading" @click="handleSave">提交</el-button>
+    </footer>
+  </div>
+</template>
+<script lang="ts" setup>
+  import { ref, reactive, onMounted, nextTick } from 'vue';
+  import { useRouter, useRoute } from 'vue-router';
+  import { ElMessage } from 'element-plus';
+  import UploadFiles from '@/components/UploadFiles/UploadFiles.vue';
+  import { getAllApproval } from '@/api/approval/approval';
+  import {
+    dangerWorkQueryDetail,
+    dangerWorkUpdateDangerWork,
+  } from '@/api/production-safety/responsibility-implementation';
+  import { formatDeptTree } from '@/views/disaster/utils/formatDeptTree';
+  import { getAllDepartments } from '@/api/auth/dept';
+  import { unformatAttachment, formatAttachmentList } from '@/components/UploadFiles/utils';
+
+  const router = useRouter();
+  const route = useRoute();
+  const formRef = ref<any>(null);
+  const loading = ref(false);
+  const detailId = route.query.id as string;
+
+  const approvalOptions = ref<any[]>([]);
+  const firstLevelDepts = ref<any[]>([]);
+  const cascaderRef = ref<any>(null);
+  const cascaderProp = { expandTrigger: 'click', checkStrictly: true, value: 'id', label: 'deptName' };
+
+  /**
+   * 1. 附件显示映射 (仅用于组件内部回显显示)
+   */
+  const listMap = reactive<any>({
+    'space.attachment': [],
+    'highAltitude.attachment': [],
+    'electricityList.attachment': [],
+    'hot.photos': [],
+    'hot.idCard': [],
+    'hot.optionCard': [],
+    'hot.safetyEducationPlan': [],
+    'hot.constructionPlan': [],
+    'hot.preparationPhotos': [],
+    'hot.safetyManagementAgreement': [],
+  });
+
+  /**
+   * 2. 初始化表单数据结构 (保持深度对象存在)
+   */
+  const formValue = reactive<any>({
+    id: detailId,
+    templateId: '',
+    applicationDepartment: '',
+    applicationDepartmentId: [],
+    applicationUnitName: '',
+    applicantName: '',
+    applicantPhone: '',
+    hazardOperationType: '',
+    remark: '',
+    // 必须预设这些对象,防止赋值时路径不存在
+    space: { attachment: '' },
+    highAltitude: { attachment: '' },
+    electricityList: { attachment: '' },
+    hot: {
+      photos: '',
+      idCard: '',
+      optionCard: '',
+      safetyEducationPlan: '',
+      constructionPlan: '',
+      preparationPhotos: '',
+      safetyManagementAgreement: '',
+    },
+    measure: [],
+    analysis: [],
+  });
+
+  const r = { required: true, message: '此项必填', trigger: ['blur', 'change'] };
+  const rules = reactive({
+    templateId: [r],
+    applicationUnitName: [r],
+    applicantName: [r],
+    applicationDepartmentId: [r],
+    applicantPhone: [r],
+  });
+
+  /**
+   * 3. 关键:上传成功回调
+   * @param obj 对应的对象名 (如 'space')
+   * @param key 对应的字段名 (如 'attachment')
+   * @param list 组件返回的最新的 fileList 数组
+   */
+  const handleUpload = async (obj: string, key: string, list: any[]) => {
+    listMap[`${obj}.${key}`] = list;
+
+    if (formValue[obj]) {
+      const formatted = await formatAttachmentList(list);
+      formValue[obj][key] = formatted.length > 0 ? JSON.stringify(formatted) : '';
+    }
+  };
+
+  /**
+   * 4. 详情回显
+   */
+  const getDetail = async () => {
+    if (!detailId) return;
+    try {
+      const res = await dangerWorkQueryDetail(detailId);
+
+      // 1. 基础属性拷贝
+      Object.assign(formValue, res);
+
+      // 2. 等待 DOM 和 v-if 完成渲染 (确保 Upload 控件已经挂载)
+      await nextTick();
+
+      const typeKeyMap: any = { 1: 'space', 2: 'highAltitude', 3: 'electricityList', 4: 'hot' };
+      const activeObjName = typeKeyMap[formValue.hazardOperationType];
+
+      if (!activeObjName) return;
+
+      // 3. 附件处理逻辑
+      Object.keys(listMap).forEach((path) => {
+        // 检查当前路径是否属于选中的作业类型 (例如 "space.attachment")
+        if (path.startsWith(activeObjName)) {
+          const [objName, fieldName] = path.split('.');
+
+          // 拿到后端返回的原始字段值 (通常是字符串)
+          const rawValue = formValue[objName]?.[fieldName];
+
+          if (rawValue) {
+            // 【核心修改】:调用你的解析函数,将字符串转为数组
+            // 确保 unformatAttachment 函数已在当前作用域可用
+            listMap[path] = unformatAttachment(rawValue);
+
+            console.log(`附件解析成功 [${path}]:`, listMap[path]);
+          }
+        }
+      });
+    } catch (err) {
+      console.error('详情加载失败:', err);
+      ElMessage.error('详情回显失败');
+    }
+  };
+
+  /**
+   * 5. 提交保存
+   */
+  const handleSave = async () => {
+    const valid = await formRef.value.validate().catch(() => false);
+    if (!valid) return ElMessage.error('请检查表单必填项');
+
+    loading.value = true;
+
+    // 深度克隆,避免操作原对象
+    const submitData = JSON.parse(JSON.stringify(formValue));
+
+    // 数据清洗:只发送当前选中的危险作业详情
+    const typeMap: any = { 1: 'space', 2: 'highAltitude', 3: 'electricityList', 4: 'hot' };
+    const currentKey = typeMap[formValue.hazardOperationType];
+
+    Object.values(typeMap).forEach((val) => {
+      if (val !== currentKey) {
+        delete submitData[val as string];
+      }
+    });
+
+    dangerWorkUpdateDangerWork(submitData)
+      .then(() => {
+        ElMessage.success('保存成功');
+        router.back();
+      })
+      .finally(() => {
+        loading.value = false;
+      });
+  };
+
+  /**
+   * 辅助:表格行操作
+   */
+  const addRow = (type: 'measure' | 'analysis') => {
+    if (type === 'measure') {
+      formValue.measure.push({ serialNumber: formValue.measure.length + 1, safetyMeasure: '', confirmer: '' });
+    } else {
+      formValue.analysis.push({
+        toxicSubstance: '',
+        flammableGas: '',
+        oxygenContent: '',
+        analysisTime: '',
+        analysisPosition: '',
+        analyst: '',
+      });
+    }
+  };
+
+  const removeRow = (type: 'measure' | 'analysis', index: number) => {
+    formValue[type].splice(index, 1);
+    if (type === 'measure') {
+      formValue.measure.forEach((item: any, i: number) => (item.serialNumber = i + 1));
+    }
+  };
+
+  const handleChangeDept = () => {
+    const node = cascaderRef.value?.getCheckedNodes()?.[0];
+    if (node) {
+      formValue.applicationDepartment = node.label;
+      formValue.applicationDepartmentId = node.pathValues;
+    }
+  };
+
+  onMounted(async () => {
+    const [depts, approvals] = await Promise.all([getAllDepartments(), getAllApproval()]);
+    firstLevelDepts.value = formatDeptTree(depts);
+    approvalOptions.value = approvals || [];
+
+    getDetail();
+  });
+</script>
+<style lang="scss" scoped>
+  @use '@/styles/page-main-layout.scss' as *;
+  @use '@/styles/page-details-layout.scss' as *;
+  .safety-platform-container {
+    .section-title-flex {
+      display: flex;
+      justify-content: space-between;
+      margin: 15px 0;
+    }
+    &__main {
+      padding: 24px;
+      background-color: #fff;
+    }
+    :deep(.el-form-item) {
+      margin-right: 20px;
+      margin-bottom: 24px;
+      vertical-align: top;
+      .el-form-item__label {
+        font-weight: bold;
+      }
+    }
+  }
+</style>

+ 8 - 3
src/views/production-safety/risk-identification-and-control/hazard-approval-manage/list.vue

@@ -172,7 +172,7 @@
   import { ElMessage, ElTableColumn } from 'element-plus';
   import { useRouter } from 'vue-router';
   import {
-    constructionSafetyUpdateApply,
+    dangerWorkSubmit,
     dangerWorkQueryPage,
     dangerWorkDeleteDangerWork,
   } from '@/api/production-safety/responsibility-implementation';
@@ -242,6 +242,8 @@
       ...queryParams,
       queryParam: {
         ...omit(queryParams.queryParam, 'responsibleDepartmentId'),
+        status: queryParams.queryParam.status !== '' ? queryParams.queryParam.status : undefined,
+        applicationDepartmentId: JSON.stringify(queryParams.queryParam.applicationDepartmentId),
       },
     }).then((res) => {
       tableData.data = res.records;
@@ -320,7 +322,7 @@
       };
 
       try {
-        await constructionSafetyUpdateApply(approvalData);
+        await dangerWorkSubmit(approvalData);
         ElMessage.success('提交成功');
         approvalVisible.value = false;
         queryTableList();
@@ -340,7 +342,10 @@
   @use '@/styles/page-details-layout.scss' as *;
   @use '@/styles/page-main-layout.scss' as *;
   @use '@/styles/basic-table-action.scss' as *;
-
+  main {
+    display: flex;
+    flex-direction: column;
+  }
   :deep(.el-tabs__header) {
     margin: 0;
   }

+ 627 - 1
src/views/production-safety/risk-identification-and-control/hazard-approval-manage/view.vue

@@ -1 +1,627 @@
-<template> xxx </template>
+<template>
+  <div class="safety-platform-container">
+    <header class="safety-platform-container__header">
+      <div class="breadcrumb-title"><BreadcrumbBack /> 查看危险作业申请</div>
+    </header>
+
+    <main class="safety-platform-container__main">
+      <el-form ref="formRef" :model="formValue" :rules="rules" disabled label-width="160px" label-position="right">
+        <div class="section-title">基础信息</div>
+        <div class="form-grid">
+          <el-form-item label="审批流程" prop="templateId" class="span-full">
+            <el-select v-model="formValue.templateId" placeholder="请选择审批流程" size="large" clearable>
+              <el-option v-for="opt in approvalOptions" :key="opt.id" :label="opt.templateName" :value="opt.id" />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="作业类型" prop="hazardOperationType">
+            <el-select disabled size="large" v-model="formValue.hazardOperationType" class="w-100">
+              <el-option :value="1" label="有限空间作业" />
+              <el-option :value="2" label="高处作业" />
+              <el-option :value="3" label="临时用电" />
+              <el-option :value="4" label="动火作业" />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="申请单位" prop="applicationUnitName"
+            ><el-input size="large" v-model="formValue.applicationUnitName"
+          /></el-form-item>
+          <el-form-item label="申请人" prop="applicantName"
+            ><el-input size="large" v-model="formValue.applicantName"
+          /></el-form-item>
+          <el-form-item label="申请部门" prop="applicationDepartment"
+            ><el-cascader
+              v-model="formValue.applicationDepartmentId"
+              size="large"
+              ref="cascaderRef"
+              :options="firstLevelDepts"
+              :props="cascaderProp"
+              :show-all-levels="false"
+              placeholder="请选择部门名称"
+              filterable
+              @change="handleChangeDept"
+              style="width: 100%"
+          /></el-form-item>
+          <el-form-item label="联系电话" prop="applicantPhone"
+            ><el-input size="large" v-model="formValue.applicantPhone"
+          /></el-form-item>
+          <el-form-item label="备注信息" prop="remark" class="span-full">
+            <el-input size="large" v-model="formValue.remark" type="textarea" :rows="2" placeholder="备注信息..." />
+          </el-form-item>
+        </div>
+
+        <div class="form-line-divider"></div>
+
+        <template v-if="formValue.hazardOperationType === 1">
+          <div class="section-title">有限空间作业详情</div>
+          <div class="form-grid">
+            <el-form-item label="所属单位" prop="space.confinedSpaceUnit"
+              ><el-input size="large" v-model="formValue.space.confinedSpaceUnit"
+            /></el-form-item>
+            <el-form-item label="空间名称" prop="space.confinedSpaceName"
+              ><el-input size="large" v-model="formValue.space.confinedSpaceName"
+            /></el-form-item>
+            <el-form-item label="负责人" prop="space.unitResponsible"
+              ><el-input size="large" v-model="formValue.space.unitResponsible"
+            /></el-form-item>
+            <el-form-item label="监护人" prop="space.supervisor"
+              ><el-input size="large" v-model="formValue.space.supervisor"
+            /></el-form-item>
+            <el-form-item label="作业人" prop="space.operator"
+              ><el-input size="large" v-model="formValue.space.operator" placeholder="多人请用逗号分隔"
+            /></el-form-item>
+            <el-form-item label="其他作业" prop="space.otherSpecialOps"
+              ><el-input size="large" v-model="formValue.space.otherSpecialOps"
+            /></el-form-item>
+            <el-form-item label="开始时间" prop="space.operationStartTime"
+              ><el-date-picker
+                size="large"
+                v-model="formValue.space.operationStartTime"
+                value-format="YYYY-MM-DD"
+                class="w-100"
+            /></el-form-item>
+            <el-form-item label="结束时间" prop="space.operationEndTime"
+              ><el-date-picker
+                size="large"
+                v-model="formValue.space.operationEndTime"
+                value-format="YYYY-MM-DD"
+                class="w-100"
+            /></el-form-item>
+          </div>
+
+          <div class="sub-group-box">
+            <div class="sub-label is-required-manual">环境当前浓度指标 (初始评估)</div>
+            <el-table :data="[formValue.space]" border class="density-table">
+              <el-table-column label="有毒有害物质 (toxicHazardous)">
+                <template #default="scope">
+                  <el-form-item prop="space.toxicHazardous" :rules="r" label-width="0" class="m-0"
+                    ><el-input v-model="scope.row.toxicHazardous"
+                  /></el-form-item>
+                </template>
+              </el-table-column>
+              <el-table-column label="可燃气 (flammable)">
+                <template #default="scope">
+                  <el-form-item prop="space.flammable" :rules="r" label-width="0" class="m-0"
+                    ><el-input v-model="scope.row.flammable"
+                  /></el-form-item>
+                </template>
+              </el-table-column>
+              <el-table-column label="氧含量 (oxygenContent)">
+                <template #default="scope">
+                  <el-form-item prop="space.oxygenContent" :rules="r" label-width="0" class="m-0"
+                    ><el-input v-model="scope.row.oxygenContent"
+                  /></el-form-item>
+                </template>
+              </el-table-column>
+            </el-table>
+          </div>
+
+          <div class="form-grid mt-20">
+            <el-form-item label="作业内容" prop="space.operationContent" class="span-full"
+              ><el-input size="large" v-model="formValue.space.operationContent" type="textarea"
+            /></el-form-item>
+            <el-form-item label="危害辨识" prop="space.hazardIdentification" class="span-full"
+              ><el-input size="large" v-model="formValue.space.hazardIdentification" type="textarea"
+            /></el-form-item>
+            <el-form-item label="作业附件" class="span-full"
+              ><UploadFiles
+                label="上传附件"
+                disabled
+                @upload-success="(l) => handleUpload('space', 'attachment', l)"
+                :fileList="listMap['space.attachment']"
+            /></el-form-item>
+          </div>
+        </template>
+
+        <template v-else-if="formValue.hazardOperationType === 2">
+          <div class="section-title">高处作业详情</div>
+          <div class="form-grid">
+            <el-form-item label="作业地点" prop="highAltitude.operationLocation"
+              ><el-input size="large" v-model="formValue.highAltitude.operationLocation"
+            /></el-form-item>
+            <el-form-item label="作业单位" prop="highAltitude.operationUnit"
+              ><el-input size="large" v-model="formValue.highAltitude.operationUnit"
+            /></el-form-item>
+            <el-form-item label="作业高度(m)" prop="highAltitude.operationHeight"
+              ><el-input-number
+                size="large"
+                v-model="formValue.highAltitude.operationHeight"
+                class="w-100"
+                :controls="false"
+            /></el-form-item>
+            <el-form-item label="作业类别" prop="highAltitude.operationType"
+              ><el-input size="large" v-model="formValue.highAltitude.operationType" placeholder="如:悬挂作业"
+            /></el-form-item>
+            <el-form-item label="作业人姓名" prop="highAltitude.operatorName"
+              ><el-input size="large" v-model="formValue.highAltitude.operatorName"
+            /></el-form-item>
+            <el-form-item label="监护人" prop="highAltitude.supervisor"
+              ><el-input size="large" v-model="formValue.highAltitude.supervisor"
+            /></el-form-item>
+            <el-form-item label="开始时间" prop="highAltitude.operationStartTime"
+              ><el-date-picker
+                size="large"
+                v-model="formValue.highAltitude.operationStartTime"
+                value-format="YYYY-MM-DD"
+                class="w-100"
+            /></el-form-item>
+            <el-form-item label="结束时间" prop="highAltitude.operationEndTime"
+              ><el-date-picker
+                size="large"
+                v-model="formValue.highAltitude.operationEndTime"
+                value-format="YYYY-MM-DD"
+                class="w-100"
+            /></el-form-item>
+            <el-form-item label="作业内容" prop="highAltitude.operationContent" class="span-full"
+              ><el-input size="large" v-model="formValue.highAltitude.operationContent" type="textarea"
+            /></el-form-item>
+            <el-form-item label="危害辨识" prop="highAltitude.hazardIdentification" class="span-full"
+              ><el-input size="large" v-model="formValue.highAltitude.hazardIdentification" type="textarea"
+            /></el-form-item>
+            <el-form-item label="作业附件" class="span-full"
+              ><UploadFiles
+                label="上传附件"
+                disabled
+                @upload-success="(l) => handleUpload('highAltitude', 'attachment', l)"
+                :fileList="listMap['highAltitude.attachment']"
+            /></el-form-item>
+          </div>
+        </template>
+
+        <template v-else-if="formValue.hazardOperationType === 3">
+          <div class="section-title">临时用电详情</div>
+          <div class="form-grid">
+            <el-form-item label="需求部门" prop="electricityList.requestDepartment"
+              ><el-input size="large" v-model="formValue.electricityList.requestDepartment"
+            /></el-form-item>
+            <el-form-item label="用电类型" prop="electricityList.electricityType">
+              <el-select v-model="formValue.electricityList.electricityType" class="w-100">
+                <el-option :value="1" label="长期" /><el-option :value="2" label="临时" />
+              </el-select>
+            </el-form-item>
+            <el-form-item label="责任人" prop="electricityList.contactPerson"
+              ><el-input size="large" v-model="formValue.electricityList.contactPerson"
+            /></el-form-item>
+            <el-form-item label="设备功率" prop="electricityList.equipmentPower"
+              ><el-input size="large" v-model="formValue.electricityList.equipmentPower"
+            /></el-form-item>
+            <el-form-item label="开始时间" prop="electricityList.operationStartTime"
+              ><el-date-picker
+                size="large"
+                v-model="formValue.electricityList.operationStartTime"
+                value-format="YYYY-MM-DD"
+                class="w-100"
+            /></el-form-item>
+            <el-form-item label="结束时间" prop="electricityList.operationEndTime"
+              ><el-date-picker
+                size="large"
+                v-model="formValue.electricityList.operationEndTime"
+                value-format="YYYY-MM-DD"
+                class="w-100"
+            /></el-form-item>
+            <el-form-item label="保护措施" prop="electricityList.safety" class="span-full"
+              ><el-input size="large" v-model="formValue.electricityList.safety"
+            /></el-form-item>
+            <el-form-item label="用电事由" prop="electricityList.reason" class="span-full"
+              ><el-input size="large" v-model="formValue.electricityList.reason" type="textarea"
+            /></el-form-item>
+            <el-form-item label="申请附件" class="span-full"
+              ><UploadFiles
+                label="上传附件"
+                disabled
+                @upload-success="(l) => handleUpload('electricityList', 'attachment', l)"
+                :fileList="listMap['electricityList.attachment']"
+            /></el-form-item>
+          </div>
+        </template>
+
+        <template v-else-if="formValue.hazardOperationType === 4">
+          <div class="section-title">动火作业详情</div>
+          <div class="sub-label">A. 动火任务信息</div>
+          <div class="form-grid">
+            <el-form-item label="动火地点" prop="hot.hotWorkLocation"
+              ><el-input size="large" v-model="formValue.hot.hotWorkLocation"
+            /></el-form-item>
+            <el-form-item label="动火级别" prop="hot.hotWorkLevel">
+              <el-select v-model="formValue.hot.hotWorkLevel" class="w-100">
+                <el-option :value="1" label="一级" /><el-option :value="2" label="二级" /><el-option
+                  :value="3"
+                  label="三级"
+                />
+              </el-select>
+            </el-form-item>
+            <el-form-item label="特殊时段" prop="hot.isSpecialPeriod">
+              <el-radio-group v-model="formValue.hot.isSpecialPeriod">
+                <el-radio :label="1">是 (节假日/重大活动)</el-radio>
+                <el-radio :label="0">否</el-radio>
+              </el-radio-group>
+            </el-form-item>
+            <el-form-item label="动火类型" prop="hot.hotWorkType"
+              ><el-input size="large" v-model="formValue.hot.hotWorkType" placeholder="气焊/电焊/打磨等"
+            /></el-form-item>
+            <el-form-item label="开始时间" prop="hot.hotWorkStart"
+              ><el-date-picker
+                size="large"
+                v-model="formValue.hot.hotWorkStart"
+                value-format="YYYY-MM-DD"
+                class="w-100"
+            /></el-form-item>
+            <el-form-item label="结束时间" prop="hot.hotWorkEnd"
+              ><el-date-picker size="large" v-model="formValue.hot.hotWorkEnd" value-format="YYYY-MM-DD" class="w-100"
+            /></el-form-item>
+            <el-form-item label="动火任务" prop="hot.hotWorkTask" class="span-full"
+              ><el-input size="large" v-model="formValue.hot.hotWorkTask" type="textarea"
+            /></el-form-item>
+            <el-form-item label="危险性分析" prop="hot.hazardAnalysis" class="span-full"
+              ><el-input size="large" v-model="formValue.hot.hazardAnalysis" type="textarea"
+            /></el-form-item>
+          </div>
+
+          <div class="sub-label">B. 责任人信息</div>
+          <div class="form-grid">
+            <el-form-item label="动火作业人员" prop="hot.hotWorkman"
+              ><el-input size="large" v-model="formValue.hot.hotWorkman"
+            /></el-form-item>
+            <el-form-item label="动火人电话" prop="hot.hotWorkContact"
+              ><el-input size="large" v-model="formValue.hot.hotWorkContact"
+            /></el-form-item>
+            <el-form-item label="施工单位监护人" prop="hot.constructionSupervisor"
+              ><el-input size="large" v-model="formValue.hot.constructionSupervisor"
+            /></el-form-item>
+            <el-form-item label="监护人电话" prop="hot.supervisorContact"
+              ><el-input size="large" v-model="formValue.hot.supervisorContact"
+            /></el-form-item>
+            <el-form-item label="现场负责人" prop="hot.constructionSiteLeader"
+              ><el-input size="large" v-model="formValue.hot.constructionSiteLeader"
+            /></el-form-item>
+            <el-form-item label="教育人" prop="hot.constructionEducator"
+              ><el-input size="large" v-model="formValue.hot.constructionEducator"
+            /></el-form-item>
+            <el-form-item label="申请部门监护人" prop="hot.hotWorkSupervisor"
+              ><el-input size="large" v-model="formValue.hot.hotWorkSupervisor"
+            /></el-form-item>
+            <el-form-item label="部门监护电话" prop="hot.supervisorNumber"
+              ><el-input size="large" v-model="formValue.hot.supervisorNumber"
+            /></el-form-item>
+          </div>
+
+          <div class="sub-label">C. 防护措施与附件</div>
+          <div class="form-grid">
+            <el-form-item label="安全防护措施" prop="hot.fireSafetyMeasures" class="span-full"
+              ><el-input size="large" v-model="formValue.hot.fireSafetyMeasures" type="textarea"
+            /></el-form-item>
+            <el-form-item label="现场检查情况" prop="hot.supervisorMeasures" class="span-full"
+              ><el-input size="large" v-model="formValue.hot.supervisorMeasures" type="textarea"
+            /></el-form-item>
+
+            <el-form-item label="动火现场照片"
+              ><UploadFiles
+                disabled
+                label="上传附件"
+                @upload-success="(l) => handleUpload('hot', 'photos', l)"
+                :fileList="listMap['hot.photos']"
+            /></el-form-item>
+            <el-form-item label="身份证复印件"
+              ><UploadFiles
+                disabled
+                label="上传附件"
+                @upload-success="(l) => handleUpload('hot', 'idCard', l)"
+                :fileList="listMap['hot.idCard']"
+            /></el-form-item>
+            <el-form-item label="特种作业证"
+              ><UploadFiles
+                disabled
+                label="上传附件"
+                @upload-success="(l) => handleUpload('hot', 'optionCard', l)"
+                :fileList="listMap['hot.optionCard']"
+            /></el-form-item>
+            <el-form-item label="安全教育记录"
+              ><UploadFiles
+                disabled
+                label="上传附件"
+                @upload-success="(l) => handleUpload('hot', 'safetyEducationPlan', l)"
+                :fileList="listMap['hot.safetyEducationPlan']"
+            /></el-form-item>
+            <el-form-item label="施工方案"
+              ><UploadFiles
+                disabled
+                label="上传附件"
+                @upload-success="(l) => handleUpload('hot', 'constructionPlan', l)"
+                :fileList="listMap['hot.constructionPlan']"
+            /></el-form-item>
+            <el-form-item label="准备工作照片"
+              ><UploadFiles
+                disabled
+                label="上传附件"
+                @upload-success="(l) => handleUpload('hot', 'preparationPhotos', l)"
+                :fileList="listMap['hot.preparationPhotos']"
+            /></el-form-item>
+            <el-form-item label="管理协议"
+              ><UploadFiles
+                disabled
+                label="上传附件"
+                @upload-success="(l) => handleUpload('hot', 'safetyManagementAgreement', l)"
+                :fileList="listMap['hot.safetyManagementAgreement']"
+            /></el-form-item>
+          </div>
+        </template>
+
+        <div class="form-line-divider"></div>
+
+        <div class="section-title-flex">
+          <span class="is-required-manual">安全措施清单</span>
+          <el-button type="primary" @click="addRow('measure')">+ 新增措施</el-button>
+        </div>
+        <el-table :data="formValue.measure" border class="mb-20">
+          <el-table-column label="序号" prop="serialNumber" width="100" align="center" />
+          <el-table-column label="措施内容"
+            ><template #default="scope"><el-input v-model="scope.row.safetyMeasure" /></template
+          ></el-table-column>
+          <el-table-column label="确认人" width="200"
+            ><template #default="scope"><el-input v-model="scope.row.confirmer" /></template
+          ></el-table-column>
+          <el-table-column label="操作" width="80" align="center">
+            <template #default="scope"
+              ><el-button type="primary" link @click="removeRow('measure', scope.$index)">删除</el-button></template
+            >
+          </el-table-column>
+        </el-table>
+
+        <div class="section-title-flex">
+          <span class="is-required-manual">危害分析记录</span>
+          <el-button type="primary" @click="addRow('analysis')">+ 新增记录</el-button>
+        </div>
+        <el-table :data="formValue.analysis" border>
+          <el-table-column label="检测部位"
+            ><template #default="scope"><el-input v-model="scope.row.analysisPosition" /></template
+          ></el-table-column>
+          <el-table-column label="有毒物质及浓度"
+            ><template #default="scope"><el-input v-model="scope.row.toxicSubstance" /></template
+          ></el-table-column>
+          <el-table-column label="可燃气及浓度"
+            ><template #default="scope"><el-input v-model="scope.row.flammableGas" /></template
+          ></el-table-column>
+          <el-table-column label="氧含量"
+            ><template #default="scope"><el-input v-model="scope.row.oxygenContent" /></template
+          ></el-table-column>
+          <el-table-column label="检测人" width="130"
+            ><template #default="scope"><el-input v-model="scope.row.analyst" /></template
+          ></el-table-column>
+          <el-table-column label="检测时间" width="220"
+            ><template #default="scope">
+              <el-date-picker
+                v-model="scope.row.analysisTime"
+                value-format="YYYY-MM-DD"
+                style="width: 100%"
+              /> </template
+          ></el-table-column>
+          <el-table-column label="操作" width="80" align="center">
+            <template #default="scope"
+              ><el-button type="primary" link @click="removeRow('analysis', scope.$index)">删除</el-button></template
+            >
+          </el-table-column>
+        </el-table>
+      </el-form>
+    </main>
+
+    <footer class="safety-platform-container__footer">
+      <el-button size="large" @click="router.back()">返回</el-button>
+    </footer>
+  </div>
+</template>
+<script lang="ts" setup>
+  import { ref, reactive, onMounted, nextTick } from 'vue';
+  import { useRouter, useRoute } from 'vue-router';
+  import { ElMessage } from 'element-plus';
+  import UploadFiles from '@/components/UploadFiles/UploadFiles.vue';
+  import { getAllApproval } from '@/api/approval/approval';
+  import { dangerWorkQueryDetail } from '@/api/production-safety/responsibility-implementation';
+  import { formatDeptTree } from '@/views/disaster/utils/formatDeptTree';
+  import { getAllDepartments } from '@/api/auth/dept';
+  import { unformatAttachment, formatAttachmentList } from '@/components/UploadFiles/utils';
+
+  const router = useRouter();
+  const route = useRoute();
+  const formRef = ref<any>(null);
+  const detailId = route.query.id as string;
+
+  const approvalOptions = ref<any[]>([]);
+  const firstLevelDepts = ref<any[]>([]);
+  const cascaderRef = ref<any>(null);
+  const cascaderProp = { expandTrigger: 'click', checkStrictly: true, value: 'id', label: 'deptName' };
+
+  /**
+   * 1. 附件显示映射 (仅用于组件内部回显显示)
+   */
+  const listMap = reactive<any>({
+    'space.attachment': [],
+    'highAltitude.attachment': [],
+    'electricityList.attachment': [],
+    'hot.photos': [],
+    'hot.idCard': [],
+    'hot.optionCard': [],
+    'hot.safetyEducationPlan': [],
+    'hot.constructionPlan': [],
+    'hot.preparationPhotos': [],
+    'hot.safetyManagementAgreement': [],
+  });
+
+  /**
+   * 2. 初始化表单数据结构 (保持深度对象存在)
+   */
+  const formValue = reactive<any>({
+    id: detailId,
+    templateId: '',
+    applicationDepartment: '',
+    applicationDepartmentId: [],
+    applicationUnitName: '',
+    applicantName: '',
+    applicantPhone: '',
+    hazardOperationType: '',
+    remark: '',
+    // 必须预设这些对象,防止赋值时路径不存在
+    space: { attachment: '' },
+    highAltitude: { attachment: '' },
+    electricityList: { attachment: '' },
+    hot: {
+      photos: '',
+      idCard: '',
+      optionCard: '',
+      safetyEducationPlan: '',
+      constructionPlan: '',
+      preparationPhotos: '',
+      safetyManagementAgreement: '',
+    },
+    measure: [],
+    analysis: [],
+  });
+
+  const r = { required: true, message: '此项必填', trigger: ['blur', 'change'] };
+  const rules = reactive({
+    templateId: [r],
+    applicationUnitName: [r],
+    applicantName: [r],
+    applicationDepartmentId: [r],
+    applicantPhone: [r],
+  });
+
+  /**
+   * 3. 关键:上传成功回调
+   * @param obj 对应的对象名 (如 'space')
+   * @param key 对应的字段名 (如 'attachment')
+   * @param list 组件返回的最新的 fileList 数组
+   */
+  const handleUpload = async (obj: string, key: string, list: any[]) => {
+    listMap[`${obj}.${key}`] = list;
+
+    if (formValue[obj]) {
+      const formatted = await formatAttachmentList(list);
+      formValue[obj][key] = formatted.length > 0 ? JSON.stringify(formatted) : '';
+    }
+  };
+
+  /**
+   * 4. 详情回显
+   */
+  const getDetail = async () => {
+    if (!detailId) return;
+    try {
+      const res = await dangerWorkQueryDetail(detailId);
+
+      // 1. 基础属性拷贝
+      Object.assign(formValue, res);
+
+      // 2. 等待 DOM 和 v-if 完成渲染 (确保 Upload 控件已经挂载)
+      await nextTick();
+
+      const typeKeyMap: any = { 1: 'space', 2: 'highAltitude', 3: 'electricityList', 4: 'hot' };
+      const activeObjName = typeKeyMap[formValue.hazardOperationType];
+
+      if (!activeObjName) return;
+
+      // 3. 附件处理逻辑
+      Object.keys(listMap).forEach((path) => {
+        // 检查当前路径是否属于选中的作业类型 (例如 "space.attachment")
+        if (path.startsWith(activeObjName)) {
+          const [objName, fieldName] = path.split('.');
+
+          // 拿到后端返回的原始字段值 (通常是字符串)
+          const rawValue = formValue[objName]?.[fieldName];
+
+          if (rawValue) {
+            // 【核心修改】:调用你的解析函数,将字符串转为数组
+            // 确保 unformatAttachment 函数已在当前作用域可用
+            listMap[path] = unformatAttachment(rawValue);
+
+            console.log(`附件解析成功 [${path}]:`, listMap[path]);
+          }
+        }
+      });
+    } catch (err) {
+      console.error('详情加载失败:', err);
+      ElMessage.error('详情回显失败');
+    }
+  };
+
+  /**
+   * 辅助:表格行操作
+   */
+  const addRow = (type: 'measure' | 'analysis') => {
+    if (type === 'measure') {
+      formValue.measure.push({ serialNumber: formValue.measure.length + 1, safetyMeasure: '', confirmer: '' });
+    } else {
+      formValue.analysis.push({
+        toxicSubstance: '',
+        flammableGas: '',
+        oxygenContent: '',
+        analysisTime: '',
+        analysisPosition: '',
+        analyst: '',
+      });
+    }
+  };
+
+  const removeRow = (type: 'measure' | 'analysis', index: number) => {
+    formValue[type].splice(index, 1);
+    if (type === 'measure') {
+      formValue.measure.forEach((item: any, i: number) => (item.serialNumber = i + 1));
+    }
+  };
+
+  const handleChangeDept = () => {
+    const node = cascaderRef.value?.getCheckedNodes()?.[0];
+    if (node) {
+      formValue.applicationDepartment = node.label;
+      formValue.applicationDepartmentId = node.pathValues;
+    }
+  };
+
+  onMounted(async () => {
+    const [depts, approvals] = await Promise.all([getAllDepartments(), getAllApproval()]);
+    firstLevelDepts.value = formatDeptTree(depts);
+    approvalOptions.value = approvals || [];
+
+    getDetail();
+  });
+</script>
+<style lang="scss" scoped>
+  @use '@/styles/page-main-layout.scss' as *;
+  @use '@/styles/page-details-layout.scss' as *;
+  .safety-platform-container {
+    .section-title-flex {
+      display: flex;
+      justify-content: space-between;
+      margin: 15px 0;
+    }
+    &__main {
+      padding: 24px;
+      background-color: #fff;
+    }
+    :deep(.el-form-item) {
+      margin-right: 20px;
+      margin-bottom: 24px;
+      vertical-align: top;
+      .el-form-item__label {
+        font-weight: bold;
+      }
+    }
+  }
+</style>