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.
212 lines
5.8 KiB
212 lines
5.8 KiB
<template>
|
|
<list-header v-if="!hideTitle" description="任务管理用于监控物理显卡的状态。它用于监控物理显卡的分配使用情况,以及查看物理显卡上运行的所有任务。" />
|
|
|
|
<Top v-if="!hideTitle" />
|
|
|
|
<table-plus :api="taskApi.getTaskList({ filters })" :columns="columns" :rowAction="rowAction"
|
|
:searchSchema="searchSchema" ref="table" :style="{ height: 'auto', ...style }" hideTag staticPage>
|
|
</table-plus>
|
|
|
|
<form-plus-drawer v-model="state.visible" v-model:form="state.formValues" :schema="state.schema" :title="state.title"
|
|
@ok="state.ok" />
|
|
</template>
|
|
|
|
<script setup lang="jsx">
|
|
import taskApi from '~/vgpu/api/task';
|
|
import { calculateDuration, roundToDecimal, timeParse, bytesToGB } from '@/utils';
|
|
import { QuestionFilled } from '@element-plus/icons-vue';
|
|
import api from '~/vgpu/api/task';
|
|
import { ElMessage, ElMessageBox, ElPopover } from 'element-plus';
|
|
import { reactive, ref, defineProps } from 'vue';
|
|
import editSchema from './editSchema';
|
|
import { mapValues, isNumber, pick } from 'lodash';
|
|
import { useRouter } from 'vue-router';
|
|
import searchSchema from './searchSchema';
|
|
import Top from './top.vue';
|
|
import useParentAction from '~/vgpu/hooks/useParentAction';
|
|
|
|
const { sendRouteChange, hasParentWindow } = useParentAction();
|
|
|
|
const props = defineProps(['hideTitle', 'filters', 'style']);
|
|
|
|
const table = ref();
|
|
|
|
const router = useRouter();
|
|
|
|
const state = reactive({
|
|
visible: false,
|
|
schema: {},
|
|
formValues: {},
|
|
title: '',
|
|
ok: () => { },
|
|
});
|
|
|
|
const columns = [
|
|
{
|
|
title: '任务名称',
|
|
dataIndex: 'name',
|
|
render: ({ name, podUid }) => (
|
|
<text-plus text={name} to={`/admin/vgpu/task/admin/detail?name=${name}&podUid=${podUid}`} />
|
|
),
|
|
},
|
|
{
|
|
title: '类型',
|
|
dataIndex: 'nataskTypeme',
|
|
render: ({ taskType }) => taskType === 'big_model' ? '大模型' : '实训',
|
|
},
|
|
{
|
|
title: '任务状态',
|
|
dataIndex: 'status',
|
|
render: ({ status, deviceIds }) => {
|
|
if (!status) return '/';
|
|
const enums = {
|
|
closed: { text: '已完成', color: '#999' },
|
|
success: { text: '运行中', color: '#2563eb' },
|
|
unknown: { text: '未知', color: '#FACC15' },
|
|
failed: { text: '错误', color: '#EF4444' },
|
|
};
|
|
const { text, color } = enums[status];
|
|
return (
|
|
<div
|
|
style={{
|
|
color,
|
|
position: 'relative',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
gap: '5px',
|
|
}}
|
|
>
|
|
<div
|
|
style={{
|
|
height: '7px',
|
|
width: '7px',
|
|
borderRadius: '50%',
|
|
backgroundColor: color,
|
|
display: 'inline-block',
|
|
}}
|
|
></div>{' '}
|
|
{text}
|
|
{(status === 'unknown' || status === 'failed') && (
|
|
<ElPopover trigger="hover" popper-style={{ width: '180px' }}>
|
|
{{
|
|
reference: () => <el-icon color="#939EA9" size="14"><QuestionFilled /></el-icon>,
|
|
default: () => (
|
|
<span style={{ marginLeft: '5px', }}>
|
|
请跳转云平台查看详情
|
|
</span>
|
|
),
|
|
}}
|
|
</ElPopover>
|
|
)}
|
|
</div>
|
|
);
|
|
},
|
|
},
|
|
{
|
|
title: '实训名称',
|
|
dataIndex: 'shixunName',
|
|
render: ({ shixunName }) => shixunName || '/',
|
|
},
|
|
{
|
|
title: '使用者角色',
|
|
width: 100,
|
|
dataIndex: 'role',
|
|
render: ({ role }) => role || '/',
|
|
},
|
|
{
|
|
title: '用户名',
|
|
dataIndex: 'username',
|
|
render: ({ username }) => username || '/',
|
|
},
|
|
// {
|
|
// title: '所属资源池',
|
|
// width: 100,
|
|
// dataIndex: 'resourcePools',
|
|
// render: ({ resourcePools }) => `${resourcePools?.length ? resourcePools.join('、') : '/'}`,
|
|
// },
|
|
{
|
|
title: '所属节点',
|
|
dataIndex: 'nodeName',
|
|
render: ({ nodeName }) => nodeName || '/',
|
|
|
|
},
|
|
{
|
|
title: 'CPU',
|
|
dataIndex: 'requestedCpuCores',
|
|
render: ({ requestedCpuCores }) => `${requestedCpuCores}核`,
|
|
},
|
|
{
|
|
title: '内存',
|
|
dataIndex: 'requestedMemory',
|
|
render: ({ requestedMemory }) => `${bytesToGB(requestedMemory)}GiB`,
|
|
},
|
|
{
|
|
title: '分配 vGPU',
|
|
width: 100,
|
|
dataIndex: 'deviceIds',
|
|
render: ({ deviceIds }) => {
|
|
return (
|
|
<ElPopover trigger="hover" popper-style={{ width: '350px' }}>
|
|
{{
|
|
reference: () => <el-tag disable-transitions>{deviceIds.length} 个</el-tag>,
|
|
default: () => (
|
|
<div
|
|
style={{
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
gap: '10px',
|
|
width: '100%',
|
|
justifyContent: 'center',
|
|
}}
|
|
>
|
|
{deviceIds.map((item) => (
|
|
<ElTag type="info">{item}</ElTag>
|
|
))}
|
|
</div>
|
|
),
|
|
}}
|
|
</ElPopover>
|
|
);
|
|
},
|
|
},
|
|
{
|
|
title: '分配算力',
|
|
dataIndex: 'allocatedCores',
|
|
render: ({ allocatedCores }) => `${allocatedCores} `,
|
|
},
|
|
{
|
|
title: '分配显存',
|
|
dataIndex: 'allocatedMem',
|
|
render: ({ allocatedMem }) =>
|
|
`${roundToDecimal(allocatedMem / 1024, 1)} GiB`,
|
|
},
|
|
|
|
{
|
|
title: '任务创建时间',
|
|
width: 140,
|
|
dataIndex: 'createTime',
|
|
render: ({ createTime }) => timeParse(createTime),
|
|
},
|
|
|
|
];
|
|
|
|
const rowAction = [
|
|
{
|
|
title: '查看详情',
|
|
onClick: (row) => {
|
|
sendRouteChange(`/admin/vgpu/task/admin/detail?name=${row.name}&podUid=${row.podUid}`);
|
|
},
|
|
},
|
|
{
|
|
title: '查看实训',
|
|
hidden: (row) => !hasParentWindow || row.taskType === 'big_model',
|
|
onClick: (row) => {
|
|
sendRouteChange(`/admins/running_pods?pod_name=${row.podName}`, 'open');
|
|
},
|
|
},
|
|
];
|
|
</script>
|
|
|
|
<style lang="scss"></style>
|