Selaa lähdekoodia

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

xiaweibo 3 kuukautta sitten
vanhempi
commit
cc32a3560a
30 muutettua tiedostoa jossa 933 lisäystä ja 583 poistoa
  1. 1 1
      src/api/production-safety-system/index.ts
  2. 183 154
      src/api/production-safety/index.ts
  3. 2 2
      src/components/UploadFiles/UploadFiles.vue
  4. 136 84
      src/views/production-safety/hiddenTroubleInvestigationAndGovernance/employeeReportHiddenTroubleManagement/components/employeeReportHiddenTroubleManagementDetail.vue
  5. 41 81
      src/views/production-safety/hiddenTroubleInvestigationAndGovernance/employeeReportHiddenTroubleManagement/configs/form.ts
  6. 21 21
      src/views/production-safety/hiddenTroubleInvestigationAndGovernance/employeeReportHiddenTroubleManagement/configs/tables.ts
  7. 77 72
      src/views/production-safety/hiddenTroubleInvestigationAndGovernance/employeeReportHiddenTroubleManagement/employeeReportHiddenTroubleManagement.vue
  8. 3 1
      src/views/production-safety/hiddenTroubleInvestigationAndGovernance/employeeReportHiddenTroubleManagement/employeeReportHiddenTroubleManagementItem.vue
  9. 4 6
      src/views/production-safety/hiddenTroubleInvestigationAndGovernance/hiddenTroubleCategoryManagement/components/hiddenTroubleCategoryManagementDetail.vue
  10. 12 18
      src/views/production-safety/hiddenTroubleInvestigationAndGovernance/hiddenTroubleCategoryManagement/configs/form.ts
  11. 11 10
      src/views/production-safety/hiddenTroubleInvestigationAndGovernance/hiddenTroubleCategoryManagement/configs/tables.ts
  12. 33 6
      src/views/production-safety/hiddenTroubleInvestigationAndGovernance/hiddenTroubleCategoryManagement/hiddenTroubleCategoryManagement.vue
  13. 1 1
      src/views/production-safety/productionSafetySystem/collegeFileManagement/collegeFileManagement.vue
  14. 78 24
      src/views/production-safety/productionSafetySystem/collegeFileManagement/components/collegeFileManagementDetail.vue
  15. 1 0
      src/views/production-safety/productionSafetySystem/collegeFileManagement/configs/form.ts
  16. 78 24
      src/views/production-safety/productionSafetySystem/doubleSystemManagement/components/doubleSystemManagementDetail.vue
  17. 1 0
      src/views/production-safety/productionSafetySystem/doubleSystemManagement/configs/form.ts
  18. 1 1
      src/views/production-safety/productionSafetySystem/doubleSystemManagement/doubleSystemManagement.vue
  19. 79 25
      src/views/production-safety/productionSafetySystem/lawManagement/components/lawManagementDetail.vue
  20. 2 0
      src/views/production-safety/productionSafetySystem/lawManagement/configs/form.ts
  21. 1 1
      src/views/production-safety/productionSafetySystem/lawManagement/lawManagement.vue
  22. 78 24
      src/views/production-safety/productionSafetySystem/safetyStandardizationSystemManagement/components/safetyStandardizationSystemManagementDetail.vue
  23. 1 0
      src/views/production-safety/productionSafetySystem/safetyStandardizationSystemManagement/configs/form.ts
  24. 1 1
      src/views/production-safety/productionSafetySystem/safetyStandardizationSystemManagement/safetyStandardizationSystemManagement.vue
  25. 78 24
      src/views/production-safety/productionSafetySystem/safetyTraining/components/safetyTrainingDetail.vue
  26. 1 0
      src/views/production-safety/productionSafetySystem/safetyTraining/configs/form.ts
  27. 1 1
      src/views/production-safety/productionSafetySystem/safetyTraining/safetyTraining.vue
  28. 1 0
      src/views/production-safety/safetyAssessment/evaluationSystem/components/EvaluationTarget.vue
  29. 6 0
      src/views/production-safety/safetyAssessment/evaluationSystem/configs/targetTables.ts
  30. 0 1
      src/views/production-safety/safetyAssessment/pointDeduction/configs/form.ts

+ 1 - 1
src/api/production-safety-system/index.ts

@@ -38,7 +38,7 @@ export interface ProductionSafetyFileQuery {
 export interface ProductionSafetyFilePageQuery {
   pageNumber: number; // 页码,从1开始
   pageSize: number; // 每页数量
-  data?: ProductionSafetyFileQuery; // 查询条件对象
+  queryParam?: ProductionSafetyFileQuery; // 查询条件对象
 }
 
 /**

+ 183 - 154
src/api/production-safety/index.ts

@@ -2,131 +2,161 @@ import { http } from '@/utils/http/axios';
 import type { QueryPageRequest, QueryPageResponse } from '@/types/basic-query';
 
 /**
- * ==================== 员工上报隐患管理 hiddenDanger ====================
+ * ==================== 员工上报隐患管理 employeeHazardReport ====================
  */
 
-// 隐患上报数据对象(详情 / 列表返回)
-export interface HiddenDanger {
+// 员工上报隐患数据对象(详情 / 列表返回)
+export interface EmployeeHazardReportDTO {
   id: number;
-  dangerName: string;
-  dangerType: number;
-  dangerTypeName?: string;
-  dangerLevel: number;
-  dangerLevelName?: string;
-  location: string;
-  description: string;
-  reporterName: string;
-  reporterPhone: string;
-  reporterDept: string;
-  reportTime: string;
-  images?: string[];
-  status: number;
-  statusName?: string;
-  handlerName?: string;
-  handleTime?: string;
-  handleResult?: string;
-  createdAt?: string;
-  updatedAt?: string;
+  hazardNo: string; // 隐患编号
+  categoryId: number; // 隐患类别 ID
+  categoryName: string; // 隐患类别名称
+  hazardDesc: string; // 隐患问题描述
+  location: string; // 隐患地点
+  reportTime: string; // 上报时间
+  sourceType: number; // 提交类型:1-员工,2-供应商,3-第三方
+  sourceTypeName: string; // 提交类型名称
+  reporterName: string; // 上报人姓名
+  reporterJobNo: string; // 上报人工号
+  reporterMobile: string; // 联系电话
+  attachment: string; // 附件 JSON
+  status: number; // 状态:1-待审核,2-需求部门通过,3-需求部门驳回,4-安全部门通过,5-安全部门驳回,6-已入账,7-已关闭
+  statusName: string; // 状态名称
+  isRewardApplied: number; // 是否申请奖品:1-是,0-否
+  createdById: number; // 创建人 ID
+  createdByName: string; // 创建人姓名
+  createdAt: string; // 创建时间
+  updatedAt: string; // 更新时间
 }
 
-// 新增隐患上报
-export interface SaveHiddenDangerReq {
-  dangerName: string;
-  dangerType: number;
-  dangerLevel: number;
-  location: string;
-  description: string;
-  reporterName: string;
-  reporterPhone: string;
-  reporterDept: string;
-  reportTime: string;
-  images?: string[];
-  status?: number;
+// 新增员工上报隐患
+export interface SaveEmployeeHazardReportReq {
+  categoryId: number; // 隐患类别 ID
+  hazardDesc: string; // 隐患问题描述
+  location: string; // 隐患地点
+  reportTime: string; // 上报时间
+  sourceType: number; // 提交类型:1-员工,2-供应商,3-第三方
+  reporterName: string; // 上报人姓名
+  reporterJobNo: string; // 上报人工号
+  reporterMobile: string; // 联系电话
+  attachment?: string; // 附件 JSON,格式 [{file_name, url}]
 }
 
-// 编辑隐患上报
-export interface UpdateHiddenDangerReq extends SaveHiddenDangerReq {
-  id: number;
+// 编辑员工上报隐患
+export interface UpdateEmployeeHazardReportReq {
+  id: number; // 主键 ID
+  categoryId?: number; // 隐患类别 ID
+  hazardDesc?: string; // 隐患问题描述
+  location?: string; // 隐患地点
+  reportTime?: string; // 上报时间
+  sourceType?: number; // 提交类型:1-员工,2-供应商,3-第三方
+  reporterName?: string; // 上报人姓名
+  reporterJobNo?: string; // 上报人工号
+  reporterMobile?: string; // 联系电话
+  attachment?: string; // 附件 JSON
 }
 
 // 查询条件
-export interface QueryHiddenDangerReq {
-  keyword?: string;
-  dangerType?: number;
-  dangerLevel?: number;
-  status?: number;
-  startDate?: string;
-  endDate?: string;
+export interface QueryEmployeeHazardReportReq {
+  hazardDesc?: string; // 隐患问题描述(模糊查询)
+  status?: number; // 状态:1–7
+  sourceTypeName?: string; // 任务来源/提交类型名称(模糊查询)
+  startDate?: string; // 上报时间范围-开始
+  endDate?: string; // 上报时间范围-结束
+  categoryId?: number; // 隐患类别 ID
+  reporterJobNo?: string; // 上报人工号
 }
 
-// 处理隐患
-export interface HandleHiddenDangerReq {
-  id: number;
-  status: number;
-  handlerName: string;
-  handleTime: string;
-  handleResult?: string;
+// 审核员工上报隐患
+export interface ApproveEmployeeHazardReportReq {
+  hazardId: number; // 隐患主表 ID
+  node: number; // 审批节点:1-需求部门,2-安全部门
+  approvalStatus: number; // 审批状态:2-通过,3-驳回
+  approvalContent?: string; // 审批意见
 }
 
-// 新增隐患上报
-export function saveHiddenDanger(data: SaveHiddenDangerReq) {
+// 兼容旧接口名称(向后兼容)
+export type HiddenDanger = EmployeeHazardReportDTO;
+export type SaveHiddenDangerReq = SaveEmployeeHazardReportReq;
+export type UpdateHiddenDangerReq = UpdateEmployeeHazardReportReq;
+export type QueryHiddenDangerReq = QueryEmployeeHazardReportReq;
+
+// 新增员工上报隐患
+export function saveEmployeeHazardReport(data: SaveEmployeeHazardReportReq) {
   return http.request<number>({
-    url: '/admin/prod/hiddenDanger/saveHiddenDanger',
+    url: '/employeeHazardReport/saveEmployeeHazardReport',
     method: 'post',
     data,
   });
 }
 
-// 编辑隐患上报
-export function updateHiddenDanger(data: UpdateHiddenDangerReq) {
+// 编辑员工上报隐患
+export function updateEmployeeHazardReport(data: UpdateEmployeeHazardReportReq) {
   return http.request({
-    url: '/admin/prod/hiddenDanger/updateHiddenDanger',
+    url: '/employeeHazardReport/updateEmployeeHazardReport',
     method: 'put',
     data,
   });
 }
 
-// 删除隐患上报
-export function deleteHiddenDanger(id: number) {
+// 删除员工上报隐患
+export function deleteEmployeeHazardReport(id: number) {
   return http.request({
-    url: `/admin/prod/hiddenDanger/deleteHiddenDanger?id=${id}`,
+    url: `/employeeHazardReport/deleteEmployeeHazardReport?id=${id}`,
     method: 'delete',
   });
 }
 
-// 根据 ID 查询隐患详情
-export function queryHiddenDangerById(id: number) {
-  return http.request<HiddenDanger>({
-    url: `/admin/prod/hiddenDanger/queryHiddenDangerById?id=${id}`,
+// 根据 ID 查询员工上报隐患详情
+export function queryEmployeeHazardReportById(id: number) {
+  return http.request<EmployeeHazardReportDTO>({
+    url: `/employeeHazardReport/queryEmployeeHazardReportById?id=${id}`,
     method: 'get',
   });
 }
 
-// 查询隐患上报列表(不分页)
-export function queryHiddenDangerList(params?: QueryHiddenDangerReq) {
-  return http.request<HiddenDanger[]>({
-    url: '/admin/prod/hiddenDanger/queryHiddenDangerList',
+// 查看员工上报隐患列表(不分页)
+export function queryEmployeeHazardReportList(params?: QueryEmployeeHazardReportReq) {
+  return http.request<EmployeeHazardReportDTO[]>({
+    url: '/employeeHazardReport/queryEmployeeHazardReportList',
     method: 'post',
-    data: params,
+    data: params || {},
   });
 }
 
-// 分页查询隐患上报
-export function queryHiddenDangerPage(query: QueryPageRequest<QueryHiddenDangerReq>) {
-  return http.request<QueryPageResponse<HiddenDanger>>({
-    url: '/admin/prod/hiddenDanger/queryHiddenDangerPage',
+// 分页查询员工上报隐患
+export function queryEmployeeHazardReportPage(query: QueryPageRequest<QueryEmployeeHazardReportReq>) {
+  return http.request<QueryPageResponse<EmployeeHazardReportDTO>>({
+    url: '/employeeHazardReport/queryEmployeeHazardReportPage',
     method: 'post',
     data: query,
   });
 }
 
-// 导出隐患上报
-export function exportHiddenDanger(params?: QueryHiddenDangerReq) {
+// 审核员工上报隐患
+export function approveEmployeeHazardReport(data: ApproveEmployeeHazardReportReq) {
+  return http.request({
+    url: '/employeeHazardReport/approveEmployeeHazardReport',
+    method: 'post',
+    data,
+  });
+}
+
+// 入账员工上报隐患
+export function accountEmployeeHazardReport(hazardId: number) {
+  return http.request({
+    url: `/employeeHazardReport/accountEmployeeHazardReport?hazardId=${hazardId}`,
+    method: 'post',
+  });
+}
+
+// 导出员工上报隐患
+export function exportEmployeeHazardReport(params?: QueryEmployeeHazardReportReq) {
   return http.request(
     {
-      url: '/admin/prod/hiddenDanger/exportHiddenDanger',
+      url: '/employeeHazardReport/exportEmployeeHazardReport',
       method: 'post',
-      data: params,
+      data: params || {},
       responseType: 'blob',
     },
     {
@@ -135,137 +165,126 @@ export function exportHiddenDanger(params?: QueryHiddenDangerReq) {
   );
 }
 
-// 导入隐患上报
+// 导入结果
 export interface ImportRes {
   successCount: number;
   failCount: number;
-  failMessages: string[];
+  failInfoList?: Array<{
+    rowNum: number;
+    failReason: string;
+  }>;
+  failMessages?: string[]; // 兼容旧版本
 }
 
-export function importHiddenDanger(file: File) {
-  const formData = new FormData();
-  formData.append('file', file);
-  return http.request<ImportRes>({
-    url: '/admin/prod/hiddenDanger/importHiddenDanger',
-    method: 'post',
-    data: formData,
-    headers: {
-      'Content-Type': 'multipart/form-data',
-    },
-  });
-}
-
-// 处理隐患
-export function handleHiddenDanger(data: HandleHiddenDangerReq) {
-  return http.request({
-    url: '/admin/prod/hiddenDanger/handleHiddenDanger',
-    method: 'put',
-    data,
-  });
-}
+// 向后兼容的接口函数(使用旧接口名称)
+export const saveHiddenDanger = saveEmployeeHazardReport;
+export const updateHiddenDanger = updateEmployeeHazardReport;
+export const deleteHiddenDanger = deleteEmployeeHazardReport;
+export const queryHiddenDangerById = queryEmployeeHazardReportById;
+export const queryHiddenDangerList = queryEmployeeHazardReportList;
+export const queryHiddenDangerPage = queryEmployeeHazardReportPage;
+export const exportHiddenDanger = exportEmployeeHazardReport;
 
 /**
- * ==================== 隐患类别管理 dangerType ====================
+ * ==================== 隐患类别管理 hazardCategory ====================
  */
 
-export interface DangerType {
+export interface HazardCategoryDTO {
   id: number;
-  typeName: string;
-  parentId: number | null;
-  parentName?: string | null;
-  sort?: number;
-  status: number;
-  statusName?: string;
-  createdAt?: string;
-  updatedAt?: string;
-  children?: DangerType[];
+  categoryName: string; // 类别名称
+  description: string; // 类别描述
+  status: number; // 状态:1-启用,0-禁用
+  parentId: number; // 父级 ID,一级为 0
+  sortOrder: number; // 排序
+  createdAt: string; // 创建时间
+  updatedAt: string; // 更新时间
 }
 
-export interface SaveDangerTypeReq {
-  typeName: string;
-  parentId?: number | null;
-  sort?: number;
-  status?: number;
+export interface SaveHazardCategoryReq {
+  categoryName: string; // 类别名称
+  description?: string; // 类别描述,最多 300 字
+  status: number; // 启用状态:1-启用,0-禁用
 }
 
-export interface UpdateDangerTypeReq extends SaveDangerTypeReq {
-  id: number;
+export interface UpdateHazardCategoryReq {
+  id: number; // 主键 ID
+  categoryName?: string; // 类别名称
+  description?: string; // 类别描述,最多 300 字
+  status?: number; // 启用状态:1-启用,0-禁用
 }
 
-export interface QueryDangerTypeReq {
-  keyword?: string;
-  parentId?: number | null;
-  status?: number;
+export interface QueryHazardCategoryReq {
+  keyword?: string; // 关键词,模糊查询类别名称、描述等
+  status?: number; // 状态:1-启用,0-禁用
+  startDate?: string; // 创建时间范围-开始
+  endDate?: string; // 创建时间范围-结束
 }
 
+// 兼容旧接口名称(向后兼容)
+export type DangerType = HazardCategoryDTO;
+export type SaveDangerTypeReq = SaveHazardCategoryReq;
+export type UpdateDangerTypeReq = UpdateHazardCategoryReq;
+export type QueryDangerTypeReq = QueryHazardCategoryReq;
+
 // 新增隐患类别
-export function saveDangerType(data: SaveDangerTypeReq) {
+export function saveHazardCategory(data: SaveHazardCategoryReq) {
   return http.request<number>({
-    url: '/admin/prod/dangerType/saveDangerType',
+    url: '/hazardCategory/saveHazardCategory',
     method: 'post',
     data,
   });
 }
 
 // 编辑隐患类别
-export function updateDangerType(data: UpdateDangerTypeReq) {
+export function updateHazardCategory(data: UpdateHazardCategoryReq) {
   return http.request({
-    url: '/admin/prod/dangerType/updateDangerType',
+    url: '/hazardCategory/updateHazardCategory',
     method: 'put',
     data,
   });
 }
 
 // 删除隐患类别
-export function deleteDangerType(id: number) {
+export function deleteHazardCategory(id: number) {
   return http.request({
-    url: `/admin/prod/dangerType/deleteDangerType?id=${id}`,
+    url: `/hazardCategory/deleteHazardCategory?id=${id}`,
     method: 'delete',
   });
 }
 
 // 根据 ID 查询隐患类别详情
-export function queryDangerTypeById(id: number) {
-  return http.request<DangerType>({
-    url: `/admin/prod/dangerType/queryDangerTypeById?id=${id}`,
+export function queryHazardCategoryById(id: number) {
+  return http.request<HazardCategoryDTO>({
+    url: `/hazardCategory/queryHazardCategoryById?id=${id}`,
     method: 'get',
   });
 }
 
-// 查隐患类别列表(不分页)
-export function queryDangerTypeList(params?: QueryDangerTypeReq) {
-  return http.request<DangerType[]>({
-    url: '/admin/prod/dangerType/queryDangerTypeList',
+// 查隐患类别列表(不分页)
+export function queryHazardCategoryList(params?: QueryHazardCategoryReq) {
+  return http.request<HazardCategoryDTO[]>({
+    url: '/hazardCategory/queryHazardCategoryList',
     method: 'post',
-    data: params,
+    data: params || {},
   });
 }
 
 // 分页查询隐患类别
-export function queryDangerTypePage(query: QueryPageRequest<QueryDangerTypeReq>) {
-  return http.request<QueryPageResponse<DangerType>>({
-    url: '/admin/prod/dangerType/queryDangerTypePage',
+export function queryHazardCategoryPage(query: QueryPageRequest<QueryHazardCategoryReq>) {
+  return http.request<QueryPageResponse<HazardCategoryDTO>>({
+    url: '/hazardCategory/queryHazardCategoryPage',
     method: 'post',
     data: query,
   });
 }
 
-// 获取隐患类别树形结构
-export function getDangerTypeTree(status?: number) {
-  return http.request<DangerType[]>({
-    url: '/admin/prod/dangerType/getDangerTypeTree',
-    method: 'get',
-    params: typeof status === 'number' ? { status } : undefined,
-  });
-}
-
 // 导出隐患类别
-export function exportDangerType(params?: QueryDangerTypeReq) {
+export function exportHazardCategory(params?: QueryHazardCategoryReq) {
   return http.request(
     {
-      url: '/admin/prod/dangerType/exportDangerType',
+      url: '/hazardCategory/exportHazardCategory',
       method: 'post',
-      data: params,
+      data: params || {},
       responseType: 'blob',
     },
     {
@@ -275,11 +294,11 @@ export function exportDangerType(params?: QueryDangerTypeReq) {
 }
 
 // 导入隐患类别
-export function importDangerType(file: File) {
+export function importHazardCategory(file: File) {
   const formData = new FormData();
   formData.append('file', file);
   return http.request<ImportRes>({
-    url: '/admin/prod/dangerType/importDangerType',
+    url: '/hazardCategory/importHazardCategory',
     method: 'post',
     data: formData,
     headers: {
@@ -287,3 +306,13 @@ export function importDangerType(file: File) {
     },
   });
 }
+
+// 向后兼容的接口函数(使用旧接口名称)
+export const saveDangerType = saveHazardCategory;
+export const updateDangerType = updateHazardCategory;
+export const deleteDangerType = deleteHazardCategory;
+export const queryDangerTypeById = queryHazardCategoryById;
+export const queryDangerTypeList = queryHazardCategoryList;
+export const queryDangerTypePage = queryHazardCategoryPage;
+export const exportDangerType = exportHazardCategory;
+export const importDangerType = importHazardCategory;

+ 2 - 2
src/components/UploadFiles/UploadFiles.vue

@@ -41,7 +41,7 @@
           <span class="file-name">{{ file.fileName }}</span>
         </div>
         <el-icon 
-          v-if="!isUploadDisabled"
+          v-if="!props.disabled"
           class="delete-button" 
           @click="removeFile(file.fileId)"
         >
@@ -86,7 +86,7 @@
   });
 
   const isUploadDisabled = computed(() => {
-    return props.disabled || fileList.value.length >= MAX_COUNT.value;
+    return  fileList.value.length >= MAX_COUNT.value;
   });
 
   // 检查文件是否已存在

+ 136 - 84
src/views/production-safety/hiddenTroubleInvestigationAndGovernance/employeeReportHiddenTroubleManagement/components/employeeReportHiddenTroubleManagementDetail.vue

@@ -3,24 +3,66 @@
     <BasicForm
       ref="basicFormRef"
       :formData="ruleFormData"
-      :formRules="isViewMode ? undefined : formRules"
-      :formConfig="computedFormConfig"
+      :formRules="formRules"
+      :formConfig="formConfig"
     >
-      <template #status>
-        <el-radio-group v-model="ruleFormData.status" :disabled="isViewMode">
-          <el-radio :value="1">待处理</el-radio>
-          <el-radio :value="2">处理中</el-radio>
-          <el-radio :value="3">已处理</el-radio>
-          <el-radio :value="4">已驳回</el-radio>
-        </el-radio-group>
+      <template #attachment>
+        <div v-if="attachmentList.length > 0">
+          <div
+            v-for="(item, index) in attachmentList"
+            :key="index"
+            class="file-item"
+            style="display: flex; align-items: center; margin-bottom: 8px;"
+          >
+            <span>{{ item.file_name || item.fileName || `附件${index + 1}` }}</span>
+            <el-button
+              type="primary"
+              link
+              size="small"
+              style="margin-left: 8px;"
+              @click="handlePreview(item.url || item.fileUrl)"
+            >
+              预览
+            </el-button>
+          </div>
+        </div>
+        <span v-else>无附件</span>
       </template>
     </BasicForm>
+    <!-- 审核弹窗 -->
+    <el-dialog v-model="approveDialogVisible" title="审核" width="500px" @close="handleApproveDialogClose">
+      <el-form :model="approveForm" label-width="100px">
+        <el-form-item label="审批节点:">
+          <el-select v-model="approveForm.node" placeholder="请选择审批节点">
+            <el-option label="需求部门" :value="1" />
+            <el-option label="安全部门" :value="2" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="审批状态:">
+          <el-radio-group v-model="approveForm.approvalStatus">
+            <el-radio :value="2">通过</el-radio>
+            <el-radio :value="3">驳回</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="审批意见:">
+          <el-input
+            v-model="approveForm.approvalContent"
+            type="textarea"
+            :rows="4"
+            placeholder="请输入审批意见"
+          />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <el-button @click="approveDialogVisible = false">取消</el-button>
+        <el-button type="primary" @click="handleApproveSubmit">确定</el-button>
+      </template>
+    </el-dialog>
+    <PreviewOnline ref="previewOnlineRef" />
   </main>
   <footer class="safety-platform-container__footer">
     <el-button @click="router.back()">返回</el-button>
-    <el-button v-if="!isViewMode" type="primary" @click="handleSubmit">
-      {{ isCreateMode ? '提交' : '保存' }}
-    </el-button>
+    <el-button v-if="isApproveMode" type="primary" @click="handleApproveClick">审核</el-button>
   </footer>
 </template>
 
@@ -33,49 +75,40 @@
   import { ACADEMY_FILE_FORM_CONFIG, ACADEMY_FILE_FORM_DATA, ACADEMY_FILE_FORM_RULES } from '../configs/form';
   import {
     queryHiddenDangerById,
-    saveHiddenDanger,
-    updateHiddenDanger,
+    approveEmployeeHazardReport,
     type HiddenDanger,
+    type ApproveEmployeeHazardReportReq,
   } from '@/api/production-safety';
+  import PreviewOnline from '@/views/disaster/components/PreviewOnline.vue';
 
   const router = useRouter();
   const route = useRoute();
 
-  const operate = computed(() => (route.query.operate as string) || 'employee-report-hidden-trouble-create');
+  const operate = computed(() => (route.query.operate as string) || 'employee-report-hidden-trouble-view');
   const currentId = computed(() => Number(route.query.id));
 
-  const isCreateMode = computed(() => operate.value === 'employee-report-hidden-trouble-create');
-  const isEditMode = computed(() => operate.value === 'employee-report-hidden-trouble-edit');
   const isViewMode = computed(() => operate.value === 'employee-report-hidden-trouble-view');
+  const isApproveMode = computed(() => operate.value === 'employee-report-hidden-trouble-approve');
 
   const { ruleFormData, formRules, ruleFormConfig, cloneRuleFormData, beforeRouteLeave } =
     useFormConfigHook(ACADEMY_FILE_FORM_CONFIG, ACADEMY_FILE_FORM_DATA, ACADEMY_FILE_FORM_RULES);
 
-  // 查看模式下,所有字段设为只读
-  const viewFormConfig = ref(
-    ACADEMY_FILE_FORM_CONFIG.map((item) => ({
-      ...item,
-      componentProps: {
-        ...item.componentProps,
-        disabled: true,
-      },
-    })),
-  );
-
-  const computedFormConfig = computed(() => {
-    if (isViewMode.value) {
-      return viewFormConfig.value;
-    }
-    return ruleFormConfig.value;
-  });
+  const formConfig = computed(() => ruleFormConfig.value);
 
   const basicFormRef = ref<InstanceType<typeof BasicForm>>();
-
-  const handleValidate = async () => {
-    if (!basicFormRef.value) return;
-    const res = await basicFormRef.value.validateForm();
-    return res;
-  };
+  const previewOnlineRef = ref<InstanceType<typeof PreviewOnline>>();
+
+  // 附件列表
+  const attachmentList = ref<Array<{ file_name?: string; fileName?: string; url?: string; fileUrl?: string }>>([]);
+
+  // 审核相关
+  const approveDialogVisible = ref(false);
+  const approveForm = ref<ApproveEmployeeHazardReportReq>({
+    hazardId: 0,
+    node: 1,
+    approvalStatus: 2,
+    approvalContent: '',
+  });
 
   const getDetail = async () => {
     if (!currentId.value) return;
@@ -83,17 +116,29 @@
       const res = await queryHiddenDangerById(currentId.value);
       if (res) {
         // 映射接口字段到表单字段
-        ruleFormData.dangerName = res.dangerName || '';
-        ruleFormData.dangerType = res.dangerType ?? undefined;
-        ruleFormData.dangerLevel = res.dangerLevel ?? undefined;
+        ruleFormData.hazardDesc = res.hazardDesc || '';
         ruleFormData.location = res.location || '';
-        ruleFormData.description = res.description || '';
-        ruleFormData.reporterName = res.reporterName || '';
-        ruleFormData.reporterPhone = res.reporterPhone || '';
-        ruleFormData.reporterDept = res.reporterDept || '';
         ruleFormData.reportTime = res.reportTime || '';
-        ruleFormData.imagesText = res.images && res.images.length ? res.images.join(',') : '';
-        ruleFormData.status = res.status ?? 1;
+        ruleFormData.sourceTypeName = res.sourceTypeName || '';
+        ruleFormData.reporterName = res.reporterName || '';
+        ruleFormData.reporterJobNo = res.reporterJobNo || '';
+        ruleFormData.reporterMobile = res.reporterMobile || '';
+
+        // 处理附件
+        if (res.attachment) {
+          try {
+            const attachmentData = typeof res.attachment === 'string' ? JSON.parse(res.attachment) : res.attachment;
+            attachmentList.value = Array.isArray(attachmentData) ? attachmentData : [];
+          } catch (e) {
+            console.error('解析附件失败:', e);
+            attachmentList.value = [];
+          }
+        } else {
+          attachmentList.value = [];
+        }
+
+        // 设置审核表单的隐患ID
+        approveForm.value.hazardId = res.id;
       }
       cloneRuleFormData();
     } catch (e) {
@@ -102,51 +147,52 @@
     }
   };
 
-  const handleSubmit = async () => {
-    const res = await handleValidate();
-    if (!res) return;
-    try {
-      const images =
-        ruleFormData.imagesText && ruleFormData.imagesText.trim().length > 0
-          ? ruleFormData.imagesText.split(',').map((item: string) => item.trim()).filter(Boolean)
-          : [];
-
-      const basePayload = {
-        dangerName: ruleFormData.dangerName,
-        dangerType: Number(ruleFormData.dangerType),
-        dangerLevel: Number(ruleFormData.dangerLevel),
-        location: ruleFormData.location,
-        description: ruleFormData.description,
-        reporterName: ruleFormData.reporterName,
-        reporterPhone: ruleFormData.reporterPhone,
-        reporterDept: ruleFormData.reporterDept,
-        reportTime: ruleFormData.reportTime,
-        images,
-        status: ruleFormData.status ?? 1,
-      };
-
-      if (isCreateMode.value) {
-        await saveHiddenDanger(basePayload);
-        ElMessage.success('创建成功');
-      } else if (isEditMode.value && currentId.value) {
-        await updateHiddenDanger({
-          id: currentId.value,
-          ...basePayload,
-        });
-        ElMessage.success('保存成功');
+  const handlePreview = (url: string) => {
+    if (url) {
+      // 根据文件扩展名判断文件类型
+      const extension = url.split('.').pop()?.toLowerCase() || '';
+      let fileType: 'pdf' | 'word' | 'excel' | 'ppt' = 'pdf';
+      if (extension === 'doc' || extension === 'docx') {
+        fileType = 'word';
+      } else if (extension === 'xls' || extension === 'xlsx') {
+        fileType = 'excel';
+      } else if (extension === 'ppt' || extension === 'pptx') {
+        fileType = 'ppt';
       }
+      previewOnlineRef.value?.open(url, fileType);
+    }
+  };
 
+  const handleApproveClick = () => {
+    approveDialogVisible.value = true;
+  };
+
+  const handleApproveDialogClose = () => {
+    approveForm.value.approvalContent = '';
+    approveForm.value.node = 1;
+    approveForm.value.approvalStatus = 2;
+  };
+
+  const handleApproveSubmit = async () => {
+    if (!approveForm.value.node || !approveForm.value.approvalStatus) {
+      ElMessage.warning('请选择审批节点和审批状态');
+      return;
+    }
+    try {
+      await approveEmployeeHazardReport(approveForm.value);
+      ElMessage.success('审核成功');
+      approveDialogVisible.value = false;
       router.back();
     } catch (e) {
-      console.error('保存隐患上报失败:', e);
-      ElMessage.error('保存失败,请重试');
+      console.error('审核失败:', e);
+      ElMessage.error('审核失败,请重试');
     }
   };
 
   onMounted(() => {
     cloneRuleFormData();
     beforeRouteLeave();
-    if (isEditMode.value || isViewMode.value) {
+    if (currentId.value) {
       getDetail();
     }
   });
@@ -154,5 +200,11 @@
 
 <style scoped lang="scss">
   @use '@/styles/page-details-layout.scss' as *;
+
+  .file-item {
+    display: flex;
+    align-items: center;
+    margin-bottom: 8px;
+  }
 </style>
 

+ 41 - 81
src/views/production-safety/hiddenTroubleInvestigationAndGovernance/employeeReportHiddenTroubleManagement/configs/form.ts

@@ -1,129 +1,89 @@
 import { FormConfig } from '@/types/basic-form';
 
-// 员工上报隐患管理表单配置
+// 员工上报隐患管理表单配置(详情页,所有字段禁用)
 export const ACADEMY_FILE_FORM_CONFIG: FormConfig[] = [
   {
-    prop: 'dangerName',
-    label: '隐患名称:',
+    prop: 'hazardDesc',
+    label: '隐患问题:',
     component: 'ElInput',
     componentProps: {
-      placeholder: '请输入隐患名称',
+      placeholder: '隐患问题描述',
+      disabled: true,
     },
   },
-  {
-    prop: 'dangerType',
-    label: '隐患类别ID:',
-    component: 'ElInput',
-    componentProps: {
-      placeholder: '请输入隐患类别ID',
-      type: 'number',
-    },
-  },
-  {
-    prop: 'dangerLevel',
-    label: '隐患等级:',
-    component: 'ElSelect',
-    componentProps: {
-      placeholder: '请选择隐患等级',
-    },
-    selectOptions: [
-      { label: '一般', value: 1 },
-      { label: '较大', value: 2 },
-      { label: '重大', value: 3 },
-    ],
-  },
   {
     prop: 'location',
-    label: '隐患位置:',
+    label: '隐患地点:',
     component: 'ElInput',
     componentProps: {
-      placeholder: '请输入隐患位置',
+      placeholder: '隐患地点',
+      disabled: true,
     },
   },
   {
-    prop: 'description',
-    label: '隐患描述:',
-    component: 'ElInput',
+    prop: 'reportTime',
+    label: '上报时间:',
+    component: 'ElDatePicker',
     componentProps: {
-      type: 'textarea',
-      rows: 3,
-      placeholder: '请输入隐患描述',
+      type: 'datetime',
+      placeholder: '上报时间',
+      valueFormat: 'YYYY-MM-DD HH:mm:ss',
+      disabled: true,
     },
   },
   {
-    prop: 'reporterName',
-    label: '上报人姓名:',
+    prop: 'sourceTypeName',
+    label: '提交类型:',
     component: 'ElInput',
     componentProps: {
-      placeholder: '请输入上报人姓名',
+      placeholder: '提交类型',
+      disabled: true,
     },
   },
   {
-    prop: 'reporterPhone',
-    label: '上报人电话:',
+    prop: 'reporterName',
+    label: '姓名:',
     component: 'ElInput',
     componentProps: {
-      placeholder: '请输入上报人电话',
+      placeholder: '姓名',
+      disabled: true,
     },
   },
   {
-    prop: 'reporterDept',
-    label: '上报人部门:',
+    prop: 'reporterJobNo',
+    label: '工号:',
     component: 'ElInput',
     componentProps: {
-      placeholder: '请输入上报人部门',
-    },
-  },
-  {
-    prop: 'reportTime',
-    label: '上报时间:',
-    component: 'ElDatePicker',
-    componentProps: {
-      type: 'datetime',
-      placeholder: '请选择上报时间',
-      valueFormat: 'YYYY-MM-DD HH:mm:ss',
+      placeholder: '工号',
+      disabled: true,
     },
   },
   {
-    prop: 'imagesText',
-    label: '隐患图片:',
+    prop: 'reporterMobile',
+    label: '联系电话:',
     component: 'ElInput',
     componentProps: {
-      type: 'textarea',
-      rows: 2,
-      placeholder: '请输入图片URL,多个用英文逗号分隔',
+      placeholder: '联系电话',
+      disabled: true,
     },
   },
   {
-    prop: 'status',
-    label: '处理状态:',
-    slot: 'status',
+    prop: 'attachment',
+    label: '附件:',
+    slot: 'attachment',
   },
 ];
 
 export const ACADEMY_FILE_FORM_DATA = {
-  dangerName: '',
-  dangerType: undefined as number | undefined,
-  dangerLevel: undefined as number | undefined,
+  hazardDesc: '',
   location: '',
-  description: '',
-  reporterName: '',
-  reporterPhone: '',
-  reporterDept: '',
   reportTime: '',
-  imagesText: '',
-  status: 1, // 默认待处理
+  sourceTypeName: '',
+  reporterName: '',
+  reporterJobNo: '',
+  reporterMobile: '',
+  attachment: '',
 };
 
-export const ACADEMY_FILE_FORM_RULES = {
-  dangerName: [{ required: true, message: '请输入隐患名称', trigger: 'blur' }],
-  dangerType: [{ required: true, message: '请输入隐患类别ID', trigger: 'blur' }],
-  dangerLevel: [{ required: true, message: '请选择隐患等级', trigger: 'change' }],
-  location: [{ required: true, message: '请输入隐患位置', trigger: 'blur' }],
-  description: [{ required: true, message: '请输入隐患描述', trigger: 'blur' }],
-  reporterName: [{ required: true, message: '请输入上报人姓名', trigger: 'blur' }],
-  reporterPhone: [{ required: true, message: '请输入上报人电话', trigger: 'blur' }],
-  reporterDept: [{ required: true, message: '请输入上报人部门', trigger: 'blur' }],
-  reportTime: [{ required: true, message: '请选择上报时间', trigger: 'change' }],
-};
+export const ACADEMY_FILE_FORM_RULES = {};
 

+ 21 - 21
src/views/production-safety/hiddenTroubleInvestigationAndGovernance/employeeReportHiddenTroubleManagement/configs/tables.ts

@@ -16,49 +16,49 @@ export const INVENTORY_TABLE_COLUMNS: TableColumnProps[] = [
     width: '80px',
   },
   {
-    label: '隐患名称',
-    prop: 'dangerName',
+    label: '隐患问题',
+    prop: 'hazardDesc',
     align: 'left',
-    minWidth: '160px',
+    minWidth: '180px',
   },
   {
-    label: '隐患类别',
-    prop: 'dangerTypeName',
+    label: '隐患地点',
+    prop: 'location',
     align: 'left',
-    minWidth: '140px',
+    minWidth: '150px',
   },
   {
-    label: '隐患等级',
-    prop: 'dangerLevelName',
-    align: 'center',
-    minWidth: '120px',
+    label: '上报时间',
+    prop: 'reportTime',
+    align: 'left',
+    minWidth: '180px',
   },
   {
-    label: '隐患位置',
-    prop: 'location',
+    label: '提交类型',
+    prop: 'sourceTypeName',
     align: 'left',
-    minWidth: '180px',
+    minWidth: '120px',
   },
   {
-    label: '上报人',
+    label: '姓名',
     prop: 'reporterName',
     align: 'left',
     minWidth: '120px',
   },
   {
-    label: '上报部门',
-    prop: 'reporterDept',
+    label: '工号',
+    prop: 'reporterJobNo',
     align: 'left',
-    minWidth: '140px',
+    minWidth: '120px',
   },
   {
-    label: '上报时间',
-    prop: 'reportTime',
+    label: '联系电话',
+    prop: 'reporterMobile',
     align: 'left',
-    minWidth: '180px',
+    minWidth: '140px',
   },
   {
-    label: '处理状态',
+    label: '状态',
     prop: 'status',
     slot: 'status',
     align: 'center',

+ 77 - 72
src/views/production-safety/hiddenTroubleInvestigationAndGovernance/employeeReportHiddenTroubleManagement/employeeReportHiddenTroubleManagement.vue

@@ -21,47 +21,35 @@
           <div class="act-search">
             <section class="select-box">
               <div class="select-box--item">
-                <span>关键字:</span>
+                <span>隐患问题:</span>
                 <el-input
-                  v-model="tableQuery.queryParam.keyword"
-                  placeholder="隐患名称/位置/上报人"
+                  v-model="tableQuery.queryParam.hazardDesc"
+                  placeholder="请输入隐患问题描述"
                   class="act-search-input"
                 />
               </div>
               <div class="select-box--item">
-                <span>隐患等级:</span>
-                <el-select
-                  v-model="tableQuery.queryParam.dangerLevel"
-                  placeholder="请选择隐患等级"
-                  clearable
-                >
-                  <el-option label="一般" :value="1" />
-                  <el-option label="较大" :value="2" />
-                  <el-option label="重大" :value="3" />
-                </el-select>
-              </div>
-              <div class="select-box--item">
-                <span>处理状态:</span>
+                <span>状态:</span>
                 <el-select
                   v-model="tableQuery.queryParam.status"
-                  placeholder="请选择处理状态"
+                  placeholder="请选择状态"
                   clearable
                 >
-                  <el-option label="待处理" :value="1" />
-                  <el-option label="处理中" :value="2" />
-                  <el-option label="已处理" :value="3" />
-                  <el-option label="已驳回" :value="4" />
+                  <el-option label="待审核" :value="1" />
+                  <el-option label="需求部门通过" :value="2" />
+                  <el-option label="需求部门驳回" :value="3" />
+                  <el-option label="安全部门通过" :value="4" />
+                  <el-option label="安全部门驳回" :value="5" />
+                  <el-option label="已入账" :value="6" />
+                  <el-option label="已关闭" :value="7" />
                 </el-select>
               </div>
               <div class="select-box--item">
-                <span>上报日期:</span>
-                <el-date-picker
-                  v-model="reportDateRange"
-                  type="daterange"
-                  range-separator="至"
-                  start-placeholder="开始日期"
-                  end-placeholder="结束日期"
-                  value-format="YYYY-MM-DD"
+                <span>任务来源:</span>
+                <el-input
+                  v-model="tableQuery.queryParam.sourceTypeName"
+                  placeholder="请输入任务来源"
+                  class="act-search-input"
                 />
               </div>
             </section>
@@ -84,28 +72,43 @@
               <span>
                 {{
                   scope.row.status === 1
-                    ? '待处理'
+                    ? '待审核'
                     : scope.row.status === 2
-                      ? '处理中'
+                      ? '需求部门通过'
                       : scope.row.status === 3
-                        ? '已处理'
+                        ? '需求部门驳回'
                         : scope.row.status === 4
-                          ? '已驳回'
-                          : '-'
+                          ? '安全部门通过'
+                          : scope.row.status === 5
+                            ? '安全部门驳回'
+                            : scope.row.status === 6
+                              ? '已入账'
+                              : scope.row.status === 7
+                                ? '已关闭'
+                                : '-'
                 }}
               </span>
             </template>
             <template #action="scope">
               <div class="action-container--div" style="justify-content: left">
-                <ActionButton text="编辑" @click="handleEdit(scope.row.id)" />
-                <ActionButton
-                  text="删除"
-                  :popconfirm="{
-                    title: '确定要删除?',
-                  }"
-                  @confirm="handleDelete(scope.row.id)"
-                />
-                <ActionButton text="查看" @click="handleView(scope.row.id)" />
+                <!-- 待审核:显示审核和查看 -->
+                <template v-if="scope.row.status === 1">
+                  <ActionButton text="审核" @click="handleApprove(scope.row.id)" />
+                  <ActionButton text="查看" @click="handleView(scope.row.id)" />
+                </template>
+                <!-- 审核通过(需求部门通过或安全部门通过):显示查看和入账 -->
+                <template v-else-if="scope.row.status === 2 || scope.row.status === 4">
+                  <ActionButton text="查看" @click="handleView(scope.row.id)" />
+                  <ActionButton text="入账" @click="handleAccount(scope.row.id)" />
+                </template>
+                <!-- 审核不通过(需求部门驳回或安全部门驳回):显示查看 -->
+                <template v-else-if="scope.row.status === 3 || scope.row.status === 5">
+                  <ActionButton text="查看" @click="handleView(scope.row.id)" />
+                </template>
+                <!-- 其他状态:显示查看 -->
+                <template v-else>
+                  <ActionButton text="查看" @click="handleView(scope.row.id)" />
+                </template>
               </div>
             </template>
           </BasicTable>
@@ -138,8 +141,11 @@
     queryHiddenDangerPage,
     deleteHiddenDanger,
     exportHiddenDanger,
+    approveEmployeeHazardReport,
+    accountEmployeeHazardReport,
     type QueryHiddenDangerReq,
     type HiddenDanger,
+    type ApproveEmployeeHazardReportReq,
   } from '@/api/production-safety';
   import { downloadByData } from '@/utils/file/download';
   import BatchImport from '@/components/batch-import/BatchImport.vue';
@@ -159,18 +165,12 @@
     pageNumber: pagination.pageNumber,
     pageSize: pagination.pageSize,
     queryParam: {
-      keyword: '',
-      dangerType: undefined,
-      dangerLevel: undefined,
+      hazardDesc: '',
       status: undefined,
-      startDate: '',
-      endDate: '',
+      sourceTypeName: '',
     },
   });
 
-  // 上报日期范围(用于双向绑定日期组件)
-  const reportDateRange = ref<[string, string] | []>([]);
-
   const handleSizeChange = (value: number) => {
     pagination.pageSize = value;
     tableQuery.pageSize = value;
@@ -187,15 +187,6 @@
   async function getTableData() {
     tableConfig.loading = true;
     try {
-      // 将日期范围同步到查询参数
-      if (reportDateRange.value && reportDateRange.value.length === 2) {
-        tableQuery.queryParam.startDate = reportDateRange.value[0];
-        tableQuery.queryParam.endDate = reportDateRange.value[1];
-      } else {
-        tableQuery.queryParam.startDate = '';
-        tableQuery.queryParam.endDate = '';
-      }
-
       const res = await queryHiddenDangerPage(tableQuery);
       if (res) {
         tableData.value = res.records || [];
@@ -217,20 +208,16 @@
   };
 
   const handleReset = () => {
-    tableQuery.queryParam.keyword = '';
-    tableQuery.queryParam.dangerType = undefined;
-    tableQuery.queryParam.dangerLevel = undefined;
+    tableQuery.queryParam.hazardDesc = '';
     tableQuery.queryParam.status = undefined;
-    tableQuery.queryParam.startDate = '';
-    tableQuery.queryParam.endDate = '';
-    reportDateRange.value = [];
+    tableQuery.queryParam.sourceTypeName = '';
     handleSearch();
   };
 
   // 批量导入
   const batchImportVisible = ref(false);
   const { urlPrefix } = useGlobSetting();
-  const importApiUrl = ref(urlJoin(urlPrefix, '/admin/prod/hiddenDanger/importHiddenDanger'));
+  const importApiUrl = ref(urlJoin(urlPrefix, '/api/employeeHazardReport/importEmployeeHazardReport'));
   const templateUrl = ref('');
 
   const handleImport = () => {
@@ -245,12 +232,9 @@
   const handleDownload = async () => {
     try {
       const exportParams: QueryHiddenDangerReq = {
-        keyword: tableQuery.queryParam.keyword || undefined,
-        dangerType: tableQuery.queryParam.dangerType,
-        dangerLevel: tableQuery.queryParam.dangerLevel,
+        hazardDesc: tableQuery.queryParam.hazardDesc || undefined,
         status: tableQuery.queryParam.status,
-        startDate: tableQuery.queryParam.startDate || undefined,
-        endDate: tableQuery.queryParam.endDate || undefined,
+        sourceTypeName: tableQuery.queryParam.sourceTypeName || undefined,
       };
       const response = await exportHiddenDanger(exportParams);
       if (response) {
@@ -304,6 +288,27 @@
     });
   };
 
+  const handleApprove = (id: number) => {
+    router.push({
+      name: 'employeeReportHiddenTroubleManagementItem',
+      query: {
+        id,
+        operate: 'employee-report-hidden-trouble-approve',
+      },
+    });
+  };
+
+  const handleAccount = async (hazardId: number) => {
+    try {
+      await accountEmployeeHazardReport(hazardId);
+      ElMessage.success('入账成功');
+      getTableData();
+    } catch (e) {
+      console.error('入账失败:', e);
+      ElMessage.error('入账失败,请重试');
+    }
+  };
+
   onMounted(() => {
     getTableData();
   });

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

@@ -25,8 +25,10 @@
         return '编辑员工上报隐患';
       case 'employee-report-hidden-trouble-view':
         return '查看员工上报隐患';
+      case 'employee-report-hidden-trouble-approve':
+        return '审核员工上报隐患';
       default:
-        return '未知操作';
+        return '查看员工上报隐患';
     }
   });
 </script>

+ 4 - 6
src/views/production-safety/hiddenTroubleInvestigationAndGovernance/hiddenTroubleCategoryManagement/components/hiddenTroubleCategoryManagementDetail.vue

@@ -79,9 +79,8 @@
     try {
       const res = await queryDangerTypeById(currentId.value);
       if (res) {
-        ruleFormData.typeName = res.typeName || '';
-        ruleFormData.parentId = (res.parentId ?? undefined) as number | undefined;
-        ruleFormData.sort = res.sort ?? 0;
+        ruleFormData.categoryName = res.categoryName || '';
+        ruleFormData.description = res.description || '';
         ruleFormData.status = res.status ?? 1;
       }
       cloneRuleFormData();
@@ -96,9 +95,8 @@
     if (!res) return;
     try {
       const basePayload = {
-        typeName: ruleFormData.typeName,
-        parentId: ruleFormData.parentId ?? null,
-        sort: Number(ruleFormData.sort ?? 0),
+        categoryName: ruleFormData.categoryName,
+        description: ruleFormData.description || '',
         status: ruleFormData.status ?? 1,
       };
 

+ 12 - 18
src/views/production-safety/hiddenTroubleInvestigationAndGovernance/hiddenTroubleCategoryManagement/configs/form.ts

@@ -3,7 +3,7 @@ import { FormConfig } from '@/types/basic-form';
 // 隐患类别管理表单配置
 export const ACADEMY_FILE_FORM_CONFIG: FormConfig[] = [
   {
-    prop: 'typeName',
+    prop: 'categoryName',
     label: '类别名称:',
     component: 'ElInput',
     componentProps: {
@@ -11,21 +11,15 @@ export const ACADEMY_FILE_FORM_CONFIG: FormConfig[] = [
     },
   },
   {
-    prop: 'parentId',
-    label: '父级ID:',
+    prop: 'description',
+    label: '类别描述:',
     component: 'ElInput',
     componentProps: {
-      placeholder: '请输入父级ID,顶级留空',
-      type: 'number',
-    },
-  },
-  {
-    prop: 'sort',
-    label: '排序:',
-    component: 'ElInput',
-    componentProps: {
-      placeholder: '请输入排序数字',
-      type: 'number',
+      type: 'textarea',
+      rows: 4,
+      placeholder: '请输入类别描述,最多300字',
+      maxlength: 300,
+      showWordLimit: true,
     },
   },
   {
@@ -36,13 +30,13 @@ export const ACADEMY_FILE_FORM_CONFIG: FormConfig[] = [
 ];
 
 export const ACADEMY_FILE_FORM_DATA = {
-  typeName: '',
-  parentId: undefined as number | undefined,
-  sort: 0,
+  categoryName: '',
+  description: '',
   status: 1, // 默认启用
 };
 
 export const ACADEMY_FILE_FORM_RULES = {
-  typeName: [{ required: true, message: '请输入类别名称', trigger: 'blur' }],
+  categoryName: [{ required: true, message: '请输入类别名称', trigger: 'blur' }],
+  status: [{ required: true, message: '请选择启用状态', trigger: 'change' }],
 };
 

+ 11 - 10
src/views/production-safety/hiddenTroubleInvestigationAndGovernance/hiddenTroubleCategoryManagement/configs/tables.ts

@@ -17,21 +17,16 @@ export const INVENTORY_TABLE_COLUMNS: TableColumnProps[] = [
   },
   {
     label: '类别名称',
-    prop: 'typeName',
+    prop: 'categoryName',
     align: 'left',
     minWidth: '160px',
   },
   {
-    label: '父级类别',
-    prop: 'parentName',
+    label: '类别描述',
+    prop: 'description',
     align: 'left',
-    minWidth: '160px',
-  },
-  {
-    label: '排序',
-    prop: 'sort',
-    align: 'center',
-    minWidth: '100px',
+    minWidth: '200px',
+    showOverflowTooltip: true,
   },
   {
     label: '状态',
@@ -40,6 +35,12 @@ export const INVENTORY_TABLE_COLUMNS: TableColumnProps[] = [
     align: 'center',
     minWidth: '120px',
   },
+  {
+    label: '排序',
+    prop: 'sortOrder',
+    align: 'center',
+    minWidth: '100px',
+  },
   {
     label: '创建时间',
     prop: 'createdAt',

+ 33 - 6
src/views/production-safety/hiddenTroubleInvestigationAndGovernance/hiddenTroubleCategoryManagement/hiddenTroubleCategoryManagement.vue

@@ -21,10 +21,10 @@
           <div class="act-search">
             <section class="select-box">
               <div class="select-box--item">
-                <span>关键:</span>
+                <span>关键:</span>
                 <el-input
                   v-model="tableQuery.queryParam.keyword"
-                  placeholder="类别名称"
+                  placeholder="类别名称/描述"
                   class="act-search-input"
                 />
               </div>
@@ -39,6 +39,17 @@
                   <el-option label="禁用" :value="0" />
                 </el-select>
               </div>
+              <div class="select-box--item">
+                <span>创建时间:</span>
+                <el-date-picker
+                  v-model="createDateRange"
+                  type="daterange"
+                  range-separator="至"
+                  start-placeholder="开始日期"
+                  end-placeholder="结束日期"
+                  value-format="YYYY-MM-DD"
+                />
+              </div>
             </section>
             <section class="search-btn">
               <el-button type="primary" @click="handleSearch">查询</el-button>
@@ -125,11 +136,15 @@
     pageSize: pagination.pageSize,
     queryParam: {
       keyword: '',
-      parentId: undefined,
       status: undefined,
+      startDate: '',
+      endDate: '',
     },
   });
 
+  // 创建时间范围(用于双向绑定日期组件)
+  const createDateRange = ref<[string, string] | []>([]);
+
   const handleSizeChange = (value: number) => {
     pagination.pageSize = value;
     tableQuery.pageSize = value;
@@ -146,6 +161,15 @@
   async function getTableData() {
     tableConfig.loading = true;
     try {
+      // 将日期范围同步到查询参数
+      if (createDateRange.value && createDateRange.value.length === 2) {
+        tableQuery.queryParam.startDate = createDateRange.value[0];
+        tableQuery.queryParam.endDate = createDateRange.value[1];
+      } else {
+        tableQuery.queryParam.startDate = '';
+        tableQuery.queryParam.endDate = '';
+      }
+
       const res = await queryDangerTypePage(tableQuery);
       if (res) {
         tableData.value = res.records || [];
@@ -169,14 +193,16 @@
   const handleReset = () => {
     tableQuery.queryParam.keyword = '';
     tableQuery.queryParam.status = undefined;
-    tableQuery.queryParam.parentId = undefined;
+    tableQuery.queryParam.startDate = '';
+    tableQuery.queryParam.endDate = '';
+    createDateRange.value = [];
     handleSearch();
   };
 
   // 批量导入
   const batchImportVisible = ref(false);
   const { urlPrefix } = useGlobSetting();
-  const importApiUrl = ref(urlJoin(urlPrefix, '/admin/prod/dangerType/importDangerType'));
+  const importApiUrl = ref(urlJoin(urlPrefix, '/api/hazardCategory/importHazardCategory'));
   const templateUrl = ref('');
 
   const handleImport = () => {
@@ -193,7 +219,8 @@
       const exportParams: QueryDangerTypeReq = {
         keyword: tableQuery.queryParam.keyword || undefined,
         status: tableQuery.queryParam.status,
-        parentId: tableQuery.queryParam.parentId,
+        startDate: tableQuery.queryParam.startDate || undefined,
+        endDate: tableQuery.queryParam.endDate || undefined,
       };
       const response = await exportDangerType(exportParams);
       if (response) {

+ 1 - 1
src/views/production-safety/productionSafetySystem/collegeFileManagement/collegeFileManagement.vue

@@ -171,7 +171,7 @@
       const pageQuery: ProductionSafetyFilePageQuery = {
         pageNumber: pagination.pageNumber,
         pageSize: pagination.pageSize,
-        data: {
+        queryParam: {
           keyword: queryParams.keyword || undefined,
           status: queryParams.status,
           classifyName: queryParams.classifyName || undefined,

+ 78 - 24
src/views/production-safety/productionSafetySystem/collegeFileManagement/components/collegeFileManagementDetail.vue

@@ -16,7 +16,9 @@
         <UploadFiles
           label="上传文件"
           :maxCount="1"
-          :fileList="uploadFileList"
+          :file-list="ruleFormData.fileUrlList"
+          :disabled="isViewMode"
+          :allow-all-file-types="true"
           @uploadSuccess="handleUploadSuccess"
         />
       </template>
@@ -69,6 +71,7 @@
     type ProductionSafetyFile,
   } from '@/api/production-safety-system';
   import type { FileItem } from '@/components/UploadFiles/types';
+  import { formatAttachmentList } from '@/components/UploadFiles/utils';
 
   const router = useRouter();
   const route = useRoute();
@@ -119,21 +122,43 @@
   };
 
   // 文件上传
-  const uploadFileList = ref<FileItem[]>([]);
-
   const handleUploadSuccess = (files: FileItem[]) => {
-    uploadFileList.value = files;
-    if (files.length > 0 && files[0].file) {
-      // 这里需要实际上传文件到服务器,获取 fileUrl
-      // 暂时使用文件对象,实际应该调用上传接口
-      ruleFormData.fileUrl = files[0].file.name; // 临时处理,需要替换为实际上传后的URL
-    }
+    ruleFormData.fileUrlList = files;
   };
 
-  const getFileName = (url: string) => {
-    if (!url) return '';
-    const parts = url.split('/');
-    return parts[parts.length - 1];
+  // 将逗号分隔的URL字符串转换为FileItem数组
+  const convertFileUrlToFileItems = (fileUrl: string): FileItem[] => {
+    if (!fileUrl || !fileUrl.trim()) {
+      return [];
+    }
+    
+    // 按逗号分割URL
+    const urls = fileUrl.split(',').map(url => url.trim()).filter(url => url);
+    
+    return urls.map((url, index) => {
+      // 从URL中提取文件名
+      const urlParts = url.split('/');
+      const fileName = urlParts[urlParts.length - 1] || `附件${index + 1}`;
+      
+      // 根据文件扩展名判断文件类型
+      const extension = fileName.split('.').pop()?.toLowerCase() || '';
+      let fileType = 'pdf';
+      if (extension === 'doc' || extension === 'docx') {
+        fileType = 'word';
+      } else if (extension === 'xls' || extension === 'xlsx') {
+        fileType = 'excel';
+      } else if (extension === 'ppt' || extension === 'pptx') {
+        fileType = 'ppt';
+      }
+      
+      return {
+        fileId: Date.now() + index,
+        fileName,
+        fileType,
+        fileSize: '0',
+        fileUrl: url,
+      };
+    });
   };
 
   const handleValidate = async () => {
@@ -159,16 +184,7 @@
         ruleFormData.status = res.status ?? 1;
         
         // 如果有文件URL,转换为FileItem格式
-        if (res.fileUrl) {
-          uploadFileList.value = [
-            {
-              fileId: Date.now(),
-              fileName: getFileName(res.fileUrl),
-              fileType: res.fileFormat?.toLowerCase() === 'pdf' ? 'pdf' : 'word',
-              fileSize: '0KB',
-            },
-          ];
-        }
+        ruleFormData.fileUrlList = convertFileUrlToFileItems(res.fileUrl || '');
       }
       cloneRuleFormData();
     } catch (e) {
@@ -180,7 +196,45 @@
   const handleSubmit = async () => {
     const res = await handleValidate();
     if (!res) return;
+    
+    // 验证文件上传(必填)
+    if (!ruleFormData.fileUrlList || ruleFormData.fileUrlList.length === 0) {
+      ElMessage.warning('请上传文件');
+      return;
+    }
+    
     try {
+      // 处理文件上传:先上传文件获取 URL,然后提取 fileUrl
+      let fileUrl = '';
+      if (ruleFormData.fileUrlList && ruleFormData.fileUrlList.length > 0) {
+        // 分离已有URL的文件和新上传的文件
+        const existingFiles: string[] = [];
+        const newFiles: FileItem[] = [];
+        
+        ruleFormData.fileUrlList.forEach((file: FileItem) => {
+          // 如果文件已经有 fileUrl 且没有 file 对象,说明是已有文件
+          if (file.fileUrl && !file.file) {
+            existingFiles.push(file.fileUrl);
+          } else {
+            // 否则是需要上传的新文件
+            newFiles.push(file);
+          }
+        });
+
+        // 上传新文件
+        let uploadedUrls: string[] = [];
+        if (newFiles.length > 0) {
+          const uploadedFiles = await formatAttachmentList(newFiles);
+          uploadedUrls = uploadedFiles
+            .map((file: any) => file.fileUrl || file.url || '')
+            .filter((url: string) => url);
+        }
+
+        // 合并已有URL和新上传的URL,取第一个作为fileUrl
+        const allUrls = [...existingFiles, ...uploadedUrls].filter((url: string) => url);
+        fileUrl = allUrls.length > 0 ? allUrls[0] : '';
+      }
+
       const basePayload: ProductionSafetyFile = {
         fileName: ruleFormData.fileName,
         classifyName: ruleFormData.classifyName,
@@ -188,7 +242,7 @@
         fileVersion: ruleFormData.fileVersion,
         fileFormat: ruleFormData.fileFormat,
         releaseDate: ruleFormData.releaseDate,
-        fileUrl: ruleFormData.fileUrl || undefined,
+        fileUrl: fileUrl || undefined,
         content: ruleFormData.content || undefined,
         status: ruleFormData.status ?? 1,
       };

+ 1 - 0
src/views/production-safety/productionSafetySystem/collegeFileManagement/configs/form.ts

@@ -77,6 +77,7 @@ export const ACADEMY_FILE_FORM_DATA = {
   fileFormat: '',
   releaseDate: '',
   fileUrl: '',
+  fileUrlList: [] as any[], // 文件列表(FileItem数组)
   content: '',
   status: 1, // 默认启用
 };

+ 78 - 24
src/views/production-safety/productionSafetySystem/doubleSystemManagement/components/doubleSystemManagementDetail.vue

@@ -16,7 +16,9 @@
         <UploadFiles
           label="上传文件"
           :maxCount="1"
-          :fileList="uploadFileList"
+          :file-list="ruleFormData.fileUrlList"
+          :disabled="isViewMode"
+          :allow-all-file-types="true"
           @uploadSuccess="handleUploadSuccess"
         />
       </template>
@@ -69,6 +71,7 @@
     type ProductionSafetyFile,
   } from '@/api/production-safety-system';
   import type { FileItem } from '@/components/UploadFiles/types';
+  import { formatAttachmentList } from '@/components/UploadFiles/utils';
 
   const router = useRouter();
   const route = useRoute();
@@ -119,21 +122,43 @@
   };
 
   // 文件上传
-  const uploadFileList = ref<FileItem[]>([]);
-
   const handleUploadSuccess = (files: FileItem[]) => {
-    uploadFileList.value = files;
-    if (files.length > 0 && files[0].file) {
-      // 这里需要实际上传文件到服务器,获取 fileUrl
-      // 暂时使用文件对象,实际应该调用上传接口
-      ruleFormData.fileUrl = files[0].file.name; // 临时处理,需要替换为实际上传后的URL
-    }
+    ruleFormData.fileUrlList = files;
   };
 
-  const getFileName = (url: string) => {
-    if (!url) return '';
-    const parts = url.split('/');
-    return parts[parts.length - 1];
+  // 将逗号分隔的URL字符串转换为FileItem数组
+  const convertFileUrlToFileItems = (fileUrl: string): FileItem[] => {
+    if (!fileUrl || !fileUrl.trim()) {
+      return [];
+    }
+    
+    // 按逗号分割URL
+    const urls = fileUrl.split(',').map(url => url.trim()).filter(url => url);
+    
+    return urls.map((url, index) => {
+      // 从URL中提取文件名
+      const urlParts = url.split('/');
+      const fileName = urlParts[urlParts.length - 1] || `附件${index + 1}`;
+      
+      // 根据文件扩展名判断文件类型
+      const extension = fileName.split('.').pop()?.toLowerCase() || '';
+      let fileType = 'pdf';
+      if (extension === 'doc' || extension === 'docx') {
+        fileType = 'word';
+      } else if (extension === 'xls' || extension === 'xlsx') {
+        fileType = 'excel';
+      } else if (extension === 'ppt' || extension === 'pptx') {
+        fileType = 'ppt';
+      }
+      
+      return {
+        fileId: Date.now() + index,
+        fileName,
+        fileType,
+        fileSize: '0',
+        fileUrl: url,
+      };
+    });
   };
 
   const handleValidate = async () => {
@@ -159,16 +184,7 @@
         ruleFormData.status = res.status ?? 1;
         
         // 如果有文件URL,转换为FileItem格式
-        if (res.fileUrl) {
-          uploadFileList.value = [
-            {
-              fileId: Date.now(),
-              fileName: getFileName(res.fileUrl),
-              fileType: res.fileFormat?.toLowerCase() === 'pdf' ? 'pdf' : 'word',
-              fileSize: '0KB',
-            },
-          ];
-        }
+        ruleFormData.fileUrlList = convertFileUrlToFileItems(res.fileUrl || '');
       }
       cloneRuleFormData();
     } catch (e) {
@@ -180,7 +196,45 @@
   const handleSubmit = async () => {
     const res = await handleValidate();
     if (!res) return;
+    
+    // 验证文件上传(必填)
+    if (!ruleFormData.fileUrlList || ruleFormData.fileUrlList.length === 0) {
+      ElMessage.warning('请上传文件');
+      return;
+    }
+    
     try {
+      // 处理文件上传:先上传文件获取 URL,然后提取 fileUrl
+      let fileUrl = '';
+      if (ruleFormData.fileUrlList && ruleFormData.fileUrlList.length > 0) {
+        // 分离已有URL的文件和新上传的文件
+        const existingFiles: string[] = [];
+        const newFiles: FileItem[] = [];
+        
+        ruleFormData.fileUrlList.forEach((file: FileItem) => {
+          // 如果文件已经有 fileUrl 且没有 file 对象,说明是已有文件
+          if (file.fileUrl && !file.file) {
+            existingFiles.push(file.fileUrl);
+          } else {
+            // 否则是需要上传的新文件
+            newFiles.push(file);
+          }
+        });
+
+        // 上传新文件
+        let uploadedUrls: string[] = [];
+        if (newFiles.length > 0) {
+          const uploadedFiles = await formatAttachmentList(newFiles);
+          uploadedUrls = uploadedFiles
+            .map((file: any) => file.fileUrl || file.url || '')
+            .filter((url: string) => url);
+        }
+
+        // 合并已有URL和新上传的URL,取第一个作为fileUrl
+        const allUrls = [...existingFiles, ...uploadedUrls].filter((url: string) => url);
+        fileUrl = allUrls.length > 0 ? allUrls[0] : '';
+      }
+
       const basePayload: ProductionSafetyFile = {
         fileName: ruleFormData.fileName,
         classifyName: ruleFormData.classifyName,
@@ -188,7 +242,7 @@
         fileVersion: ruleFormData.fileVersion,
         fileFormat: ruleFormData.fileFormat,
         releaseDate: ruleFormData.releaseDate,
-        fileUrl: ruleFormData.fileUrl || undefined,
+        fileUrl: fileUrl || undefined,
         content: ruleFormData.content || undefined,
         status: ruleFormData.status ?? 1,
       };

+ 1 - 0
src/views/production-safety/productionSafetySystem/doubleSystemManagement/configs/form.ts

@@ -77,6 +77,7 @@ export const DUAL_SYSTEM_FORM_DATA = {
   fileFormat: '',
   releaseDate: '',
   fileUrl: '',
+  fileUrlList: [] as any[], // 文件列表(FileItem数组)
   content: '',
   status: 1, // 默认启用
 };

+ 1 - 1
src/views/production-safety/productionSafetySystem/doubleSystemManagement/doubleSystemManagement.vue

@@ -171,7 +171,7 @@
       const pageQuery: ProductionSafetyFilePageQuery = {
         pageNumber: pagination.pageNumber,
         pageSize: pagination.pageSize,
-        data: {
+        queryParam: {
           keyword: queryParams.keyword || undefined,
           status: queryParams.status,
           classifyName: queryParams.classifyName || undefined,

+ 79 - 25
src/views/production-safety/productionSafetySystem/lawManagement/components/lawManagementDetail.vue

@@ -16,7 +16,9 @@
         <UploadFiles
           label="上传文件"
           :maxCount="1"
-          :fileList="uploadFileList"
+          :file-list="ruleFormData.fileUrlList"
+          :disabled="isViewMode"
+          :allow-all-file-types="true"
           @uploadSuccess="handleUploadSuccess"
         />
       </template>
@@ -69,6 +71,7 @@
     type ProductionSafetyFile,
   } from '@/api/production-safety-system';
   import type { FileItem } from '@/components/UploadFiles/types';
+  import { formatAttachmentList } from '@/components/UploadFiles/utils';
 
   const router = useRouter();
   const route = useRoute();
@@ -119,21 +122,43 @@
   };
 
   // 文件上传
-  const uploadFileList = ref<FileItem[]>([]);
-
   const handleUploadSuccess = (files: FileItem[]) => {
-    uploadFileList.value = files;
-    if (files.length > 0 && files[0].file) {
-      // 这里需要实际上传文件到服务器,获取 fileUrl
-      // 暂时使用文件对象,实际应该调用上传接口
-      ruleFormData.fileUrl = files[0].file.name; // 临时处理,需要替换为实际上传后的URL
-    }
+    ruleFormData.fileUrlList = files;
   };
 
-  const getFileName = (url: string) => {
-    if (!url) return '';
-    const parts = url.split('/');
-    return parts[parts.length - 1];
+  // 将逗号分隔的URL字符串转换为FileItem数组
+  const convertFileUrlToFileItems = (fileUrl: string): FileItem[] => {
+    if (!fileUrl || !fileUrl.trim()) {
+      return [];
+    }
+    
+    // 按逗号分割URL
+    const urls = fileUrl.split(',').map(url => url.trim()).filter(url => url);
+    
+    return urls.map((url, index) => {
+      // 从URL中提取文件名
+      const urlParts = url.split('/');
+      const fileName = urlParts[urlParts.length - 1] || `附件${index + 1}`;
+      
+      // 根据文件扩展名判断文件类型
+      const extension = fileName.split('.').pop()?.toLowerCase() || '';
+      let fileType = 'pdf';
+      if (extension === 'doc' || extension === 'docx') {
+        fileType = 'word';
+      } else if (extension === 'xls' || extension === 'xlsx') {
+        fileType = 'excel';
+      } else if (extension === 'ppt' || extension === 'pptx') {
+        fileType = 'ppt';
+      }
+      
+      return {
+        fileId: Date.now() + index,
+        fileName,
+        fileType,
+        fileSize: '0',
+        fileUrl: url,
+      };
+    });
   };
 
   const handleValidate = async () => {
@@ -159,16 +184,7 @@
         ruleFormData.status = res.status ?? 1;
         
         // 如果有文件URL,转换为FileItem格式
-        if (res.fileUrl) {
-          uploadFileList.value = [
-            {
-              fileId: Date.now(),
-              fileName: getFileName(res.fileUrl),
-              fileType: res.fileFormat?.toLowerCase() === 'pdf' ? 'pdf' : 'word',
-              fileSize: '0KB',
-            },
-          ];
-        }
+        ruleFormData.fileUrlList = convertFileUrlToFileItems(res.fileUrl || '');
       }
       cloneRuleFormData();
     } catch (e) {
@@ -180,7 +196,45 @@
   const handleSubmit = async () => {
     const res = await handleValidate();
     if (!res) return;
+    
+    // 验证文件上传(必填)
+    if (!ruleFormData.fileUrlList || ruleFormData.fileUrlList.length === 0) {
+      ElMessage.warning('请上传文件');
+      return;
+    }
+    
     try {
+      // 处理文件上传:先上传文件获取 URL,然后提取 fileUrl
+      let fileUrl = '';
+      if (ruleFormData.fileUrlList && ruleFormData.fileUrlList.length > 0) {
+        // 分离已有URL的文件和新上传的文件
+        const existingFiles: string[] = [];
+        const newFiles: FileItem[] = [];
+        
+        ruleFormData.fileUrlList.forEach((file: FileItem) => {
+          // 如果文件已经有 fileUrl 且没有 file 对象,说明是已有文件
+          if (file.fileUrl && !file.file) {
+            existingFiles.push(file.fileUrl);
+          } else {
+            // 否则是需要上传的新文件
+            newFiles.push(file);
+          }
+        });
+
+        // 上传新文件
+        let uploadedUrls: string[] = [];
+        if (newFiles.length > 0) {
+          const uploadedFiles = await formatAttachmentList(newFiles);
+          uploadedUrls = uploadedFiles
+            .map((file: any) => file.fileUrl || file.url || '')
+            .filter((url: string) => url);
+        }
+
+        // 合并已有URL和新上传的URL,取第一个作为fileUrl
+        const allUrls = [...existingFiles, ...uploadedUrls].filter((url: string) => url);
+        fileUrl = allUrls.length > 0 ? allUrls[0] : '';
+      }
+
       const basePayload: ProductionSafetyFile = {
         fileName: ruleFormData.fileName,
         classifyName: ruleFormData.classifyName,
@@ -188,7 +242,7 @@
         fileVersion: ruleFormData.fileVersion,
         fileFormat: ruleFormData.fileFormat,
         releaseDate: ruleFormData.releaseDate,
-        fileUrl: ruleFormData.fileUrl || undefined,
+        fileUrl: fileUrl || undefined,
         content: ruleFormData.content || undefined,
         status: ruleFormData.status ?? 1,
       };
@@ -219,7 +273,7 @@
       ruleFormData.fileFormat = ruleFormData.fileFormat || '';
       ruleFormData.status = ruleFormData.status ?? 1;
       ruleFormData.content = ruleFormData.content || '';
-      uploadFileList.value = [];
+      ruleFormData.fileUrlList = [];
     }
     if (isEditMode.value || isViewMode.value) {
       getDetail();

+ 2 - 0
src/views/production-safety/productionSafetySystem/lawManagement/configs/form.ts

@@ -77,6 +77,7 @@ export const LAW_REGULATION_FORM_DATA = {
   fileFormat: '',
   releaseDate: '',
   fileUrl: '',
+  fileUrlList: [] as any[], // 文件列表(FileItem数组)
   content: '',
   status: 1, // 默认启用
 };
@@ -88,4 +89,5 @@ export const LAW_REGULATION_FORM_RULES = {
   fileVersion: [{ required: true, message: '请输入文件版本号', trigger: 'blur' }],
   fileFormat: [{ required: true, message: '请选择文件格式', trigger: 'change' }],
   releaseDate: [{ required: true, message: '请选择发布日期', trigger: 'change' }],
+  // 文件上传的验证在 handleSubmit 中手动处理
 };

+ 1 - 1
src/views/production-safety/productionSafetySystem/lawManagement/lawManagement.vue

@@ -171,7 +171,7 @@
       const pageQuery: ProductionSafetyFilePageQuery = {
         pageNumber: pagination.pageNumber,
         pageSize: pagination.pageSize,
-        data: {
+        queryParam: {
           keyword: queryParams.keyword || undefined,
           status: queryParams.status,
           classifyName: queryParams.classifyName || undefined,

+ 78 - 24
src/views/production-safety/productionSafetySystem/safetyStandardizationSystemManagement/components/safetyStandardizationSystemManagementDetail.vue

@@ -16,7 +16,9 @@
         <UploadFiles
           label="上传文件"
           :maxCount="1"
-          :fileList="uploadFileList"
+          :file-list="ruleFormData.fileUrlList"
+          :disabled="isViewMode"
+          :allow-all-file-types="true"
           @uploadSuccess="handleUploadSuccess"
         />
       </template>
@@ -73,6 +75,7 @@
     type ProductionSafetyFile,
   } from '@/api/production-safety-system';
   import type { FileItem } from '@/components/UploadFiles/types';
+  import { formatAttachmentList } from '@/components/UploadFiles/utils';
 
   const router = useRouter();
   const route = useRoute();
@@ -127,21 +130,43 @@
   };
 
   // 文件上传
-  const uploadFileList = ref<FileItem[]>([]);
-
   const handleUploadSuccess = (files: FileItem[]) => {
-    uploadFileList.value = files;
-    if (files.length > 0 && files[0].file) {
-      // 这里需要实际上传文件到服务器,获取 fileUrl
-      // 暂时使用文件对象,实际应该调用上传接口
-      ruleFormData.fileUrl = files[0].file.name; // 临时处理,需要替换为实际上传后的URL
-    }
+    ruleFormData.fileUrlList = files;
   };
 
-  const getFileName = (url: string) => {
-    if (!url) return '';
-    const parts = url.split('/');
-    return parts[parts.length - 1];
+  // 将逗号分隔的URL字符串转换为FileItem数组
+  const convertFileUrlToFileItems = (fileUrl: string): FileItem[] => {
+    if (!fileUrl || !fileUrl.trim()) {
+      return [];
+    }
+    
+    // 按逗号分割URL
+    const urls = fileUrl.split(',').map(url => url.trim()).filter(url => url);
+    
+    return urls.map((url, index) => {
+      // 从URL中提取文件名
+      const urlParts = url.split('/');
+      const fileName = urlParts[urlParts.length - 1] || `附件${index + 1}`;
+      
+      // 根据文件扩展名判断文件类型
+      const extension = fileName.split('.').pop()?.toLowerCase() || '';
+      let fileType = 'pdf';
+      if (extension === 'doc' || extension === 'docx') {
+        fileType = 'word';
+      } else if (extension === 'xls' || extension === 'xlsx') {
+        fileType = 'excel';
+      } else if (extension === 'ppt' || extension === 'pptx') {
+        fileType = 'ppt';
+      }
+      
+      return {
+        fileId: Date.now() + index,
+        fileName,
+        fileType,
+        fileSize: '0',
+        fileUrl: url,
+      };
+    });
   };
 
   const handleValidate = async () => {
@@ -167,16 +192,7 @@
         ruleFormData.status = res.status ?? 1;
         
         // 如果有文件URL,转换为FileItem格式
-        if (res.fileUrl) {
-          uploadFileList.value = [
-            {
-              fileId: Date.now(),
-              fileName: getFileName(res.fileUrl),
-              fileType: res.fileFormat?.toLowerCase() === 'pdf' ? 'pdf' : 'word',
-              fileSize: '0KB',
-            },
-          ];
-        }
+        ruleFormData.fileUrlList = convertFileUrlToFileItems(res.fileUrl || '');
       }
       cloneRuleFormData();
     } catch (e) {
@@ -188,7 +204,45 @@
   const handleSubmit = async () => {
     const res = await handleValidate();
     if (!res) return;
+    
+    // 验证文件上传(必填)
+    if (!ruleFormData.fileUrlList || ruleFormData.fileUrlList.length === 0) {
+      ElMessage.warning('请上传文件');
+      return;
+    }
+    
     try {
+      // 处理文件上传:先上传文件获取 URL,然后提取 fileUrl
+      let fileUrl = '';
+      if (ruleFormData.fileUrlList && ruleFormData.fileUrlList.length > 0) {
+        // 分离已有URL的文件和新上传的文件
+        const existingFiles: string[] = [];
+        const newFiles: FileItem[] = [];
+        
+        ruleFormData.fileUrlList.forEach((file: FileItem) => {
+          // 如果文件已经有 fileUrl 且没有 file 对象,说明是已有文件
+          if (file.fileUrl && !file.file) {
+            existingFiles.push(file.fileUrl);
+          } else {
+            // 否则是需要上传的新文件
+            newFiles.push(file);
+          }
+        });
+
+        // 上传新文件
+        let uploadedUrls: string[] = [];
+        if (newFiles.length > 0) {
+          const uploadedFiles = await formatAttachmentList(newFiles);
+          uploadedUrls = uploadedFiles
+            .map((file: any) => file.fileUrl || file.url || '')
+            .filter((url: string) => url);
+        }
+
+        // 合并已有URL和新上传的URL,取第一个作为fileUrl
+        const allUrls = [...existingFiles, ...uploadedUrls].filter((url: string) => url);
+        fileUrl = allUrls.length > 0 ? allUrls[0] : '';
+      }
+
       const basePayload: ProductionSafetyFile = {
         fileName: ruleFormData.fileName,
         classifyName: ruleFormData.classifyName,
@@ -196,7 +250,7 @@
         fileVersion: ruleFormData.fileVersion,
         fileFormat: ruleFormData.fileFormat,
         releaseDate: ruleFormData.releaseDate,
-        fileUrl: ruleFormData.fileUrl || undefined,
+        fileUrl: fileUrl || undefined,
         content: ruleFormData.content || undefined,
         status: ruleFormData.status ?? 1,
       };

+ 1 - 0
src/views/production-safety/productionSafetySystem/safetyStandardizationSystemManagement/configs/form.ts

@@ -77,6 +77,7 @@ export const SAFETY_STANDARDIZATION_FORM_DATA = {
   fileFormat: '',
   releaseDate: '',
   fileUrl: '',
+  fileUrlList: [] as any[], // 文件列表(FileItem数组)
   content: '',
   status: 1, // 默认启用
 };

+ 1 - 1
src/views/production-safety/productionSafetySystem/safetyStandardizationSystemManagement/safetyStandardizationSystemManagement.vue

@@ -171,7 +171,7 @@
       const pageQuery: ProductionSafetyFilePageQuery = {
         pageNumber: pagination.pageNumber,
         pageSize: pagination.pageSize,
-        data: {
+        queryParam: {
           keyword: queryParams.keyword || undefined,
           status: queryParams.status,
           classifyName: queryParams.classifyName || undefined,

+ 78 - 24
src/views/production-safety/productionSafetySystem/safetyTraining/components/safetyTrainingDetail.vue

@@ -16,7 +16,9 @@
         <UploadFiles
           label="上传文件"
           :maxCount="1"
-          :fileList="uploadFileList"
+          :file-list="ruleFormData.fileUrlList"
+          :disabled="isViewMode"
+          :allow-all-file-types="true"
           @uploadSuccess="handleUploadSuccess"
         />
       </template>
@@ -73,6 +75,7 @@
     type ProductionSafetyFile,
   } from '@/api/production-safety-system';
   import type { FileItem } from '@/components/UploadFiles/types';
+  import { formatAttachmentList } from '@/components/UploadFiles/utils';
 
   const router = useRouter();
   const route = useRoute();
@@ -126,21 +129,43 @@
   };
 
   // 文件上传
-  const uploadFileList = ref<FileItem[]>([]);
-
   const handleUploadSuccess = (files: FileItem[]) => {
-    uploadFileList.value = files;
-    if (files.length > 0 && files[0].file) {
-      // 这里需要实际上传文件到服务器,获取 fileUrl
-      // 暂时使用文件对象,实际应该调用上传接口
-      ruleFormData.fileUrl = files[0].file.name; // 临时处理,需要替换为实际上传后的URL
-    }
+    ruleFormData.fileUrlList = files;
   };
 
-  const getFileName = (url: string) => {
-    if (!url) return '';
-    const parts = url.split('/');
-    return parts[parts.length - 1];
+  // 将逗号分隔的URL字符串转换为FileItem数组
+  const convertFileUrlToFileItems = (fileUrl: string): FileItem[] => {
+    if (!fileUrl || !fileUrl.trim()) {
+      return [];
+    }
+    
+    // 按逗号分割URL
+    const urls = fileUrl.split(',').map(url => url.trim()).filter(url => url);
+    
+    return urls.map((url, index) => {
+      // 从URL中提取文件名
+      const urlParts = url.split('/');
+      const fileName = urlParts[urlParts.length - 1] || `附件${index + 1}`;
+      
+      // 根据文件扩展名判断文件类型
+      const extension = fileName.split('.').pop()?.toLowerCase() || '';
+      let fileType = 'pdf';
+      if (extension === 'doc' || extension === 'docx') {
+        fileType = 'word';
+      } else if (extension === 'xls' || extension === 'xlsx') {
+        fileType = 'excel';
+      } else if (extension === 'ppt' || extension === 'pptx') {
+        fileType = 'ppt';
+      }
+      
+      return {
+        fileId: Date.now() + index,
+        fileName,
+        fileType,
+        fileSize: '0',
+        fileUrl: url,
+      };
+    });
   };
 
   const handleValidate = async () => {
@@ -166,16 +191,7 @@
         ruleFormData.status = res.status ?? 1;
 
         // 如果有文件URL,转换为FileItem格式
-        if (res.fileUrl) {
-          uploadFileList.value = [
-            {
-              fileId: Date.now(),
-              fileName: getFileName(res.fileUrl),
-              fileType: res.fileFormat?.toLowerCase() === 'pdf' ? 'pdf' : 'word',
-              fileSize: '0KB',
-            },
-          ];
-        }
+        ruleFormData.fileUrlList = convertFileUrlToFileItems(res.fileUrl || '');
       }
       cloneRuleFormData();
     } catch (e) {
@@ -187,7 +203,45 @@
   const handleSubmit = async () => {
     const res = await handleValidate();
     if (!res) return;
+    
+    // 验证文件上传(必填)
+    if (!ruleFormData.fileUrlList || ruleFormData.fileUrlList.length === 0) {
+      ElMessage.warning('请上传文件');
+      return;
+    }
+    
     try {
+      // 处理文件上传:先上传文件获取 URL,然后提取 fileUrl
+      let fileUrl = '';
+      if (ruleFormData.fileUrlList && ruleFormData.fileUrlList.length > 0) {
+        // 分离已有URL的文件和新上传的文件
+        const existingFiles: string[] = [];
+        const newFiles: FileItem[] = [];
+        
+        ruleFormData.fileUrlList.forEach((file: FileItem) => {
+          // 如果文件已经有 fileUrl 且没有 file 对象,说明是已有文件
+          if (file.fileUrl && !file.file) {
+            existingFiles.push(file.fileUrl);
+          } else {
+            // 否则是需要上传的新文件
+            newFiles.push(file);
+          }
+        });
+
+        // 上传新文件
+        let uploadedUrls: string[] = [];
+        if (newFiles.length > 0) {
+          const uploadedFiles = await formatAttachmentList(newFiles);
+          uploadedUrls = uploadedFiles
+            .map((file: any) => file.fileUrl || file.url || '')
+            .filter((url: string) => url);
+        }
+
+        // 合并已有URL和新上传的URL,取第一个作为fileUrl
+        const allUrls = [...existingFiles, ...uploadedUrls].filter((url: string) => url);
+        fileUrl = allUrls.length > 0 ? allUrls[0] : '';
+      }
+
       const basePayload: ProductionSafetyFile = {
         fileName: ruleFormData.fileName,
         classifyName: ruleFormData.classifyName,
@@ -195,7 +249,7 @@
         fileVersion: ruleFormData.fileVersion,
         fileFormat: ruleFormData.fileFormat,
         releaseDate: ruleFormData.releaseDate,
-        fileUrl: ruleFormData.fileUrl || undefined,
+        fileUrl: fileUrl || undefined,
         content: ruleFormData.content || undefined,
         status: ruleFormData.status ?? 1,
       };

+ 1 - 0
src/views/production-safety/productionSafetySystem/safetyTraining/configs/form.ts

@@ -77,6 +77,7 @@ export const INDUSTRY_STANDARD_FORM_DATA = {
   fileFormat: '',
   releaseDate: '',
   fileUrl: '',
+  fileUrlList: [] as any[], // 文件列表(FileItem数组)
   content: '',
   status: 1, // 默认启用
 };

+ 1 - 1
src/views/production-safety/productionSafetySystem/safetyTraining/safetyTraining.vue

@@ -171,7 +171,7 @@
       const pageQuery: ProductionSafetyFilePageQuery = {
         pageNumber: pagination.pageNumber,
         pageSize: pagination.pageSize,
-        data: {
+        queryParam: {
           keyword: queryParams.keyword || undefined,
           status: queryParams.status,
           classifyName: queryParams.classifyName || undefined,

+ 1 - 0
src/views/production-safety/safetyAssessment/evaluationSystem/components/EvaluationTarget.vue

@@ -477,6 +477,7 @@
               isAdvancedGroup: item.isAdvancedGroup || false, // 是否先进集体(需要接口返回,暂时使用 false)
               departmentSort: item.scoreRank || 0, // 部门排序(使用排名)
               departmentLeader: item.deptUserName || '-', // 部门负责人
+              baseScore: 100, // 基础分,默认为100
               totalScore, // 总分数
               addScore, // 加分项分数
               subtractScore, // 减分项分数

+ 6 - 0
src/views/production-safety/safetyAssessment/evaluationSystem/configs/targetTables.ts

@@ -88,6 +88,12 @@ export const EVALUATION_ADVANCED_GROUP_TABLE_COLUMNS: TableColumnProps[] = [
     align: 'left',
     minWidth: '140px',
   },
+  {
+    label: '基础分',
+    prop: 'baseScore',
+    align: 'center',
+    minWidth: '100px',
+  },
   {
     label: '总分数',
     prop: 'totalScore',

+ 0 - 1
src/views/production-safety/safetyAssessment/pointDeduction/configs/form.ts

@@ -27,7 +27,6 @@ export const POINT_DEDUCTION_FORM_CONFIG: FormConfig[] = [
       min: 1,
       precision: 0, // 不允许小数点,只能输入整数
       placeholder: '请输入扣分值',
-      disabled: true, // 禁用扣分值字段
     },
   },
   {