Bläddra i källkod

fix: 安全文化活动、材料、宣传导入导出

hewei 1 månad sedan
förälder
incheckning
3b7cd59156

+ 56 - 0
src/api/safety-culture/index.ts

@@ -38,7 +38,9 @@ export interface safetyCultureFileQuery {
   status?: number; // 状态:1-启用,0-禁用
   classifyName?: string; // 分类名称
   startTime?: string; // 上传日期范围-开始日期
+  startDate?: string; // 上传日期范围-开始日期
   endTime?: string; // 上传日期范围-结束日期
+  endDate?: string; // 上传日期范围-结束日期
 }
 
 /**
@@ -450,3 +452,57 @@ export function feedbackSafetyCultureActivityManagement(data: addSafetyCultureFi
     data,
   });
 }
+
+/**
+ * 安全宣传栏导出
+ */
+
+export function securityPromotionExport(data: safetyCultureFileQuery) {
+  return http.request(
+    {
+      url: '/safetypublicitybulletinboard/exportSafetyPublicityBulletinBoard',
+      method: 'post',
+      data,
+      responseType: 'blob',
+    },
+    {
+      isTransformResponse: false,
+    },
+  );
+}
+
+/**
+ * 安全材料导出
+ */
+
+export function exportSafetyCultureMaterials(data: safetyCultureFileQuery) {
+  return http.request(
+    {
+      url: '/safety-culture/exportSafetyCultureMaterials',
+      method: 'post',
+      data,
+      responseType: 'blob',
+    },
+    {
+      isTransformResponse: false,
+    },
+  );
+}
+
+/**
+ * 安全文化活动导出
+ */
+
+export function safetyCultureActivityExport(data: safetyCultureFileQuery) {
+  return http.request(
+    {
+      url: '/safetyCulture/activity/exportSelected',
+      method: 'post',
+      data,
+      responseType: 'blob',
+    },
+    {
+      isTransformResponse: false,
+    },
+  );
+}

+ 455 - 423
src/views/production-safety/safety-culture/safetyCultureActivityManagement/safetyCultureActivityManagement.vue

@@ -10,19 +10,18 @@
             <el-button type="primary" :icon="Plus" class="search-table-container--button" @click="handleCreate">
               新增
             </el-button>
-            <!-- <el-button plain class="search-table-container--button" @click="handleImport">
-              导入
-            </el-button>
-            <el-button plain class="search-table-container--button" @click="handleDownload">
-              导出
-            </el-button> -->
+            <el-button plain class="search-table-container--button" @click="handleImport"> 导入 </el-button>
           </div>
 
           <div class="act-search">
             <section class="select-box">
               <div class="select-box--item">
                 <span>行动项内容/计划名称:</span>
-                <el-input v-model="queryParams.keyword" placeholder="搜索行动项内容/计划名称" class="act-search-input" />
+                <el-input
+                  v-model="queryParams.keyword"
+                  placeholder="搜索行动项内容/计划名称"
+                  class="act-search-input"
+                />
               </div>
               <div class="select-box--item">
                 <span>状态:</span>
@@ -41,20 +40,33 @@
               </div>
               <div class="select-box--item">
                 <span>计划日期范围:</span>
-                <el-date-picker v-model="uploadDateRange" type="daterange" range-separator="至" start-placeholder="开始日期"
-                  end-placeholder="结束日期" value-format="YYYY-MM-DD" format="YYYY-MM-DD" />
+                <el-date-picker
+                  v-model="uploadDateRange"
+                  type="daterange"
+                  range-separator="至"
+                  start-placeholder="开始日期"
+                  end-placeholder="结束日期"
+                  value-format="YYYY-MM-DD"
+                  format="YYYY-MM-DD"
+                />
               </div>
             </section>
             <section class="search-btn">
               <el-button type="primary" @click="handleSearch">查询</el-button>
               <el-button @click="handleReset">重置</el-button>
+              <el-button plain @click="handleDownload"> 导出 </el-button>
             </section>
           </div>
         </header>
 
         <div class="batch-table">
-          <BasicTable ref="basicTableRef" :tableData="tableData" :tableConfig="tableConfig"
-            @update:pageSize="handleSizeChange" @update:pageNumber="handleCurrentChange">
+          <BasicTable
+            ref="basicTableRef"
+            :tableData="tableData"
+            :tableConfig="tableConfig"
+            @update:pageSize="handleSizeChange"
+            @update:pageNumber="handleCurrentChange"
+          >
             <!-- <template #actionContent="scope">
               <span class="action-content" @click="activityRegistration(scope.row.id)">
                 {{ scope.row.actionContent || '-'}}
@@ -63,18 +75,27 @@
             <template #action="scope">
               <div class="action-container--div" style="justify-content: left">
                 <ActionButton text="编辑" v-if="scope.row.status === 1" @click="handleEdit(scope.row.id)" />
-                <ActionButton text="删除" v-if="scope.row.status === 1" :popconfirm="{
-                  title: '确定要删除?',
-                }" @confirm="handleDelete(scope.row.id)" />
+                <ActionButton
+                  text="删除"
+                  v-if="scope.row.status === 1"
+                  :popconfirm="{
+                    title: '确定要删除?',
+                  }"
+                  @confirm="handleDelete(scope.row.id)"
+                />
                 <ActionButton text="查看" @click="handleView(scope.row.id)" />
-                <ActionButton text="下发" @click="handleDispatch(scope.row.id)" v-if="scope.row.status === 1"/>
-                <ActionButton text="活动报名" @click="activityRegistration(scope.row.id)" v-if="scope.row.status !== 1"/>
+                <ActionButton text="下发" @click="handleDispatch(scope.row.id)" v-if="scope.row.status === 1" />
+                <ActionButton
+                  text="活动报名"
+                  @click="activityRegistration(scope.row.id)"
+                  v-if="scope.row.status !== 1"
+                />
               </div>
             </template>
           </BasicTable>
         </div>
       </div>
-      
+
       <el-dialog
         v-model="showIssueDialog"
         title="安全文化活动下发"
@@ -150,442 +171,453 @@
           <el-button type="primary" @click="handleIssueSave">保存</el-button>
         </template>
       </el-dialog>
-
     </main>
-    <BatchImport v-if="batchImportVisible" :visible="batchImportVisible" :import-api-url="importApiUrl"
-      :template-url="templateUrl" template-name="下载模板" :show-template="false" @close="batchImportVisible = false"
-      @update="handleUpdate" />
+    <BatchImport
+      v-if="batchImportVisible"
+      :visible="batchImportVisible"
+      :import-api-url="importApiUrl"
+      :template-url="templateUrl"
+      template-name="安全文化活动管理导入模版"
+      :show-template="false"
+      @close="batchImportVisible = false"
+      @update="handleUpdate"
+    />
   </div>
 </template>
 
 <script setup lang="ts">
-import { onMounted, reactive, ref } from 'vue';
-import { ElMessage } from 'element-plus';
-import { Plus } from '@element-plus/icons-vue';
-import BasicTable from '@/components/BasicTable.vue';
-import useTableConfig from '@/hooks/useTableConfigHook';
-import ActionButton from '@/components/ActionButton.vue';
-import { TABLE_OPTIONS, INVENTORY_TABLE_COLUMNS } from './configs/tables';
-import { useRouter } from 'vue-router';
-import {
-  safetyCultureActivityManagementFilePage,
-  deleteSafetyCultureActivityManagement,
-  getAllDepartments,
-  activityDistribution,
-  type safetyCultureFileQuery,
-  type safetyCultureFilePageQuery,
-} from '@/api/safety-culture';
-import type { DeptTree } from '@/types/dept/type';
-import { downloadByData } from '@/utils/file/download';
-import BatchImport from '@/components/batch-import/BatchImport.vue';
-import { useGlobSetting } from '@/hooks/setting';
-import urlJoin from 'url-join';
-import { http } from '@/utils/http/axios';
-import { queryAvailableUserList } from '@/api/production-safety/responsibility-implementation';
-
-const router = useRouter();
-
-/** 下发弹窗:点击下发打开弹窗,弹窗内部门用 queryAllDeptTree、负责人用 queryAvailableUserList,点击保存才触发下发接口 */
-const showIssueDialog = ref(false);
-const distributionId = ref<number>(0);
-const issueFormRef = ref();
-const issueForm = ref({
-  rectificationDepartmentId: undefined as number | undefined,
-  rectificationResponsibleUserId: undefined as number | undefined,
-  rectificationResponsiblePersonName: '' as string,
-  startDate: '' as string,
-  endDate: '' as string,
-});
-const issueRules = {
-  rectificationDepartmentId: [{ required: true, message: '请选择整改责任部门', trigger: 'change' }],
-  rectificationResponsibleUserId: [{ required: true, message: '请选择整改负责人', trigger: 'change' }],
-  startDate: [{ required: true, message: '请选择计划开始日期', trigger: 'change' }],
-  endDate: [{ required: true, message: '请选择计划结束日期', trigger: 'change' }],
-};
-/** 下发弹窗部门树,与新增隐患台账复查人员所属部门一致(getAllDepartments 取第一级 children) */
-const cascaderDeptProp = {
-  checkStrictly: true,
-  expandTrigger: 'hover' as const,
-  value: 'id',
-  label: 'deptName',
-  emitPath: false,
-};
-const issueDeptTree = ref<DeptTree[]>([]);
-const issueUserList = ref<Array<{ id: number; realname?: string; username?: string }>>([]);
-
-// 表格
-const basicTableRef = ref<InstanceType<typeof BasicTable>>();
-
-const { tableConfig, pagination } = useTableConfig(INVENTORY_TABLE_COLUMNS, TABLE_OPTIONS);
-
-const tableData = ref<any[]>([]);
-const deptNameMap = ref<Record<string, string>>({});
-
-const CATEGORY_NAME_MAP: Record<string, string> = {
-  '0': '外部院级文件',
-  '1': '内部院级文件',
-  '2': '内部院级文件',
-};
-
-const normalizeCategoryName = (row: any): string => {
-  const raw = row?.categoryName ?? row?.classifyName ?? row?.category;
-  if (raw == null || raw === '') {
-    return '-';
-  }
-  const stringValue = String(raw);
-  if (stringValue.includes('外部') || stringValue.includes('内部')) {
-    return stringValue;
-  }
-  return CATEGORY_NAME_MAP[stringValue] || stringValue;
-};
+  import { onMounted, reactive, ref } from 'vue';
+  import { ElMessage } from 'element-plus';
+  import { Plus } from '@element-plus/icons-vue';
+  import BasicTable from '@/components/BasicTable.vue';
+  import useTableConfig from '@/hooks/useTableConfigHook';
+  import ActionButton from '@/components/ActionButton.vue';
+  import { TABLE_OPTIONS, INVENTORY_TABLE_COLUMNS } from './configs/tables';
+  import { useRouter } from 'vue-router';
+  import {
+    safetyCultureActivityManagementFilePage,
+    deleteSafetyCultureActivityManagement,
+    getAllDepartments,
+    activityDistribution,
+    safetyCultureActivityExport,
+    type safetyCultureFileQuery,
+    type safetyCultureFilePageQuery,
+  } from '@/api/safety-culture';
+  import type { DeptTree } from '@/types/dept/type';
+  import { downloadByData } from '@/utils/file/download';
+  import BatchImport from '@/components/batch-import/BatchImport.vue';
+  import { useGlobSetting } from '@/hooks/setting';
+  import urlJoin from 'url-join';
+  import { queryAvailableUserList } from '@/api/production-safety/responsibility-implementation';
+
+  const router = useRouter();
+
+  /** 下发弹窗:点击下发打开弹窗,弹窗内部门用 queryAllDeptTree、负责人用 queryAvailableUserList,点击保存才触发下发接口 */
+  const showIssueDialog = ref(false);
+  const distributionId = ref<number>(0);
+  const issueFormRef = ref();
+  const issueForm = ref({
+    rectificationDepartmentId: undefined as number | undefined,
+    rectificationResponsibleUserId: undefined as number | undefined,
+    rectificationResponsiblePersonName: '' as string,
+    startDate: '' as string,
+    endDate: '' as string,
+  });
+  const issueRules = {
+    rectificationDepartmentId: [{ required: true, message: '请选择整改责任部门', trigger: 'change' }],
+    rectificationResponsibleUserId: [{ required: true, message: '请选择整改负责人', trigger: 'change' }],
+    startDate: [{ required: true, message: '请选择计划开始日期', trigger: 'change' }],
+    endDate: [{ required: true, message: '请选择计划结束日期', trigger: 'change' }],
+  };
+  /** 下发弹窗部门树,与新增隐患台账复查人员所属部门一致(getAllDepartments 取第一级 children) */
+  const cascaderDeptProp = {
+    checkStrictly: true,
+    expandTrigger: 'hover' as const,
+    value: 'id',
+    label: 'deptName',
+    emitPath: false,
+  };
+  const issueDeptTree = ref<DeptTree[]>([]);
+  const issueUserList = ref<Array<{ id: number; realname?: string; username?: string }>>([]);
 
-const normalizeListText = (value: unknown): string => {
-  if (Array.isArray(value)) {
-    const list = value.map((item) => String(item).trim()).filter((item) => item);
-    return list.length ? list.join('、') : '-';
-  }
-  if (value == null || value === '') {
-    return '-';
-  }
-  const text = String(value).trim();
-  if (!text) {
-    return '-';
-  }
-  return text.includes(',') ? text.split(',').map((item) => item.trim()).filter((item) => item).join('、') || '-' : text;
-};
+  // 表格
+  const basicTableRef = ref<InstanceType<typeof BasicTable>>();
 
-const parseIdList = (value: unknown): string[] => {
-  if (Array.isArray(value)) {
-    return value.map((item) => String(item).trim()).filter((item) => item);
-  }
-  if (value == null || value === '') {
-    return [];
-  }
-  const text = String(value).trim();
-  if (!text) {
-    return [];
-  }
-  return text.split(',').map((item) => item.trim()).filter((item) => item);
-};
-
-const flattenDeptTree = (tree: DeptTree[]): DeptTree[] => {
-  const result: DeptTree[] = [];
-  const walk = (nodes: DeptTree[]) => {
-    nodes.forEach((node) => {
-      result.push(node);
-      if (node.children?.length) {
-        walk(node.children);
-      }
-    });
+  const { tableConfig, pagination } = useTableConfig(INVENTORY_TABLE_COLUMNS, TABLE_OPTIONS);
+
+  const tableData = ref<any[]>([]);
+  const deptNameMap = ref<Record<string, string>>({});
+
+  const CATEGORY_NAME_MAP: Record<string, string> = {
+    '0': '外部院级文件',
+    '1': '内部院级文件',
+    '2': '内部院级文件',
+  };
+
+  const normalizeCategoryName = (row: any): string => {
+    const raw = row?.categoryName ?? row?.classifyName ?? row?.category;
+    if (raw == null || raw === '') {
+      return '-';
+    }
+    const stringValue = String(raw);
+    if (stringValue.includes('外部') || stringValue.includes('内部')) {
+      return stringValue;
+    }
+    return CATEGORY_NAME_MAP[stringValue] || stringValue;
   };
-  walk(tree || []);
-  return result;
-};
-
-const loadDeptNameMap = async () => {
-  try {
-    const deptTree = await getAllDepartments();
-    const flatList = flattenDeptTree(deptTree || []);
-    const map: Record<string, string> = {};
-    flatList.forEach((dept) => {
-      if (dept.id != null) {
-        map[String(dept.id)] = dept.deptName;
+
+  const normalizeListText = (value: unknown): string => {
+    if (Array.isArray(value)) {
+      const list = value.map((item) => String(item).trim()).filter((item) => item);
+      return list.length ? list.join('、') : '-';
+    }
+    if (value == null || value === '') {
+      return '-';
+    }
+    const text = String(value).trim();
+    if (!text) {
+      return '-';
+    }
+    return text.includes(',')
+      ? text
+          .split(',')
+          .map((item) => item.trim())
+          .filter((item) => item)
+          .join('、') || '-'
+      : text;
+  };
+
+  const parseIdList = (value: unknown): string[] => {
+    if (Array.isArray(value)) {
+      return value.map((item) => String(item).trim()).filter((item) => item);
+    }
+    if (value == null || value === '') {
+      return [];
+    }
+    const text = String(value).trim();
+    if (!text) {
+      return [];
+    }
+    return text
+      .split(',')
+      .map((item) => item.trim())
+      .filter((item) => item);
+  };
+
+  const flattenDeptTree = (tree: DeptTree[]): DeptTree[] => {
+    const result: DeptTree[] = [];
+    const walk = (nodes: DeptTree[]) => {
+      nodes.forEach((node) => {
+        result.push(node);
+        if (node.children?.length) {
+          walk(node.children);
+        }
+      });
+    };
+    walk(tree || []);
+    return result;
+  };
+
+  const loadDeptNameMap = async () => {
+    try {
+      const deptTree = await getAllDepartments();
+      const flatList = flattenDeptTree(deptTree || []);
+      const map: Record<string, string> = {};
+      flatList.forEach((dept) => {
+        if (dept.id != null) {
+          map[String(dept.id)] = dept.deptName;
+        }
+      });
+      deptNameMap.value = map;
+    } catch (error) {
+      console.error('加载部门字典失败:', error);
+      deptNameMap.value = {};
+    }
+  };
+
+  const normalizeCooperateDeptName = (row: any): string => {
+    const rawName = row?.cooperateDeptName || row?.specificDeptName;
+    if (rawName) {
+      return normalizeListText(rawName);
+    }
+
+    const ids = parseIdList(row?.cooperateDeptIds);
+    if (!ids.length) {
+      return '-';
+    }
+
+    const names = ids.map((id) => deptNameMap.value[id] || id).filter((item) => item);
+    return names.length ? names.join('、') : '-';
+  };
+
+  const normalizeResponsibleDeptName = (row: any): string => {
+    const rawName = row?.responsibleDeptName;
+    if (rawName) {
+      return normalizeListText(rawName);
+    }
+
+    const ids = parseIdList(row?.responsibleDeptId);
+    if (!ids.length) {
+      return '-';
+    }
+
+    const names = ids.map((id) => deptNameMap.value[id] || id).filter((item) => item);
+    return names.length ? names.join('、') : '-';
+  };
+
+  const queryParams = reactive<safetyCultureFileQuery>({
+    keyword: '', // 文件名称/编号(模糊查询)
+    status: undefined, // 状态:1-启用,0-禁用
+    classifyName: '', // 分类名称:外部院级文件/内部院级文件
+    startDate: '', // 上传日期范围-开始日期
+    endDate: '', // 上传日期范围-结束日期
+  });
+
+  // 上传日期范围(用于日期选择器)
+  const uploadDateRange = ref<[string, string] | null>(null);
+
+  const handleSizeChange = (value: number) => {
+    pagination.pageSize = value;
+    getTableData();
+  };
+
+  const handleCurrentChange = (value: number) => {
+    pagination.pageNumber = value;
+    getTableData();
+  };
+
+  async function getTableData() {
+    tableConfig.loading = true;
+    try {
+      const pageQuery: safetyCultureFilePageQuery = {
+        pageNumber: pagination.pageNumber,
+        pageSize: pagination.pageSize,
+        queryParam: {
+          keyword: queryParams.keyword || undefined,
+          status: queryParams.status,
+          classifyName: queryParams.classifyName || undefined,
+          startDate: queryParams.startDate || undefined,
+          endDate: queryParams.endDate || undefined,
+        },
+      };
+      const res = await safetyCultureActivityManagementFilePage(pageQuery);
+      if (res) {
+        tableData.value = (res.records || []).map((item: any) => ({
+          ...item,
+          categoryNameDisplay: normalizeCategoryName(item),
+          responsibleDeptNameDisplay: normalizeResponsibleDeptName(item),
+          responsiblePersonNameDisplay: normalizeListText(
+            item.responsiblePersonName || item.specificPersonName || item.responsiblePersonId,
+          ),
+          cooperateDeptNameDisplay: normalizeCooperateDeptName(item),
+        }));
+        pagination.total = res.totalRow || 0;
       }
-    });
-    deptNameMap.value = map;
-  } catch (error) {
-    console.error('加载部门字典失败:', error);
-    deptNameMap.value = {};
+    } catch (e) {
+      console.error('获取院级文件列表失败:', e);
+      tableData.value = [];
+      pagination.total = 0;
+    } finally {
+      tableConfig.loading = false;
+    }
   }
-};
 
-const normalizeCooperateDeptName = (row: any): string => {
-  const rawName = row?.cooperateDeptName || row?.specificDeptName;
-  if (rawName) {
-    return normalizeListText(rawName);
-  }
+  const handleSearch = () => {
+    // 处理日期范围
+    if (uploadDateRange.value && uploadDateRange.value.length === 2) {
+      queryParams.startDate = uploadDateRange.value[0];
+      queryParams.endDate = uploadDateRange.value[1];
+    } else {
+      queryParams.startDate = '';
+      queryParams.endDate = '';
+    }
 
-  const ids = parseIdList(row?.cooperateDeptIds);
-  if (!ids.length) {
-    return '-';
-  }
+    pagination.pageNumber = 1;
+    getTableData();
+  };
 
-  const names = ids.map((id) => deptNameMap.value[id] || id).filter((item) => item);
-  return names.length ? names.join('、') : '-';
-};
+  const handleReset = () => {
+    queryParams.keyword = '';
+    queryParams.status = undefined;
+    queryParams.classifyName = '';
+    queryParams.startDate = '';
+    queryParams.endDate = '';
+    uploadDateRange.value = null;
+    handleSearch();
+  };
 
-const normalizeResponsibleDeptName = (row: any): string => {
-  const rawName = row?.responsibleDeptName;
-  if (rawName) {
-    return normalizeListText(rawName);
-  }
+  // 批量导入
+  const batchImportVisible = ref(false);
+  const { urlPrefix } = useGlobSetting();
+  const importApiUrl = ref(urlJoin(urlPrefix, '/safetyCulture/activity/import'));
+  const templateUrl = ref('./skyeye-file-upload/sfysecurity/TEMPLATE/安全文化活动导入模版.xlsx');
 
-  const ids = parseIdList(row?.responsibleDeptId);
-  if (!ids.length) {
-    return '-';
-  }
+  const handleImport = () => {
+    batchImportVisible.value = true;
+  };
+
+  const handleUpdate = () => {
+    batchImportVisible.value = false;
+    getTableData();
+  };
 
-  const names = ids.map((id) => deptNameMap.value[id] || id).filter((item) => item);
-  return names.length ? names.join('、') : '-';
-};
-
-const queryParams = reactive<safetyCultureFileQuery>({
-  keyword: '', // 文件名称/编号(模糊查询)
-  status: undefined, // 状态:1-启用,0-禁用
-  classifyName: '', // 分类名称:外部院级文件/内部院级文件
-  startDate: '', // 上传日期范围-开始日期
-  endDate: '', // 上传日期范围-结束日期
-});
-
-// 上传日期范围(用于日期选择器)
-const uploadDateRange = ref<[string, string] | null>(null);
-
-const handleSizeChange = (value: number) => {
-  pagination.pageSize = value;
-  getTableData();
-};
-
-const handleCurrentChange = (value: number) => {
-  pagination.pageNumber = value;
-  getTableData();
-};
-
-
-async function getTableData() {
-  tableConfig.loading = true;
-  try {
-    const pageQuery: safetyCultureFilePageQuery = {
-      pageNumber: pagination.pageNumber,
-      pageSize: pagination.pageSize,
-      queryParam: {
+  const handleDownload = async () => {
+    try {
+      const exportParams: safetyCultureFileQuery = {
         keyword: queryParams.keyword || undefined,
         status: queryParams.status,
         classifyName: queryParams.classifyName || undefined,
         startDate: queryParams.startDate || undefined,
         endDate: queryParams.endDate || undefined,
-      },
-    };
-    const res = await safetyCultureActivityManagementFilePage(pageQuery);
-    if (res) {
-      tableData.value = (res.records || []).map((item: any) => ({
-        ...item,
-        categoryNameDisplay: normalizeCategoryName(item),
-        responsibleDeptNameDisplay: normalizeResponsibleDeptName(item),
-        responsiblePersonNameDisplay: normalizeListText(
-          item.responsiblePersonName || item.specificPersonName || item.responsiblePersonId,
-        ),
-        cooperateDeptNameDisplay: normalizeCooperateDeptName(item),
-      }));
-      pagination.total = res.totalRow || 0;
+      };
+      const response = await safetyCultureActivityExport(exportParams);
+      if (response) {
+        const fileName = `安全文化活动管理_${new Date().toISOString().split('T')[0]}.xlsx`;
+        downloadByData(response, fileName);
+        ElMessage.success('导出成功');
+      }
+    } catch (e) {
+      console.error('导出安全文化活动文件失败:', e);
+      ElMessage.error('导出失败,请重试');
     }
-  } catch (e) {
-    console.error('获取院级文件列表失败:', e);
-    tableData.value = [];
-    pagination.total = 0;
-  } finally {
-    tableConfig.loading = false;
-  }
-}
-
-const handleSearch = () => {
-  // 处理日期范围
-  if (uploadDateRange.value && uploadDateRange.value.length === 2) {
-    queryParams.startDate = uploadDateRange.value[0];
-    queryParams.endDate = uploadDateRange.value[1];
-  } else {
-    queryParams.startDate = '';
-    queryParams.endDate = '';
-  }
+  };
 
-  pagination.pageNumber = 1;
-  getTableData();
-};
-
-const handleReset = () => {
-  queryParams.keyword = '';
-  queryParams.status = undefined;
-  queryParams.classifyName = '';
-  queryParams.startDate = '';
-  queryParams.endDate = '';
-  uploadDateRange.value = null;
-  handleSearch();
-};
-
-// 批量导入
-const batchImportVisible = ref(false);
-const { urlPrefix } = useGlobSetting();
-const importApiUrl = ref(urlJoin(urlPrefix, '/productionSafety/academyFile/import'));
-const templateUrl = ref('./skyeye-file-upload/sfysecurity/TEMPLATE/import-academy-file-template.xlsx');
-
-const handleImport = () => {
-  batchImportVisible.value = true;
-};
-
-const handleUpdate = () => {
-  batchImportVisible.value = false;
-  getTableData();
-};
-
-const handleDownload = async () => {
-  try {
-    const exportParams: safetyCultureFileQuery = {
-      keyword: queryParams.keyword || undefined,
-      status: queryParams.status,
-      classifyName: queryParams.classifyName || undefined,
-      startDate: queryParams.startDate || undefined,
-      endDate: queryParams.endDate || undefined,
-    };
-    // const response = await exportAcademyFile(exportParams, queryParams.classifyName || undefined);
-    // if (response) {
-    //   const fileName = `院级文件管理_${new Date().toISOString().split('T')[0]}.xlsx`;
-    //   downloadByData(response, fileName);
-    //   ElMessage.success('导出成功');
-    // }
-  } catch (e) {
-    console.error('导出院级文件失败:', e);
-    ElMessage.error('导出失败,请重试');
-  }
-};
-
-const handleCreate = () => {
-  router.push({
-    name: 'safetyCultureActivityManagementItem',
-    query: {
-      operate: 'safety-culture-material-create',
-    },
-  });
-};
-
-const handleEdit = (id: number) => {
-  router.push({
-    name: 'safetyCultureActivityManagementItem',
-    query: {
-      id,
-      operate: 'safety-culture-material-edit',
-    },
-  });
-};
+  const handleCreate = () => {
+    router.push({
+      name: 'safetyCultureActivityManagementItem',
+      query: {
+        operate: 'safety-culture-material-create',
+      },
+    });
+  };
 
-const handleDelete = async (id: number) => {
-  try {
-    await deleteSafetyCultureActivityManagement(id);
-    ElMessage.success('删除成功');
-    getTableData();
-  } catch (e) {
-    console.error('删除安全文化活动失败:', e);
-    ElMessage.error('删除失败,请重试');
-  }
-};
-
-const handleView = (id: number) => {
-   router.push({
-    name: 'safetyCultureActivityManagementItem',
-    query: {
-      id,
-      operate: 'safety-culture-material-view',
-    },
-  });
-};
-
-const activityRegistration = async (id: number) => {
-  router.push({
-    name: 'safetyCultureActivityManagementActivityRegistration',
-    query: {
-      id,
-      operate: 'safety-culture-material-view',
-    },
-  });
-};
-
-const onIssueDialogOpen = async () => {
-  try {
-    const [deptRes, userRes] = await Promise.all([
-      getAllDepartments(),
-      queryAvailableUserList({ pageNumber: 1, pageSize: 9999, queryParam: {} }),
-    ]);
-    const fullTree = (deptRes as DeptTree[]) ?? [];
-    issueDeptTree.value = Array.isArray(fullTree) && fullTree[0]?.children ? fullTree[0].children : [];
-    issueUserList.value = (userRes as any)?.records ?? [];
-  } catch (e) {
-    console.error('获取部门/用户列表失败:', e);
-    ElMessage.error(e?.message || e?.data || '加载部门或负责人列表失败');
-    issueDeptTree.value = [];
-    issueUserList.value = [];
-  }
-};
-
-const onIssueDeptChange = () => {
-  issueForm.value.rectificationResponsibleUserId = undefined;
-  issueForm.value.rectificationResponsiblePersonName = '';
-};
-
-const handleDispatch = (id: number) => {
-  distributionId.value = id;
-  showIssueDialog.value = true;
-};
-
-/** 从部门树中根据 id 查找部门名称 */
-function findDeptNameById(nodes: DeptTree[] | undefined, id: number): string {
-  if (!nodes?.length) return '';
-  for (const n of nodes) {
-    if (n.id === id) return n.deptName ?? '';
-    if (n.children?.length) {
-      const found = findDeptNameById(n.children, id);
-      if (found) return found;
+  const handleEdit = (id: number) => {
+    router.push({
+      name: 'safetyCultureActivityManagementItem',
+      query: {
+        id,
+        operate: 'safety-culture-material-edit',
+      },
+    });
+  };
+
+  const handleDelete = async (id: number) => {
+    try {
+      await deleteSafetyCultureActivityManagement(id);
+      ElMessage.success('删除成功');
+      getTableData();
+    } catch (e) {
+      console.error('删除安全文化活动失败:', e);
+      ElMessage.error('删除失败,请重试');
     }
-  }
-  return '';
-};
-
-const handleIssueSave = async () => {
-  await issueFormRef.value?.validate?.().catch(() => {});
-  const { rectificationDepartmentId, rectificationResponsibleUserId } = issueForm.value;
-  if (rectificationDepartmentId == null || rectificationResponsibleUserId == null) {
-    ElMessage.warning('请选择整改责任部门和整改负责人');
-    return;
-  }
-  if (!issueForm.value.startDate || !issueForm.value.endDate) {
-    ElMessage.warning('请选择计划开始日期和计划结束日期');
-    return;
-  }
-  const selectedUser = issueUserList.value.find((u) => u.id === rectificationResponsibleUserId);
-  const personName = selectedUser?.realname ?? selectedUser?.username ?? '';
-  const deptName = findDeptNameById(issueDeptTree.value, rectificationDepartmentId);
-  try {
-    await activityDistribution({
-      id: distributionId.value,
-      specificDeptId: String(rectificationDepartmentId),
-      specificPersonId: String(rectificationResponsibleUserId),
-      startTime: issueForm.value.startDate,
-      endTime: issueForm.value.endDate,
+  };
+
+  const handleView = (id: number) => {
+    router.push({
+      name: 'safetyCultureActivityManagementItem',
+      query: {
+        id,
+        operate: 'safety-culture-material-view',
+      },
     });
-    ElMessage.success('下发成功');
-    showIssueDialog.value = false;
-    getTableData();
-  } catch (e) {
-    console.error('下发失败:', e);
-    ElMessage.error(e?.message || e?.data || '下发失败,请重试');
+  };
+
+  const activityRegistration = async (id: number) => {
+    router.push({
+      name: 'safetyCultureActivityManagementActivityRegistration',
+      query: {
+        id,
+        operate: 'safety-culture-material-view',
+      },
+    });
+  };
+
+  const onIssueDialogOpen = async () => {
+    try {
+      const [deptRes, userRes] = await Promise.all([
+        getAllDepartments(),
+        queryAvailableUserList({ pageNumber: 1, pageSize: 9999, queryParam: {} }),
+      ]);
+      const fullTree = (deptRes as DeptTree[]) ?? [];
+      issueDeptTree.value = Array.isArray(fullTree) && fullTree[0]?.children ? fullTree[0].children : [];
+      issueUserList.value = (userRes as any)?.records ?? [];
+    } catch (e) {
+      console.error('获取部门/用户列表失败:', e);
+      ElMessage.error(e?.message || e?.data || '加载部门或负责人列表失败');
+      issueDeptTree.value = [];
+      issueUserList.value = [];
+    }
+  };
+
+  const onIssueDeptChange = () => {
+    issueForm.value.rectificationResponsibleUserId = undefined;
+    issueForm.value.rectificationResponsiblePersonName = '';
+  };
+
+  const handleDispatch = (id: number) => {
+    distributionId.value = id;
+    showIssueDialog.value = true;
+  };
+
+  /** 从部门树中根据 id 查找部门名称 */
+  function findDeptNameById(nodes: DeptTree[] | undefined, id: number): string {
+    if (!nodes?.length) return '';
+    for (const n of nodes) {
+      if (n.id === id) return n.deptName ?? '';
+      if (n.children?.length) {
+        const found = findDeptNameById(n.children, id);
+        if (found) return found;
+      }
+    }
+    return '';
   }
-};
 
-onMounted(() => {
-  loadDeptNameMap().finally(() => {
-    getTableData();
+  const handleIssueSave = async () => {
+    await issueFormRef.value?.validate?.().catch(() => {});
+    const { rectificationDepartmentId, rectificationResponsibleUserId } = issueForm.value;
+    if (rectificationDepartmentId == null || rectificationResponsibleUserId == null) {
+      ElMessage.warning('请选择整改责任部门和整改负责人');
+      return;
+    }
+    if (!issueForm.value.startDate || !issueForm.value.endDate) {
+      ElMessage.warning('请选择计划开始日期和计划结束日期');
+      return;
+    }
+    const selectedUser = issueUserList.value.find((u) => u.id === rectificationResponsibleUserId);
+    const personName = selectedUser?.realname ?? selectedUser?.username ?? '';
+    const deptName = findDeptNameById(issueDeptTree.value, rectificationDepartmentId);
+    try {
+      await activityDistribution({
+        id: distributionId.value,
+        specificDeptId: String(rectificationDepartmentId),
+        specificPersonId: String(rectificationResponsibleUserId),
+        startTime: issueForm.value.startDate,
+        endTime: issueForm.value.endDate,
+      });
+      ElMessage.success('下发成功');
+      showIssueDialog.value = false;
+      getTableData();
+    } catch (e) {
+      console.error('下发失败:', e);
+      ElMessage.error(e?.message || e?.data || '下发失败,请重试');
+    }
+  };
+
+  onMounted(() => {
+    loadDeptNameMap().finally(() => {
+      getTableData();
+    });
   });
-  // loginSw();
-});
 </script>
 
 <style scoped lang="scss">
-@use '@/styles/page-details-layout.scss' as *;
-@use '@/styles/page-main-layout.scss' as *;
-@use '@/styles/basic-table-action.scss' as *;
-@use '@/views/traffic/violation/style/act-search-table.scss' as *;
-
-.action-content {
-  color: #409eff;
-  cursor: pointer;
-}
-
-
+  @use '@/styles/page-details-layout.scss' as *;
+  @use '@/styles/page-main-layout.scss' as *;
+  @use '@/styles/basic-table-action.scss' as *;
+  @use '@/views/traffic/violation/style/act-search-table.scss' as *;
+
+  .action-content {
+    color: #409eff;
+    cursor: pointer;
+  }
 </style>

+ 221 - 215
src/views/production-safety/safety-culture/safetyCultureMaterialManagement/safetyCultureMaterialManagement.vue

@@ -10,12 +10,7 @@
             <el-button type="primary" :icon="Plus" class="search-table-container--button" @click="handleCreate">
               新增
             </el-button>
-            <!-- <el-button plain class="search-table-container--button" @click="handleImport">
-              导入
-            </el-button>
-            <el-button plain class="search-table-container--button" @click="handleDownload">
-              导出
-            </el-button> -->
+            <el-button plain class="search-table-container--button" @click="handleImport"> 导入 </el-button>
           </div>
 
           <div class="act-search">
@@ -40,20 +35,33 @@
               </div>
               <div class="select-box--item">
                 <span>计划日期范围:</span>
-                <el-date-picker v-model="uploadDateRange" type="daterange" range-separator="至" start-placeholder="开始日期"
-                  end-placeholder="结束日期" value-format="YYYY-MM-DD" format="YYYY-MM-DD" />
+                <el-date-picker
+                  v-model="uploadDateRange"
+                  type="daterange"
+                  range-separator="至"
+                  start-placeholder="开始日期"
+                  end-placeholder="结束日期"
+                  value-format="YYYY-MM-DD"
+                  format="YYYY-MM-DD"
+                />
               </div>
             </section>
             <section class="search-btn">
               <el-button type="primary" @click="handleSearch">查询</el-button>
               <el-button @click="handleReset">重置</el-button>
+              <el-button plain @click="handleDownload"> 导出 </el-button>
             </section>
           </div>
         </header>
 
         <div class="batch-table">
-          <BasicTable ref="basicTableRef" :tableData="tableData" :tableConfig="tableConfig"
-            @update:pageSize="handleSizeChange" @update:pageNumber="handleCurrentChange">
+          <BasicTable
+            ref="basicTableRef"
+            :tableData="tableData"
+            :tableConfig="tableConfig"
+            @update:pageSize="handleSizeChange"
+            @update:pageNumber="handleCurrentChange"
+          >
             <template #status="scope">
               <span>
                 {{ scope.row.status === 1 ? '启用' : scope.row.status === 0 ? '禁用' : '-' }}
@@ -62,9 +70,13 @@
             <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="删除"
+                  :popconfirm="{
+                    title: '确定要删除?',
+                  }"
+                  @confirm="handleDelete(scope.row.id)"
+                />
                 <ActionButton text="查看" @click="handleView(scope.row.id)" />
                 <ActionButton text="下载" @click="handleDownloadFile(scope.row)" />
               </div>
@@ -73,238 +85,232 @@
         </div>
       </div>
     </main>
-    <BatchImport v-if="batchImportVisible" :visible="batchImportVisible" :import-api-url="importApiUrl"
-      :template-url="templateUrl" template-name="下载模板" :show-template="false" @close="batchImportVisible = false"
-      @update="handleUpdate" />
+    <BatchImport
+      v-if="batchImportVisible"
+      :visible="batchImportVisible"
+      :import-api-url="importApiUrl"
+      :template-url="templateUrl"
+      template-name="安全文化材料管理导入模版"
+      :show-template="true"
+      @close="batchImportVisible = false"
+      @update="handleUpdate"
+    />
   </div>
 </template>
 
 <script setup lang="ts">
-import { onMounted, reactive, ref } from 'vue';
-import { ElMessage } from 'element-plus';
-import { Plus } from '@element-plus/icons-vue';
-import BasicTable from '@/components/BasicTable.vue';
-import useTableConfig from '@/hooks/useTableConfigHook';
-import ActionButton from '@/components/ActionButton.vue';
-import { TABLE_OPTIONS, INVENTORY_TABLE_COLUMNS } from './configs/tables';
-import { useRouter } from 'vue-router';
-import {
-  querySafetyCultureMaterialsPage,
-  deleteSafetyCultureMaterials,
-  type safetyCultureFileQuery,
-  type safetyCultureFilePageQuery,
-} from '@/api/safety-culture';
-import { downloadByData } from '@/utils/file/download';
-import BatchImport from '@/components/batch-import/BatchImport.vue';
-import { useGlobSetting } from '@/hooks/setting';
-import urlJoin from 'url-join';
-import { http } from '@/utils/http/axios';
-
-
-const router = useRouter();
+  import { onMounted, reactive, ref } from 'vue';
+  import { ElMessage } from 'element-plus';
+  import { Plus } from '@element-plus/icons-vue';
+  import BasicTable from '@/components/BasicTable.vue';
+  import useTableConfig from '@/hooks/useTableConfigHook';
+  import ActionButton from '@/components/ActionButton.vue';
+  import { TABLE_OPTIONS, INVENTORY_TABLE_COLUMNS } from './configs/tables';
+  import { useRouter } from 'vue-router';
+  import {
+    querySafetyCultureMaterialsPage,
+    deleteSafetyCultureMaterials,
+    exportSafetyCultureMaterials,
+    type safetyCultureFileQuery,
+    type safetyCultureFilePageQuery,
+  } from '@/api/safety-culture';
+  import { downloadByData } from '@/utils/file/download';
+  import BatchImport from '@/components/batch-import/BatchImport.vue';
+  import { useGlobSetting } from '@/hooks/setting';
+  import urlJoin from 'url-join';
 
-// 表格
-const basicTableRef = ref<InstanceType<typeof BasicTable>>();
+  const router = useRouter();
 
-const { tableConfig, pagination } = useTableConfig(INVENTORY_TABLE_COLUMNS, TABLE_OPTIONS);
+  // 表格
+  const basicTableRef = ref<InstanceType<typeof BasicTable>>();
 
-const tableData = ref<any[]>([]);
+  const { tableConfig, pagination } = useTableConfig(INVENTORY_TABLE_COLUMNS, TABLE_OPTIONS);
 
-const queryParams = reactive<safetyCultureFileQuery>({
-  keyword: '', // 文件名称/编号(模糊查询)
-  status: undefined, // 状态:1-启用,0-禁用
-  classifyName: '', // 分类名称:外部院级文件/内部院级文件
-  startDate: '', // 上传日期范围-开始日期
-  endDate: '', // 上传日期范围-结束日期
-});
+  const tableData = ref<any[]>([]);
 
-// 上传日期范围(用于日期选择器)
-const uploadDateRange = ref<[string, string] | null>(null);
+  const queryParams = reactive<safetyCultureFileQuery>({
+    keyword: '', // 文件名称/编号(模糊查询)
+    status: undefined, // 状态:1-启用,0-禁用
+    classifyName: '', // 分类名称:外部院级文件/内部院级文件
+    startDate: '', // 上传日期范围-开始日期
+    endDate: '', // 上传日期范围-结束日期
+  });
 
-const handleSizeChange = (value: number) => {
-  pagination.pageSize = value;
-  getTableData();
-};
+  // 上传日期范围(用于日期选择器)
+  const uploadDateRange = ref<[string, string] | null>(null);
 
-const handleCurrentChange = (value: number) => {
-  pagination.pageNumber = value;
-  getTableData();
-};
+  const handleSizeChange = (value: number) => {
+    pagination.pageSize = value;
+    getTableData();
+  };
 
+  const handleCurrentChange = (value: number) => {
+    pagination.pageNumber = value;
+    getTableData();
+  };
 
-async function getTableData() {
-  tableConfig.loading = true;
-  try {
-    const pageQuery: safetyCultureFilePageQuery = {
-      pageNumber: pagination.pageNumber,
-      pageSize: pagination.pageSize,
-      queryParam: {
-        keyword: queryParams.keyword || undefined,
-        status: queryParams.status,
-        classifyName: queryParams.classifyName || undefined,
-        startDate: queryParams.startDate || undefined,
-        endDate: queryParams.endDate || undefined,
-      },
-    };
-    const res = await querySafetyCultureMaterialsPage(pageQuery, queryParams.classifyName || undefined);
-    if (res) {
-      // 映射返回数据字段到表格字段
-      tableData.value = res.records.map((item) => ({
-        id: item.id,
-        fileName: item.fileName, // 文件名称
-        fileCode: item.fileCode, // 文件编号
-        classifyName: item.classifyName, // 分类名称
-        fileVersion: item.fileVersion, // 文件版本号
-        fileFormat: item.fileFormat === 1 ? 'PDF' : 'WORD', // 文件格式
-        releaseDate: item.releaseDate, // 发布日期
-        status: item.status, // 状态:1-启用,0-禁用
-        publishDate: item.publishDate, // 发布日期
-        fileUrl: item.fileUrl, // 文件地址
-        uploadTime: item.uploadTime || item.createdAt, // 上传时间
-        categoryName: item.categoryName, // 分类名称
-      }));
-      pagination.total = res.totalRow || 0;
+  async function getTableData() {
+    tableConfig.loading = true;
+    try {
+      const pageQuery: safetyCultureFilePageQuery = {
+        pageNumber: pagination.pageNumber,
+        pageSize: pagination.pageSize,
+        queryParam: {
+          keyword: queryParams.keyword || undefined,
+          status: queryParams.status,
+          classifyName: queryParams.classifyName || undefined,
+          startDate: queryParams.startDate || undefined,
+          endDate: queryParams.endDate || undefined,
+        },
+      };
+      const res = await querySafetyCultureMaterialsPage(pageQuery, queryParams.classifyName || undefined);
+      if (res) {
+        // 映射返回数据字段到表格字段
+        tableData.value = res.records.map((item) => ({
+          id: item.id,
+          fileName: item.fileName, // 文件名称
+          fileCode: item.fileCode, // 文件编号
+          classifyName: item.classifyName, // 分类名称
+          fileVersion: item.fileVersion, // 文件版本号
+          fileFormat: item.fileFormat === 1 ? 'PDF' : 'WORD', // 文件格式
+          releaseDate: item.releaseDate, // 发布日期
+          status: item.status, // 状态:1-启用,0-禁用
+          publishDate: item.publishDate, // 发布日期
+          fileUrl: item.fileUrl, // 文件地址
+          uploadTime: item.uploadTime || item.createdAt, // 上传时间
+          categoryName: item.categoryName, // 分类名称
+        }));
+        pagination.total = res.totalRow || 0;
+      }
+    } catch (e) {
+      console.error('获取院级文件列表失败:', e);
+      tableData.value = [];
+      pagination.total = 0;
+    } finally {
+      tableConfig.loading = false;
     }
-  } catch (e) {
-    console.error('获取院级文件列表失败:', e);
-    tableData.value = [];
-    pagination.total = 0;
-  } finally {
-    tableConfig.loading = false;
   }
-}
 
-const handleSearch = () => {
-  // 处理日期范围
-  if (uploadDateRange.value && uploadDateRange.value.length === 2) {
-    queryParams.startDate = uploadDateRange.value[0];
-    queryParams.endDate = uploadDateRange.value[1];
-  } else {
+  const handleSearch = () => {
+    // 处理日期范围
+    if (uploadDateRange.value && uploadDateRange.value.length === 2) {
+      queryParams.startDate = uploadDateRange.value[0];
+      queryParams.endDate = uploadDateRange.value[1];
+    } else {
+      queryParams.startDate = '';
+      queryParams.endDate = '';
+    }
+
+    pagination.pageNumber = 1;
+    getTableData();
+  };
+
+  const handleReset = () => {
+    queryParams.keyword = '';
+    queryParams.status = undefined;
+    queryParams.classifyName = '';
     queryParams.startDate = '';
     queryParams.endDate = '';
-  }
+    uploadDateRange.value = null;
+    handleSearch();
+  };
 
-  pagination.pageNumber = 1;
-  getTableData();
-};
+  // 批量导入
+  const batchImportVisible = ref(false);
+  const { urlPrefix } = useGlobSetting();
+  const importApiUrl = ref(urlJoin(urlPrefix, '/safety-culture/importSafetyCultureMaterials'));
+  const templateUrl = ref('./skyeye-file-upload/sfysecurity/TEMPLATE/安全文化材料活动导入模版.xlsx');
 
-const handleReset = () => {
-  queryParams.keyword = '';
-  queryParams.status = undefined;
-  queryParams.classifyName = '';
-  queryParams.startDate = '';
-  queryParams.endDate = '';
-  uploadDateRange.value = null;
-  handleSearch();
-};
+  const handleImport = () => {
+    batchImportVisible.value = true;
+  };
 
-// 批量导入
-const batchImportVisible = ref(false);
-const { urlPrefix } = useGlobSetting();
-const importApiUrl = ref(urlJoin(urlPrefix, '/productionSafety/SafetyCultureMaterials/import'));
-const templateUrl = ref('./skyeye-file-upload/sfysecurity/TEMPLATE/import-academy-file-template.xlsx');
+  const handleUpdate = () => {
+    batchImportVisible.value = false;
+    getTableData();
+  };
 
-const handleImport = () => {
-  batchImportVisible.value = true;
-};
+  const handleDownload = async () => {
+    try {
+      const exportParams: safetyCultureFileQuery = {
+        keyword: queryParams.keyword || undefined,
+        status: queryParams.status,
+        classifyName: queryParams.classifyName || undefined,
+        startTime: queryParams.startDate || undefined,
+        endTime: queryParams.endDate || undefined,
+        startDate: queryParams.startDate || undefined,
+        endDate: queryParams.endDate || undefined,
+      };
+      const response = await exportSafetyCultureMaterials(exportParams);
+      if (response) {
+        const fileName = `安全文化材料管理_${new Date().toISOString().split('T')[0]}.xlsx`;
+        downloadByData(response, fileName);
+        ElMessage.success('导出成功');
+      }
+    } catch (e) {
+      console.error('导出安全文化材料文件失败:', e);
+      ElMessage.error('导出失败,请重试');
+    }
+  };
 
-const handleUpdate = () => {
-  batchImportVisible.value = false;
-  getTableData();
-};
+  // 文件下载
+  const handleDownloadFile = (row: any) => {
+    const url = row?.fileUrl;
+    if (!url) {
+      ElMessage.warning('暂无文件可下载');
+      return;
+    }
+    window.open(url, '_blank');
+  };
 
-const handleDownload = async () => {
-  try {
-    const exportParams: safetyCultureFileQuery = {
-      keyword: queryParams.keyword || undefined,
-      status: queryParams.status,
-      classifyName: queryParams.classifyName || undefined,
-      startDate: queryParams.startDate || undefined,
-      endDate: queryParams.endDate || undefined,
-    };
-    // const response = await exportSafetyCultureMaterials(exportParams, queryParams.classifyName || undefined);
-    // if (response) {
-    //   const fileName = `院级文件管理_${new Date().toISOString().split('T')[0]}.xlsx`;
-    //   downloadByData(response, fileName);
-    //   ElMessage.success('导出成功');
-    // }
-  } catch (e) {
-    console.error('导出院级文件失败:', e);
-    ElMessage.error('导出失败,请重试');
-  }
-};
+  const handleCreate = () => {
+    router.push({
+      name: 'safetyCultureMaterialManagementItem',
+      query: {
+        operate: 'safety-culture-material-create',
+      },
+    });
+  };
 
-// 文件下载
-const handleDownloadFile = (row: any) => {
-  const url = row?.fileUrl;
-  if (!url) {
-    ElMessage.warning('暂无文件可下载');
-    return;
-  }
-  window.open(url, '_blank');
-};
+  const handleEdit = (id: number) => {
+    router.push({
+      name: 'safetyCultureMaterialManagementItem',
+      query: {
+        id,
+        operate: 'safety-culture-material-edit',
+      },
+    });
+  };
 
-const handleCreate = () => {
-  router.push({
-    name: 'safetyCultureMaterialManagementItem',
-    query: {
-      operate: 'safety-culture-material-create',
-    },
-  });
-};
+  const handleDelete = async (id: number) => {
+    try {
+      await deleteSafetyCultureMaterials(id);
+      ElMessage.success('删除成功');
+      getTableData();
+    } catch (e) {
+      console.error('删除院级文件失败:', e);
+      ElMessage.error('删除失败,请重试');
+    }
+  };
 
-const handleEdit = (id: number) => {
-  router.push({
-    name: 'safetyCultureMaterialManagementItem',
-    query: {
-      id,
-      operate: 'safety-culture-material-edit',
-    },
-  });
-};
+  const handleView = (id: number) => {
+    router.push({
+      name: 'safetyCultureMaterialManagementItem',
+      query: {
+        id,
+        operate: 'safety-culture-material-view',
+      },
+    });
+  };
 
-const handleDelete = async (id: number) => {
-  try {
-    await deleteSafetyCultureMaterials(id);
-    ElMessage.success('删除成功');
+  onMounted(() => {
     getTableData();
-  } catch (e) {
-    console.error('删除院级文件失败:', e);
-    ElMessage.error('删除失败,请重试');
-  }
-};
-
-const handleView = (id: number) => {
-  router.push({
-    name: 'safetyCultureMaterialManagementItem',
-    query: {
-      id,
-      operate: 'safety-culture-material-view',
-    },
-  });
-};
-
-const loginSw = async () => {
-  http.request<number>({
-    url: '/api/login/auth',
-    method: 'post',
-    data: {
-      "username": "admin",
-      "password": "e14874aaefbf1666a9ad3d11f2a77892",
-      "captchaVerification": ""
-    },
   });
-};
-
-onMounted(() => {
-  getTableData();
-  // loginSw();
-});
 </script>
 
 <style scoped lang="scss">
-@use '@/styles/page-details-layout.scss' as *;
-@use '@/styles/page-main-layout.scss' as *;
-@use '@/styles/basic-table-action.scss' as *;
-@use '@/views/traffic/violation/style/act-search-table.scss' as *;
-</style>
+  @use '@/styles/page-details-layout.scss' as *;
+  @use '@/styles/page-main-layout.scss' as *;
+  @use '@/styles/basic-table-action.scss' as *;
+  @use '@/views/traffic/violation/style/act-search-table.scss' as *;
+</style>

+ 235 - 225
src/views/production-safety/safety-culture/safetyPublicityBoardManagement/safetyPublicityBoardManagement.vue

@@ -10,12 +10,7 @@
             <el-button type="primary" :icon="Plus" class="search-table-container--button" @click="handleCreate">
               新增
             </el-button>
-            <!-- <el-button plain class="search-table-container--button" @click="handleImport">
-              导入
-            </el-button>
-            <el-button plain class="search-table-container--button" @click="handleDownload">
-              导出
-            </el-button> -->
+            <el-button plain class="search-table-container--button" @click="handleImport"> 导入 </el-button>
           </div>
 
           <div class="act-search">
@@ -40,20 +35,33 @@
               </div>
               <div class="select-box--item">
                 <span>上传日期范围:</span>
-                <el-date-picker v-model="uploadDateRange" type="daterange" range-separator="至" start-placeholder="开始日期"
-                  end-placeholder="结束日期" value-format="YYYY-MM-DD" format="YYYY-MM-DD" />
+                <el-date-picker
+                  v-model="uploadDateRange"
+                  type="daterange"
+                  range-separator="至"
+                  start-placeholder="开始日期"
+                  end-placeholder="结束日期"
+                  value-format="YYYY-MM-DD"
+                  format="YYYY-MM-DD"
+                />
               </div>
             </section>
             <section class="search-btn">
               <el-button type="primary" @click="handleSearch">查询</el-button>
               <el-button @click="handleReset">重置</el-button>
+              <el-button plain @click="handleDownload"> 导出 </el-button>
             </section>
           </div>
         </header>
 
         <div class="batch-table">
-          <BasicTable ref="basicTableRef" :tableData="tableData" :tableConfig="tableConfig"
-            @update:pageSize="handleSizeChange" @update:pageNumber="handleCurrentChange">
+          <BasicTable
+            ref="basicTableRef"
+            :tableData="tableData"
+            :tableConfig="tableConfig"
+            @update:pageSize="handleSizeChange"
+            @update:pageNumber="handleCurrentChange"
+          >
             <template #status="scope">
               <span>
                 {{ scope.row.status === 1 ? '启用' : scope.row.status === 0 ? '禁用' : '-' }}
@@ -62,9 +70,13 @@
             <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="删除"
+                  :popconfirm="{
+                    title: '确定要删除?',
+                  }"
+                  @confirm="handleDelete(scope.row.id)"
+                />
                 <ActionButton text="查看" @click="handleView(scope.row.id)" />
                 <ActionButton text="下载" @click="handleDownloadFile(scope.row)" />
               </div>
@@ -73,254 +85,252 @@
         </div>
       </div>
     </main>
-    <BatchImport v-if="batchImportVisible" :visible="batchImportVisible" :import-api-url="importApiUrl"
-      :template-url="templateUrl" template-name="下载模板" :show-template="false" @close="batchImportVisible = false"
-      @update="handleUpdate" />
+    <BatchImport
+      v-if="batchImportVisible"
+      :visible="batchImportVisible"
+      :import-api-url="importApiUrl"
+      :template-url="templateUrl"
+      template-name="安全宣传栏管理导入模版"
+      :show-template="true"
+      @close="batchImportVisible = false"
+      @update="handleUpdate"
+    />
   </div>
 </template>
 
 <script setup lang="ts">
-import { onMounted, reactive, ref } from 'vue';
-import { ElMessage } from 'element-plus';
-import { Plus } from '@element-plus/icons-vue';
-import BasicTable from '@/components/BasicTable.vue';
-import useTableConfig from '@/hooks/useTableConfigHook';
-import ActionButton from '@/components/ActionButton.vue';
-import { TABLE_OPTIONS, INVENTORY_TABLE_COLUMNS } from './configs/tables';
-import { useRouter } from 'vue-router';
-import {
-  querySafetyPublicityBoardPage,
-  deleteSafetyPublicityBoardPage,
-  type safetyCultureFilePageQuery,
-  type safetyCultureFileQuery,
-} from '@/api/safety-culture';
-import { downloadByData } from '@/utils/file/download';
-import BatchImport from '@/components/batch-import/BatchImport.vue';
-import { useGlobSetting } from '@/hooks/setting';
-import urlJoin from 'url-join';
-import { http } from '@/utils/http/axios';
+  import { onMounted, reactive, ref } from 'vue';
+  import { ElMessage } from 'element-plus';
+  import { Plus } from '@element-plus/icons-vue';
+  import BasicTable from '@/components/BasicTable.vue';
+  import useTableConfig from '@/hooks/useTableConfigHook';
+  import ActionButton from '@/components/ActionButton.vue';
+  import { TABLE_OPTIONS, INVENTORY_TABLE_COLUMNS } from './configs/tables';
+  import { useRouter } from 'vue-router';
+  import {
+    querySafetyPublicityBoardPage,
+    deleteSafetyPublicityBoardPage,
+    securityPromotionExport,
+    type safetyCultureFilePageQuery,
+    type safetyCultureFileQuery,
+  } from '@/api/safety-culture';
+  import { downloadByData } from '@/utils/file/download';
+  import BatchImport from '@/components/batch-import/BatchImport.vue';
+  import { useGlobSetting } from '@/hooks/setting';
+  import urlJoin from 'url-join';
+
+  const router = useRouter();
+
+  // 表格
+  const basicTableRef = ref<InstanceType<typeof BasicTable>>();
+
+  const { tableConfig, pagination } = useTableConfig(INVENTORY_TABLE_COLUMNS, TABLE_OPTIONS);
+
+  const tableData = ref<any[]>([]);
+
+  const queryParams = reactive<safetyCultureFileQuery>({
+    keyword: '', // 文件名称/编号(模糊查询)
+    status: undefined, // 状态:1-启用,0-禁用
+    classifyName: '', // 分类名称:外部院级文件/内部院级文件
+    startTime: '', // 上传日期范围-开始日期
+    endTime: '', // 上传日期范围-结束日期
+  });
 
+  // 上传日期范围(用于日期选择器)
+  const uploadDateRange = ref<[string, string] | null>(null);
 
-const router = useRouter();
+  const handleSizeChange = (value: number) => {
+    pagination.pageSize = value;
+    getTableData();
+  };
 
-// 表格
-const basicTableRef = ref<InstanceType<typeof BasicTable>>();
+  const handleCurrentChange = (value: number) => {
+    pagination.pageNumber = value;
+    getTableData();
+  };
 
-const { tableConfig, pagination } = useTableConfig(INVENTORY_TABLE_COLUMNS, TABLE_OPTIONS);
+  async function getTableData() {
+    tableConfig.loading = true;
+    try {
+      const pageQuery: safetyCultureFilePageQuery = {
+        pageNumber: pagination.pageNumber,
+        pageSize: pagination.pageSize,
+        queryParam: {
+          keyword: queryParams.keyword || undefined,
+          status: queryParams.status,
+          classifyName: queryParams.classifyName || undefined,
+          startTime: queryParams.startTime || undefined,
+          endTime: queryParams.endTime || undefined,
+        },
+      };
+      const res = await querySafetyPublicityBoardPage(pageQuery);
+      if (res) {
+        tableData.value = res.records.map((item) => ({
+          id: item.id,
+          fileName: item.materialName || item.fileName,
+          status: item.status,
+          categoryName: item.categoryName || item.classifyName,
+          fileCode: item.description || '-',
+          fileVersion: item.createdAt,
+          attachmentUrl: item.attachmentUrl,
+          fileUrl: item.fileUrl,
+        }));
+        pagination.total = res.totalRow || 0;
+      }
+    } catch (e) {
+      console.error('获取院级文件列表失败:', e);
+      tableData.value = [];
+      pagination.total = 0;
+    } finally {
+      tableConfig.loading = false;
+    }
+  }
 
-const tableData = ref<any[]>([]);
+  const handleSearch = () => {
+    // 处理日期范围
+    if (uploadDateRange.value && uploadDateRange.value.length === 2) {
+      queryParams.startTime = uploadDateRange.value[0];
+      queryParams.endTime = uploadDateRange.value[1];
+    } else {
+      queryParams.startTime = '';
+      queryParams.endTime = '';
+    }
 
-const queryParams = reactive<safetyCultureFileQuery>({
-  keyword: '', // 文件名称/编号(模糊查询)
-  status: undefined, // 状态:1-启用,0-禁用
-  classifyName: '', // 分类名称:外部院级文件/内部院级文件
-  startTime: '', // 上传日期范围-开始日期
-  endTime: '', // 上传日期范围-结束日期
-});
+    pagination.pageNumber = 1;
+    getTableData();
+  };
 
-// 上传日期范围(用于日期选择器)
-const uploadDateRange = ref<[string, string] | null>(null);
+  const handleReset = () => {
+    queryParams.keyword = '';
+    queryParams.status = undefined;
+    queryParams.classifyName = '';
+    queryParams.startTime = '';
+    queryParams.endTime = '';
+    uploadDateRange.value = null;
+    handleSearch();
+  };
 
-const handleSizeChange = (value: number) => {
-  pagination.pageSize = value;
-  getTableData();
-};
+  // 批量导入
+  const batchImportVisible = ref(false);
+  const { urlPrefix } = useGlobSetting();
+  const importApiUrl = ref(urlJoin(urlPrefix, '/safetypublicitybulletinboard/importSafetyPublicityBulletinBoard'));
+  const templateUrl = ref('./skyeye-file-upload/sfysecurity/TEMPLATE/安全宣传栏活动导入模版.xlsx');
 
-const handleCurrentChange = (value: number) => {
-  pagination.pageNumber = value;
-  getTableData();
-};
+  const handleImport = () => {
+    batchImportVisible.value = true;
+  };
 
+  const handleUpdate = () => {
+    batchImportVisible.value = false;
+    getTableData();
+  };
 
-async function getTableData() {
-  tableConfig.loading = true;
-  try {
-    const pageQuery: safetyCultureFilePageQuery = {
-      pageNumber: pagination.pageNumber,
-      pageSize: pagination.pageSize,
-      queryParam: {
+  // 导出
+  const handleDownload = async () => {
+    try {
+      const exportParams: safetyCultureFileQuery = {
         keyword: queryParams.keyword || undefined,
         status: queryParams.status,
         classifyName: queryParams.classifyName || undefined,
         startTime: queryParams.startTime || undefined,
         endTime: queryParams.endTime || undefined,
-      },
-    };
-    const res = await querySafetyPublicityBoardPage(pageQuery);
-    if (res) {
-      tableData.value = res.records.map((item) => ({
-        id: item.id,
-        fileName: item.materialName || item.fileName,
-        status: item.status,
-        categoryName: item.categoryName || item.classifyName,
-        fileCode: item.description || '-',
-        fileVersion: item.createdAt,
-        attachmentUrl: item.attachmentUrl,
-        fileUrl: item.fileUrl,
-      }));
-      pagination.total = res.totalRow || 0;
+        startDate: queryParams.startTime || undefined,
+        endDate: queryParams.endTime || undefined,
+      };
+      const response = await securityPromotionExport(exportParams);
+      if (response) {
+        const fileName = `安全宣传栏管理_${new Date().toISOString().split('T')[0]}.xlsx`;
+        downloadByData(response, fileName);
+        ElMessage.success('导出成功');
+      }
+    } catch (e) {
+      console.error('导出安全宣传栏失败:', e);
+      ElMessage.error('导出失败,请重试');
     }
-  } catch (e) {
-    console.error('获取院级文件列表失败:', e);
-    tableData.value = [];
-    pagination.total = 0;
-  } finally {
-    tableConfig.loading = false;
-  }
-}
-
-const handleSearch = () => {
-  // 处理日期范围
-  if (uploadDateRange.value && uploadDateRange.value.length === 2) {
-    queryParams.startTime = uploadDateRange.value[0];
-    queryParams.endTime = uploadDateRange.value[1];
-  } else {
-    queryParams.startTime = '';
-    queryParams.endTime = '';
-  }
-
-  pagination.pageNumber = 1;
-  getTableData();
-};
-
-const handleReset = () => {
-  queryParams.keyword = '';
-  queryParams.status = undefined;
-  queryParams.classifyName = '';
-  queryParams.startTime = '';
-  queryParams.endTime = '';
-  uploadDateRange.value = null;
-  handleSearch();
-};
-
-// 批量导入
-const batchImportVisible = ref(false);
-const { urlPrefix } = useGlobSetting();
-const importApiUrl = ref(urlJoin(urlPrefix, '/productionSafety/SafetyCultureMaterials/import'));
-const templateUrl = ref('./skyeye-file-upload/sfysecurity/TEMPLATE/import-academy-file-template.xlsx');
+  };
 
-const handleImport = () => {
-  batchImportVisible.value = true;
-};
+  // 文件下载
+  const handleDownloadFile = (row: any) => {
+    const parseAttachmentUrls = (attachmentUrl?: string): string[] => {
+      if (!attachmentUrl || !attachmentUrl.trim()) {
+        return [];
+      }
 
-const handleUpdate = () => {
-  batchImportVisible.value = false;
-  getTableData();
-};
+      const normalized = attachmentUrl.trim();
+      if (normalized.startsWith('[') && normalized.endsWith(']')) {
+        try {
+          const parsed = JSON.parse(normalized);
+          if (Array.isArray(parsed)) {
+            return parsed.map((item) => String(item).trim()).filter((item) => item);
+          }
+        } catch (error) {
+          console.error('解析 attachmentUrl 失败:', error);
+        }
+      }
 
-const handleDownload = async () => {
-  try {
-    const exportParams: safetyCultureFileQuery = {
-      keyword: queryParams.keyword || undefined,
-      status: queryParams.status,
-      classifyName: queryParams.classifyName || undefined,
-      startTime: queryParams.startTime || undefined,
-      endTime: queryParams.endTime || undefined,
+      return normalized
+        .split(',')
+        .map((url) => url.trim())
+        .filter((url) => url);
     };
-    // const response = await exportSafetyCultureMaterials(exportParams, queryParams.classifyName || undefined);
-    // if (response) {
-    //   const fileName = `院级文件管理_${new Date().toISOString().split('T')[0]}.xlsx`;
-    //   downloadByData(response, fileName);
-    //   ElMessage.success('导出成功');
-    // }
-  } catch (e) {
-    console.error('导出院级文件失败:', e);
-    ElMessage.error('导出失败,请重试');
-  }
-};
 
-// 文件下载
-const handleDownloadFile = (row: any) => {
-  const parseAttachmentUrls = (attachmentUrl?: string): string[] => {
-    if (!attachmentUrl || !attachmentUrl.trim()) {
-      return [];
-    }
-
-    const normalized = attachmentUrl.trim();
-    if (normalized.startsWith('[') && normalized.endsWith(']')) {
-      try {
-        const parsed = JSON.parse(normalized);
-        if (Array.isArray(parsed)) {
-          return parsed.map((item) => String(item).trim()).filter((item) => item);
-        }
-      } catch (error) {
-        console.error('解析 attachmentUrl 失败:', error);
-      }
+    const attachmentUrls = parseAttachmentUrls(row?.attachmentUrl);
+    const url = attachmentUrls[0] || row?.fileUrl;
+    if (!url) {
+      ElMessage.warning('暂无文件可下载');
+      return;
     }
+    window.open(url, '_blank');
+  };
 
-    return normalized.split(',').map((url) => url.trim()).filter((url) => url);
+  const handleCreate = () => {
+    router.push({
+      name: 'safetyPublicityBoardManagementItem',
+      query: {
+        operate: 'safety-publicity-board-create',
+      },
+    });
   };
 
-  const attachmentUrls = parseAttachmentUrls(row?.attachmentUrl);
-  const url = attachmentUrls[0] || row?.fileUrl;
-  if (!url) {
-    ElMessage.warning('暂无文件可下载');
-    return;
-  }
-  window.open(url, '_blank');
-};
+  const handleEdit = (id: number) => {
+    router.push({
+      name: 'safetyPublicityBoardManagementItem',
+      query: {
+        id,
+        operate: 'safety-publicity-board-edit',
+      },
+    });
+  };
 
-const handleCreate = () => {
-  router.push({
-    name: 'safetyPublicityBoardManagementItem',
-    query: {
-      operate: 'safety-publicity-board-create',
-    },
-  });
-};
+  const handleDelete = async (id: number) => {
+    try {
+      await deleteSafetyPublicityBoardPage(id);
+      ElMessage.success('删除成功');
+      getTableData();
+    } catch (e) {
+      console.error('删除院级文件失败:', e);
+      ElMessage.error('删除失败,请重试');
+    }
+  };
 
-const handleEdit = (id: number) => {
-  router.push({
-    name: 'safetyPublicityBoardManagementItem',
-    query: {
-      id,
-      operate: 'safety-publicity-board-edit',
-    },
-  });
-};
+  const handleView = (id: number) => {
+    router.push({
+      name: 'safetyPublicityBoardManagementItem',
+      query: {
+        id,
+        operate: 'safety-publicity-board-view',
+      },
+    });
+  };
 
-const handleDelete = async (id: number) => {
-  try {
-    await deleteSafetyPublicityBoardPage(id);
-    ElMessage.success('删除成功');
+  onMounted(() => {
     getTableData();
-  } catch (e) {
-    console.error('删除院级文件失败:', e);
-    ElMessage.error('删除失败,请重试');
-  }
-};
-
-const handleView = (id: number) => {
-  router.push({
-    name: 'safetyPublicityBoardManagementItem',
-    query: {
-      id,
-      operate: 'safety-publicity-board-view',
-    },
   });
-};
-
-const loginSw = async () => {
-  http.request<number>({
-    url: '/api/login/auth',
-    method: 'post',
-    data: {
-      "username": "admin",
-      "password": "e14874aaefbf1666a9ad3d11f2a77892",
-      "captchaVerification": ""
-    },
-  });
-};
-
-onMounted(() => {
-  getTableData();
-  // loginSw();
-});
 </script>
 
 <style scoped lang="scss">
-@use '@/styles/page-details-layout.scss' as *;
-@use '@/styles/page-main-layout.scss' as *;
-@use '@/styles/basic-table-action.scss' as *;
-@use '@/views/traffic/violation/style/act-search-table.scss' as *;
+  @use '@/styles/page-details-layout.scss' as *;
+  @use '@/styles/page-main-layout.scss' as *;
+  @use '@/styles/basic-table-action.scss' as *;
+  @use '@/views/traffic/violation/style/act-search-table.scss' as *;
 </style>