evaluationDepartment.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  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 class="act-search">
  10. <section class="select-box">
  11. <div class="select-box--item">
  12. <span>考核表名称:</span>
  13. <el-input
  14. v-model="tableQuery.queryParam.evaluationTableName"
  15. placeholder="搜索考核表名称"
  16. class="act-search-input"
  17. />
  18. </div>
  19. <div class="select-box--item">
  20. <span>状态:</span>
  21. <el-select
  22. v-model="tableQuery.queryParam.status"
  23. placeholder="请选择状态"
  24. clearable
  25. >
  26. <el-option
  27. v-for="item in EVALUATION_SYSTEM_STATUS_OPTIONS"
  28. :key="item.value"
  29. :label="item.label"
  30. :value="item.value"
  31. />
  32. </el-select>
  33. </div>
  34. <div>
  35. <span>计划日期范围:</span>
  36. <el-date-picker
  37. v-model="tableQuery.queryParam.dateRange"
  38. type="daterange"
  39. range-separator="至"
  40. start-placeholder="开始日期"
  41. end-placeholder="结束日期"
  42. value-format="YYYY-MM-DD"
  43. format="YYYY-MM-DD"
  44. />
  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
  55. ref="basicTableRef"
  56. :tableData="tableData"
  57. :tableConfig="tableConfig"
  58. @update:pageSize="handleSizeChange"
  59. @update:pageNumber="handleCurrentChange"
  60. @update:selection="handleSelectionChange"
  61. >
  62. <template #status="scope">
  63. <span>
  64. {{ EVALUATION_SYSTEM_STATUS_LABEL[String(scope.row.status)] || scope.row.statusName || '-' }}
  65. </span>
  66. </template>
  67. <template #evaluationDocument="scope">
  68. <!-- <div
  69. class="file-container--div"
  70. v-for="item in parseAttachments(scope.row.evaluationDocument)"
  71. :key="item.fileUrl"
  72. >
  73. <img
  74. class="file-container--div__icon"
  75. @click="previewOnline(item.fileUrl, item.fileType as keyof typeof FILE_TYPE_ICON)"
  76. :src="FILE_TYPE_ICON[item.fileType]"
  77. />
  78. <span
  79. class="file-container--div__name"
  80. @click="previewOnline(item.fileUrl, item.fileType as keyof typeof FILE_TYPE_ICON)"
  81. >{{ item.fileName }}</span
  82. >
  83. <img
  84. class="file-container--div__download"
  85. :src="DownloadIcon"
  86. @click="downloadFile(item.fileUrl, item.fileName)"
  87. />
  88. </div> -->
  89. <div class="file-list">
  90. <div class="file-item" v-for="file in scope.row.evaluationDocument" :key="file.fileId">
  91. <span class="file-item--name">{{ file.fileName }}</span>
  92. <div class="file-item--footer">
  93. <el-button link type="primary" @click="previewOnline(file.fileUrl, file.fileType)"
  94. >预览</el-button
  95. >
  96. <el-button link type="primary" @click.stop="downloadFile(file.fileUrl, file.fileName)"
  97. >下载</el-button
  98. >
  99. </div>
  100. </div>
  101. </div>
  102. </template>
  103. <template #action="scope">
  104. <div class="action-container--div" style="justify-content: left">
  105. <!-- 待反馈(2):显示反馈 -->
  106. <template v-if="Number(scope.row.status) === 2">
  107. <ActionButton text="反馈" @click="handleFeedback(scope.row.id)" />
  108. </template>
  109. <!-- 已完成(1):显示反馈和先进个人申报 -->
  110. <template v-else-if="Number(scope.row.status) === 1">
  111. <!-- <ActionButton text="反馈" @click="handleFeedback(scope.row.id)" /> -->
  112. <ActionButton text="先进个人申报" @click="handleAdvancedPerson(scope.row)" />
  113. </template>
  114. <!-- 已作废(5):显示反馈 -->
  115. <template v-else-if="Number(scope.row.status) === 5">
  116. <ActionButton text="反馈" @click="handleFeedback(scope.row.id)" />
  117. </template>
  118. </div>
  119. </template>
  120. </BasicTable>
  121. </div>
  122. </div>
  123. </main>
  124. <PreviewOnline ref="previewOnlineRef" />
  125. </div>
  126. </template>
  127. <script lang="ts" setup>
  128. import { onMounted, reactive, ref } from 'vue';
  129. import BasicTable from '@/components/BasicTable.vue';
  130. import useTableConfig from '@/hooks/useTableConfigHook';
  131. import ActionButton from '@/components/ActionButton.vue';
  132. import { TABLE_OPTIONS, EVALUATION_DEPARTMENT_TABLE_COLUMNS } from './configs/tables';
  133. import { EVALUATION_SYSTEM_STATUS_OPTIONS, EVALUATION_SYSTEM_STATUS_LABEL } from '../evaluationSystem/configs/status';
  134. import { useRouter } from 'vue-router';
  135. import type { QueryPageRequest } from '@/types/basic-query';
  136. import DownloadIcon from '@/views/disaster/disaster-control/src/svg/download.svg';
  137. import { downloadFile } from '@/views/disaster/utils';
  138. import PreviewOnline from '@/views/disaster/components/PreviewOnline.vue';
  139. import { FILE_TYPE_ICON } from '@/components/UploadFiles/constants';
  140. import { querySecurityExamineDept } from '@/api/evaluationSystem';
  141. import type { QuerySecurityExamineDeptParams } from '@/api/evaluationSystem';
  142. const router = useRouter();
  143. // 表格
  144. const basicTableRef = ref<InstanceType<typeof BasicTable>>();
  145. const { tableConfig, pagination } = useTableConfig(EVALUATION_DEPARTMENT_TABLE_COLUMNS, TABLE_OPTIONS);
  146. const tableData = ref<any[]>([]);
  147. const tableQuery = reactive<QueryPageRequest<any>>({
  148. pageNumber: pagination.pageNumber,
  149. pageSize: pagination.pageSize,
  150. queryParam: {
  151. evaluationTableName: '',
  152. status: undefined as number | undefined,
  153. dateRange: null,
  154. startTime: '',
  155. endTime: '',
  156. },
  157. });
  158. const handleSizeChange = (value: number) => {
  159. pagination.pageSize = value;
  160. tableQuery.pageSize = value;
  161. getTableData();
  162. };
  163. const handleCurrentChange = (value: number) => {
  164. pagination.pageNumber = value;
  165. tableQuery.pageNumber = value;
  166. getTableData();
  167. };
  168. const selectionItems = ref<any[]>([]);
  169. const handleSelectionChange = (selection: any[]) => {
  170. selectionItems.value = selection;
  171. };
  172. async function getTableData() {
  173. tableConfig.loading = true;
  174. try {
  175. const params: QuerySecurityExamineDeptParams = {
  176. pageNumber: tableQuery.pageNumber,
  177. pageSize: tableQuery.pageSize,
  178. queryParam: {
  179. exName: tableQuery.queryParam.evaluationTableName || undefined,
  180. status: tableQuery.queryParam.status !== undefined && tableQuery.queryParam.status !== null
  181. ? tableQuery.queryParam.status
  182. : undefined,
  183. deptName: undefined, // 部门名称(如果需要可以添加搜索条件)
  184. planStartTime: tableQuery.queryParam.startTime || undefined,
  185. planEndTime: tableQuery.queryParam.endTime || undefined,
  186. },
  187. };
  188. const res = await querySecurityExamineDept(params);
  189. if (res) {
  190. // 映射返回数据字段到表格字段
  191. tableData.value = res.records.map((item) => ({
  192. id: item.id,
  193. evaluationTableName: item.exName, // 考核表名称
  194. status: item.status, // 状态(使用数字状态码)
  195. statusName: item.statusName, // 状态名称
  196. evaluationDocument: JSON.parse(item.attachments || '[]'), // 考核文档
  197. plannedCompletionTime: item.planEndTime || '-', // 计划完成时间(使用计划结束时间)
  198. // 保留原始数据,供其他操作使用
  199. psemId: item.psemId,
  200. deptId: item.deptId,
  201. deptName: item.deptName,
  202. scores: item.scores,
  203. scoreRank: item.scoreRank,
  204. isAdvancedGroup: item.isAdvancedGroup,
  205. }));
  206. pagination.total = res.totalRow;
  207. }
  208. } catch (e) {
  209. console.error('获取部门考核列表失败:', e);
  210. tableData.value = [];
  211. pagination.total = 0;
  212. } finally {
  213. tableConfig.loading = false;
  214. }
  215. }
  216. const handleSearch = () => {
  217. // 处理日期范围
  218. if (tableQuery.queryParam.dateRange && tableQuery.queryParam.dateRange.length === 2) {
  219. tableQuery.queryParam.startTime = tableQuery.queryParam.dateRange[0];
  220. tableQuery.queryParam.endTime = tableQuery.queryParam.dateRange[1];
  221. } else {
  222. tableQuery.queryParam.startTime = '';
  223. tableQuery.queryParam.endTime = '';
  224. }
  225. pagination.pageNumber = 1;
  226. tableQuery.pageNumber = 1;
  227. getTableData();
  228. };
  229. const handleReset = () => {
  230. tableQuery.queryParam.evaluationTableName = '';
  231. tableQuery.queryParam.status = undefined;
  232. tableQuery.queryParam.dateRange = null;
  233. handleSearch();
  234. };
  235. const handleFeedback = (id: number) => {
  236. router.push({
  237. name: 'EvaluationDepartmentItem',
  238. query: {
  239. id,
  240. operate: 'evaluationDepartment-feedback',
  241. },
  242. });
  243. };
  244. const handleAdvancedPerson = (row: any) => {
  245. router.push({
  246. name: 'EvaluationDepartmentItem',
  247. query: {
  248. id: row.id,
  249. operate: 'evaluationDepartment-advanced-person',
  250. isAdvancedGroup: row.isAdvancedGroup,
  251. },
  252. });
  253. };
  254. // 预览
  255. const previewOnlineRef = ref<InstanceType<typeof PreviewOnline>>();
  256. const previewOnline = (url: string | undefined, type: keyof typeof FILE_TYPE_ICON) => {
  257. if (url) {
  258. previewOnlineRef.value?.open(url, type);
  259. }
  260. };
  261. // 解析逗号分隔的URL字符串为文件列表
  262. const parseAttachments = (attachmentsStr: string | undefined): Array<{
  263. fileUrl: string;
  264. fileName: string;
  265. fileType: string;
  266. }> => {
  267. if (!attachmentsStr || !attachmentsStr.trim()) {
  268. return [];
  269. }
  270. // 按逗号分割URL
  271. const urls = attachmentsStr.split(',').map(url => url.trim()).filter(url => url);
  272. return urls.map((url) => {
  273. // 从URL中提取文件名
  274. const urlParts = url.split('/');
  275. const fileName = urlParts[urlParts.length - 1] || '未知文件';
  276. // 根据文件扩展名判断文件类型
  277. const extension = fileName.split('.').pop()?.toLowerCase() || '';
  278. let fileType = 'pdf';
  279. if (extension === 'doc' || extension === 'docx') {
  280. fileType = 'word';
  281. } else if (extension === 'xls' || extension === 'xlsx') {
  282. fileType = 'excel';
  283. } else if (extension === 'ppt' || extension === 'pptx') {
  284. fileType = 'ppt';
  285. }
  286. return {
  287. fileUrl: url,
  288. fileName,
  289. fileType,
  290. };
  291. });
  292. };
  293. onMounted(() => {
  294. getTableData();
  295. });
  296. </script>
  297. <style scoped lang="scss">
  298. @use '@/styles/page-details-layout.scss' as *;
  299. @use '@/styles/page-main-layout.scss' as *;
  300. @use '@/styles/basic-table-action.scss' as *;
  301. @use '@/styles/basic-table-file.scss' as *;
  302. @use '@/views/traffic/violation/style/act-search-table.scss' as *;
  303. </style>