safetyCultureActivityManagementExecutor.vue 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637
  1. <template>
  2. <div class="safety-platform-container">
  3. <header class="safety-platform-container__header">
  4. <div class="breadcrumb-title"> 安全文化活动开展 </div>
  5. </header>
  6. <main class="safety-platform-container__main">
  7. <div class="search-table-container">
  8. <header>
  9. <div style="position: relative">
  10. <!-- <el-button type="primary" class="search-table-container--button" @click="handleCreate">
  11. 新增
  12. </el-button> -->
  13. <!-- <el-button plain class="search-table-container--button" @click="handleImport">
  14. 导入
  15. </el-button>
  16. <el-button plain class="search-table-container--button" @click="handleDownload">
  17. 导出
  18. </el-button> -->
  19. </div>
  20. <div class="act-search">
  21. <section class="select-box">
  22. <div class="select-box--item">
  23. <span>行动项内容/计划名称:</span>
  24. <el-input v-model="queryParams.keyword" placeholder="搜索行动项内容/计划名称" class="act-search-input" />
  25. </div>
  26. <div class="select-box--item">
  27. <span>状态:</span>
  28. <el-select v-model="queryParams.status" placeholder="请选择状态" clearable>
  29. <!-- <el-option label="未下发" :value="1" /> -->
  30. <el-option label="待反馈" :value="2" />
  31. <el-option label="已完成" :value="3" />
  32. </el-select>
  33. </div>
  34. <div class="select-box--item">
  35. <span>分类名称:</span>
  36. <el-select v-model="queryParams.classifyName" placeholder="请选择分类" clearable>
  37. <el-option label="安全综合工作" value="安全综合工作" />
  38. <el-option label="生产安全工作" value="生产安全工作" />
  39. </el-select>
  40. </div>
  41. <div class="select-box--item">
  42. <span>计划日期范围:</span>
  43. <el-date-picker v-model="uploadDateRange" type="daterange" range-separator="至" start-placeholder="开始日期"
  44. end-placeholder="结束日期" value-format="YYYY-MM-DD" format="YYYY-MM-DD" />
  45. </div>
  46. </section>
  47. <section class="search-btn">
  48. <el-button type="primary" @click="handleSearch">查询</el-button>
  49. <el-button @click="handleReset">重置</el-button>
  50. </section>
  51. </div>
  52. </header>
  53. <div class="batch-table">
  54. <BasicTable ref="basicTableRef" :tableData="tableData" :tableConfig="tableConfig"
  55. @update:pageSize="handleSizeChange" @update:pageNumber="handleCurrentChange">
  56. <!-- <template #actionContent="scope">
  57. <div class="file-item" v-for="file in scope.row.fileUrlList" :key="file.fileId">
  58. <span class="file-item--name">{{ file.fileName }}</span>
  59. <div class="file-item--footer">
  60. <el-button link type="primary" @click="previewOnline(file.fileUrl, file.fileType)"
  61. >预览</el-button
  62. >
  63. <el-button link type="primary" @click.stop="downloadFile(file.fileUrl, file.fileName)"
  64. >下载</el-button
  65. >
  66. </div>
  67. </div>
  68. </template> -->
  69. <template #action="scope">
  70. <div class="action-container--div" style="justify-content: left">
  71. <ActionButton text="编辑" v-if="scope.row.status === 1" @click="handleEdit(scope.row.id)" />
  72. <ActionButton text="删除" v-if="scope.row.status === 1" :popconfirm="{
  73. title: '确定要删除?',
  74. }" @confirm="handleDelete(scope.row.id)" />
  75. <ActionButton text="查看" @click="handleView(scope.row.id)" />
  76. <ActionButton text="反馈" @click="handleFeedback(scope.row.id)" v-if="scope.row.status == 2"/>
  77. <!-- <ActionButton text="下发" @click="handleDispatch(scope.row.id)" v-if="scope.row.status === 1"/> -->
  78. <ActionButton text="活动报名" @click="activityRegistration(scope.row.id)" v-if="scope.row.status !== 1"/>
  79. </div>
  80. </template>
  81. </BasicTable>
  82. </div>
  83. </div>
  84. <el-dialog
  85. v-model="showIssueDialog"
  86. title="下发安全文化活动"
  87. width="500px"
  88. destroy-on-close
  89. @open="onIssueDialogOpen"
  90. >
  91. <el-form ref="issueFormRef" :model="issueForm" :rules="issueRules" label-width="140px">
  92. <el-form-item label="具体负责人部门" prop="rectificationDepartmentId">
  93. <el-cascader
  94. v-model="issueForm.rectificationDepartmentId"
  95. :options="issueDeptTree"
  96. :props="cascaderDeptProp"
  97. :show-all-levels="false"
  98. placeholder="请选择具体负责人部门"
  99. filterable
  100. clearable
  101. style="width: 100%"
  102. @change="onIssueDeptChange"
  103. />
  104. </el-form-item>
  105. <el-form-item label="具体负责人" prop="rectificationResponsibleUserId">
  106. <el-select
  107. v-model="issueForm.rectificationResponsibleUserId"
  108. placeholder="选择具体负责人"
  109. filterable
  110. clearable
  111. style="width: 100%"
  112. >
  113. <el-option
  114. v-for="user in issueUserList"
  115. :key="user.id"
  116. :label="user.realname ?? user.username"
  117. :value="user.id"
  118. />
  119. </el-select>
  120. </el-form-item>
  121. <el-form-item label="计划开始日期:" prop="startDate">
  122. <el-date-picker
  123. v-model="issueForm.startDate"
  124. type="date"
  125. placeholder="请选择计划开始日期"
  126. value-format="YYYY-MM-DD"
  127. format="YYYY-MM-DD"
  128. style="width: 100%"
  129. :disabled-date="(date: Date) => {
  130. if (issueForm.endDate) {
  131. return date > new Date(issueForm.endDate);
  132. }
  133. return false;
  134. }"
  135. />
  136. </el-form-item>
  137. <el-form-item label="计划结束日期:" prop="endDate">
  138. <el-date-picker
  139. v-model="issueForm.endDate"
  140. type="date"
  141. placeholder="请选择计划结束日期"
  142. value-format="YYYY-MM-DD"
  143. format="YYYY-MM-DD"
  144. style="width: 100%"
  145. :disabled-date="(date: Date) => {
  146. if (issueForm.startDate) {
  147. return date < new Date(issueForm.startDate);
  148. }
  149. return false;
  150. }"
  151. />
  152. </el-form-item>
  153. </el-form>
  154. <template #footer>
  155. <el-button @click="showIssueDialog = false">取消</el-button>
  156. <el-button type="primary" @click="handleIssueSave">保存</el-button>
  157. </template>
  158. </el-dialog>
  159. <PreviewOnline ref="previewOnlineRef" />
  160. </main>
  161. <BatchImport v-if="batchImportVisible" :visible="batchImportVisible" :import-api-url="importApiUrl"
  162. :template-url="templateUrl" template-name="下载模板" :show-template="false" @close="batchImportVisible = false"
  163. @update="handleUpdate" />
  164. </div>
  165. </template>
  166. <script setup lang="ts">
  167. import { onMounted, reactive, ref } from 'vue';
  168. import { ElMessage } from 'element-plus';
  169. import BasicTable from '@/components/BasicTable.vue';
  170. import useTableConfig from '@/hooks/useTableConfigHook';
  171. import ActionButton from '@/components/ActionButton.vue';
  172. import { TABLE_OPTIONS, INVENTORY_TABLE_COLUMNS } from './configs/tables';
  173. import { useRouter } from 'vue-router';
  174. import {
  175. safetyCultureActivityManagementExecutorFilePage,
  176. deleteSafetyCultureActivityManagement,
  177. getAllDepartments,
  178. activityDistribution,
  179. type safetyCultureFileQuery,
  180. type safetyCultureFilePageQuery,
  181. } from '@/api/safety-culture';
  182. import type { DeptTree } from '@/types/dept/type';
  183. import { downloadByData } from '@/utils/file/download';
  184. import BatchImport from '@/components/batch-import/BatchImport.vue';
  185. import { useGlobSetting } from '@/hooks/setting';
  186. import urlJoin from 'url-join';
  187. import { http } from '@/utils/http/axios';
  188. import { queryAvailableUserList } from '@/api/production-safety/responsibility-implementation';
  189. import PreviewOnline from '@/views/disaster/components/PreviewOnline.vue';
  190. const router = useRouter();
  191. const previewOnlineRef = ref<InstanceType<typeof PreviewOnline>>();
  192. /** 下发弹窗:点击下发打开弹窗,弹窗内部门用 queryAllDeptTree、负责人用 queryAvailableUserList,点击保存才触发下发接口 */
  193. const showIssueDialog = ref(false);
  194. const distributionId = ref<number>(0);
  195. const issueFormRef = ref();
  196. const issueForm = ref({
  197. rectificationDepartmentId: undefined as number | undefined,
  198. rectificationResponsibleUserId: undefined as number | undefined,
  199. rectificationResponsiblePersonName: '' as string,
  200. startDate: '' as string,
  201. endDate: '' as string,
  202. });
  203. const issueRules = {
  204. rectificationDepartmentId: [{ required: true, message: '请选择整改责任部门', trigger: 'change' }],
  205. rectificationResponsibleUserId: [{ required: true, message: '请选择整改负责人', trigger: 'change' }],
  206. startDate: [{ required: true, message: '请选择计划开始日期', trigger: 'change' }],
  207. endDate: [{ required: true, message: '请选择计划结束日期', trigger: 'change' }],
  208. };
  209. /** 下发弹窗部门树,与新增隐患台账复查人员所属部门一致(getAllDepartments 取第一级 children) */
  210. const cascaderDeptProp = {
  211. checkStrictly: true,
  212. expandTrigger: 'hover' as const,
  213. value: 'id',
  214. label: 'deptName',
  215. emitPath: false,
  216. };
  217. const issueDeptTree = ref<DeptTree[]>([]);
  218. const issueUserList = ref<Array<{ id: number; realname?: string; username?: string }>>([]);
  219. // 表格
  220. const basicTableRef = ref<InstanceType<typeof BasicTable>>();
  221. const { tableConfig, pagination } = useTableConfig(INVENTORY_TABLE_COLUMNS, TABLE_OPTIONS);
  222. const tableData = ref<any[]>([]);
  223. const deptNameMap = ref<Record<string, string>>({});
  224. const CATEGORY_NAME_MAP: Record<string, string> = {
  225. '0': '外部院级文件',
  226. '1': '内部院级文件',
  227. '2': '内部院级文件',
  228. };
  229. const normalizeCategoryName = (row: any): string => {
  230. const raw = row?.categoryName ?? row?.classifyName ?? row?.category;
  231. if (raw == null || raw === '') {
  232. return '-';
  233. }
  234. const stringValue = String(raw);
  235. if (stringValue.includes('外部') || stringValue.includes('内部')) {
  236. return stringValue;
  237. }
  238. return CATEGORY_NAME_MAP[stringValue] || stringValue;
  239. };
  240. const normalizeListText = (value: unknown): string => {
  241. if (Array.isArray(value)) {
  242. const list = value.map((item) => String(item).trim()).filter((item) => item);
  243. return list.length ? list.join('、') : '-';
  244. }
  245. if (value == null || value === '') {
  246. return '-';
  247. }
  248. const text = String(value).trim();
  249. if (!text) {
  250. return '-';
  251. }
  252. return text.includes(',') ? text.split(',').map((item) => item.trim()).filter((item) => item).join('、') || '-' : text;
  253. };
  254. const parseIdList = (value: unknown): string[] => {
  255. if (Array.isArray(value)) {
  256. return value.map((item) => String(item).trim()).filter((item) => item);
  257. }
  258. if (value == null || value === '') {
  259. return [];
  260. }
  261. const text = String(value).trim();
  262. if (!text) {
  263. return [];
  264. }
  265. return text.split(',').map((item) => item.trim()).filter((item) => item);
  266. };
  267. const flattenDeptTree = (tree: DeptTree[]): DeptTree[] => {
  268. const result: DeptTree[] = [];
  269. const walk = (nodes: DeptTree[]) => {
  270. nodes.forEach((node) => {
  271. result.push(node);
  272. if (node.children?.length) {
  273. walk(node.children);
  274. }
  275. });
  276. };
  277. walk(tree || []);
  278. return result;
  279. };
  280. const loadDeptNameMap = async () => {
  281. try {
  282. const deptTree = await getAllDepartments();
  283. const flatList = flattenDeptTree(deptTree || []);
  284. const map: Record<string, string> = {};
  285. flatList.forEach((dept) => {
  286. if (dept.id != null) {
  287. map[String(dept.id)] = dept.deptName;
  288. }
  289. });
  290. deptNameMap.value = map;
  291. } catch (error) {
  292. console.error('加载部门字典失败:', error);
  293. deptNameMap.value = {};
  294. }
  295. };
  296. const normalizeCooperateDeptName = (row: any): string => {
  297. const rawName = row?.cooperateDeptNames;
  298. if (rawName) {
  299. return normalizeListText(rawName);
  300. }
  301. const ids = parseIdList(row?.cooperateDeptIds);
  302. if (!ids.length) {
  303. return '-';
  304. }
  305. const names = ids.map((id) => deptNameMap.value[id] || id).filter((item) => item);
  306. return names.length ? names.join('、') : '-';
  307. };
  308. const normalizeResponsibleDeptName = (row: any): string => {
  309. const rawName = row?.responsibleDeptName;
  310. if (rawName) {
  311. return normalizeListText(rawName);
  312. }
  313. const ids = parseIdList(row?.responsibleDeptId);
  314. if (!ids.length) {
  315. return '-';
  316. }
  317. const names = ids.map((id) => deptNameMap.value[id] || id).filter((item) => item);
  318. return names.length ? names.join('、') : '-';
  319. };
  320. const queryParams = reactive<safetyCultureFileQuery>({
  321. keyword: '', // 文件名称/编号(模糊查询)
  322. status: undefined, // 状态:1-启用,0-禁用
  323. classifyName: '', // 分类名称:外部院级文件/内部院级文件
  324. startDate: '', // 上传日期范围-开始日期
  325. endDate: '', // 上传日期范围-结束日期
  326. });
  327. // 上传日期范围(用于日期选择器)
  328. const uploadDateRange = ref<[string, string] | null>(null);
  329. const handleSizeChange = (value: number) => {
  330. pagination.pageSize = value;
  331. getTableData();
  332. };
  333. const handleCurrentChange = (value: number) => {
  334. pagination.pageNumber = value;
  335. getTableData();
  336. };
  337. async function getTableData() {
  338. tableConfig.loading = true;
  339. try {
  340. const pageQuery: safetyCultureFilePageQuery = {
  341. pageNumber: pagination.pageNumber,
  342. pageSize: pagination.pageSize,
  343. queryParam: {
  344. keyword: queryParams.keyword || undefined,
  345. status: queryParams.status,
  346. classifyName: queryParams.classifyName || undefined,
  347. startDate: queryParams.startDate || undefined,
  348. endDate: queryParams.endDate || undefined,
  349. },
  350. };
  351. const res = await safetyCultureActivityManagementExecutorFilePage(pageQuery);
  352. if (res) {
  353. tableData.value = (res.records || []).map((item: any) => ({
  354. ...item,
  355. categoryNameDisplay: normalizeCategoryName(item),
  356. responsibleDeptNameDisplay: normalizeResponsibleDeptName(item),
  357. responsiblePersonNameDisplay: normalizeListText(
  358. item.responsiblePersonName || item.specificPersonName || item.responsiblePersonId,
  359. ),
  360. cooperateDeptNameDisplay: normalizeCooperateDeptName(item),
  361. fileUrlList: JSON.parse(item.attachmentUrl || '[]'),
  362. }));
  363. pagination.total = res.totalRow || 0;
  364. }
  365. } catch (e) {
  366. console.error('获取院级文件列表失败:', e);
  367. tableData.value = [];
  368. pagination.total = 0;
  369. } finally {
  370. tableConfig.loading = false;
  371. }
  372. }
  373. const handleSearch = () => {
  374. // 处理日期范围
  375. if (uploadDateRange.value && uploadDateRange.value.length === 2) {
  376. queryParams.startDate = uploadDateRange.value[0];
  377. queryParams.endDate = uploadDateRange.value[1];
  378. } else {
  379. queryParams.startDate = '';
  380. queryParams.endDate = '';
  381. }
  382. pagination.pageNumber = 1;
  383. getTableData();
  384. };
  385. const handleReset = () => {
  386. queryParams.keyword = '';
  387. queryParams.status = undefined;
  388. queryParams.classifyName = '';
  389. queryParams.startDate = '';
  390. queryParams.endDate = '';
  391. uploadDateRange.value = null;
  392. handleSearch();
  393. };
  394. // 批量导入
  395. const batchImportVisible = ref(false);
  396. const { urlPrefix } = useGlobSetting();
  397. const importApiUrl = ref(urlJoin(urlPrefix, '/productionSafety/academyFile/import'));
  398. const templateUrl = ref('./skyeye-file-upload/sfysecurity/TEMPLATE/import-academy-file-template.xlsx');
  399. const handleImport = () => {
  400. batchImportVisible.value = true;
  401. };
  402. const handleUpdate = () => {
  403. batchImportVisible.value = false;
  404. getTableData();
  405. };
  406. const handleDownload = async () => {
  407. try {
  408. const exportParams: safetyCultureFileQuery = {
  409. keyword: queryParams.keyword || undefined,
  410. status: queryParams.status,
  411. classifyName: queryParams.classifyName || undefined,
  412. startDate: queryParams.startDate || undefined,
  413. endDate: queryParams.endDate || undefined,
  414. };
  415. // const response = await exportAcademyFile(exportParams, queryParams.classifyName || undefined);
  416. // if (response) {
  417. // const fileName = `院级文件管理_${new Date().toISOString().split('T')[0]}.xlsx`;
  418. // downloadByData(response, fileName);
  419. // ElMessage.success('导出成功');
  420. // }
  421. } catch (e) {
  422. console.error('导出院级文件失败:', e);
  423. ElMessage.error('导出失败,请重试');
  424. }
  425. };
  426. const handleCreate = () => {
  427. router.push({
  428. name: 'safetyCultureActivityManagementExecutorActivityRegistration',
  429. query: {
  430. operate: 'safety-culture-material-create',
  431. },
  432. });
  433. };
  434. const handleEdit = (id: number) => {
  435. router.push({
  436. name: 'safetyCultureActivityManagementExecutorActivityRegistration',
  437. query: {
  438. id,
  439. operate: 'safety-culture-material-edit',
  440. },
  441. });
  442. };
  443. const handleDelete = async (id: number) => {
  444. try {
  445. await deleteSafetyCultureActivityManagement(id);
  446. ElMessage.success('删除成功');
  447. getTableData();
  448. } catch (e) {
  449. console.error('删除安全文化活动失败:', e);
  450. ElMessage.error('删除失败,请重试');
  451. }
  452. };
  453. const handleView = (id: number) => {
  454. router.push({
  455. name: 'safetyCultureActivityManagementExecutorItem',
  456. query: {
  457. id,
  458. operate: 'safety-culture-material-view',
  459. },
  460. });
  461. };
  462. const activityRegistration = async (id: number) => {
  463. router.push({
  464. name: 'safetyCultureActivityManagementExecutorActivityRegistration',
  465. query: {
  466. id,
  467. operate: 'safety-culture-material-view',
  468. },
  469. });
  470. };
  471. const handleFeedback = (id: number) => {
  472. router.push({
  473. name: 'safetyCultureActivityManagementExecutorItem',
  474. query: {
  475. id,
  476. operate: 'safety-culture-material-feedback',
  477. },
  478. });
  479. };
  480. const onIssueDialogOpen = async () => {
  481. try {
  482. const [deptRes, userRes] = await Promise.all([
  483. getAllDepartments(),
  484. queryAvailableUserList({ pageNumber: 1, pageSize: 9999, queryParam: {} }),
  485. ]);
  486. const fullTree = (deptRes as DeptTree[]) ?? [];
  487. issueDeptTree.value = Array.isArray(fullTree) && fullTree[0]?.children ? fullTree[0].children : [];
  488. issueUserList.value = (userRes as any)?.records ?? [];
  489. } catch (e) {
  490. console.error('获取部门/用户列表失败:', e);
  491. ElMessage.error(e?.message || e?.data || '加载部门或负责人列表失败');
  492. issueDeptTree.value = [];
  493. issueUserList.value = [];
  494. }
  495. };
  496. const onIssueDeptChange = () => {
  497. issueForm.value.rectificationResponsibleUserId = undefined;
  498. issueForm.value.rectificationResponsiblePersonName = '';
  499. };
  500. const handleDispatch = (id: number) => {
  501. distributionId.value = id;
  502. showIssueDialog.value = true;
  503. };
  504. /** 从部门树中根据 id 查找部门名称 */
  505. function findDeptNameById(nodes: DeptTree[] | undefined, id: number): string {
  506. if (!nodes?.length) return '';
  507. for (const n of nodes) {
  508. if (n.id === id) return n.deptName ?? '';
  509. if (n.children?.length) {
  510. const found = findDeptNameById(n.children, id);
  511. if (found) return found;
  512. }
  513. }
  514. return '';
  515. };
  516. const handleIssueSave = async () => {
  517. await issueFormRef.value?.validate?.().catch(() => {});
  518. const { rectificationDepartmentId, rectificationResponsibleUserId } = issueForm.value;
  519. if (rectificationDepartmentId == null || rectificationResponsibleUserId == null) {
  520. ElMessage.warning('请选择整改责任部门和整改负责人');
  521. return;
  522. }
  523. if (!issueForm.value.startDate || !issueForm.value.endDate) {
  524. ElMessage.warning('请选择计划开始日期和计划结束日期');
  525. return;
  526. }
  527. const selectedUser = issueUserList.value.find((u) => u.id === rectificationResponsibleUserId);
  528. const personName = selectedUser?.realname ?? selectedUser?.username ?? '';
  529. const deptName = findDeptNameById(issueDeptTree.value, rectificationDepartmentId);
  530. try {
  531. await activityDistribution({
  532. id: distributionId.value,
  533. specificDeptId: String(rectificationDepartmentId),
  534. specificPersonId: String(rectificationResponsibleUserId),
  535. startTime: issueForm.value.startDate,
  536. endTime: issueForm.value.endDate,
  537. });
  538. ElMessage.success('下发成功');
  539. showIssueDialog.value = false;
  540. getTableData();
  541. } catch (e) {
  542. console.error('下发失败:', e);
  543. ElMessage.error(e?.message || e?.data || '下发失败,请重试');
  544. }
  545. };
  546. const handlePreview = (url: string) => {
  547. if (url) {
  548. // 根据文件扩展名判断文件类型
  549. const extension = url.split('.').pop()?.toLowerCase() || '';
  550. let fileType: 'pdf' | 'word' | 'excel' | 'ppt' = 'pdf';
  551. if (extension === 'doc' || extension === 'docx') {
  552. fileType = 'word';
  553. } else if (extension === 'xls' || extension === 'xlsx') {
  554. fileType = 'excel';
  555. } else if (extension === 'ppt' || extension === 'pptx') {
  556. fileType = 'ppt';
  557. }
  558. previewOnlineRef.value?.open(url, fileType);
  559. }
  560. };
  561. const previewOnline = (url: string | undefined, type) => {
  562. if (url) {
  563. previewOnlineRef.value?.open(url, type);
  564. }
  565. };
  566. onMounted(() => {
  567. loadDeptNameMap().finally(() => {
  568. getTableData();
  569. });
  570. // loginSw();
  571. });
  572. </script>
  573. <style scoped lang="scss">
  574. @use '@/styles/page-details-layout.scss' as *;
  575. @use '@/styles/page-main-layout.scss' as *;
  576. @use '@/styles/basic-table-action.scss' as *;
  577. @use '@/views/traffic/violation/style/act-search-table.scss' as *;
  578. .action-content {
  579. color: #409eff;
  580. cursor: pointer;
  581. }
  582. </style>