PageDisposalManagement.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  1. <template>
  2. <div class="disaster-precaution-container">
  3. <header class="disaster-precaution-container__header">
  4. <span class="disaster-precaution-container__title">灾害处置管理</span>
  5. </header>
  6. <main class="disaster-precaution-container__main">
  7. <div class="disaster-precaution">
  8. <header class="disaster-precaution__header">
  9. <el-button
  10. type="primary"
  11. class="disaster-precaution__header--button"
  12. :icon="Plus"
  13. v-if="disposalManagementPermissions"
  14. @click="handleCreateDisposalManagement"
  15. >
  16. 创建灾害处置任务
  17. </el-button>
  18. <Search
  19. :searchConfig="DISPOSAL_MANAGEMENT_SEARCH_CONFIG"
  20. :searchData="searchData"
  21. @update:searchData="handleSearch"
  22. >
  23. <template #reportDeptIds>
  24. <el-select
  25. v-model="searchData.reportDeptIds"
  26. multiple
  27. placeholder="请选择上报单位"
  28. filterable
  29. class="custom-select"
  30. @change="handleChangeReportDeptIds"
  31. >
  32. <el-option v-for="item in firstLevelDepts" :key="item.id" :label="item.deptName" :value="item.id" />
  33. </el-select>
  34. </template>
  35. </Search>
  36. </header>
  37. <section class="disaster-precaution__section">
  38. <div
  39. class="collapse-container"
  40. v-loading="collapseLoading"
  41. :class="disposalManagementPermissions ? 'collapse-container--permission' : 'collapse-container--default'"
  42. >
  43. <div class="empty-container" v-if="collapseList.length === 0">
  44. <img :src="Empty" />
  45. <span>暂无数据</span>
  46. </div>
  47. <template v-else>
  48. <CollapseItem
  49. ref="collapseItemRef"
  50. v-for="item in collapseList"
  51. :key="item.id"
  52. :name="item.taskName"
  53. :defaultOpen="item.id === collapseList[0].id"
  54. >
  55. <template #viewOperation>
  56. <el-tooltip
  57. :content="isViewTask(item.tableData[0].disasterReportTaskInfoList) ? '查看' : '任务尚未发布'"
  58. placement="top"
  59. effect="light"
  60. >
  61. <img
  62. :src="ViewDocument"
  63. :class="[
  64. 'collapse-item__icon',
  65. { 'collapse-item__icon--disabled': !isViewTask(item.tableData[0].disasterReportTaskInfoList) },
  66. ]"
  67. @click.stop="isViewTask(item.tableData[0].disasterReportTaskInfoList) && handleViewTask(item.id)"
  68. />
  69. </el-tooltip>
  70. </template>
  71. <template #batchOperation v-if="disposalManagementPermissions">
  72. <el-button
  73. type="primary"
  74. v-if="isBatchRelease(item.tableData[0].disasterReportTaskInfoList)"
  75. @click.stop="handleBatchRelease(item.id)"
  76. >发布
  77. </el-button>
  78. <el-button
  79. type="primary"
  80. v-if="isBatchWithdraw(item.tableData[0].disasterReportTaskInfoList)"
  81. @click.stop="handleBatchWithdraw(item.id)"
  82. >撤回
  83. </el-button>
  84. <el-button
  85. type="primary"
  86. v-if="isBatchDelete(item.tableData[0].disasterReportTaskInfoList)"
  87. @click.stop="handleBatchDelete(item.id)"
  88. >删除
  89. </el-button>
  90. </template>
  91. <template #main-table>
  92. <el-button
  93. type="primary"
  94. :icon="Plus"
  95. class="main-table__button"
  96. @click="handleCreateReportTask(item.id, item.taskName)"
  97. >新增</el-button
  98. >
  99. <BasicTable :tableData="item.tableData[0].disasterReportTaskInfoList" :tableConfig="tableConfig">
  100. <template #status="scope">
  101. <div class="active-status--div">
  102. <div
  103. class="dot"
  104. :style="{ backgroundColor: ACTIVE_STATUS_COLOR[scope.row.status as ACTIVE_STATUS] }"
  105. />
  106. <span>{{ ACTIVE_STATUS_MAP[scope.row.status] }}</span>
  107. </div>
  108. </template>
  109. <template #taskStage="scope">
  110. <span>{{ getTaskStage(scope.row.taskStage) }}</span>
  111. </template>
  112. <template #reportPrincipals="scope">
  113. <p v-for="user in scope.row.reportPrincipalInfoList" :key="user.reportPrincipalId">
  114. {{ user.reportPrincipalName }}({{ user.reportPrincipalStaffNo }})
  115. </p>
  116. </template>
  117. <template #action="scope">
  118. <ActionButton
  119. text="编辑"
  120. v-if="disposalManagementPermissions && scope.row.status === ACTIVE_STATUS.NOT_EFFECTIVE"
  121. @click="handleEditReportTask(item.id, scope.row.id)"
  122. />
  123. <ActionButton
  124. text="发布"
  125. :popconfirm="{
  126. title: '确定发布吗?',
  127. }"
  128. @confirm="handlePublishReportTask(scope.row.id, item.id)"
  129. v-if="disposalManagementPermissions && scope.row.status === ACTIVE_STATUS.NOT_EFFECTIVE"
  130. />
  131. <ActionButton
  132. text="撤回"
  133. :popconfirm="{
  134. title: '确定撤回吗?',
  135. }"
  136. @confirm="handleWithdrawReportTask(scope.row.id, item.id)"
  137. v-if="
  138. disposalManagementPermissions &&
  139. (scope.row.taskStage === TASK_STAGE.TO_BE_REPORTED ||
  140. scope.row.taskStage === TASK_STAGE.OVERDUE)
  141. "
  142. />
  143. <ActionButton
  144. text="删除"
  145. :popconfirm="{
  146. title: '确定删除吗?',
  147. }"
  148. @confirm="handleDeleteReportTask(scope.row.id)"
  149. v-if="disposalManagementPermissions && scope.row.status === ACTIVE_STATUS.NOT_EFFECTIVE"
  150. />
  151. <ActionButton text="查看" v-if="scope.row.status === ACTIVE_STATUS.ACTIVE" />
  152. </template>
  153. </BasicTable>
  154. </template>
  155. </CollapseItem>
  156. </template>
  157. </div>
  158. <div class="pagination-container" v-if="collapseList.length > 0">
  159. <el-pagination
  160. :current-page="currentPage"
  161. :page-size="pageSize"
  162. :page-sizes="DISASTER_CONTROL_PAGE_SIZE_CONFIG"
  163. layout="prev, pager, next, jumper, sizes, total"
  164. background
  165. :total="total"
  166. @size-change="handleSizeChange"
  167. @current-change="handleCurrentChange"
  168. />
  169. </div>
  170. </section>
  171. </div>
  172. </main>
  173. </div>
  174. </template>
  175. <script setup lang="ts">
  176. import { Plus } from '@element-plus/icons-vue';
  177. import Search from '@/views/disaster/components/Search.vue';
  178. import CollapseItem from './src/components/CollapseItem.vue';
  179. import BasicTable from '@/components/BasicTable.vue';
  180. import { getAllDepartments } from '@/api/auth/dept';
  181. import { onMounted, reactive, ref, nextTick } from 'vue';
  182. import { formatDeptTree } from '@/views/disaster/utils/formatDeptTree';
  183. import type { DeptTreeItem } from '@/types/dept/type';
  184. import {
  185. getDisasterControlCollapseData,
  186. getDisasterControlTableData,
  187. publishDisasterHandleTask,
  188. withdrawDisasterHandleTask,
  189. deleteDisasterHandleTask,
  190. deleteDisasterReportTask,
  191. editDisasterReportTask,
  192. } from '@/api/disaster-control';
  193. import type { disasterReportTaskInfoListResponse } from '@/types/disaster-control';
  194. import { DEFAULT_PAGE_SIZE, DISASTER_CONTROL_PAGE_SIZE_CONFIG, TASK_STAGE } from './src/constant';
  195. import type {
  196. DisposalManagementCollapseListResponse,
  197. DisposalManagementTableResponse,
  198. } from '@/types/disaster-control';
  199. import useTableConfig from '@/hooks/useTableConfigHook';
  200. import {
  201. DISPOSAL_MANAGEMENT_SEARCH_CONFIG,
  202. DISPOSAL_MANAGEMENT_TABLE_COLUMNS,
  203. DISPOSAL_MANAGEMENT_TABLE_OPTIONS,
  204. } from './src/config';
  205. import { getTaskStage } from './src/util';
  206. import {
  207. ACTIVE_STATUS,
  208. ACTIVE_STATUS_COLOR,
  209. ACTIVE_STATUS_MAP,
  210. DISASTER_PERMISSIONS,
  211. } from '@/views/disaster/constant';
  212. import ActionButton from '@/components/ActionButton.vue';
  213. import { useRouter } from 'vue-router';
  214. import Empty from 'assets/images/empty@1X.png';
  215. import ViewDocument from './src/svg/view-document.svg';
  216. import { useUserInfoHook } from '@/views/disaster/hooks/userInfo';
  217. import { openMessageBox } from '@/utils/element-plus/messageBox';
  218. import { ElMessage } from 'element-plus';
  219. const { permissions } = useUserInfoHook();
  220. const firstLevelDepts = ref<DeptTreeItem[]>([]);
  221. const searchData = reactive({
  222. reportDeptIds: null,
  223. status: null,
  224. taskStage: null,
  225. });
  226. const currentPage = ref(1);
  227. const pageSize = ref(DEFAULT_PAGE_SIZE);
  228. const total = ref(0);
  229. const collapseLoading = ref(false);
  230. const collapseItemRef = ref<InstanceType<typeof CollapseItem>[]>([]);
  231. const collapseList = ref<DisposalManagementCollapseListResponse<DisposalManagementTableResponse>[]>([]);
  232. const disposalManagementPermissions = ref(false);
  233. const { tableConfig } = useTableConfig(DISPOSAL_MANAGEMENT_TABLE_COLUMNS, DISPOSAL_MANAGEMENT_TABLE_OPTIONS, false);
  234. const handleSizeChange = async (size: number) => {
  235. pageSize.value = size;
  236. await getDisposalData();
  237. await getDisposalTableData();
  238. };
  239. const handleCurrentChange = async (page: number) => {
  240. currentPage.value = page;
  241. await getDisposalData();
  242. await getDisposalTableData();
  243. };
  244. const handleSearch = () => {
  245. getDisposalTableData();
  246. };
  247. const handleChangeReportDeptIds = (value: number[]) => {
  248. if (!value) return;
  249. if (value.length === 0) {
  250. searchData.reportDeptIds = null;
  251. }
  252. };
  253. const taskIds = ref<number[]>([]);
  254. const router = useRouter();
  255. const Task_RouterName = 'disaster-control-disposal-management-task-item';
  256. const Table_RouterName = 'disaster-control-disposal-management-item';
  257. const handleCreateDisposalManagement = () => {
  258. router.push({
  259. name: Task_RouterName,
  260. query: {
  261. operate: 'create',
  262. },
  263. });
  264. };
  265. const handleCreateReportTask = (id: number, taskName: string) => {
  266. router.push({
  267. name: Table_RouterName,
  268. params: {
  269. id,
  270. },
  271. query: {
  272. operate: 'create',
  273. taskName,
  274. },
  275. });
  276. };
  277. const handleEditReportTask = (id: number, reportTaskId: number) => {
  278. router.push({
  279. name: Table_RouterName,
  280. params: {
  281. id,
  282. },
  283. query: {
  284. reportTaskId,
  285. operate: 'edit',
  286. },
  287. });
  288. };
  289. const handlePublishReportTask = async (id: number, handleTaskId: number) => {
  290. await editDisasterReportTask({
  291. id,
  292. handleTaskId,
  293. taskStage: TASK_STAGE.TO_BE_REPORTED,
  294. status: ACTIVE_STATUS.ACTIVE,
  295. });
  296. ElMessage.success('发布成功');
  297. await getDisposalTableData();
  298. };
  299. const handleWithdrawReportTask = async (id: number, handleTaskId: number) => {
  300. await editDisasterReportTask({
  301. id,
  302. handleTaskId,
  303. taskStage: TASK_STAGE.TO_BE_RELEASED,
  304. status: ACTIVE_STATUS.NOT_EFFECTIVE,
  305. });
  306. ElMessage.success('已取消发布');
  307. await getDisposalTableData();
  308. };
  309. const handleDeleteReportTask = async (id: number) => {
  310. await deleteDisasterReportTask(id);
  311. await getDisposalTableData();
  312. ElMessage.success('删除成功');
  313. };
  314. const getDisposalData = async () => {
  315. collapseLoading.value = true;
  316. const res = await getDisasterControlCollapseData({
  317. pageNumber: currentPage.value,
  318. pageSize: pageSize.value,
  319. queryParam: {},
  320. });
  321. collapseList.value = res.records.map((item) => ({
  322. ...item,
  323. tableData: [
  324. {
  325. handleTaskId: item.id,
  326. disasterReportTaskInfoList: [],
  327. },
  328. ],
  329. }));
  330. taskIds.value = collapseList.value.map((item) => item.id);
  331. total.value = res.totalRow;
  332. collapseLoading.value = false;
  333. nextTick(() => {
  334. collapseItemRef.value[0]?.openFirstCollapseItem();
  335. });
  336. };
  337. const getDisposalTableData = async () => {
  338. tableConfig.loading = true;
  339. const params = {
  340. handleTaskIds: taskIds.value,
  341. ...searchData,
  342. };
  343. const res = await getDisasterControlTableData(params);
  344. collapseList.value.forEach((item) => {
  345. item.tableData = res.filter((tableItem) => tableItem.handleTaskId === item.id);
  346. });
  347. tableConfig.loading = false;
  348. };
  349. const isViewTask = (disasterReportTaskInfoList: disasterReportTaskInfoListResponse[]) => {
  350. return disasterReportTaskInfoList.some((item) => item.status === ACTIVE_STATUS.ACTIVE);
  351. };
  352. const isBatchRelease = (disasterReportTaskInfoList: disasterReportTaskInfoListResponse[]) => {
  353. return disasterReportTaskInfoList.some((item) => item.status === ACTIVE_STATUS.NOT_EFFECTIVE);
  354. };
  355. const isBatchWithdraw = (disasterReportTaskInfoList: disasterReportTaskInfoListResponse[]) => {
  356. return disasterReportTaskInfoList.some((item) => item.status === ACTIVE_STATUS.ACTIVE);
  357. };
  358. const isBatchDelete = (disasterReportTaskInfoList: disasterReportTaskInfoListResponse[]) => {
  359. return disasterReportTaskInfoList.every((item) => item.status === ACTIVE_STATUS.NOT_EFFECTIVE);
  360. };
  361. const handleViewTask = (id: number) => {
  362. console.log('查看任务ID' + id);
  363. };
  364. const handleBatchRelease = async (id: number) => {
  365. const confirmed = await openMessageBox('', '确定发布吗?', 'warning');
  366. if (!confirmed) return;
  367. await publishDisasterHandleTask(id);
  368. ElMessage.success('发布成功');
  369. await getDisposalTableData();
  370. };
  371. const handleBatchWithdraw = async (id: number) => {
  372. const confirmed = await openMessageBox('', '确定撤回吗?', 'warning');
  373. if (!confirmed) return;
  374. await withdrawDisasterHandleTask(id);
  375. ElMessage.success('撤回成功');
  376. await getDisposalTableData();
  377. };
  378. const handleBatchDelete = async (id: number) => {
  379. const confirmed = await openMessageBox('', '确定删除吗?', 'warning');
  380. if (!confirmed) return;
  381. await deleteDisasterHandleTask(id);
  382. ElMessage.success('删除成功');
  383. await getDisposalData();
  384. await getDisposalTableData();
  385. };
  386. onMounted(async () => {
  387. const result = await getAllDepartments();
  388. await getDisposalData();
  389. await getDisposalTableData();
  390. disposalManagementPermissions.value = Boolean(
  391. permissions.find((item: { code: string }) => item.code === DISASTER_PERMISSIONS.DISPOSAL_MANAGEMENT),
  392. );
  393. firstLevelDepts.value = formatDeptTree(result);
  394. });
  395. </script>
  396. <style scoped lang="scss">
  397. @use '../style/disaster.scss' as *;
  398. @use './src/style/collapse.scss' as *;
  399. @use './src/style/common.scss' as *;
  400. $collapse-container-height-default: calc(68vh - 43px);
  401. $collapse-container-height-permission: calc(63vh - 45px);
  402. .collapse-container {
  403. &--permission {
  404. height: $collapse-container-height-permission;
  405. max-height: $collapse-container-height-permission;
  406. }
  407. &--default {
  408. height: $collapse-container-height-default;
  409. max-height: $collapse-container-height-default;
  410. }
  411. }
  412. .collapse-item__icon {
  413. width: 20px;
  414. &--disabled {
  415. cursor: not-allowed;
  416. opacity: 0.5;
  417. }
  418. }
  419. </style>