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.
 
 
 

877 lines
26 KiB

<template>
<div class="task_component">
<t-card>
<template #title>
<t-space direction="vertical">
<t-breadcrumb>
<t-breadcrumbItem>首页</t-breadcrumbItem>
<t-breadcrumbItem>任务管理中心</t-breadcrumbItem>
</t-breadcrumb>
</t-space>
</template>
<template #actions>
<t-button
v-if="role == 'ROLE_ADMIN'"
theme="primary"
@click="publishTask"
>发布任务</t-button
>
</template>
<t-table
bordered
hover
tableLayout="auto"
row-key="id"
:data="data"
:columns="columns"
:scroll="{ type: 'virtual', rowHeight: 69, bufferSize: 10 }"
resizable
/>
<t-dialog
theme="danger"
header="删除"
:body="delBody"
:visible="delVisible"
@confirm="onConfirmDelete"
:onClose="closeDelDialog"
:cancelBtn="null"
/>
<t-drawer
:visible="pathVisible"
size="'100%'"
header="自定义路径规划"
:onConfirm="saveDiyPath"
@cancel="pathVisible = false"
:onOverlayClick="() => (pathVisible = false)"
:closeBtn="true"
>
<div class="path_wrap">
<PathPlan :excelData="excelData" />
</div>
</t-drawer>
<t-dialog
header="修改操作员"
:visible="updateOperVisible"
:footer="false"
:onClose="operClose"
>
<template v-slot:body>
<t-form
:data="formData"
:rules="pubRules"
ref="form"
@reset="onReset"
@submit="onSubmit"
>
<t-form-item label="操作员" name="operatorId">
<t-select
v-model="formData.operatorId"
class="demo-select-base"
clearable
filterable
placeholder="请选择分配的操作员"
>
<t-option
v-for="item in userList"
:value="item.username"
:label="item.nickname"
:key="item.id"
>
{{ item.nickname }}
</t-option>
</t-select>
</t-form-item>
<t-form-item>
<t-space size="10px">
<t-button theme="primary" type="submit">提交</t-button>
<t-button theme="default" variant="base" type="reset"
>重置</t-button
>
</t-space>
</t-form-item>
</t-form>
</template>
</t-dialog>
</t-card>
<t-drawer
size="medium"
closeOnEscKeydown
sizeDraggable
:visible="uploadVisible"
header="上传excel"
:footer="false"
@close="handleClose"
:onConfirm="handleConfirm"
>
<t-upload
ref="uploadRef"
:action="actionAddress"
:headers="getHeaders()"
v-model="files"
status="success"
theme="file-input"
placeholder="未选择文件"
@fail="handleFail"
@success="handleSuccess"
accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
></t-upload>
</t-drawer>
<t-dialog
:visible="publishVisible"
:cancelBtn="null"
:confirmBtn="null"
v-if="role == 'ROLE_ADMIN'"
:onClose="handleCancel"
>
<template v-slot:body>
<Publish :handleCancel="handleCancel" :getTaskList="getTaskList" />
</template>
</t-dialog>
<t-dialog
theme="danger"
header="删除"
:visible="stopTaskVisible"
:onClose="() => (stopTaskVisible = false)"
:onConfirm="handleStopTask"
>
<p style="font-size: 16px; margin: 20px 0">
结束任务后将不能再继续对该任务进行核查!
</p>
</t-dialog>
</div>
</template>
<script lang="jsx">
import {
taskListApi,
delExcelByTaskIdApi,
stopTaskApi,
delTaskApi,
updateOperByTaskIdApi,
} from '@/api/task'
import { getNuclearExcelApi } from '@/api'
import PathPlan from 'cpns/PathPlan'
import Publish from 'cpns/Publish'
import { checkCanDiyPathApi, pathPlanApi, getPlanPathListApi } from '@/api/path'
import {
useAccountStore,
useTaskStore,
useImageStore,
useCameraStore,
} from '@/store'
import { allOperatorApi } from '@/api/publish'
import { getCameraConfig } from '@/api/camera'
import moment from 'moment'
import Cookie from '@/utils/cookie'
const accountStore = useAccountStore()
const taskStore = useTaskStore()
const imageStore = useImageStore()
const cameraStore = useCameraStore()
export default {
data() {
return {
stopTaskInfo: {},
stopTaskVisible: false,
publishVisible: false,
excelData: [],
pathVisible: false,
userList: [],
formData: { operatorId: '' },
pubRules: {
operatorId: [{ required: true, message: '请选择要分配的操作员' }],
},
updateOperVisible: false,
operTaskId: null,
deleteDialogIndex: false,
delVisible: false,
files: [],
tips: '上传格式仅支持xlsx',
uploadVisible: false,
data: [],
currentTaskId: '',
columns: [
{
colKey: 'taskName',
title: '任务名称',
width: 160,
},
{
colKey: 'operatorName',
title: '操作员',
width: 130,
},
{
colKey: 'publishedId',
title: '发布者',
width: 130,
},
{
colKey: 'publishTime',
title: '发布时间',
width: 190,
cell: (h, { row }) =>
moment(row.publishTime).format('YYYY-MM-DD HH:mm'),
},
{
colKey: 'nuclearStationName',
title: '核电站名称',
ellipsis: true,
width: 220,
},
{
colKey: 'nuclearCoreName',
title: '核反应堆',
width: 120,
},
{
colKey: 'status',
title: '任务状态',
width: 120,
cell: (h, { row }) => {
if (row.status == 0) {
return (
<div class="not_start_table_btn">
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
fill="none"
version="1.1"
width="24"
height="23.999755859375"
viewBox="0 0 24 23.999755859375"
>
<g>
<path
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"
fill="#FFFFFF"
fill-opacity="1"
/>
</g>
</svg>
<span>未开始</span>
</div>
)
} else if (row.status == 1) {
return (
<div
class="process_table_btn"
onClick={() => this.viewProcessTask()}
>
进行中
</div>
)
} else if (row.status == 2) {
return (
<div
class="process_table_btn continue_table_btn"
style={{ cursor: 'default' }}
>
任务暂停
</div>
)
} else {
return (
<div class="finished_table_btn">
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
fill="none"
version="1.1"
width="23.99990463256836"
height="24"
viewBox="0 0 23.99990463256836 24"
>
<g>
<path
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"
fill="#FFFFFF"
fill-opacity="1"
/>
</g>
</svg>
<span>已完成</span>
</div>
)
}
},
},
{
colKey: 'checkOrder',
title: '检测路径',
width: 120,
cell: (h, { row }) => {
if (row.checkOrder == 0) {
return '横向规则'
} else if (row.checkOrder == 1) {
return '纵向规则'
} else {
return '自定义'
}
},
},
{
colKey: 'startTime',
title: '开始时间',
width: 190,
cell: (h, { row }) => {
return row.startTime
? moment(row.startTime).format('YYYY-MM-DD HH:mm')
: '---'
},
},
{
colKey: 'endTime',
title: '完成时间',
width: 190,
cell: (h, { row }) => {
return row.endTime
? moment(row.endTime).format('YYYY-MM-DD HH:mm')
: '---'
},
},
{
title: '操作',
fixed: 'right',
colKey: 'oper',
cell: (h, { row }) => {
if (this.role == 'ROLE_ADMIN') {
return (
<div>
<t-button
variant="text"
theme="primary"
onClick={() => this.showDeleteDialog(true, row.id)}
>
删除任务
</t-button>
<t-button
variant="text"
theme="primary"
disabled={row.canUpload}
onClick={() => this.showDeleteDialog(false, row.id)}
>
删除excel
</t-button>
<t-button
variant="text"
theme="primary"
disabled={!row.canUpload}
onClick={() => this.uploadExcel(row.id)}
>
上传Excel
</t-button>
<t-button
variant="text"
theme="primary"
onClick={() => this.updateOper(row.id)}
>
修改操作员
</t-button>
<t-button
variant="text"
theme="primary"
disabled={row.canUpload || row.status != 0}
onClick={() => this.showPathDialog(row.id)}
>
自定义路径规划
</t-button>
<t-button
variant="text"
theme={
row.canUpload
? 'primary'
: row.hasError
? 'danger'
: 'success'
}
disabled={row.canUpload}
onClick={() =>
this.viewDetail(
row.id,
row.nuclearCoreName,
2,
row.nuclearStationName,
row.operatorName,
false,
row,
)
}
>
详情
</t-button>
</div>
)
} else {
return (
<div style={{ display: 'flex' }}>
{row.status == 2 && this.role == 'ROLE_USER' ? (
<div
class="continue_table_btn"
style={{ marginRight: '10px' }}
onClick={() => this.startTask(row, row.nuclearCoreName)}
>
继续任务
</div>
) : null}
{row.status == 0 && this.role == 'ROLE_USER' ? (
<div
style={{ marginRight: '10px' }}
class={
row.canUpload
? 'start_table_btn disable_table_btn'
: 'start_table_btn'
}
onClick={() =>
this.startTask(
row,
row.nuclearCoreName,
1,
row.canUpload,
)
}
>
开始任务
</div>
) : null}
<div>
{[0, 1, 2].includes(row.status) &&
this.role == 'ROLE_USER' ? (
<div
style={{ marginRight: '10px' }}
onClick={() => this.changeTaskStatusTo3(row)}
class={
row.canUpload
? 'start_table_btn disable_table_btn'
: 'start_table_btn'
}
>
结束任务
</div>
) : null}
</div>
<div
onClick={() =>
this.viewDetail(
row.id,
row.nuclearCoreName,
1,
row.nuclearStationName,
row.operatorName,
row.canUpload,
row,
)
}
class={
row.canUpload
? 'start_table_btn disable_table_btn'
: 'start_table_btn'
}
>
查看详情
</div>
</div>
)
}
},
},
],
}
},
props: [
'startCaptureFunc',
'handleSimulationBrightness',
'handleExposureTime',
'startFlashLight',
],
components: {
PathPlan,
Publish,
},
computed: {
testArrLength() {
const testArr = taskStore.excelData.filter(
item => item.firstSign && item.secondSign,
)
return testArr.length
},
hasTestedLength() {
const testArr = taskStore.excelData.filter(
item => item.firstSign && item.secondSign,
)
const hasTested = testArr.filter(item => item.result != 0)
return hasTested.length
},
actionAddress() {
return `${import.meta.env.VITE_BASE_URL}/upload/${this.currentTaskId}`
},
role() {
return Cookie.getCookie('r')
},
delBody() {
if (this.deleteDialogIndex) {
return '确认要删除当前任务吗,请确保当前任务已经废弃!'
} else {
return '确认要清空当前任务已上传的Excel路径规划吗,此操作不可逆!'
}
},
},
methods: {
async handleStopTask() {
const res = await stopTaskApi({ ...this.stopTaskInfo, status: 3 })
if (res?.code == 200) {
this.getTaskList()
this.stopTaskVisible = false
}
},
changeTaskStatusTo3(row) {
this.stopTaskVisible = true
this.stopTaskInfo = row
},
handleCancel() {
this.publishVisible = false
},
publishTask() {
this.publishVisible = true
},
async getExcelList(taskId) {
const res = await getNuclearExcelApi(taskId)
if (res?.code == 200) {
// 根据data的serialNumber算出序列号
const list = res.data.list
list.map(item => {
const arr = item.serialNumber.split('-')
item.num = parseInt(arr[0]) * 14 + parseInt(arr[1]) + 1
})
this.excelData = list
}
},
async saveDiyPath() {
const res = await pathPlanApi(this.currentTaskId, taskStore.pathData)
if (res?.code == 200) {
this.pathVisible = false
this.$message.success('设置成功')
// 更新list
this.getTaskList()
}
},
showPathDialog(taskId) {
this.currentTaskId = taskId
this.getExcelList(taskId)
const confirmDia = this.$dialog.confirm({
header: '提示',
body: '已开始的任务无法更改路径。复杂路径规划后,将清除创建任务时所选择的规则路径,确认要进行自定义规划吗?',
confirmBtn: '确定',
cancelBtn: '取消',
onConfirm: async ({ e }) => {
const res = await checkCanDiyPathApi(taskId)
if (res?.code == 200) {
// 这需要查询原先的路径 进行回显
const listRes = await getPlanPathListApi(taskId)
if (listRes?.code == 200) {
if (listRes?.data) {
taskStore.updatePathData(listRes?.data)
}
}
this.pathVisible = true
} else {
this.$message.error(res?.msg)
}
// 请求成功后,销毁弹框
confirmDia.destroy()
},
onClose: ({ e, trigger }) => {
confirmDia.hide()
},
})
},
async getAllOperator() {
const res = await allOperatorApi()
if (res?.code == 200) {
this.userList = res?.data
}
},
onReset() {
this.$message.success('重置成功')
},
async onSubmit({ validateResult, firstError }) {
if (validateResult === true) {
const res = await updateOperByTaskIdApi(this.operTaskId, this.formData)
if (res?.code == 200) {
this.getTaskList()
this.updateOperVisible = false
this.operTaskId = null
this.$message.success('修改成功')
}
} else {
this.$message.warning(firstError)
}
},
updateOper(taskId) {
this.operTaskId = taskId
if (this.role == 'ROLE_ADMIN') {
this.getAllOperator()
}
this.updateOperVisible = true
},
operClose() {
this.updateOperVisible = false
},
onConfirmDelete() {
if (this.deleteDialogIndex) {
this.delTask(this.operTaskId)
} else {
this.delExcel(this.operTaskId)
}
},
closeDelDialog() {
this.delVisible = false
},
showDeleteDialog(index, taskId) {
this.deleteDialogIndex = index
this.operTaskId = taskId
this.delVisible = true
},
viewProcessTask() {
accountStore.changePage(0)
taskStore.updateCurrentDetailTaskId(null)
},
async startTask(row, coreName, flag, canUpload) {
if (flag == 1 && canUpload) {
return
}
this.startCaptureFunc()
this.startFlashLight()
setTimeout(() => {
this.startFlashLight()
}, 1000)
// websocketsend(openFlashLight)
// 需要设置相机的参数 根据核堆id获取
const res = await getCameraConfig(row.nuclearCoreId)
if (res?.code == 200) {
if (res?.data?.exposure) {
// 改变相机的exposure
this.handleExposureTime(res?.data?.exposure)
}
if (res?.data?.brightness) {
// 改变相机的simulation_brightness
this.handleSimulationBrightness(res?.data?.brightness)
}
}
taskStore.updateTaskStatus(row.status)
taskStore.updateCurrentCoord(row.currentCoord)
imageStore.updateNuclearCoreName(coreName)
Cookie.setCookie('core_name', coreName)
imageStore.updateOperatorName(row.operatorName)
imageStore.updateNuclearStationName(row.nuclearCoreName)
imageStore.updateShowImage(false)
accountStore.changePage(0)
await taskStore.getExcelList(row.id)
taskStore.updateCurrentTaskId(row.id)
taskStore.updateCurrentDetailTaskId(null)
},
async viewDetail(
taskId,
nuclearCoreName,
flag,
nuclearStationName,
operatorName,
canUpload,
row,
) {
if (flag == 1 && canUpload) {
return
}
this.startCaptureFunc()
this.startFlashLight()
setTimeout(() => {
this.startFlashLight()
}, 1000)
// websocketsend(openFlashLight)
// 需要设置相机的参数 根据核堆id获取
const res = await getCameraConfig(row.nuclearCoreId)
if (res?.code == 200) {
if (res?.data?.exposure) {
// 改变相机的exposure
this.handleExposureTime(res?.data?.exposure)
}
if (res?.data?.brightness) {
// 改变相机的simulation_brightness
this.handleSimulationBrightness(res?.data?.brightness)
}
}
// 直接取消继续任务按钮
cameraStore.updateContinueTask(false)
imageStore.updateNuclearStationName(nuclearStationName)
imageStore.updateOperatorName(operatorName)
imageStore.updateNuclearCoreName(nuclearCoreName)
taskStore.updateCurrentDetailTaskId(taskId)
imageStore.updateShowImage(false)
accountStore.changePage(0)
taskStore.getExcelList(taskId)
},
handleSuccess({ response }) {
console.log(response)
if (response?.code == 200) {
this.uploadVisible = false
this.getTaskList()
this.$message.success('上传成功')
} else {
this.$message.error(response?.msg)
}
},
handleFail({ file }) {
this.$message.error(`文件 ${file.name} 上传失败`)
},
getHeaders() {
return {
Authorization: Cookie.getCookie('t'),
}
},
handleClose() {
this.uploadVisible = false
},
handleConfirm() {
console.log(this.$refs)
this.$refs.uploadRef.triggerUpload()
},
async delTask(taskId) {
const res = await delTaskApi(taskId)
if (res?.code == 200) {
if (res?.data?.result) {
this.$message.success('删除任务成功')
this.getTaskList()
this.delVisible = false
}
}
},
async delExcel(taskId) {
const res = await delExcelByTaskIdApi(taskId)
if (res?.code == 200) {
if (res?.data?.result) {
this.$message.success('删除该任务的excel计划表成功')
this.getTaskList()
this.delVisible = false
}
}
},
uploadExcel(taskId) {
this.currentTaskId = taskId
this.uploadVisible = true
},
async getTaskList() {
const res = await taskListApi()
if (res?.code == 200) {
this.data = res?.data
}
},
},
mounted() {
this.getTaskList()
},
}
</script>
<style lang="scss">
.task_component {
height: 90vh;
overflow: scroll;
}
.process_table_btn {
width: 93.18px;
height: 32px;
border-radius: 32px;
display: flex;
padding: 6px 25px;
align-items: center;
justify-content: center;
font-size: 14px;
font-weight: normal;
box-sizing: border-box;
white-space: nowrap;
letter-spacing: 0.07em;
color: #ffffff;
background: #ed7b2f;
cursor: pointer;
}
.start_table_btn {
cursor: pointer;
width: 93.18px;
box-sizing: border-box;
white-space: nowrap;
height: 32px;
border-radius: 32px;
display: flex;
padding: 6px 25px;
align-items: center;
justify-content: center;
font-size: 14px;
font-weight: normal;
letter-spacing: 0.07em;
color: #ffffff;
background: #00a870;
}
.continue_table_btn {
cursor: pointer;
width: 93.18px;
height: 32px;
border-radius: 32px;
display: flex;
padding: 6px 25px;
box-sizing: border-box;
white-space: nowrap;
align-items: center;
justify-content: center;
font-size: 14px;
font-weight: normal;
letter-spacing: 0.07em;
color: #ffffff;
background: #0052d9;
}
.finished_table_btn {
width: 93.18px;
box-sizing: border-box;
white-space: nowrap;
height: 32px;
border-radius: 32px;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 14px;
font-weight: normal;
letter-spacing: 0.07em;
color: #ffffff;
padding: 0 13px 0 5px;
background: #00a870;
}
.not_start_table_btn {
width: 93.18px;
box-sizing: border-box;
white-space: nowrap;
height: 32px;
border-radius: 32px;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 14px;
font-weight: normal;
letter-spacing: 0.07em;
color: #ffffff;
padding: 0 13px 0 5px;
background: #d8d8d8;
}
.disable_table_btn {
background: #d8d8d8;
cursor: default;
}
.path_wrap {
display: flex;
align-items: center;
justify-content: center;
}
::-webkit-scrollbar {
width: 0; /*隐藏滚动条空间*/
background-color: transparent; /*隐藏背景*/
}
</style>