evaluationSystem.vue 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712
  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"> 添加 </el-button>
  11. </div>
  12. <div class="act-search">
  13. <section class="select-box">
  14. <div class="select-box--item">
  15. <span>安全考核表名称:</span>
  16. <el-input
  17. v-model="tableQuery.queryParam.exName"
  18. placeholder="搜索安全考核表名称"
  19. class="act-search-input"
  20. />
  21. </div>
  22. <div class="select-box--item">
  23. <span>状态:</span>
  24. <el-select v-model="tableQuery.queryParam.status" placeholder="请选择状态" clearable>
  25. <el-option
  26. v-for="item in EVALUATION_SYSTEM_STATUS_OPTIONS"
  27. :key="item.value"
  28. :label="item.label"
  29. :value="item.value"
  30. />
  31. </el-select>
  32. </div>
  33. <div class="select-box--item">
  34. <span>所属部门:</span>
  35. <el-input
  36. v-model="tableQuery.queryParam.deptName"
  37. placeholder="请输入所属部门"
  38. class="act-search-input"
  39. />
  40. </div>
  41. <div>
  42. <span>计划日期范围:</span>
  43. <el-date-picker
  44. v-model="dateRange"
  45. type="daterange"
  46. range-separator="至"
  47. start-placeholder="开始日期"
  48. end-placeholder="结束日期"
  49. value-format="YYYY-MM-DD"
  50. format="YYYY-MM-DD"
  51. />
  52. </div>
  53. </section>
  54. <section class="search-btn">
  55. <el-button type="primary" @click="handleSearch">查询</el-button>
  56. <el-button @click="handleReset">重置</el-button>
  57. </section>
  58. </div>
  59. </header>
  60. <div class="batch-table">
  61. <BasicTable
  62. ref="basicTableRef"
  63. :tableData="tableData"
  64. :tableConfig="tableConfig"
  65. @update:pageSize="handleSizeChange"
  66. @update:pageNumber="handleCurrentChange"
  67. >
  68. <template #evaluationTableName="scope">
  69. <span class="evaluation-table-name">{{ scope.row.evaluationTableName }}</span>
  70. </template>
  71. <template #evaluationDocument="scope">
  72. <div
  73. class="file-container--div"
  74. v-for="item in parseAttachments(scope.row.evaluationDocument)"
  75. :key="item.fileUrl"
  76. >
  77. <img
  78. class="file-container--div__icon"
  79. @click="previewOnline(item.fileUrl, item.fileType as keyof typeof FILE_TYPE_ICON)"
  80. :src="FILE_TYPE_ICON[item.fileType]"
  81. />
  82. <span
  83. class="file-container--div__name"
  84. @click="previewOnline(item.fileUrl, item.fileType as keyof typeof FILE_TYPE_ICON)"
  85. >{{ item.fileName }}</span
  86. >
  87. <img
  88. class="file-container--div__download"
  89. :src="DownloadIcon"
  90. @click="downloadFile(item.fileUrl, item.fileName)"
  91. />
  92. </div>
  93. </template>
  94. <template #status="scope">
  95. <span>
  96. {{ EVALUATION_SYSTEM_STATUS_LABEL[String(scope.row.status)] || '-' }}
  97. </span>
  98. </template>
  99. <template #action="scope">
  100. <div class="action-container--div" style="justify-content: left">
  101. <!-- 未下发:编辑 / 删除 / 下发 -->
  102. <template v-if="Number(scope.row.status) === 0">
  103. <ActionButton text="编辑" @click="handleEdit(scope.row.id)" />
  104. <ActionButton
  105. text="删除"
  106. :popconfirm="{
  107. title: '确定要删除?',
  108. }"
  109. @confirm="handleDelete(scope.row.id)"
  110. />
  111. <ActionButton text="下发" @click="handleIssue(scope.row.id)" />
  112. </template>
  113. <!-- 待反馈:作废 / 考核对象 -->
  114. <template v-else-if="Number(scope.row.status) === 2">
  115. <ActionButton
  116. text="作废"
  117. :popconfirm="{
  118. title: '确定要作废?',
  119. }"
  120. @confirm="handleCancel(scope.row.id)"
  121. />
  122. <ActionButton text="考核对象" @click="handleTarget(scope.row.id)" />
  123. </template>
  124. <!-- 待评分:评分 / 作废 / 考核对象 -->
  125. <template v-else-if="Number(scope.row.status) === 3">
  126. <ActionButton text="评分" @click="handleScore(scope.row.id)" />
  127. <ActionButton
  128. text="作废"
  129. :popconfirm="{
  130. title: '确定要作废?',
  131. }"
  132. @confirm="handleCancel(scope.row.id)"
  133. />
  134. <ActionButton text="考核对象" @click="handleTarget(scope.row.id)" />
  135. </template>
  136. <!-- 待审核:审核 / 作废 / 考核对象 -->
  137. <template v-else-if="Number(scope.row.status) === 4">
  138. <ActionButton text="审核" @click="handleAudit(scope.row.id)" />
  139. <ActionButton
  140. text="作废"
  141. :popconfirm="{
  142. title: '确定要作废?',
  143. }"
  144. @confirm="handleCancel(scope.row.id)"
  145. />
  146. <ActionButton text="考核对象" @click="handleTarget(scope.row.id)" />
  147. </template>
  148. <!-- 已作废:删除 / 考核对象 -->
  149. <template v-else-if="Number(scope.row.status) === 5">
  150. <ActionButton
  151. text="删除"
  152. :popconfirm="{
  153. title: '确定要删除?',
  154. }"
  155. @confirm="handleDelete(scope.row.id)"
  156. />
  157. <ActionButton text="考核对象" @click="handleTarget(scope.row.id)" />
  158. </template>
  159. <!-- 已完成:删除 / 考核对象 / 部门排序 / 先进个人 -->
  160. <template v-else-if="Number(scope.row.status) === 1">
  161. <ActionButton
  162. text="删除"
  163. :popconfirm="{
  164. title: '确定要删除?',
  165. }"
  166. @confirm="handleDelete(scope.row.id)"
  167. />
  168. <ActionButton text="考核对象" @click="handleTarget(scope.row.id)" />
  169. <ActionButton text="部门排序" @click="handleAdvancedGroup(scope.row.id)" />
  170. <ActionButton text="先进个人" @click="handleAdvancedIndividual(scope.row.id)" />
  171. </template>
  172. </div>
  173. </template>
  174. </BasicTable>
  175. </div>
  176. </div>
  177. <!-- 下发弹窗 -->
  178. <el-dialog v-model="issueDialogVisible" title="下发考核表" width="480px" destroy-on-close>
  179. <el-form :model="issueForm" label-width="130px" class="issue-dialog-form">
  180. <el-form-item label="部门名称:">
  181. <el-cascader
  182. ref="issueDeptCascaderRef"
  183. v-model="issueDeptIds"
  184. :options="deptTree"
  185. :props="cascaderDeptProp"
  186. :show-all-levels="false"
  187. placeholder="请选择部门(可多选)"
  188. filterable
  189. clearable
  190. collapse-tags
  191. collapse-tags-tooltip
  192. style="width: 100%"
  193. @change="handleIssueDeptChange"
  194. />
  195. </el-form-item>
  196. <el-form-item label="用户名称:">
  197. <el-select
  198. v-model="issueForm.userGroupId"
  199. placeholder="请选择用户组"
  200. filterable
  201. clearable
  202. style="width: 100%"
  203. >
  204. <el-option v-for="item in userGroupOptions" :key="item.id" :label="item.name" :value="item.id" />
  205. </el-select>
  206. </el-form-item>
  207. <el-form-item label="部门自评审核人:">
  208. <el-select
  209. v-model="issueForm.deptSelfApproveUserId"
  210. placeholder="请选择部门自评审核人"
  211. filterable
  212. clearable
  213. style="width: 100%"
  214. >
  215. <el-option
  216. v-for="user in deptSelfApproveUserList"
  217. :key="user.id"
  218. :label="user.realname"
  219. :value="user.id"
  220. />
  221. </el-select>
  222. </el-form-item>
  223. <el-form-item label="计划开始日期:">
  224. <el-date-picker
  225. v-model="issueForm.startDate"
  226. type="date"
  227. placeholder="请选择计划开始日期"
  228. value-format="YYYY-MM-DD"
  229. format="YYYY-MM-DD"
  230. style="width: 100%"
  231. :disabled-date="(date: Date) => {
  232. if (issueForm.endDate) {
  233. return date > new Date(issueForm.endDate);
  234. }
  235. return false;
  236. }"
  237. />
  238. </el-form-item>
  239. <el-form-item label="计划结束日期:">
  240. <el-date-picker
  241. v-model="issueForm.endDate"
  242. type="date"
  243. placeholder="请选择计划结束日期"
  244. value-format="YYYY-MM-DD"
  245. format="YYYY-MM-DD"
  246. style="width: 100%"
  247. :disabled-date="(date: Date) => {
  248. if (issueForm.startDate) {
  249. return date < new Date(issueForm.startDate);
  250. }
  251. return false;
  252. }"
  253. />
  254. </el-form-item>
  255. </el-form>
  256. <template #footer>
  257. <span class="dialog-footer">
  258. <el-button @click="issueDialogVisible = false">取消</el-button>
  259. <el-button type="primary" @click="handleIssueConfirm">确定</el-button>
  260. </span>
  261. </template>
  262. </el-dialog>
  263. </main>
  264. <PreviewOnline ref="previewOnlineRef" />
  265. </div>
  266. </template>
  267. <script lang="ts" setup>
  268. import { onMounted, reactive, ref } from 'vue';
  269. import BasicTable from '@/components/BasicTable.vue';
  270. import useTableConfig from '@/hooks/useTableConfigHook';
  271. import ActionButton from '@/components/ActionButton.vue';
  272. import { TABLE_OPTIONS, EVALUATION_SYSTEM_TABLE_COLUMNS } from './configs/tables';
  273. import { EVALUATION_SYSTEM_STATUS_OPTIONS, EVALUATION_SYSTEM_STATUS_LABEL } from './configs/status';
  274. import { useRouter } from 'vue-router';
  275. import type { QueryPageRequest } from '@/types/basic-query';
  276. import {
  277. querySecurityExamine,
  278. deleteSecurityExamine,
  279. saveSecurityExamineIssue,
  280. updateSecurityExamineRepeal,
  281. } from '@/api/evaluationSystem';
  282. import type { EvaluationSystemQueryParam } from '@/api/evaluationSystem';
  283. import { ElMessage } from 'element-plus';
  284. import DownloadIcon from '@/views/disaster/disaster-control/src/svg/download.svg';
  285. import { downloadFile } from '@/views/disaster/utils';
  286. import PreviewOnline from '@/views/disaster/components/PreviewOnline.vue';
  287. import { FILE_TYPE_ICON } from '@/components/UploadFiles/constants';
  288. import { getAllDepartments } from '@/api/auth/dept';
  289. import type { DeptTree } from '@/types/dept/type';
  290. import { queryUserGroupPage } from '@/api/system/person-group';
  291. import type { PersonGroupListItem } from '@/types/person-group/type';
  292. import { queryAvailableUserList } from '@/api/production-safety/responsibility-implementation';
  293. import type { UserLisItem } from '@/api/system/user-operate';
  294. const router = useRouter();
  295. // 表格
  296. const basicTableRef = ref<InstanceType<typeof BasicTable>>();
  297. const { tableConfig, pagination } = useTableConfig(EVALUATION_SYSTEM_TABLE_COLUMNS, TABLE_OPTIONS);
  298. const tableData = ref<any[]>([]);
  299. // 日期范围(用于日期选择器)
  300. const dateRange = ref<[string, string] | null>(null);
  301. // 下发弹窗相关
  302. const issueDialogVisible = ref(false);
  303. const currentIssueId = ref<number | null>(null);
  304. const issueForm = reactive({
  305. departmentName: '',
  306. startDate: '',
  307. endDate: '',
  308. userGroupId: undefined as number | undefined,
  309. deptSelfApproveUserId: undefined as number | undefined, // 部门自评审核人ID
  310. });
  311. const issueDeptIds = ref<number[]>([]);
  312. // 用户组(用于选择用户名称)
  313. const userGroupOptions = ref<PersonGroupListItem[]>([]);
  314. // 部门自评审核人用户列表
  315. const deptSelfApproveUserList = ref<UserLisItem[]>([]);
  316. // 部门树(复用物品领取记录的部门字段下拉框逻辑)
  317. const issueDeptCascaderRef = ref();
  318. const deptTree = ref<DeptTree[]>([]);
  319. const cascaderDeptProp = {
  320. checkStrictly: true,
  321. expandTrigger: 'hover' as const,
  322. value: 'id',
  323. label: 'deptName',
  324. emitPath: false,
  325. multiple: true,
  326. };
  327. const getDeptTreeData = async () => {
  328. try {
  329. const res = await getAllDepartments();
  330. deptTree.value = res?.[0]?.children ?? [];
  331. } catch (e) {
  332. console.error('获取部门树失败:', e);
  333. }
  334. };
  335. // 获取用户组列表(用于下发时选择用户名称)
  336. const getUserGroupOptions = async () => {
  337. try {
  338. const res = await queryUserGroupPage({
  339. pageNumber: 1,
  340. pageSize: 9999,
  341. queryParam: '',
  342. });
  343. userGroupOptions.value = res?.records ?? [];
  344. } catch (e) {
  345. console.error('获取用户组列表失败:', e);
  346. userGroupOptions.value = [];
  347. }
  348. };
  349. // 获取部门自评审核人用户列表
  350. const getDeptSelfApproveUserList = async () => {
  351. try {
  352. const res = await queryAvailableUserList({
  353. pageNumber: 1,
  354. pageSize: 9999,
  355. queryParam: {}, // 不传递 deptId 参数
  356. });
  357. deptSelfApproveUserList.value = res?.records || [];
  358. } catch (e) {
  359. console.error('获取部门自评审核人列表失败:', e);
  360. deptSelfApproveUserList.value = [];
  361. }
  362. };
  363. const tableQuery = reactive<QueryPageRequest<EvaluationSystemQueryParam>>({
  364. pageNumber: pagination.pageNumber,
  365. pageSize: pagination.pageSize,
  366. queryParam: {
  367. exName: '', // 考核表名称
  368. status: undefined, // 状态(数字或 undefined)
  369. deptName: '', // 所属部门
  370. planStartTime: '', // 计划开始时间
  371. planEndTime: '', // 计划结束时间
  372. },
  373. });
  374. const handleSizeChange = (value: number) => {
  375. pagination.pageSize = value;
  376. tableQuery.pageSize = value;
  377. getTableData();
  378. };
  379. const handleCurrentChange = (value: number) => {
  380. pagination.pageNumber = value;
  381. tableQuery.pageNumber = value;
  382. getTableData();
  383. };
  384. async function getTableData() {
  385. tableConfig.loading = true;
  386. try {
  387. const res = await querySecurityExamine(tableQuery);
  388. if (res) {
  389. // 映射返回数据字段到表格字段
  390. tableData.value = res.records.map((item) => ({
  391. id: item.id,
  392. evaluationTableName: item.exName, // 考核表名称
  393. status: item.status, // 状态
  394. statusName: item.statusName, // 状态名称
  395. issueDepartment: item.deptNames, // 下发部门
  396. issueCount: item.issueNum, // 下发数(接口未返回,暂时设为0)
  397. feedbackCount: item.replyNum, // 反馈数(接口未返回,暂时设为0)
  398. feedbackRatio: item.replyRate, // 反馈比例(接口未返回,暂时设为0%)
  399. evaluationDocument: item.attachments, // 考核文档
  400. plannedCompletionTime:
  401. item.planStartTime && item.planEndTime
  402. ? `${item.planStartTime} 至 ${item.planEndTime}`
  403. : item.planStartTime || item.planEndTime || '-', // 计划完成时间
  404. }));
  405. pagination.total = res.totalRow;
  406. }
  407. } catch (e) {
  408. console.error('获取安全考核管理列表失败:', e);
  409. tableData.value = [];
  410. pagination.total = 0;
  411. } finally {
  412. tableConfig.loading = false;
  413. }
  414. }
  415. const handleSearch = () => {
  416. // 处理日期范围
  417. if (dateRange.value && dateRange.value.length === 2) {
  418. tableQuery.queryParam.planStartTime = dateRange.value[0];
  419. tableQuery.queryParam.planEndTime = dateRange.value[1];
  420. } else {
  421. tableQuery.queryParam.planStartTime = '';
  422. tableQuery.queryParam.planEndTime = '';
  423. }
  424. pagination.pageNumber = 1;
  425. tableQuery.pageNumber = 1;
  426. getTableData();
  427. };
  428. const handleReset = () => {
  429. tableQuery.queryParam.exName = '';
  430. tableQuery.queryParam.status = undefined;
  431. tableQuery.queryParam.deptName = '';
  432. tableQuery.queryParam.planStartTime = '';
  433. tableQuery.queryParam.planEndTime = '';
  434. dateRange.value = null;
  435. handleSearch();
  436. };
  437. const handleCreate = () => {
  438. router.push({
  439. name: 'EvaluationSystemItem',
  440. query: {
  441. operate: 'evaluationSystem-create',
  442. },
  443. });
  444. };
  445. const handleEdit = (id: number) => {
  446. router.push({
  447. name: 'EvaluationSystemItem',
  448. query: {
  449. id,
  450. operate: 'evaluationSystem-edit',
  451. },
  452. });
  453. };
  454. const handleDelete = async (id: number) => {
  455. try {
  456. await deleteSecurityExamine(id);
  457. ElMessage.success('删除成功');
  458. getTableData();
  459. } catch (e: any) {
  460. console.error('删除失败:', e);
  461. ElMessage.error(e?.message || '删除失败,请重试');
  462. }
  463. };
  464. // 下发
  465. const handleIssue = async (id: number) => {
  466. currentIssueId.value = id;
  467. issueForm.departmentName = '';
  468. issueForm.startDate = '';
  469. issueForm.endDate = '';
  470. issueForm.userGroupId = undefined;
  471. issueForm.deptSelfApproveUserId = undefined;
  472. issueDeptIds.value = [];
  473. issueDialogVisible.value = true;
  474. // 弹窗打开时才加载下发弹窗所需数据
  475. await Promise.all([getDeptTreeData(), getUserGroupOptions(), getDeptSelfApproveUserList()]);
  476. };
  477. const handleIssueDeptChange = () => {
  478. const nodes = issueDeptCascaderRef.value?.getCheckedNodes?.() ?? [];
  479. issueForm.departmentName = nodes
  480. .map((n: { label?: string; pathLabels?: string[] }) => n.pathLabels?.join('/') || n.label || '')
  481. .filter(Boolean)
  482. .join(',');
  483. };
  484. const handleIssueConfirm = async () => {
  485. if (!currentIssueId.value) {
  486. ElMessage.error('缺少考核表ID');
  487. return;
  488. }
  489. if (!issueDeptIds.value?.length) {
  490. ElMessage.error('请至少选择一个部门');
  491. return;
  492. }
  493. // 验证日期:开始日期不能大于结束日期
  494. if (issueForm.startDate && issueForm.endDate) {
  495. const startDate = new Date(issueForm.startDate);
  496. const endDate = new Date(issueForm.endDate);
  497. if (startDate > endDate) {
  498. ElMessage.error('计划开始日期不能大于计划结束日期');
  499. return;
  500. }
  501. }
  502. try {
  503. const payload = {
  504. id: currentIssueId.value,
  505. deptNames: issueForm.departmentName,
  506. deptIds: issueDeptIds.value,
  507. getUserGroupId: issueForm.userGroupId,
  508. deptSelfApproveUserId: issueForm.deptSelfApproveUserId,
  509. planStartTime: issueForm.startDate || undefined,
  510. planEndTime: issueForm.endDate || undefined,
  511. };
  512. await saveSecurityExamineIssue(payload);
  513. ElMessage.success('下发成功');
  514. issueDialogVisible.value = false;
  515. getTableData();
  516. } catch (e) {
  517. console.error('下发失败:', e);
  518. ElMessage.error('下发失败,请重试');
  519. }
  520. };
  521. // 作废
  522. const handleCancel = async (id: number) => {
  523. try {
  524. await updateSecurityExamineRepeal(id);
  525. ElMessage.success('作废成功');
  526. getTableData();
  527. } catch (e: any) {
  528. console.error('作废失败:', e);
  529. ElMessage.error(e?.message || '作废失败,请重试');
  530. }
  531. };
  532. // 评分:跳转到考核对象列表,并仅展示“待评分”tab
  533. const handleScore = (id: number) => {
  534. router.push({
  535. name: 'EvaluationSystemItem',
  536. query: {
  537. id,
  538. operate: 'evaluationSystem-target',
  539. singleStatus: '3', // 3 表示“待评分”
  540. },
  541. });
  542. };
  543. // 审核:跳转到考核对象列表,并仅展示“待审核”tab
  544. const handleAudit = (id: number) => {
  545. router.push({
  546. name: 'EvaluationSystemItem',
  547. query: {
  548. id,
  549. operate: 'evaluationSystem-target',
  550. singleStatus: '4', // 4 表示“待审核”
  551. },
  552. });
  553. };
  554. // 考核对象
  555. const handleTarget = (id: number) => {
  556. router.push({
  557. name: 'EvaluationSystemItem',
  558. query: {
  559. id,
  560. operate: 'evaluationSystem-target',
  561. },
  562. });
  563. };
  564. // 部门排序
  565. const handleAdvancedGroup = (id: number) => {
  566. router.push({
  567. name: 'EvaluationSystemItem',
  568. query: {
  569. id,
  570. operate: 'evaluationSystem-advanced-group',
  571. },
  572. });
  573. };
  574. // 先进个人
  575. const handleAdvancedIndividual = (id: number) => {
  576. router.push({
  577. name: 'EvaluationSystemItem',
  578. query: {
  579. id,
  580. operate: 'evaluationSystem-advanced-person',
  581. },
  582. });
  583. };
  584. const handleView = (id: number) => {
  585. router.push({
  586. name: 'EvaluationSystemItem',
  587. query: {
  588. id,
  589. operate: 'evaluationSystem-view',
  590. },
  591. });
  592. };
  593. // 预览
  594. const previewOnlineRef = ref<InstanceType<typeof PreviewOnline>>();
  595. const previewOnline = (url: string | undefined, type: keyof typeof FILE_TYPE_ICON) => {
  596. if (url) {
  597. previewOnlineRef.value?.open(url, type);
  598. }
  599. };
  600. // 解析逗号分隔的URL字符串为文件列表
  601. const parseAttachments = (
  602. attachmentsStr: string | undefined,
  603. ): Array<{
  604. fileUrl: string;
  605. fileName: string;
  606. fileType: string;
  607. }> => {
  608. if (!attachmentsStr || !attachmentsStr.trim()) {
  609. return [];
  610. }
  611. // 按逗号分割URL
  612. const urls = attachmentsStr
  613. .split(',')
  614. .map((url) => url.trim())
  615. .filter((url) => url);
  616. return urls.map((url) => {
  617. // 从URL中提取文件名
  618. const urlParts = url.split('/');
  619. const fileName = urlParts[urlParts.length - 1] || '未知文件';
  620. // 根据文件扩展名判断文件类型
  621. const extension = fileName.split('.').pop()?.toLowerCase() || '';
  622. let fileType = 'pdf';
  623. if (extension === 'doc' || extension === 'docx') {
  624. fileType = 'word';
  625. } else if (extension === 'xls' || extension === 'xlsx') {
  626. fileType = 'excel';
  627. } else if (extension === 'ppt' || extension === 'pptx') {
  628. fileType = 'ppt';
  629. }
  630. return {
  631. fileUrl: url,
  632. fileName,
  633. fileType,
  634. };
  635. });
  636. };
  637. onMounted(() => {
  638. getTableData();
  639. });
  640. </script>
  641. <style scoped lang="scss">
  642. @use '@/styles/page-details-layout.scss' as *;
  643. @use '@/styles/page-main-layout.scss' as *;
  644. @use '@/styles/basic-table-action.scss' as *;
  645. @use '@/styles/basic-table-file.scss' as *;
  646. @use '@/views/traffic/violation/style/act-search-table.scss' as *;
  647. .evaluation-table-name {
  648. color: #1777ff;
  649. white-space: nowrap;
  650. overflow: hidden;
  651. text-overflow: ellipsis;
  652. display: block;
  653. }
  654. .issue-dialog-form {
  655. :deep(.el-form-item__content) {
  656. width: 100%;
  657. }
  658. }
  659. </style>