13 changed files with 463 additions and 618 deletions
@ -0,0 +1,70 @@ |
|||||||
|
import { globalServer } from '../index' |
||||||
|
|
||||||
|
interface Param { |
||||||
|
page: number |
||||||
|
size: number |
||||||
|
} |
||||||
|
|
||||||
|
export const getTaskList = (params: Param) => |
||||||
|
globalServer<{ |
||||||
|
tasks: TaskList[] |
||||||
|
total: number |
||||||
|
}>({ |
||||||
|
url: 'api/task/summary', |
||||||
|
method: 'get', |
||||||
|
data: params, |
||||||
|
|
||||||
|
}) |
||||||
|
|
||||||
|
|
||||||
|
export const getTaskInfo = (taskId: string) => globalServer<{ details: TaskInfo[] }>({ |
||||||
|
url: 'api/task/detail', |
||||||
|
method: 'GET', |
||||||
|
params: { task: taskId }, |
||||||
|
}) |
||||||
|
|
||||||
|
export interface TaskCreateParams { |
||||||
|
site: string |
||||||
|
devices: { |
||||||
|
sn: string |
||||||
|
disk?: string |
||||||
|
host?: string |
||||||
|
}[], |
||||||
|
mode: 'import' | 'export' | 'update' |
||||||
|
startTime?: string |
||||||
|
endTime?: string |
||||||
|
} |
||||||
|
|
||||||
|
export const createTask = (params: TaskCreateParams) => globalServer({ |
||||||
|
url: 'api/task/apply', |
||||||
|
method: 'POST', |
||||||
|
data: params, |
||||||
|
}) |
||||||
|
|
||||||
|
export const cancelTask = (taskId: string) => globalServer({ |
||||||
|
url: 'api/task/cancel', |
||||||
|
method: 'POST', |
||||||
|
data: { task: taskId }, |
||||||
|
}) |
||||||
|
|
||||||
|
export type TaskInfo = { |
||||||
|
finish: number; |
||||||
|
id: string; |
||||||
|
info: string; |
||||||
|
site: string; |
||||||
|
sn: string; |
||||||
|
status: -1 | 0 | 1 | 2; // -1 失败, 0 未开始, 1 进行中, 2 成功
|
||||||
|
task_id: string; |
||||||
|
total: number; |
||||||
|
}; |
||||||
|
|
||||||
|
export interface TaskList { |
||||||
|
endTime: string; // 结束时间(可能是空字符串)
|
||||||
|
id: string; // "task759956"
|
||||||
|
info: string; // ""
|
||||||
|
mode: string; // "export"
|
||||||
|
site: string; // "test1"
|
||||||
|
startTime: string; // 开始时间(可能是空字符串)
|
||||||
|
status: -1 | 0 | 1 | 2 | 3; // -1 失败, 0 未开始, 1 进行中, 2 取消, 3 成功
|
||||||
|
loading?: boolean |
||||||
|
} |
@ -0,0 +1,130 @@ |
|||||||
|
<template> |
||||||
|
<div class="task-list wh-full"> |
||||||
|
<EdfsWrap title="任务列表" class="h-full"> |
||||||
|
<EdfsTable class="wh-full" v-loading="loading" :data="list" ref="tableRef" :highlight-current-row="true" |
||||||
|
:page-total="total" :current-page="queryParams.page" :page-size="queryParams.size" row-class-name="row" |
||||||
|
@pageCurrentChange="handleJump"> |
||||||
|
<template v-for="(col, idx) in tableCol" :key="idx"> |
||||||
|
<el-table-column v-if="col.prop.endsWith('Time')" :label="col.label" :min-width="col.minWidth"> |
||||||
|
<template #default="scope"> |
||||||
|
{{ dayjs(scope.row.createTime).format('YYYY-MM-DD HH:mm:ss') }} |
||||||
|
</template> |
||||||
|
</el-table-column> |
||||||
|
<el-table-column v-else-if="col.prop === 'status'" :prop="col.prop" :label="col.label" |
||||||
|
:min-width="col.minWidth"> |
||||||
|
<template #default="scope"> |
||||||
|
{{taskStatus.find(r => r.value === scope.row.status)?.label || '--'}} |
||||||
|
</template> |
||||||
|
</el-table-column> |
||||||
|
<el-table-column v-else-if="col.prop === 'mode'" :prop="col.prop" :label="col.label" |
||||||
|
:min-width="col.minWidth"> |
||||||
|
<template #default="scope"> |
||||||
|
{{taskMode.find(r => r.value === scope.row.mode)?.label || '--'}} |
||||||
|
</template> |
||||||
|
</el-table-column> |
||||||
|
<el-table-column v-else :prop="col.prop" :label="col.label" :min-width="col.minWidth" /> |
||||||
|
</template> |
||||||
|
<el-table-column label="操作" width="210" align="center"> |
||||||
|
<template #default="scope"> |
||||||
|
<EdfsButton size="small" link type="primary" inner-text="详情" @click="onDetail(scope.row)" /> |
||||||
|
<EdfsButton size="small" link type="danger" v-if="[0, 1].includes(scope.row.mode)" inner-text="取消任务" |
||||||
|
@click="onCancel(scope.row.id)" /> |
||||||
|
</template> |
||||||
|
</el-table-column> |
||||||
|
</EdfsTable> |
||||||
|
|
||||||
|
</EdfsWrap> |
||||||
|
</div> |
||||||
|
<InfoDrawer ref="InfoDrawerRef" /> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script setup lang="ts"> |
||||||
|
import { cancelTask, getTaskInfo, getTaskList, type TaskInfo, type TaskList } from '@/api/module/taks' |
||||||
|
import { useMessage } from '@/composables/useMessage' |
||||||
|
import dayjs from 'dayjs' |
||||||
|
import InfoDrawer from './infoDrawer.vue' |
||||||
|
|
||||||
|
const message = useMessage() |
||||||
|
const taskStatus = [{ |
||||||
|
value: -1, |
||||||
|
label: '执行失败' |
||||||
|
}, { |
||||||
|
label: '等待执行', |
||||||
|
value: 0 |
||||||
|
}, { |
||||||
|
label: '执行中', |
||||||
|
value: 1 |
||||||
|
}, { |
||||||
|
label: '已取消', |
||||||
|
value: 2 |
||||||
|
}, { |
||||||
|
label: '执行成功', |
||||||
|
value: 3 |
||||||
|
}] |
||||||
|
|
||||||
|
const taskMode = [{ |
||||||
|
value: 'export', |
||||||
|
label: '迁移' |
||||||
|
}, { |
||||||
|
value: 'import', |
||||||
|
label: '导入' |
||||||
|
}, { |
||||||
|
value: 'update', |
||||||
|
label: '升级' |
||||||
|
}] |
||||||
|
|
||||||
|
const tableCol = [ |
||||||
|
{ label: '任务ID', prop: 'id', minWidth: '10%' }, |
||||||
|
{ label: '站点', prop: 'site', minWidth: '16%' }, |
||||||
|
{ label: '任务类型', prop: 'mode', minWidth: '10%' }, |
||||||
|
{ label: '任务状态', prop: 'status', minWidth: '10%' }, |
||||||
|
{ label: '创建时间', prop: 'startTime', minWidth: '10%' }, |
||||||
|
] |
||||||
|
|
||||||
|
|
||||||
|
const loading = ref(true) |
||||||
|
const total = ref(0) |
||||||
|
const list = ref<TaskList[]>([]) |
||||||
|
const queryParams = reactive({ |
||||||
|
page: 1, |
||||||
|
size: undefined, |
||||||
|
|
||||||
|
}) |
||||||
|
const tableRef = ref() |
||||||
|
const getList = async () => { |
||||||
|
if (!queryParams.size) { |
||||||
|
queryParams.size = tableRef.value.getSize() |
||||||
|
} |
||||||
|
loading.value = true |
||||||
|
|
||||||
|
const res = await getTaskList(queryParams as any) |
||||||
|
|
||||||
|
if (res !== null && res.code === 0) { |
||||||
|
list.value = res.data.tasks |
||||||
|
total.value = res.data.total |
||||||
|
} |
||||||
|
|
||||||
|
loading.value = false |
||||||
|
} |
||||||
|
|
||||||
|
function handleJump(page: number) { |
||||||
|
queryParams.page = page |
||||||
|
getList() |
||||||
|
} |
||||||
|
|
||||||
|
const InfoDrawerRef = ref<typeof InfoDrawer>() |
||||||
|
function onDetail(row: TaskList) { |
||||||
|
InfoDrawerRef.value?.open(row) |
||||||
|
} |
||||||
|
const onCancel = async (id: string) => { |
||||||
|
await message.delConfirm(`是否确认取消该任务?`) |
||||||
|
const res = await cancelTask(id) |
||||||
|
if (res.code !== 0) return |
||||||
|
await getList() |
||||||
|
} |
||||||
|
onMounted(() => { |
||||||
|
getList() |
||||||
|
}) |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped></style> |
@ -0,0 +1,107 @@ |
|||||||
|
<template> |
||||||
|
<div class="fault-rule-drawer"> |
||||||
|
<el-drawer v-model="isShowDrawer" title="任务详情" direction="rtl" size="50%" modal-class="model-dev-opn" |
||||||
|
:before-close="handleBeforeClose"> |
||||||
|
<main class="wh-full" v-loading="loading"> |
||||||
|
<template v-for="detail in detailList"> |
||||||
|
<el-descriptions border :title="`${detail.sn}任务详情`"> |
||||||
|
<el-descriptions-item :label-width="60" label="状态"> <el-tag size="small">{{statusList.find(r => r.value === |
||||||
|
detail.status)?.label || '--' |
||||||
|
}}</el-tag></el-descriptions-item> |
||||||
|
<el-descriptions-item :label-width="100" label="总数数据量">{{ detail.total }}</el-descriptions-item> |
||||||
|
<el-descriptions-item :label-width="110" label="已完成数据量">{{ detail.finish }}</el-descriptions-item> |
||||||
|
<el-descriptions-item :label-width="60" label="信息"> |
||||||
|
{{ detail?.info ? detail.info : '暂无信息' }} |
||||||
|
</el-descriptions-item> |
||||||
|
<el-descriptions-item label="当前进度"> |
||||||
|
<template v-if="detail.total === 0"> |
||||||
|
<span>暂无进度</span> |
||||||
|
</template> |
||||||
|
<el-progress v-else style="width: 95%;" :percentage="Math.floor((detail.finish / detail.total) * 100)" |
||||||
|
:text-inside="true" :stroke-width="20" /> |
||||||
|
</el-descriptions-item> |
||||||
|
</el-descriptions> |
||||||
|
</template> |
||||||
|
</main> |
||||||
|
</el-drawer> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script setup lang="ts"> |
||||||
|
import { getSubTopic, type PubMsgData } from '@/utils/zmq' |
||||||
|
import ZMQWorker from '@/composables/useZMQJsonWorker' |
||||||
|
import { getTaskInfo, type TaskInfo, type TaskList } from '@/api/module/taks' |
||||||
|
import { useMessage } from '@/composables/useMessage' |
||||||
|
|
||||||
|
const message = useMessage() |
||||||
|
const worker = ZMQWorker.getInstance() |
||||||
|
const isShowDrawer = defineModel<boolean>() |
||||||
|
|
||||||
|
const detailList = ref<TaskInfo[]>([]) |
||||||
|
const loading = ref(false) |
||||||
|
|
||||||
|
async function onDetail(row: TaskList) { |
||||||
|
loading.value = true |
||||||
|
const res = await getTaskInfo(row.id); |
||||||
|
if (res.code === 0) { |
||||||
|
detailList.value = res?.data?.details ?? [] |
||||||
|
} else { |
||||||
|
message.error('获取任务详情失败') |
||||||
|
} |
||||||
|
loading.value = false |
||||||
|
} |
||||||
|
const curentTaskId = ref('') |
||||||
|
async function open(row: TaskList) { |
||||||
|
isShowDrawer.value = true |
||||||
|
curentTaskId.value = row.id |
||||||
|
await onDetail(row) |
||||||
|
worker.subscribe(getSubTopic('server', 'event', 'task'), zmqTaskCb) |
||||||
|
} |
||||||
|
|
||||||
|
const statusList = [ |
||||||
|
{ label: '未开始', value: 0 }, |
||||||
|
{ label: '进行中', value: 1 }, |
||||||
|
{ label: '成功', value: 2 }, |
||||||
|
{ label: '失败', value: -1 }, |
||||||
|
] |
||||||
|
|
||||||
|
|
||||||
|
function zmqTaskCb(msg: PubMsgData) { |
||||||
|
const { feedback, result, id } = msg |
||||||
|
const taskId = feedback[0] |
||||||
|
const deviceSN = feedback[1] |
||||||
|
const deviceStatus = feedback[2] || '未知状态' |
||||||
|
const finish = feedback[3] || 0 |
||||||
|
const total = feedback[4] || 0 |
||||||
|
if (curentTaskId.value !== taskId) return |
||||||
|
const detail = detailList.value.find(item => item.sn === deviceSN) |
||||||
|
if (!detail) return |
||||||
|
detail.status = deviceStatus |
||||||
|
detail.finish = finish |
||||||
|
detail.total = total |
||||||
|
} |
||||||
|
|
||||||
|
function handleBeforeClose(done: () => void) { |
||||||
|
isShowDrawer.value = false |
||||||
|
curentTaskId.value = '' |
||||||
|
done() |
||||||
|
} |
||||||
|
|
||||||
|
defineExpose({ |
||||||
|
open, |
||||||
|
}) |
||||||
|
</script> |
||||||
|
|
||||||
|
<style scoped lang="scss"> |
||||||
|
.fault-rule-drawer { |
||||||
|
font-size: 16px; |
||||||
|
|
||||||
|
:deep(.edfs-wrap) { |
||||||
|
width: auto; |
||||||
|
} |
||||||
|
|
||||||
|
:deep(.el-drawer__header) { |
||||||
|
color: var(--text-color); |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
Loading…
Reference in new issue