TransferTask.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. <template>
  2. <van-nav-bar title="调度任务" left-text="返回" right-text="刷新" @click-left="goBack" @click-right="refresh" />
  3. <div class="content">
  4. <van-form @submit="searchDatas">
  5. <van-field
  6. v-model="formDataSelect.workCategory"
  7. label="任务类型"
  8. placeholder="请选择任务类型"
  9. is-link
  10. readonly
  11. @click="showWorkTypePicker = true"
  12. />
  13. <van-field
  14. v-model="formData.positionBeginNo"
  15. label="起始货位"
  16. placeholder="请输入起始货位名称"
  17. @keyup.enter="searchDatas"
  18. />
  19. <van-field
  20. v-model="formData.positionEndNo"
  21. label="终点货位"
  22. placeholder="请输入终点货位名称"
  23. @keyup.enter="searchDatas"
  24. />
  25. <van-field
  26. v-model="formDataSelect.executeStatus"
  27. label="执行状态"
  28. placeholder="请选择执行状态"
  29. is-link
  30. readonly
  31. @click="showExecuteStatusPicker = true"
  32. />
  33. <van-field
  34. v-model="formDataSelect.success"
  35. label="是否成功"
  36. placeholder="请选择是否成功"
  37. is-link
  38. readonly
  39. @click="showSuccessPicker = true"
  40. />
  41. <div class="form-buttons">
  42. <van-button type="default" block @click="clearFilter">清空</van-button>
  43. <van-button type="primary" block @click="searchDatas">查询</van-button>
  44. </div>
  45. </van-form>
  46. <van-list
  47. v-model:loading="loading"
  48. :finished="finished"
  49. :finished-text="'没有更多了'"
  50. @load="loadMore"
  51. >
  52. <van-cell-group v-for="record in taskList" :key="record.schedulingTasksId" class="task-item">
  53. <van-cell title="单据编号" :value="record.documentNo" />
  54. <van-cell title="任务类型" :value="record.workCategory" />
  55. <van-cell title="起始货位" :value="record.positionBeginName" />
  56. <van-cell title="终点货位" :value="record.positionEndName" />
  57. <van-cell title="执行状态" :value="record.executeStatus" />
  58. <van-cell title="是否成功">
  59. <template #default>
  60. <van-tag v-if="record.success === true" color="#07c160">成功</van-tag>
  61. <van-tag v-if="record.executeStatus === '未开始'" color="#07c160">未开始</van-tag>
  62. <van-tag v-else color="#ff4d4f">失败</van-tag>
  63. </template>
  64. </van-cell>
  65. <div class="task-operations">
  66. <van-tag v-if="record.executeStatus === '已完成'" color="#07c160">已完成</van-tag>
  67. <van-button v-if="record.executeStatus === '执行中'" type="danger" size="small" @click="cancelTask(record)">取消任务</van-button>
  68. <van-button v-if="record.executeStatus === '未开始'" type="primary" size="small" @click="executeTask(record)">执行</van-button>
  69. </div>
  70. </van-cell-group>
  71. </van-list>
  72. </div>
  73. <!-- 选择器弹窗 -->
  74. <van-popup v-model:show="showWorkTypePicker" round position="bottom">
  75. <van-picker
  76. :columns="workTypeColumns"
  77. @confirm="(value) => handleWorkTypeConfirm(value)"
  78. @cancel="showWorkTypePicker = false"
  79. />
  80. </van-popup>
  81. <van-popup v-model:show="showExecuteStatusPicker" round position="bottom">
  82. <van-picker
  83. :columns="executeStatusColumns"
  84. @confirm="(value) => handleExecuteStatusConfirm(value)"
  85. @cancel="showExecuteStatusPicker = false"
  86. />
  87. </van-popup>
  88. <van-popup v-model:show="showSuccessPicker" round position="bottom">
  89. <van-picker
  90. :columns="successColumns"
  91. @confirm="(value) => handleSuccessConfirm(value)"
  92. @cancel="showSuccessPicker = false"
  93. />
  94. </van-popup>
  95. <!-- 添加全局加载状态 -->
  96. <van-loading v-if="executing" class="global-loading" type="spinner">执行中...</van-loading>
  97. <van-overlay :show="executing" />
  98. </template>
  99. <script setup>
  100. import { ref, onMounted } from 'vue';
  101. import { useRouter } from 'vue-router';
  102. import { showToast,Loading } from 'vant';
  103. import { processException } from '../common/Common.js';
  104. import { ajaxApiGet, ajaxApiPost } from '../common/utils.js';
  105. const router = useRouter();
  106. const loading = ref(false);
  107. const finished = ref(false);
  108. const executing = ref(false); // 执行状态
  109. const taskList = ref([]);
  110. const formData = ref({
  111. workCategory: null,
  112. positionBeginNo: null,
  113. positionEndNo: null,
  114. executeStatus: null,
  115. agvNo: null,
  116. success: null,
  117. });
  118. const formDataSelect = ref({
  119. workCategory: null,
  120. positionBeginNo: null,
  121. positionEndNo: null,
  122. executeStatus: null,
  123. agvNo: null,
  124. success: null,
  125. });
  126. const totalSize = ref(0);
  127. const pagination = ref({
  128. start: 1,
  129. length: 10,
  130. });
  131. // 选择器状态
  132. const showWorkTypePicker = ref(false);
  133. const showExecuteStatusPicker = ref(false);
  134. const showSuccessPicker = ref(false);
  135. // 选择器列数据
  136. const workTypeColumns = ref([
  137. { text: '入库', value: 'STOCKIN' },
  138. { text: '出库', value: 'STOCKOUT' },
  139. { text: '调拨', value: 'ADJUST' },
  140. { text: '出库返回', value: 'STOCKOUTRETURN' },
  141. { text: '全部', value: '' },
  142. ]);
  143. const executeStatusColumns = ref([
  144. { text: '全部', value: '' },
  145. { text: '未开始', value: 'NotStarted' },
  146. { text: '执行中', value: 'Executing' },
  147. { text: '已完成', value: 'Completed' },
  148. ]);
  149. const successColumns = ref([
  150. { text: '全部', value: '' },
  151. { text: '成功', value: true },
  152. { text: '失败', value: false },
  153. ]);
  154. // 返回
  155. const goBack = () => {
  156. router.back();
  157. };
  158. // 刷新
  159. const refresh = () => {
  160. pagination.value.start = 1;
  161. taskList.value = [];
  162. finished.value = false;
  163. getTableDatas();
  164. };
  165. // 执行任务
  166. const executeTask = async record => {
  167. executing.value = true;
  168. try {
  169. await executeTaskById(record.schedulingTasksId);
  170. await searchDatas();
  171. showToast({
  172. type: 'success',
  173. message: '执行成功!',
  174. duration: 2000,
  175. });
  176. } catch (error) {
  177. console.log('error',error);
  178. showToast({
  179. type: 'warning',
  180. message: error,
  181. duration: 3000,
  182. });
  183. } finally {
  184. executing.value = false;
  185. }
  186. };
  187. // 取消任务
  188. const cancelTask = async record => {
  189. executing.value = true;
  190. try {
  191. await cancelTaskById(record.schedulingTasksId);
  192. await searchDatas();
  193. showToast({
  194. type: 'success',
  195. message: '取消成功!',
  196. duration: 2000,
  197. });
  198. } catch (error) {
  199. console.log('error',error);
  200. showToast({
  201. type: 'warning',
  202. message: error,
  203. duration: 3000,
  204. });
  205. } finally {
  206. executing.value = false;
  207. }
  208. };
  209. const isManualSearch = ref(false);
  210. // 条件变化查询
  211. const searchDatas = () => {
  212. pagination.value.start = 1;
  213. taskList.value = [];
  214. finished.value = false;
  215. // 添加一个标志防止自动加载
  216. isManualSearch.value = true;
  217. getTableDatas().finally(() => {
  218. isManualSearch.value = false;
  219. });
  220. };
  221. // 加载更多
  222. const loadMore = () => {
  223. if (isManualSearch.value) return;
  224. if (taskList.value.length >= totalSize.value) {
  225. finished.value = true;
  226. return;
  227. }
  228. pagination.value.start++;
  229. getTableDatas();
  230. };
  231. // 清空条件
  232. const clearFilter = () => {
  233. formData.value = {
  234. workCategory: null,
  235. positionBeginNo: null,
  236. positionEndNo: null,
  237. executeStatus: null,
  238. agvNo: null,
  239. success: null,
  240. };
  241. formDataSelect.value = {
  242. workCategory: null,
  243. positionBeginNo: null,
  244. positionEndNo: null,
  245. executeStatus: null,
  246. agvNo: null,
  247. success: null,
  248. };
  249. searchDatas();
  250. };
  251. // 处理任务类型选择
  252. const handleWorkTypeConfirm = value => {
  253. formData.value.workCategory = value.selectedOptions[0].value;
  254. formDataSelect.value.workCategory = value.selectedOptions[0].text;
  255. showWorkTypePicker.value = false;
  256. searchDatas();
  257. };
  258. // 处理执行状态选择
  259. const handleExecuteStatusConfirm = value => {
  260. formData.value.executeStatus = value.selectedOptions[0].value;
  261. formDataSelect.value.executeStatus = value.selectedOptions[0].text;
  262. showExecuteStatusPicker.value = false;
  263. searchDatas();
  264. };
  265. // 处理是否成功选择
  266. const handleSuccessConfirm = value => {
  267. formData.value.success = value.selectedOptions[0].value;
  268. formDataSelect.value.success = value.selectedOptions[0].text;
  269. showSuccessPicker.value = false;
  270. searchDatas();
  271. };
  272. onMounted(() => {
  273. getTableDatas();
  274. });
  275. // 查询调度任务
  276. const getTableDatas = () => {
  277. const start = (pagination.value.start - 1) * pagination.value.length;
  278. const params = {
  279. ...formData.value,
  280. ...pagination.value,
  281. start,
  282. };
  283. loading.value = true;
  284. const url = '/api/SchedulingTasksResource/querySchedulingTasks';
  285. // ✅ 返回 ajaxApiPost 的 Promise
  286. return ajaxApiPost(url, params).then(
  287. success => {
  288. const { errorCode, errorMessage, datas, total } = success;
  289. if (errorCode === 0) {
  290. if (datas && datas.length > 0) {
  291. if (pagination.value.start === 1) {
  292. taskList.value = datas;
  293. } else {
  294. taskList.value = [...taskList.value, ...datas];
  295. }
  296. totalSize.value = total;
  297. } else {
  298. if (pagination.value.start === 1) {
  299. taskList.value = [];
  300. }
  301. totalSize.value = 0;
  302. }
  303. } else {
  304. if (pagination.value.start === 1) {
  305. taskList.value = [];
  306. }
  307. totalSize.value = 0;
  308. showToast({
  309. type: 'warning',
  310. message: errorMessage,
  311. duration: 3000,
  312. });
  313. }
  314. loading.value = false;
  315. },
  316. error => {
  317. processException(error);
  318. loading.value = false;
  319. },
  320. );
  321. };
  322. // 执行任务Api
  323. const executeTaskById = id => {
  324. const url = `/api/SchedulingTasksResource/executeTaskById?schedulingTasksId=${id}`;
  325. return ajaxApiGet(url).then(
  326. success => {
  327. const { errorCode, errorMessage } = success;
  328. if (errorCode !== 0) {
  329. return Promise.reject(errorMessage);
  330. }
  331. },
  332. error => {
  333. processException(error);
  334. return Promise.reject(error);
  335. },
  336. );
  337. };
  338. // 取消任务Api
  339. const cancelTaskById = id => {
  340. const url = `/api/SchedulingTasksResource/cancelWorkById?schedulingTasksId=${id}`;
  341. return ajaxApiGet(url).then(
  342. success => {
  343. const { errorCode, errorMessage } = success;
  344. if (errorCode !== 0) {
  345. return Promise.reject(errorMessage);
  346. }
  347. },
  348. error => {
  349. processException(error);
  350. return Promise.reject(error);
  351. },
  352. );
  353. };
  354. </script>
  355. <style scoped>
  356. .content {
  357. padding: 16px;
  358. background-color: #f5f5f5;
  359. min-height: 100vh;
  360. }
  361. .form-buttons {
  362. display: flex;
  363. gap: 12px;
  364. margin-top: 16px;
  365. }
  366. .task-item {
  367. margin-top: 16px;
  368. border-radius: 8px;
  369. overflow: hidden;
  370. box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  371. }
  372. .task-operations {
  373. display: flex;
  374. gap: 8px;
  375. padding: 12px 16px;
  376. background-color: #f9f9f9;
  377. border-top: 1px solid #f0f0f0;
  378. justify-content: flex-end;
  379. }
  380. :deep(.van-cell) {
  381. font-size: 14px;
  382. }
  383. :deep(.van-cell__title) {
  384. font-weight: 500;
  385. color: #333;
  386. }
  387. :deep(.van-cell__value) {
  388. color: #666;
  389. }
  390. :deep(.van-form-item) {
  391. margin-bottom: 12px;
  392. }
  393. /* 全局加载样式 */
  394. .global-loading {
  395. position: fixed;
  396. top: 50%;
  397. left: 50%;
  398. transform: translate(-50%, -50%);
  399. z-index: 2001;
  400. padding: 10px 20px;
  401. background: rgba(0, 0, 0, 0.7);
  402. color: white;
  403. border-radius: 4px;
  404. display: flex;
  405. align-items: center;
  406. gap: 8px;
  407. }
  408. </style>