evaluationSystem.vue 25 KB

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