taskProgress.vue 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. <template>
  2. <a-modal
  3. v-model:visible="visible"
  4. :width="500"
  5. title-align="start"
  6. top="20px"
  7. :align-center="false"
  8. :mask-closable="false"
  9. :esc-to-close="false"
  10. :closable="false"
  11. @before-open="modalBeforeOpen"
  12. >
  13. <template #title> 任务进度 </template>
  14. <a-descriptions
  15. :data="taskInfo"
  16. title="任务详情"
  17. :align="{ label: 'right' }"
  18. :column="1"
  19. />
  20. <a-collapse
  21. v-if="taskFilterInfo.length"
  22. expand-icon-position="right"
  23. style="margin: 8px 0"
  24. :default-active-key="[1]"
  25. >
  26. <a-collapse-item :key="1" header="筛选条件">
  27. <a-descriptions
  28. :data="taskFilterInfo"
  29. title=""
  30. :align="{ label: 'right' }"
  31. :column="1"
  32. />
  33. </a-collapse-item>
  34. </a-collapse>
  35. <a-descriptions title="进度" :column="1" :align="{ label: 'right' }">
  36. <a-descriptions-item label="任务总数">
  37. {{ total }}
  38. </a-descriptions-item>
  39. <a-descriptions-item label="完成数量">
  40. {{ finishCount }}
  41. </a-descriptions-item>
  42. <a-descriptions-item label="总体进度">
  43. <a-progress :percent="progressNum" :stroke-width="10" />
  44. </a-descriptions-item>
  45. </a-descriptions>
  46. <template #footer>
  47. <a-button v-if="progressNum >= 1" type="primary" @click="close"
  48. >确定</a-button
  49. >
  50. <a-button v-else @click="toCancel">取消</a-button>
  51. </template>
  52. </a-modal>
  53. </template>
  54. <script setup lang="ts">
  55. import { ref } from 'vue';
  56. import { DescData, Message } from '@arco-design/web-vue';
  57. import useModal from '@/hooks/modal';
  58. import useTimeout from '@/hooks/timout';
  59. import { PICTURE_TYPE } from '@/constants/enumerate';
  60. import { useUserStore } from '@/store';
  61. import { TrackConfigType } from '@/store/modules/app/types';
  62. import { TrackExportDetailListFilter } from '@/api/types/task';
  63. import { objTypeOf } from '@/utils/utils';
  64. import { modalConfirm } from '../../../utils/arco';
  65. import { TrackTaskData } from '../../../../electron/db/models/trackTask';
  66. type FilterDataType = TrackExportDetailListFilter | string[];
  67. defineOptions({
  68. name: 'ModifySet',
  69. });
  70. /* modal */
  71. const { visible, open, close } = useModal();
  72. defineExpose({ open, close });
  73. const { addSetTimeout, clearSetTimeout } = useTimeout();
  74. const userStore = useUserStore();
  75. const PROGRESS_KEY = 'progress';
  76. const taskInfo = ref<DescData[]>([]);
  77. const taskFilterInfo = ref<DescData[]>([]);
  78. const task = ref<TrackTaskData>({} as TrackTaskData);
  79. const total = ref(0);
  80. const finishCount = ref(0);
  81. const progressNum = ref(0);
  82. async function updateProgress() {
  83. clearSetTimeout(PROGRESS_KEY);
  84. finishCount.value = await window.db.getTrackTaskDetailCount({
  85. trackTaskId: task.value.id,
  86. status: 'FINISH',
  87. });
  88. progressNum.value = !total.value
  89. ? 0
  90. : Math.floor((10000 * finishCount.value) / total.value) / 10000;
  91. // console.log(total.value, finishCount.value, progressNum.value);
  92. if (finishCount.value === total.value) {
  93. await window.db.updateTrackTaskStatus({
  94. id: task.value.id,
  95. status: 'FINISH',
  96. });
  97. window.electron.stopWinProcess();
  98. return;
  99. }
  100. addSetTimeout(PROGRESS_KEY, updateProgress, 0.5 * 1000);
  101. }
  102. function getExportUrl() {
  103. const page = '#/track-task-export';
  104. const user = window.btoa(
  105. encodeURIComponent(JSON.stringify(userStore.$state))
  106. );
  107. return `${page}?user=${user}`;
  108. }
  109. /* init modal */
  110. async function modalBeforeOpen() {
  111. const res = await window.db.getUnfinishTrackTask(
  112. userStore.curSchoolInfo.id
  113. );
  114. if (!res) {
  115. Message.warning('没有未完成任务');
  116. close();
  117. return;
  118. }
  119. await window.db.releaseAllRunningTaskDetail(res.id);
  120. task.value = res;
  121. const trackConfig = JSON.parse(res.trackConfig) as TrackConfigType;
  122. const filterData = res.filterData
  123. ? (JSON.parse(res.filterData) as FilterDataType)
  124. : null;
  125. updateTaskFilerInfo(filterData);
  126. taskInfo.value = [
  127. {
  128. value: res.semesterName,
  129. label: '学期',
  130. },
  131. {
  132. value: res.examName,
  133. label: '考试',
  134. },
  135. ];
  136. if (res.courseId) {
  137. taskInfo.value.push({
  138. value: `${res.courseName}(${res.courseCode})`,
  139. label: '科目',
  140. });
  141. }
  142. if (res.paperNumber) {
  143. taskInfo.value.push({
  144. value: res.paperNumber,
  145. label: '试卷编码',
  146. });
  147. }
  148. taskInfo.value.push(
  149. ...[
  150. {
  151. value: trackConfig.pictureType.map((k) => PICTURE_TYPE[k]).join(','),
  152. label: '下载文件',
  153. },
  154. {
  155. value: trackConfig.outputDir,
  156. label: '保存目录',
  157. },
  158. ]
  159. );
  160. total.value = await window.db.getTrackTaskDetailCount({
  161. trackTaskId: res.id,
  162. });
  163. if (total.value === 0) {
  164. await window.db.updateTrackTaskStatus({
  165. id: task.value.id,
  166. status: 'FINISH',
  167. });
  168. Message.warning('当前无可执行任务!');
  169. close();
  170. return;
  171. }
  172. updateProgress();
  173. // 开启导出进程
  174. const appConfig = window.api.getConfigData({});
  175. window.electron.startWinProcess(
  176. appConfig.downloadProcessCount,
  177. getExportUrl()
  178. );
  179. // window.electron.startWinProcess(2, getExportUrl());
  180. }
  181. function updateTaskFilerInfo(data: FilterDataType | null) {
  182. taskFilterInfo.value = [];
  183. if (!data) return;
  184. if (objTypeOf(data) === 'array') {
  185. taskFilterInfo.value = [
  186. {
  187. value: (data as string[]).join(','),
  188. label: '选择的学生',
  189. },
  190. ];
  191. return;
  192. }
  193. if (Object.keys(data as TrackExportDetailListFilter).length === 2) return;
  194. const datas = data as Required<TrackExportDetailListFilter>;
  195. // 设置的详情数据
  196. taskFilterInfo.value = [
  197. {
  198. label: '学院',
  199. value: datas.college,
  200. },
  201. {
  202. label: '专业',
  203. value: datas.majorName,
  204. },
  205. {
  206. label: '班级',
  207. value: datas.className,
  208. },
  209. {
  210. label: '姓名',
  211. value: datas.studentName,
  212. },
  213. {
  214. label: '学号',
  215. value: datas.studentCode,
  216. },
  217. {
  218. label: '学号区间',
  219. value:
  220. datas.startStudentCode || datas.endStudentCode
  221. ? `${datas.startStudentCode}~${datas.endStudentCode}`
  222. : '',
  223. },
  224. {
  225. label: '成绩区间',
  226. value:
  227. datas.startScore || datas.endScore
  228. ? `${datas.startScore}~${datas.endScore}`
  229. : '',
  230. },
  231. {
  232. label: '客观题分区间',
  233. value:
  234. datas.objectiveStartScore || datas.objectiveEndScore
  235. ? `${datas.objectiveStartScore}~${datas.objectiveEndScore}`
  236. : '',
  237. },
  238. {
  239. label: '主观题分区间',
  240. value:
  241. datas.subjectiveStartScore || datas.subjectiveEndScore
  242. ? `${datas.subjectiveStartScore}~${datas.subjectiveEndScore}`
  243. : '',
  244. },
  245. ].filter((item) => item.value);
  246. }
  247. async function toCancel() {
  248. const confirmRes = await modalConfirm(
  249. '提示',
  250. `确定要停止正在执行的任务吗?`
  251. ).catch(() => false);
  252. if (confirmRes !== 'confirm') return;
  253. window.electron.stopWinProcess();
  254. close();
  255. }
  256. </script>