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.

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