|
|
@@ -0,0 +1,636 @@
|
|
|
+<template>
|
|
|
+ <div class="safety-platform-container">
|
|
|
+ <header class="safety-platform-container__header">
|
|
|
+ <div class="breadcrumb-title"> 安全文化活动管理 </div>
|
|
|
+ </header>
|
|
|
+ <main class="safety-platform-container__main">
|
|
|
+ <div class="search-table-container">
|
|
|
+ <header>
|
|
|
+ <div style="position: relative">
|
|
|
+ <!-- <el-button type="primary" 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> -->
|
|
|
+ </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" />
|
|
|
+ </div>
|
|
|
+ <div class="select-box--item">
|
|
|
+ <span>状态:</span>
|
|
|
+ <el-select v-model="queryParams.status" 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>
|
|
|
+ <el-select v-model="queryParams.classifyName" placeholder="请选择分类" clearable>
|
|
|
+ <el-option label="安全综合工作" value="安全综合工作" />
|
|
|
+ <el-option label="生产安全工作" value="生产安全工作" />
|
|
|
+ </el-select>
|
|
|
+ </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" />
|
|
|
+ </div>
|
|
|
+ </section>
|
|
|
+ <section class="search-btn">
|
|
|
+ <el-button type="primary" @click="handleSearch">查询</el-button>
|
|
|
+ <el-button @click="handleReset">重置</el-button>
|
|
|
+ </section>
|
|
|
+ </div>
|
|
|
+ </header>
|
|
|
+
|
|
|
+ <div class="batch-table">
|
|
|
+ <BasicTable ref="basicTableRef" :tableData="tableData" :tableConfig="tableConfig"
|
|
|
+ @update:pageSize="handleSizeChange" @update:pageNumber="handleCurrentChange">
|
|
|
+ <!-- <template #actionContent="scope">
|
|
|
+ <div class="file-item" v-for="file in scope.row.fileUrlList" :key="file.fileId">
|
|
|
+ <span class="file-item--name">{{ file.fileName }}</span>
|
|
|
+ <div class="file-item--footer">
|
|
|
+ <el-button link type="primary" @click="previewOnline(file.fileUrl, file.fileType)"
|
|
|
+ >预览</el-button
|
|
|
+ >
|
|
|
+ <el-button link type="primary" @click.stop="downloadFile(file.fileUrl, file.fileName)"
|
|
|
+ >下载</el-button
|
|
|
+ >
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </template> -->
|
|
|
+ <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="查看" @click="handleView(scope.row.id)" />
|
|
|
+ <ActionButton text="反馈" @click="handleFeedback(scope.row.id)" v-if="scope.row.status == 2"/>
|
|
|
+ <!-- <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="安全文化活动下发"
|
|
|
+ width="500px"
|
|
|
+ destroy-on-close
|
|
|
+ @open="onIssueDialogOpen"
|
|
|
+ >
|
|
|
+ <el-form ref="issueFormRef" :model="issueForm" :rules="issueRules" label-width="140px">
|
|
|
+ <el-form-item label="具体负责人部门" prop="rectificationDepartmentId">
|
|
|
+ <el-cascader
|
|
|
+ v-model="issueForm.rectificationDepartmentId"
|
|
|
+ :options="issueDeptTree"
|
|
|
+ :props="cascaderDeptProp"
|
|
|
+ :show-all-levels="false"
|
|
|
+ placeholder="请选择具体负责人部门"
|
|
|
+ filterable
|
|
|
+ clearable
|
|
|
+ style="width: 100%"
|
|
|
+ @change="onIssueDeptChange"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="具体负责人" prop="rectificationResponsibleUserId">
|
|
|
+ <el-select
|
|
|
+ v-model="issueForm.rectificationResponsibleUserId"
|
|
|
+ placeholder="选择具体负责人"
|
|
|
+ filterable
|
|
|
+ clearable
|
|
|
+ style="width: 100%"
|
|
|
+ >
|
|
|
+ <el-option
|
|
|
+ v-for="user in issueUserList"
|
|
|
+ :key="user.id"
|
|
|
+ :label="user.realname ?? user.username"
|
|
|
+ :value="user.id"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="计划开始日期:" prop="startDate">
|
|
|
+ <el-date-picker
|
|
|
+ v-model="issueForm.startDate"
|
|
|
+ type="date"
|
|
|
+ placeholder="请选择计划开始日期"
|
|
|
+ value-format="YYYY-MM-DD"
|
|
|
+ format="YYYY-MM-DD"
|
|
|
+ style="width: 100%"
|
|
|
+ :disabled-date="(date: Date) => {
|
|
|
+ if (issueForm.endDate) {
|
|
|
+ return date > new Date(issueForm.endDate);
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="计划结束日期:" prop="endDate">
|
|
|
+ <el-date-picker
|
|
|
+ v-model="issueForm.endDate"
|
|
|
+ type="date"
|
|
|
+ placeholder="请选择计划结束日期"
|
|
|
+ value-format="YYYY-MM-DD"
|
|
|
+ format="YYYY-MM-DD"
|
|
|
+ style="width: 100%"
|
|
|
+ :disabled-date="(date: Date) => {
|
|
|
+ if (issueForm.startDate) {
|
|
|
+ return date < new Date(issueForm.startDate);
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ <template #footer>
|
|
|
+ <el-button @click="showIssueDialog = false">取消</el-button>
|
|
|
+ <el-button type="primary" @click="handleIssueSave">保存</el-button>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
+
|
|
|
+ <PreviewOnline ref="previewOnlineRef" />
|
|
|
+
|
|
|
+ </main>
|
|
|
+ <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 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 {
|
|
|
+ safetyCultureActivityManagementExecutorFilePage,
|
|
|
+ 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';
|
|
|
+import PreviewOnline from '@/views/disaster/components/PreviewOnline.vue';
|
|
|
+const router = useRouter();
|
|
|
+
|
|
|
+const previewOnlineRef = ref<InstanceType<typeof PreviewOnline>>();
|
|
|
+
|
|
|
+/** 下发弹窗:点击下发打开弹窗,弹窗内部门用 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;
|
|
|
+};
|
|
|
+
|
|
|
+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 safetyCultureActivityManagementExecutorFilePage(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),
|
|
|
+ fileUrlList: JSON.parse(item.attachmentUrl || '[]'),
|
|
|
+ }));
|
|
|
+ pagination.total = res.totalRow || 0;
|
|
|
+ }
|
|
|
+ } 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: 'safetyCultureActivityManagementExecutorActivityRegistration',
|
|
|
+ query: {
|
|
|
+ operate: 'safety-culture-material-create',
|
|
|
+ },
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+const handleEdit = (id: number) => {
|
|
|
+ router.push({
|
|
|
+ name: 'safetyCultureActivityManagementExecutorActivityRegistration',
|
|
|
+ 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('删除失败,请重试');
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+const handleView = (id: number) => {
|
|
|
+ router.push({
|
|
|
+ name: 'safetyCultureActivityManagementExecutorItem',
|
|
|
+ query: {
|
|
|
+ id,
|
|
|
+ operate: 'safety-culture-material-view',
|
|
|
+ },
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+const activityRegistration = async (id: number) => {
|
|
|
+ router.push({
|
|
|
+ name: 'safetyCultureActivityManagementExecutorActivityRegistration',
|
|
|
+ query: {
|
|
|
+ id,
|
|
|
+ operate: 'safety-culture-material-view',
|
|
|
+ },
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+const handleFeedback = (id: number) => {
|
|
|
+ router.push({
|
|
|
+ name: 'safetyCultureActivityManagementExecutorItem',
|
|
|
+ query: {
|
|
|
+ id,
|
|
|
+ operate: 'safety-culture-material-feedback',
|
|
|
+ },
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+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 '';
|
|
|
+};
|
|
|
+
|
|
|
+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 || '下发失败,请重试');
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+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 previewOnline = (url: string | undefined, type) => {
|
|
|
+ if (url) {
|
|
|
+ previewOnlineRef.value?.open(url, type);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+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;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+</style>
|