You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

709 lines
20 KiB

2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
  1. <template>
  2. <div class="task_component">
  3. <t-card>
  4. <template #title>
  5. <t-space direction="vertical">
  6. <t-breadcrumb>
  7. <t-breadcrumbItem>首页</t-breadcrumbItem>
  8. <t-breadcrumbItem>任务管理中心</t-breadcrumbItem>
  9. </t-breadcrumb>
  10. </t-space>
  11. </template>
  12. <t-table
  13. bordered
  14. hover
  15. tableLayout="auto"
  16. row-key="id"
  17. :data="data"
  18. :columns="columns"
  19. :height="500"
  20. :scroll="{ type: 'virtual', rowHeight: 69, bufferSize: 10 }"
  21. resizable
  22. />
  23. <t-dialog
  24. theme="danger"
  25. header="删除"
  26. :body="delBody"
  27. :visible="delVisible"
  28. @confirm="onConfirmDelete"
  29. :onClose="closeDelDialog"
  30. :cancelBtn="null"
  31. />
  32. <t-drawer
  33. :visible="pathVisible"
  34. size="'100%'"
  35. header="自定义路径规划"
  36. :onConfirm="saveDiyPath"
  37. @cancel="pathVisible = false"
  38. :onOverlayClick="() => (pathVisible = false)"
  39. :closeBtn="true"
  40. >
  41. <div class="path_wrap">
  42. <PathPlan :excelData="excelData" />
  43. </div>
  44. </t-drawer>
  45. <t-dialog
  46. header="修改操作员"
  47. :visible="updateOperVisible"
  48. :footer="false"
  49. :onClose="operClose"
  50. >
  51. <template v-slot:body>
  52. <t-form
  53. :data="formData"
  54. :rules="pubRules"
  55. ref="form"
  56. @reset="onReset"
  57. @submit="onSubmit"
  58. >
  59. <t-form-item label="操作员" name="operatorId">
  60. <t-select
  61. v-model="formData.operatorId"
  62. class="demo-select-base"
  63. clearable
  64. filterable
  65. placeholder="请选择分配的操作员"
  66. >
  67. <t-option
  68. v-for="item in userList"
  69. :value="item.username"
  70. :label="item.nickname"
  71. :key="item.id"
  72. >
  73. {{ item.nickname }}
  74. </t-option>
  75. </t-select>
  76. </t-form-item>
  77. <t-form-item>
  78. <t-space size="10px">
  79. <t-button theme="primary" type="submit">提交</t-button>
  80. <t-button theme="default" variant="base" type="reset"
  81. >重置</t-button
  82. >
  83. </t-space>
  84. </t-form-item>
  85. </t-form>
  86. </template>
  87. </t-dialog>
  88. </t-card>
  89. <t-drawer
  90. size="medium"
  91. closeOnEscKeydown
  92. sizeDraggable
  93. :visible="uploadVisible"
  94. header="上传excel"
  95. :footer="false"
  96. @close="handleClose"
  97. :onConfirm="handleConfirm"
  98. >
  99. <t-upload
  100. ref="uploadRef"
  101. :action="actionAddress"
  102. :headers="getHeaders()"
  103. v-model="files"
  104. status="success"
  105. theme="file-input"
  106. placeholder="未选择文件"
  107. @fail="handleFail"
  108. @success="handleSuccess"
  109. accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
  110. ></t-upload>
  111. </t-drawer>
  112. </div>
  113. </template>
  114. <script lang="jsx">
  115. import {
  116. taskListApi,
  117. delExcelByTaskIdApi,
  118. delTaskApi,
  119. updateOperByTaskIdApi,
  120. } from '@/api/task'
  121. import { getNuclearExcelApi } from '@/api'
  122. import PathPlan from 'cpns/PathPlan'
  123. import { checkCanDiyPathApi, pathPlanApi, getPlanPathListApi } from '@/api/path'
  124. import { useAccountStore, useTaskStore, useImageStore } from '@/store'
  125. import { allOperatorApi } from '@/api/publish'
  126. import moment from 'moment'
  127. import Cookie from '@/utils/cookie'
  128. const accountStore = useAccountStore()
  129. const taskStore = useTaskStore()
  130. const imageStore = useImageStore()
  131. export default {
  132. data() {
  133. return {
  134. excelData: [],
  135. pathVisible: false,
  136. userList: [],
  137. formData: { operatorId: '' },
  138. pubRules: {
  139. operatorId: [{ required: true, message: '请选择要分配的操作员' }],
  140. },
  141. updateOperVisible: false,
  142. operTaskId: null,
  143. deleteDialogIndex: false,
  144. delVisible: false,
  145. files: [],
  146. tips: '上传格式仅支持xlsx',
  147. uploadVisible: false,
  148. data: [],
  149. currentTaskId: '',
  150. columns: [
  151. {
  152. colKey: 'taskName',
  153. title: '任务名称',
  154. width: 120,
  155. },
  156. {
  157. colKey: 'operatorName',
  158. title: '操作员',
  159. width: 80,
  160. },
  161. {
  162. colKey: 'publishTime',
  163. title: '发布时间',
  164. width: 190,
  165. cell: (h, { row }) =>
  166. moment(row.publishTime).format('YYYY-MM-DD HH:mm'),
  167. },
  168. {
  169. colKey: 'nuclearStationName',
  170. title: '核电站名称',
  171. ellipsis: true,
  172. width: 220,
  173. },
  174. {
  175. colKey: 'nuclearCoreName',
  176. title: '核反应堆',
  177. width: 120,
  178. },
  179. {
  180. colKey: 'status',
  181. title: '任务状态',
  182. width: 120,
  183. cell: (h, { row }) => {
  184. if (row.status == 0) {
  185. if (this.role == 'ROLE_ADMIN') {
  186. return (
  187. <div class="not_start_table_btn">
  188. <svg
  189. xmlns="http://www.w3.org/2000/svg"
  190. xmlns:xlink="http://www.w3.org/1999/xlink"
  191. fill="none"
  192. version="1.1"
  193. width="24"
  194. height="23.999755859375"
  195. viewBox="0 0 24 23.999755859375"
  196. >
  197. <g>
  198. <path
  199. d="M12,0C18.6275,0,24,5.37245,24,11.9999C24,18.6273,18.6275,23.9998,12,23.9998C5.3725,23.9998,0,18.6273,0,11.9999C0,5.37245,5.3725,0,12,0ZM12,16.1103C10.9964,16.1103,10.1827,16.9238,10.1827,17.9276C10.1827,18.9312,10.9964,19.7449,12,19.7449C13.0036,19.7449,13.8173,18.9312,13.8173,17.9276C13.8173,16.9238,13.0036,16.1103,12,16.1103ZM11.9477,14.6896C12.8122,14.6896,13.5129,13.9887,13.5129,13.1245L13.5129,5.82005C13.5129,4.95557,12.8122,4.25489,11.9477,4.25489C11.0833,4.25489,10.3826,4.95581,10.3826,5.82005L10.3826,13.1245C10.3826,13.9889,11.0833,14.6896,11.9477,14.6896Z"
  200. fill="#FFFFFF"
  201. fill-opacity="1"
  202. />
  203. </g>
  204. </svg>
  205. <span>未开始</span>
  206. </div>
  207. )
  208. }
  209. return (
  210. <div
  211. class={
  212. row.canUpload
  213. ? 'start_table_btn disable_table_btn'
  214. : 'start_table_btn'
  215. }
  216. onClick={() =>
  217. this.startTask(row, row.nuclearCoreName, 1, row.canUpload)
  218. }
  219. >
  220. 开始任务
  221. </div>
  222. )
  223. } else if (row.status == 1) {
  224. return (
  225. <div
  226. class="process_table_btn"
  227. onClick={() => this.viewProcessTask()}
  228. >
  229. 进行中
  230. </div>
  231. )
  232. } else if (row.status == 2) {
  233. if (this.role == 'ROLE_ADMIN') {
  234. return (
  235. <div class="process_table_btn disable_table_btn">
  236. 任务暂停
  237. </div>
  238. )
  239. } else {
  240. return (
  241. <div
  242. class="continue_table_btn"
  243. onClick={() => this.startTask(row, row.nuclearCoreName)}
  244. >
  245. 继续任务
  246. </div>
  247. )
  248. }
  249. } else {
  250. return (
  251. <div class="finished_table_btn">
  252. <svg
  253. xmlns="http://www.w3.org/2000/svg"
  254. xmlns:xlink="http://www.w3.org/1999/xlink"
  255. fill="none"
  256. version="1.1"
  257. width="23.99990463256836"
  258. height="24"
  259. viewBox="0 0 23.99990463256836 24"
  260. >
  261. <g>
  262. <path
  263. d="M12,24C5.37298,24,0,18.627,0,12C0,5.373,5.37298,0,12,0C18.6269,0,23.9999,5.373,23.9999,12C23.9999,18.627,18.6269,24,12,24ZM9.32396,16.712C9.81214,17.2003,10.6038,17.2003,11.092,16.712L18.6699,9.134C19.1581,8.64578,19.1581,7.85422,18.6699,7.366C18.1817,6.87778,17.3902,6.87778,16.9019,7.366L10.154,14.006L7.13397,10.986C6.64586,10.4971,5.85378,10.4968,5.3653,10.9853C4.87681,11.4738,4.87712,12.2659,5.36598,12.754L9.32396,16.712Z"
  264. fill="#FFFFFF"
  265. fill-opacity="1"
  266. />
  267. </g>
  268. </svg>
  269. <span>已完成</span>
  270. </div>
  271. )
  272. }
  273. },
  274. },
  275. {
  276. colKey: 'checkOrder',
  277. title: '检测路径',
  278. width: 120,
  279. cell: (h, { row }) => {
  280. if (row.checkOrder == 0) {
  281. return '横向规则'
  282. } else if (row.checkOrder == 1) {
  283. return '纵向规则'
  284. } else {
  285. return '自定义'
  286. }
  287. },
  288. },
  289. {
  290. colKey: 'startTime',
  291. title: '开始时间',
  292. width: 190,
  293. cell: (h, { row }) => {
  294. return row.startTime
  295. ? moment(row.startTime).format('YYYY-MM-DD HH:mm')
  296. : '---'
  297. },
  298. },
  299. {
  300. colKey: 'endTime',
  301. title: '完成时间',
  302. width: 190,
  303. cell: (h, { row }) => {
  304. return row.endTime
  305. ? moment(row.endTime).format('YYYY-MM-DD HH:mm')
  306. : '---'
  307. },
  308. },
  309. {
  310. title: '操作',
  311. fixed: 'right',
  312. colKey: 'oper',
  313. cell: (h, { row }) => {
  314. if (this.role == 'ROLE_ADMIN') {
  315. return (
  316. <div>
  317. <t-button
  318. variant="text"
  319. theme="primary"
  320. onClick={() => this.showDeleteDialog(true, row.id)}
  321. >
  322. 删除任务
  323. </t-button>
  324. <t-button
  325. variant="text"
  326. theme="primary"
  327. disabled={row.canUpload}
  328. onClick={() => this.showDeleteDialog(false, row.id)}
  329. >
  330. 删除excel
  331. </t-button>
  332. <t-button
  333. variant="text"
  334. theme="primary"
  335. disabled={!row.canUpload}
  336. onClick={() => this.uploadExcel(row.id)}
  337. >
  338. 上传Excel
  339. </t-button>
  340. <t-button
  341. variant="text"
  342. theme="primary"
  343. onClick={() => this.updateOper(row.id)}
  344. >
  345. 修改操作员
  346. </t-button>
  347. <t-button
  348. variant="text"
  349. theme="primary"
  350. disabled={row.canUpload}
  351. onClick={() => this.showPathDialog(row.id)}
  352. >
  353. 自定义路径规划
  354. </t-button>
  355. <t-button
  356. variant="text"
  357. theme="primary"
  358. disabled={row.canUpload}
  359. onClick={() =>
  360. this.viewDetail(
  361. row.id,
  362. row.nuclearCoreName,
  363. 2,
  364. row.nuclearStationName,
  365. row.operatorName,
  366. )
  367. }
  368. >
  369. 详情
  370. </t-button>
  371. </div>
  372. )
  373. } else {
  374. return (
  375. <div
  376. onClick={() =>
  377. this.viewDetail(
  378. row.id,
  379. row.nuclearCoreName,
  380. 1,
  381. row.nuclearStationName,
  382. row.operatorName,
  383. row.canUpload,
  384. )
  385. }
  386. class={
  387. row.canUpload
  388. ? 'start_table_btn disable_table_btn'
  389. : 'start_table_btn'
  390. }
  391. >
  392. 查看详情
  393. </div>
  394. )
  395. }
  396. },
  397. },
  398. ],
  399. }
  400. },
  401. components: {
  402. PathPlan,
  403. },
  404. computed: {
  405. actionAddress() {
  406. return `${import.meta.env.VITE_BASE_URL}/upload/${this.currentTaskId}`
  407. },
  408. role() {
  409. return Cookie.getCookie('r')
  410. },
  411. delBody() {
  412. if (this.deleteDialogIndex) {
  413. return '确认要删除当前任务吗,请确保当前任务已经废弃!'
  414. } else {
  415. return '确认要清空当前任务已上传的Excel路径规划吗,此操作不可逆!'
  416. }
  417. },
  418. },
  419. methods: {
  420. async getExcelList(taskId) {
  421. const res = await getNuclearExcelApi(taskId)
  422. if (res?.code == 200) {
  423. // 根据data的serialNumber算出序列号
  424. const list = res.data.list
  425. list.map(item => {
  426. const arr = item.serialNumber.split('-')
  427. item.num = parseInt(arr[0]) * 14 + parseInt(arr[1]) + 1
  428. })
  429. this.excelData = list
  430. }
  431. },
  432. async saveDiyPath() {
  433. const res = await pathPlanApi(this.currentTaskId, taskStore.pathData)
  434. if (res?.code == 200) {
  435. this.pathVisible = false
  436. this.$message.success('设置成功')
  437. }
  438. },
  439. showPathDialog(taskId) {
  440. this.currentTaskId = taskId
  441. this.getExcelList(taskId)
  442. const confirmDia = this.$dialog.confirm({
  443. header: '提示',
  444. body: '已开始的任务无法更改路径。复杂路径规划后,将清除创建任务时所选择的规则路径,确认要进行自定义规划吗?',
  445. confirmBtn: '确定',
  446. cancelBtn: '取消',
  447. onConfirm: async ({ e }) => {
  448. const res = await checkCanDiyPathApi(taskId)
  449. if (res?.code == 200) {
  450. // 这需要查询原先的路径 进行回显
  451. const listRes = await getPlanPathListApi(taskId)
  452. if (listRes?.code == 200) {
  453. if (listRes?.data) {
  454. taskStore.updatePathData(listRes?.data)
  455. }
  456. }
  457. this.pathVisible = true
  458. } else {
  459. this.$message.error(res?.msg)
  460. }
  461. // 请求成功后,销毁弹框
  462. confirmDia.destroy()
  463. },
  464. onClose: ({ e, trigger }) => {
  465. confirmDia.hide()
  466. },
  467. })
  468. },
  469. async getAllOperator() {
  470. const res = await allOperatorApi()
  471. if (res?.code == 200) {
  472. this.userList = res?.data
  473. }
  474. },
  475. onReset() {
  476. this.$message.success('重置成功')
  477. },
  478. async onSubmit({ validateResult, firstError }) {
  479. if (validateResult === true) {
  480. const res = await updateOperByTaskIdApi(this.operTaskId, this.formData)
  481. if (res?.code == 200) {
  482. this.getTaskList()
  483. this.updateOperVisible = false
  484. this.operTaskId = null
  485. this.$message.success('修改成功')
  486. }
  487. } else {
  488. this.$message.warning(firstError)
  489. }
  490. },
  491. updateOper(taskId) {
  492. this.operTaskId = taskId
  493. this.updateOperVisible = true
  494. },
  495. operClose() {
  496. this.updateOperVisible = false
  497. },
  498. onConfirmDelete() {
  499. if (this.deleteDialogIndex) {
  500. this.delTask(this.operTaskId)
  501. } else {
  502. this.delExcel(this.operTaskId)
  503. }
  504. },
  505. closeDelDialog() {
  506. this.delVisible = false
  507. },
  508. showDeleteDialog(index, taskId) {
  509. this.deleteDialogIndex = index
  510. this.operTaskId = taskId
  511. this.delVisible = true
  512. },
  513. viewProcessTask() {
  514. accountStore.changePage(0)
  515. taskStore.updateCurrentDetailTaskId(null)
  516. },
  517. startTask(row, coreName, flag, canUpload) {
  518. if (flag == 1 && canUpload) {
  519. return
  520. }
  521. taskStore.updateTaskStatus(row.status)
  522. taskStore.updateCurrentCoord(row.currentCoord)
  523. imageStore.updateNuclearCoreName(coreName)
  524. imageStore.updateShowImage(false)
  525. accountStore.changePage(0)
  526. taskStore.getExcelList(row.id)
  527. taskStore.updateCurrentTaskId(row.id)
  528. taskStore.updateCurrentDetailTaskId(null)
  529. },
  530. viewDetail(
  531. taskId,
  532. nuclearCoreName,
  533. flag,
  534. nuclearStationName,
  535. operatorName,
  536. canUpload,
  537. ) {
  538. if (flag == 1 && canUpload) {
  539. return
  540. }
  541. imageStore.updateNuclearStationName(nuclearStationName)
  542. imageStore.updateOperatorName(operatorName)
  543. imageStore.updateNuclearCoreName(nuclearCoreName)
  544. taskStore.updateCurrentDetailTaskId(taskId)
  545. imageStore.updateShowImage(false)
  546. accountStore.changePage(0)
  547. taskStore.getExcelList(taskId)
  548. },
  549. handleSuccess({ response }) {
  550. console.log(response)
  551. if (response?.code == 200) {
  552. this.uploadVisible = false
  553. this.getTaskList()
  554. this.$message.success('上传成功')
  555. } else {
  556. this.$message.error(response?.msg)
  557. }
  558. },
  559. handleFail({ file }) {
  560. this.$message.error(`文件 ${file.name} 上传失败`)
  561. },
  562. getHeaders() {
  563. return {
  564. Authorization: Cookie.getCookie('t'),
  565. }
  566. },
  567. handleClose() {
  568. this.uploadVisible = false
  569. },
  570. handleConfirm() {
  571. console.log(this.$refs)
  572. this.$refs.uploadRef.triggerUpload()
  573. },
  574. async delTask(taskId) {
  575. const res = await delTaskApi(taskId)
  576. if (res?.code == 200) {
  577. if (res?.data?.result) {
  578. this.$message.success('删除任务成功')
  579. this.getTaskList()
  580. this.delVisible = false
  581. }
  582. }
  583. },
  584. async delExcel(taskId) {
  585. const res = await delExcelByTaskIdApi(taskId)
  586. if (res?.code == 200) {
  587. if (res?.data?.result) {
  588. this.$message.success('删除该任务的excel计划表成功')
  589. this.getTaskList()
  590. this.delVisible = false
  591. }
  592. }
  593. },
  594. uploadExcel(taskId) {
  595. this.currentTaskId = taskId
  596. this.uploadVisible = true
  597. },
  598. async getTaskList() {
  599. const res = await taskListApi()
  600. if (res?.code == 200) {
  601. this.data = res?.data
  602. }
  603. },
  604. },
  605. mounted() {
  606. this.getTaskList()
  607. if (this.role == 'USER_ADMIN') {
  608. this.getAllOperator()
  609. }
  610. },
  611. }
  612. </script>
  613. <style lang="scss">
  614. .process_table_btn {
  615. width: 93.18px;
  616. height: 32px;
  617. border-radius: 32px;
  618. display: flex;
  619. padding: 6px 25px;
  620. align-items: center;
  621. justify-content: center;
  622. font-size: 14px;
  623. font-weight: normal;
  624. box-sizing: border-box;
  625. white-space: nowrap;
  626. letter-spacing: 0.07em;
  627. color: #ffffff;
  628. background: #ed7b2f;
  629. cursor: pointer;
  630. }
  631. .start_table_btn {
  632. cursor: pointer;
  633. width: 93.18px;
  634. box-sizing: border-box;
  635. white-space: nowrap;
  636. height: 32px;
  637. border-radius: 32px;
  638. display: flex;
  639. padding: 6px 25px;
  640. align-items: center;
  641. justify-content: center;
  642. font-size: 14px;
  643. font-weight: normal;
  644. letter-spacing: 0.07em;
  645. color: #ffffff;
  646. background: #00a870;
  647. }
  648. .continue_table_btn {
  649. cursor: pointer;
  650. width: 93.18px;
  651. height: 32px;
  652. border-radius: 32px;
  653. display: flex;
  654. padding: 6px 25px;
  655. box-sizing: border-box;
  656. white-space: nowrap;
  657. align-items: center;
  658. justify-content: center;
  659. font-size: 14px;
  660. font-weight: normal;
  661. letter-spacing: 0.07em;
  662. color: #ffffff;
  663. background: #0052d9;
  664. }
  665. .finished_table_btn {
  666. width: 93.18px;
  667. box-sizing: border-box;
  668. white-space: nowrap;
  669. height: 32px;
  670. border-radius: 32px;
  671. display: flex;
  672. align-items: center;
  673. justify-content: space-between;
  674. font-size: 14px;
  675. font-weight: normal;
  676. letter-spacing: 0.07em;
  677. color: #ffffff;
  678. padding: 0 13px 0 5px;
  679. background: #00a870;
  680. }
  681. .not_start_table_btn {
  682. width: 93.18px;
  683. box-sizing: border-box;
  684. white-space: nowrap;
  685. height: 32px;
  686. border-radius: 32px;
  687. display: flex;
  688. align-items: center;
  689. justify-content: space-between;
  690. font-size: 14px;
  691. font-weight: normal;
  692. letter-spacing: 0.07em;
  693. color: #ffffff;
  694. padding: 0 13px 0 5px;
  695. background: #d8d8d8;
  696. }
  697. .disable_table_btn {
  698. background: #d8d8d8;
  699. cursor: default;
  700. }
  701. .path_wrap {
  702. display: flex;
  703. align-items: center;
  704. justify-content: center;
  705. }
  706. </style>