PageTaskExecution.vue 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  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. <Search
  10. :searchConfig="TASK_EXECUTION_SEARCH_CONFIG"
  11. :searchData="searchData"
  12. @update:searchData="handleSearch"
  13. />
  14. </header>
  15. <BasicTable
  16. :table-config="tableConfig"
  17. :table-data="tableData"
  18. @update:pageSize="handleSizeChange"
  19. @update:pageNumber="handleCurrentChange"
  20. >
  21. <template #taskName="scope">
  22. <div class="task-name--div">
  23. <el-tooltip :content="scope.row.name" placement="top" effect="light">
  24. <span>{{ scope.row.name }}</span>
  25. </el-tooltip>
  26. <img :src="OverdueIcon" v-if="scope.row.overdue" />
  27. </div>
  28. </template>
  29. <template #inspectType="scope">
  30. <span>{{ INSPECT_TYPE_MAP[scope.row.inspectType] }}</span>
  31. </template>
  32. <template #taskStage="scope">
  33. <span>{{ TASK_STAGE_MAP[scope.row.taskState] }}</span>
  34. </template>
  35. <!-- action button 不仅分任务情况 还要分 人物权限 -->
  36. <template #action="scope">
  37. <!-- 检查任务操作入口 -->
  38. <div class="action-container" v-if="scope.row.taskState === TASK_STAGE.PENDING_CHECK">
  39. <ActionButton text="去检查" @click="handleCheckItem(scope.row.id, 'check')" />
  40. <!-- 仅检查责任人可以看到 -->
  41. <ActionButton
  42. text="添加检查人"
  43. @click="handleAddCheckUser(scope.row.id)"
  44. v-if="scope.row.userTypeList.includes(USER_TYPE.CHECK_RESPONSIBLE)"
  45. />
  46. </div>
  47. <!-- 审批任务操作入口 -->
  48. <div class="action-container" v-else-if="scope.row.taskState === TASK_STAGE.PENDING_APPROVAL">
  49. <!-- 审批人员可以看到 -->
  50. <ActionButton
  51. text="去审批"
  52. v-if="scope.row.userTypeList.includes(USER_TYPE.APPROVER)"
  53. @click="handleCheckItem(scope.row.id, 'approve')"
  54. />
  55. <!-- 检查责任人、检查执行人员可以看到 -->
  56. <ActionButton
  57. v-else
  58. text="撤回"
  59. :popconfirm="{
  60. title: '确定撤回吗?',
  61. }"
  62. @confirm="handleWithdrawTask(scope.row.id, scope.row.taskState)"
  63. />
  64. </div>
  65. <!-- 完成任务操作入口 -->
  66. <div class="action-container" v-else-if="scope.row.taskState === TASK_STAGE.COMPLETED">
  67. <ActionButton text="查看" @click="handleCheckItem(scope.row.id, 'view')" />
  68. <!-- 仅审批人员可以看到 -->
  69. <ActionButton
  70. v-if="
  71. scope.row.userTypeList.includes(USER_TYPE.APPROVER) && !isOverdue24Hours(scope.row.dueCompleteTime)
  72. "
  73. text="撤回"
  74. :popconfirm="{
  75. title: '确定撤回吗?',
  76. }"
  77. @confirm="handleWithdrawTask(scope.row.id, scope.row.taskState)"
  78. />
  79. </div>
  80. </template>
  81. </BasicTable>
  82. </div>
  83. </main>
  84. <el-dialog v-model="userInfo" title="添加检查人" destroy-on-close>
  85. <InspectorSelect
  86. :customUserList="currentTaskInspectorList"
  87. :currentTaskId="currentTaskId"
  88. @cancel="userInfo = false"
  89. />
  90. </el-dialog>
  91. </div>
  92. </template>
  93. <script setup lang="ts">
  94. import { ref, onMounted, reactive, onUnmounted } from 'vue';
  95. import BasicTable from '@/components/BasicTable.vue';
  96. import ActionButton from '@/components/ActionButton.vue';
  97. import Search from '@/views/disaster/components/Search.vue';
  98. import InspectorSelect from '@/views/disaster/components/InspectorSelect.vue';
  99. import useTableConfig from '@/hooks/useTableConfigHook';
  100. import {
  101. getTaskExecutionList,
  102. getTaskInspectorList,
  103. withdrawTaskInspect,
  104. withdrawTaskApproval,
  105. } from '@/api/disaster-precaution';
  106. import type { TaskExecutionListResponse } from '@/types/disaster-precaution';
  107. import OverdueIcon from '@/assets/svg/overdue.svg';
  108. import { TASK_STAGE } from './src/constants/task-execution';
  109. import { INSPECT_TYPE_MAP, TASK_STAGE_MAP } from './src/constants/task-execution';
  110. import { TABLE_OPTIONS_EXECUTION, TASK_EXECUTION_TABLE_COLUMNS, TASK_EXECUTION_SEARCH_CONFIG } from './src/config';
  111. import type { TaskExecutionListQuery } from '@/types/disaster-precaution';
  112. import type { QueryPageRequest } from '@/types/disaster';
  113. import { USER_TYPE } from './src/constants/task-execution';
  114. import type { PersonGroupItem } from '@/types/person-group/type';
  115. import { useRouter } from 'vue-router';
  116. import { ElMessage } from 'element-plus';
  117. const router = useRouter();
  118. const userInfo = ref(false);
  119. const searchData = reactive({
  120. inspectType: '',
  121. taskState: '',
  122. });
  123. const tableData = ref<TaskExecutionListResponse[]>([]);
  124. const { tableConfig, pagination } = useTableConfig(TASK_EXECUTION_TABLE_COLUMNS, TABLE_OPTIONS_EXECUTION);
  125. // 添加刷新时间变量,用于触发视图更新
  126. const refreshTime = ref(Date.now());
  127. let refreshTimer: number | null = null;
  128. let taskManagementListQuery: QueryPageRequest<TaskExecutionListQuery> = {
  129. pageNumber: pagination.pageNumber,
  130. pageSize: pagination.pageSize,
  131. queryParam: {},
  132. };
  133. const handleSearch = () => {
  134. taskManagementListQuery.queryParam = {};
  135. if (searchData.inspectType !== '') {
  136. taskManagementListQuery.queryParam.inspectType = searchData.inspectType;
  137. }
  138. if (searchData.taskState !== '') {
  139. taskManagementListQuery.queryParam.taskState = searchData.taskState;
  140. }
  141. if (Object.keys(taskManagementListQuery.queryParam).length > 0) {
  142. pagination.pageNumber = 1;
  143. taskManagementListQuery.pageNumber = 1;
  144. }
  145. getTableData();
  146. };
  147. const handleSizeChange = (value: number) => {
  148. pagination.pageSize = value;
  149. taskManagementListQuery.pageSize = value;
  150. getTableData();
  151. };
  152. const handleCurrentChange = (value: number) => {
  153. pagination.pageNumber = value;
  154. taskManagementListQuery.pageNumber = value;
  155. getTableData();
  156. };
  157. const currentTaskId = ref<number>();
  158. const currentTaskInspectorList = ref<PersonGroupItem[]>([]);
  159. const handleAddCheckUser = async (id: number) => {
  160. currentTaskId.value = id;
  161. const res = await getTaskInspectorList(currentTaskId.value);
  162. currentTaskInspectorList.value = res.map((item) => {
  163. return {
  164. ...item,
  165. checked: true,
  166. };
  167. });
  168. userInfo.value = true;
  169. };
  170. const defaultRouterName = 'disaster-precaution-task-execution-detail';
  171. const handleCheckItem = (id: number, operationType: 'check' | 'approve' | 'view') => {
  172. router.push({
  173. name: defaultRouterName,
  174. params: {
  175. id,
  176. },
  177. query: {
  178. operationType,
  179. },
  180. });
  181. };
  182. const handleWithdrawTask = async (id: number, state: number) => {
  183. if (state === TASK_STAGE.PENDING_APPROVAL) {
  184. await withdrawTaskInspect(id);
  185. } else if (state === TASK_STAGE.COMPLETED) {
  186. await withdrawTaskApproval(id);
  187. }
  188. ElMessage.success('已取消发布');
  189. getTableData();
  190. };
  191. const getTableData = async () => {
  192. tableConfig.loading = true;
  193. const res = await getTaskExecutionList(taskManagementListQuery);
  194. tableData.value = res.records;
  195. pagination.total = res.totalRow;
  196. tableConfig.loading = false;
  197. };
  198. // 判断是否超过应完成时间24小时
  199. const isOverdue24Hours = (dueCompleteTime: string) => {
  200. if (!dueCompleteTime) return false;
  201. const dueTime = new Date(dueCompleteTime).getTime();
  202. const currentTime = refreshTime.value;
  203. // 计算24小时的毫秒数: 24 * 60 * 60 * 1000 = 86400000
  204. return currentTime > dueTime + 86400000;
  205. };
  206. onMounted(() => {
  207. getTableData();
  208. // 设置定时器,每分钟更新一次时间
  209. refreshTimer = window.setInterval(() => {
  210. refreshTime.value = Date.now();
  211. }, 1000);
  212. });
  213. // 组件销毁时清除定时器
  214. onUnmounted(() => {
  215. if (refreshTimer !== null) {
  216. clearInterval(refreshTimer);
  217. refreshTimer = null;
  218. }
  219. });
  220. </script>
  221. <style scoped lang="scss">
  222. @use '../style/disaster.scss' as *;
  223. @use './src/style/task-execution.scss' as *;
  224. </style>