update:创建算例,上传结果文件功能更新

This commit is contained in:
2025-11-20 14:40:05 +08:00
parent 551218659c
commit e9b2e3156b
10 changed files with 1293 additions and 130 deletions

View File

@@ -193,7 +193,7 @@ const uploadLocalFileFn = async (File: any) => {
const performanceInfoList = [
{
chineseName: '指标名称',
englishName: 'performanceName',
englishName: 'nodeName',
},
{
chineseName: '英文名',

View File

@@ -2,7 +2,7 @@
<div class="comp-content">
<el-drawer v-model="visible" :title="`新增参数`" :size="400" :close-on-click-modal="false" @close="closeFun">
<div class="content">
<TableForm ref="tableFormRef" :tableName="tableName" />
<TableForm ref="tableFormRef" :tableName="tableName" :data="{}" />
</div>
<template #footer>
<div>

View File

@@ -203,6 +203,10 @@ const addConfigParamFn = async (data: any) => {
return;
}
if (!tableData.value) {
tableData.value = [];
}
tableData.value.push(addData);
baseTableRef.value.setDataFun(tableData.value);

View File

@@ -2,31 +2,38 @@
<div class="filter-project-content">
<el-form :model="filterFormData">
<el-form-item label="类型:">
<el-select v-model="filterFormData.ProjectType"></el-select>
<el-select v-model="filterFormData.ProjectType" @change="projectInfoChangeFn('projectType')">
<el-option v-for="item in projectTypeList" :key="item.uuid" :label="item.dictName" :value="item.dictValue"></el-option>
</el-select>
</el-form-item>
<el-form-item label="项目:">
<el-select v-model="filterFormData.projectName"></el-select>
<el-select v-model="filterFormData.projectName" filterable @change="projectInfoChangeFn('projectName')">
<el-option v-for="item in projectList" :key="item.id" :label="item.nodeName" :value="item.uuid"></el-option>
</el-select>
</el-form-item>
<el-form-item label="节点:">
<el-select v-model="filterFormData.phaseName"></el-select>
<el-select v-model="filterFormData.phaseName" @change="projectInfoChangeFn('phaseName')">
<el-option v-for="item in pheseList" :key="item.id" :label="item.nodeName" :value="item.uuid"></el-option>
</el-select>
</el-form-item>
<el-form-item label="学科">
<!-- <el-form-item label="工位">
<el-select v-model="filterFormData.discipline"></el-select>
</el-form-item>
<el-form-item label="归属:">
<el-select v-model="filterFormData.attribution"></el-select>
</el-form-item>
</el-form-item> -->
<el-form-item>
<div class="check-box">
<el-radio-group v-model="filterFormData.taskType" >
<!-- <el-radio-group v-model="filterFormData.taskType">
<el-radio-button label="全部" value="all" />
<el-radio-button label="试验" value="test" />
<el-radio-button label="仿真" value="simulation" />
</el-radio-group>
</el-radio-group> -->
<el-dropdown>
<span class="el-dropdown-link">
@@ -40,7 +47,8 @@
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item v-for="item in dropdownList" :key="item.value" @click="expendChangeFn(item.value)"> {{ item.name }}</el-dropdown-item>
<el-dropdown-item v-for="item in dropdownList" :key="item.value" @click="expendChangeFn(item.value)"> {{
item.name }}</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
@@ -52,20 +60,22 @@
</template>
<script setup lang="ts">
import { getChildrenNodeListApi, queryNodeListApi } from '@/api/project/node';
import { getDictionaryDataApi } from '@/api/system/systemData';
import { ref, reactive, onMounted } from 'vue';
const props = defineProps({
projectCurrentInfo: {
type: Object,
default: () => {},
default: () => { },
},
});
const emits = defineEmits(['filterParamChangeFn']);
const filterFormData = reactive<any>({
ProjectType: 'default',
projectName: 'project',
phaseName: 'phase',
const filterFormData = reactive({
ProjectType: 'self_develop',
projectName: '',
phaseName: '',
discipline: 'discipline',
attribution: 'personal',
taskType: 'all',
@@ -91,7 +101,7 @@ const dropdownList = ref([
},
]);
const expendChangeFn = (data:string) => {
const expendChangeFn = (data: string) => {
filterFormData.expendType = data;
filterParamChangeFn();
};
@@ -100,39 +110,120 @@ const filterParamChangeFn = () => {
emits('filterParamChangeFn', filterFormData);
};
onMounted(() => {
// 获取项目类型列表
const projectTypeList = ref<any>([]);
const getProjectTypeFn = async () => {
const res:any = await getDictionaryDataApi({
dictClass: 'PROJECT_TYPE',
});
if (res && res.code === 200) {
projectTypeList.value = res.data;
} else {
projectTypeList.value = [];
}
};
// 获取项目列表
const projectList = ref<any>([]);
const getProjectListFn = async () => {
const res: any = await queryNodeListApi({
current: 1,
nodeType: 'project',
size: 999,
nodeSubType: filterFormData.ProjectType,
});
if (res && res.code === 200) {
projectList.value = res.data.data;
if ( projectList.value.length) {
filterFormData.projectName = projectList.value[0].uuid;
}
} else {
filterFormData.projectName = '';
}
};
// 获取阶段列表
const pheseList = ref<any>([]);
const getPhaseListFn = async() => {
if (filterFormData.projectName) {
const res:any = await getChildrenNodeListApi({
current: 1,
size: 999,
nodeId: filterFormData.projectName,
nodeType: 'phase',
});
if (res && res.code === 200) {
pheseList.value = res.data;
if ( pheseList.value.length) {
filterFormData.phaseName = pheseList.value[0].uuid;
}
} else {
pheseList.value = [];
filterFormData.phaseName = '';
}
} else {
filterFormData.phaseName = '';
}
};
const projectInfoChangeFn = async (flag:any) => {
if (flag === 'projectType') {
filterFormData.projectName = '';
filterFormData.phaseName = '';
await getProjectListFn();
}
if (flag === 'projectName') {
await getPhaseListFn();
}
emits('filterParamChangeFn', filterFormData);
};
onMounted(async () => {
if (props.projectCurrentInfo) {
} else {
await getProjectTypeFn();
await getProjectListFn();
await getPhaseListFn();
projectInfoChangeFn('null');
}
});
</script>
<style lang="scss" scoped>
.filter-project-content {
width: 100%;
.filter-project-content{
.check-box {
width: 100%;
.check-box{
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: flex-end;
}
height: 100%;
display: flex;
align-items: center;
justify-content: flex-end;
}
}
.el-dropdown{
color: var(--el-color-primary);
margin-left: 10px;
.el-dropdown {
color: var(--el-color-primary);
margin-left: 10px;
}
.example-showcase .el-dropdown-link {
cursor: pointer;
color: var(--el-color-primary);
display: flex;
align-items: center;
}
</style>

View File

@@ -6,10 +6,12 @@
</div>
<div class="tree-content">
<el-tree
ref="taskTreeRef"
:data="dataSource"
node-key="id"
highlight-current
:expand-on-click-node="false"
:default-expanded-keys="defaultExpandKeys"
@current-change="nodeChangeClickFn"
@node-contextmenu="rowRightClickFn"
>
@@ -26,87 +28,125 @@
<el-icon v-else :size="16" class="blue">
<Folder />
</el-icon>
<span v-if="data.nodeType === NODE_TYPE.RUN" :title="data.runName" class="name ellipsis">{{ data.nodeName
|| data.runName }}</span>
<span class="name">{{ node.label }}</span>
<span class="name" v-else>{{ data.nodeName || data.runName }}</span>
</div>
<div v-if="data.nodeType === NODE_TYPE.RUN">
<div class="run-suatus" v-if="data.nodeType === NODE_TYPE.RUN">
<el-icon class="info" title="未开始" v-if="data.status === 0">
<InfoFilled />
</el-icon>
<el-icon class="upload" title="进行中" v-if="data.status === 1">
<HelpFilled />
</el-icon>
<el-icon class="success" title="已完成" v-if="data.status === 2">
<SuccessFilled />
</el-icon>
<el-icon class="upload" title="回传中" v-if="data.status === 3">
<UploadFilled />
</el-icon>
<el-icon class="warn" title="异常" v-if="data.status === 4">
<WarningFilled />
</el-icon>
</div>
</div>
</template>
</el-tree>
<createRunDiv
v-if="showRunCreateOrEditWindow"
:operate-flag="windowFlag"
:div-info="rightClickNode"
@close="showRunCreateOrEditWindow = false"
@comfirm="createRunFn"
@update="updateRunInfoFn"
></createRunDiv>
</div>
<Teleport to="body">
<div class="fileMenu" ref="fileMenuRef" :id="'fileMenu' + tableId" @contextmenu.stop="" @contextmenu.prevent="">
<p class="menuButton" v-if="rightClickNodeInfo?.nodeType === NODE_TYPE.TASK">
<p class="menuButton" v-if="rightClickNodeInfo?.nodeType === NODE_TYPE.TASK" @click="showDiaFn('createRun')">
<el-icon>
<CirclePlus />
</el-icon>新建算例
</p>
<p class="menuButton" v-if="rightClickNodeInfo?.nodeType === NODE_TYPE.TASK">
<p class="menuButton" v-if="rightClickNodeInfo?.nodeType === NODE_TYPE.TASK" @click="showDiaFn('updateTask')">
<el-icon>
<Operation />
</el-icon>状态修改
</p>
<p class="menuButton" v-if="rightClickNodeInfo?.nodeType === NODE_TYPE.TASK">
<p class="menuButton" v-if="rightClickNodeInfo?.nodeType === NODE_TYPE.TASK" @click="showDiaFn('inputParam')">
<el-icon>
<SetUp />
</el-icon>输入参数
</p>
<p class="menuButton" v-if="rightClickNodeInfo?.nodeType === NODE_TYPE.TASK">
<p class="menuButton" v-if="rightClickNodeInfo?.nodeType === NODE_TYPE.TASK" @click="showDiaFn('focukTask')">
<el-icon>
<StarFilled />
</el-icon>关注任务
</p>
<p class="menuButton" v-if="rightClickNodeInfo?.nodeType === NODE_TYPE.RUN">
<p
class="menuButton"
v-if="rightClickNodeInfo?.nodeType === NODE_TYPE.RUN"
@click="showDiaFn('createChildRun')"
>
<el-icon>
<Files />
</el-icon>建子算例
</p>
<p class="menuButton" v-if="rightClickNodeInfo?.nodeType === NODE_TYPE.RUN">
<p class="menuButton" v-if="rightClickNodeInfo?.nodeType === NODE_TYPE.RUN" @click="showDiaFn('copyRun')">
<el-icon>
<DocumentCopy />
</el-icon>复制算例
</p>
<p class="menuButton" v-if="rightClickNodeInfo?.nodeType === NODE_TYPE.RUN">
<p class="menuButton" v-if="rightClickNodeInfo?.nodeType === NODE_TYPE.RUN" @click="showDiaFn('editRun')">
<el-icon>
<Edit />
</el-icon>编辑说明
</p>
<p class="menuButton" v-if="rightClickNodeInfo?.nodeType === NODE_TYPE.RUN">
<p class="menuButton" v-if="rightClickNodeInfo?.nodeType === NODE_TYPE.RUN" @click="showDiaFn('shareRun')">
<el-icon>
<CopyDocument />
</el-icon>共享算例
</p>
<p class="menuButton">
<p class="menuButton" @click="showDiaFn('showPerformance')">
<el-icon>
<DataLine />
</el-icon>查看指标
</p>
<p class="menuButton">
<p class="menuButton" @click="showDiaFn('runVersion')">
<el-icon>
<Share />
</el-icon>算例版本
</p>
<p class="menuButton" v-if="rightClickNodeInfo?.nodeType === NODE_TYPE.RUN">
<p
class="menuButton"
v-if="rightClickNodeInfo?.nodeType === NODE_TYPE.RUN"
@click="showDiaFn('archiveOriginalExamples')"
>
<el-icon>
<FolderChecked />
</el-icon>归档原始算例
</p>
<p class="menuButton" v-if="rightClickNodeInfo?.nodeType === NODE_TYPE.RUN">
<p
class="menuButton"
v-if="rightClickNodeInfo?.nodeType === NODE_TYPE.RUN"
@click="showDiaFn('archiveOptimizationExamples')"
>
<el-icon>
<FolderRemove />
</el-icon>归档优化算例
</p>
<p class="menuButton" v-if="rightClickNodeInfo?.nodeType === NODE_TYPE.RUN">
<p class="menuButton" v-if="rightClickNodeInfo?.nodeType === NODE_TYPE.RUN" @click="showDiaFn('delRun')">
<el-icon>
<Delete />
</el-icon>删除算例
</p>
</div>
</Teleport>
</div>
</template>
@@ -116,79 +156,110 @@ import { ref, onMounted, onBeforeUnmount } from 'vue';
import filterProject from '../filterProject/index.vue';
import { NODE_TYPE } from '@/utils/enum/node';
import { Folder, Document, ScaleToOriginal } from '@element-plus/icons-vue';
import createRunDiv from './operateComponent/createRunDiv.vue';
import { addTaskRunApi, createRunDirApi, deleteTaskRunApi, getTaskRunTreeApi, queryTaskRunApi } from '@/api/project/task';
const emits = defineEmits(['nodeClickFn']);
// 过滤数内容
const filterParamChangeFn = (data: any) => {
console.log(data, 'data');
};
const tableId = ref(new Date().getTime());
const showFileMenu = ref(false);
const showRunCreateOrEditWindow = ref(false);
const taskTreeRef = ref();
const defaultExpandKeys = ref<any>([]);
// 过滤数内容
const filterParamChangeFn = async (data: any) => {
console.log(data, 'data');
currentNodeInfo.value = {};
emits('nodeClickFn', { node: currentNodeInfo.value });
await getTaskRunTreeDataFn(data);
};
const dataSource = ref<any[]>([
{
id: 1,
label: '节点 1',
children: [
]);
const getTaskRunTreeDataFn = async (data: any) => {
if (data.projectName && data.phaseName) {
const res: any = await getTaskRunTreeApi(
{
id: 4,
label: '任务 1-1',
nodeType: 'task',
children: [
projectNodeId: data.projectName,
phaseNodeId: data.phaseName,
idMap: [
{
id: 9,
label: '算例 1-1-1',
nodeType: 'run',
key: data.projectName,
value: 'tag1',
},
{
id: 10,
label: '算例 1-1-2',
nodeType: 'run',
key: data.phaseName,
value: 'tag2',
},
{
key: null,
value: 'tag3',
},
{
key: null,
value: 'tag4',
},
{
key: null,
value: 'tag5',
},
{
key: null,
value: 'tag6',
},
{
key: null,
value: 'tag7',
},
{
key: null,
value: 'tag8',
},
{
key: null,
value: 'tag9',
},
{
key: null,
value: 'tag10',
},
],
},
],
},
{
id: 2,
label: '节点 2',
children: [
{
id: 5,
label: '任务 2-1',
nodeType: 'task',
tagMap: [
{
key: 'project',
value: 'tag1',
},
{
key: 'phase',
value: 'tag2',
},
{
key: 'machine',
value: 'tag4',
},
{
key: 'workspace',
value: 'tag5',
},
{
key: 'discipline',
value: 'tag6',
},
],
}
);
},
{
id: 6,
label: '任务 2-2',
nodeType: 'task',
if (res && res.code === 200) {
dataSource.value = res.data;
}
} else {
dataSource.value = [];
}
},
],
},
{
id: 3,
label: '节点 3',
children: [
{
id: 7,
label: '任务 3-1',
nodeType: 'task',
};
},
{
id: 8,
label: '任务 3-2',
nodeType: 'task',
},
],
},
]);
const showFileMenu = ref(false);
/**
* 点击选中的节点数据
*/
@@ -196,7 +267,7 @@ const currentNodeInfo = ref<any>(null);
const nodeChangeClickFn = (data: any) => {
clearTreeMenuFn();
currentNodeInfo.value = data;
defaultExpandKeys.value = [data.id];
emits('nodeClickFn', { node: currentNodeInfo.value });
};
@@ -204,12 +275,15 @@ const nodeChangeClickFn = (data: any) => {
* 右键菜单选择的节点信息
*/
const rightClickNodeInfo = ref<any>(null);
const rightClickNode = ref<any>(null);
// 右键菜单
const rowRightClickFn = (e: any, data: any) => {
clearTreeMenuFn();
const rowRightClickFn = (e: any, data: any, node: any) => {
// clearTreeMenuFn();
console.log('1234', data);
console.log('1234', node);
rightClickNodeInfo.value = data;
rightClickNode.value = data;
if (rightClickNodeInfo.value.nodeType != NODE_TYPE.TASK && rightClickNodeInfo.value.nodeType != NODE_TYPE.RUN) {
return;
@@ -252,13 +326,179 @@ const rowRightClickFn = (e: any, data: any) => {
};
const clearTreeMenuFn = () => {
rightClickNodeInfo.value = null;
// rightClickNodeInfo.value = null;
const menuElement = document.getElementById('fileMenu' + tableId.value) as HTMLElement;
if (menuElement) {
menuElement.style.display = 'none';
}
};
const windowFlag = ref('');
const showDiaFn = (flag: string) => {
windowFlag.value = flag;
switch (windowFlag.value) {
// 新建算例
case 'createRun':
showRunCreateOrEditWindow.value = true;
console.log(showRunCreateOrEditWindow.value, 'showRunCreateOrEditWindow.value');
break;
// 状态修改
case 'updateTask':
break;
// 输入参数
case 'inputParam':
break;
// 关注任务
case 'focukTask':
break;
// 建子算例
case 'createChildRun':
showRunCreateOrEditWindow.value = true;
break;
// 复制算例
case 'copyRun':
showRunCreateOrEditWindow.value = true;
break;
// 编辑说明
case 'editRun':
showRunCreateOrEditWindow.value = true;
break;
// 共享算例
case 'shareRun':
break;
// 查看指标
case 'showPerformance':
break;
// 算例版本
case 'runVersion':
break;
// 归档原始算例
case 'archiveOriginalExamples':
break;
// 归档优化算例
case 'archiveOptimizationExamples':
break;
// 删除算例
case 'delRun':
deleteTaskRunFn();
break;
}
};
// 确认创建算例,复制算例,新建子算例
const createRunFn = async (data: any) => {
console.log(data, 'data');
const { info, flag }: any = data;
console.log(flag, 'flag.value');
console.log(flag, 'flag.value');
if (flag === 'createRun') {
// 调用接口新增算例信息后,插入对应节点下
const res: any = await addTaskRunApi({
runName: info.runNames,
flowTemplate: info.templateName,
taskId: rightClickNodeInfo.value?.uuid,
totalStep: 1,
parentId: '',
});
if (res && res.code === 200) {
const runUuid = res.data;
const runInfo = await getRunDetailInfoFn(runUuid);
await createRunResultDirFn(runUuid);
// 创建完算例后创建算例下的文件夹
// info.label = info.runNames;
runInfo.nodeType = NODE_TYPE.RUN;
// info.id = new Date().getTime();
taskTreeRef.value.append(runInfo, rightClickNode.value);
}
} else {
info.label = info.runNames;
info.nodeType = NODE_TYPE.RUN;
info.id = new Date().getTime();
taskTreeRef.value.insertAfter(info, rightClickNode.value);
}
showRunCreateOrEditWindow.value = false;
};
// 更新算例信息
const updateRunInfoFn = async (data: any) => {
console.log(data, 'data');
showRunCreateOrEditWindow.value = false;
};
const getRunDetailInfoFn = async (id: any) => {
const res: any = await queryTaskRunApi({
runId: id,
});
if (res && res.code === 200) {
const run = res.data[0];
return run;
}
};
const dirNames = ref([
'图片结果', '曲线结果', '报告结果',
]);
// 在算例下新建文件夹
const createRunResultDirFn = async (runId:any) => {
for (let i = 0;i < dirNames.value.length;i++) {
await createRunDirApi({
dirName: dirNames.value[i],
dirType: 2,
uuId: runId,
});
}
};
// 删除算例
const deleteTaskRunFn = async () => {
const res:any = await deleteTaskRunApi({
runId: rightClickNode.value.id,
});
if (res && res.code === 200) {
taskTreeRef.value.remove( rightClickNode.value);
if (rightClickNode.value.id === currentNodeInfo.value.id ) {
currentNodeInfo.value = {};
emits('nodeClickFn', { node: currentNodeInfo.value });
}
}
};
onMounted(() => {
document.addEventListener('click', clearTreeMenuFn);
@@ -284,13 +524,14 @@ onBeforeUnmount(() => {
width: 100%;
.custom-tree-node {
width: 100%;
width: calc(100% - 40px);
display: flex;
align-items: center;
justify-content: space-between;
.title-info {
height: 100%;
width: calc(100% - 40px);
display: flex;
align-items: center;
@@ -299,9 +540,16 @@ onBeforeUnmount(() => {
}
.name {
padding-left: 4px;
padding-left: 8px;
}
}
.run-suatus {
width: 80px;
display: flex;
align-items: center;
justify-content: flex-end;
}
}
}
@@ -378,4 +626,29 @@ onBeforeUnmount(() => {
background-color: #bfbfbf;
}
}
.ellipsis {
white-space: nowrap;
/* 防止文本换行 */
overflow: hidden;
/* 隐藏溢出的内容 */
text-overflow: ellipsis;
/* 显示省略号来代表被修剪的文本 */
}
.info {
color: grey;
}
.success {
color: #67c23a;
}
.warn {
color: #f56c6c;
}
.upload {
color: #409eff;
}
</style>

View File

@@ -0,0 +1,214 @@
<template>
<Dialog
v-model="visible"
:diaTitle="pageTitle"
:width="'30%'"
:height="'50%'"
:zIndex="100"
@close="handleCloseFn"
show-footer
>
<el-form v-loading="createLoading" label-width="120" ref="formRef" :model="runInfoFormData" @submit.prevent="">
<el-form-item label="拼接工况信息:">
<el-radio-group v-model="runInfoFormData.isJointProjectInfo" @change="changeJoinFn">
<el-radio :value="true"></el-radio>
<el-radio :value="false"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="算例名称:" prop="runNames">
<el-input ref="runNameRef" placeholder="例V1" v-model="runInfoFormData.runNames" />
</el-form-item>
<el-form-item
label="流程模板:"
prop="templateName"
:rules="[
{
required: true,
pattern: /\S/,
message: '请选择模板',
trigger: 'check',
},
]"
>
<el-select v-model="runInfoFormData.templateName" filterable @change="templateChangeFn">
<el-option v-for="item in templateNameList" :key="item.uuid" :value="item.uuid" :label="item.templateName"></el-option>
</el-select>
</el-form-item>
<el-form-item label="父级算例:" v-if="operateType === 'createChildRun'">
<el-select v-model="runInfoFormData.taskVersion" filterable >
<el-option v-for="item in runAllVersion" :key="item.id" :value="item.id" :label="item.label"></el-option>
</el-select>
</el-form-item>
<el-form-item label="算例说明:">
<el-input rows="4" :autosize="{ minRows: 2, maxRows: 6 }" type="textarea" v-model="runInfoFormData.descript" />
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="handleCloseFn">取消</el-button>
<el-button type="primary" @click="createSuccessFn">确认</el-button>
</span>
</template>
</Dialog>
</template>
<script setup lang="ts">
import { ref, defineProps, defineEmits, watch, reactive, onMounted } from 'vue';
import Dialog from '@/components/common/dialog/index.vue';
import { NODE_TYPE } from '@/utils/enum/node';
import { ElMessage } from 'element-plus';
import { queryFlowTemplateApi } from '@/api/capability/flow';
const props = defineProps({
divInfo: {
type: Object,
default: () => {
},
},
operateFlag: {
type: String,
default: 'createRun',
},
});
const visible = ref(true);
const createLoading = ref(false);
const runInfoFormData = reactive<any>({
isJointProjectInfo: true,
runNames: '',
templateName: '',
taskVersion: '',
descript: '',
});
const templateNameList = ref<any>([
]);
const templateChangeFn = () => {
};
const runAllVersion = ref<any>([
]);
const emits = defineEmits(['close', 'comfirm', 'update']);
const pageTitle = ref('创建算例');
const operateType = ref('');
const handleCloseFn = () => {
emits('close');
};
// 确认事件
const createSuccessFn = () => {
if (!runInfoFormData.templateName) {
runInfoFormData.templateName = 1;
// ElMessage.warning('未选择流程模板,无法新建算例!');
// return;
}
if ( operateType.value != 'editRun') {
emits('comfirm', {
info: runInfoFormData,
flag: operateType.value,
});
} else {
emits('update', {
info: runInfoFormData,
flag: operateType.value,
});
}
};
// 拼接改变
const changeJoinFn = () => {
if (runInfoFormData.isJointProjectInfo) {
runInfoFormData.runNames = props.divInfo.nodeName + '_算例' + new Date().getTime();
} else {
runInfoFormData.runNames = '算例' + new Date().getTime();
}
};
watch(() => props.operateFlag, (newVal) => {
if (newVal) {
operateType.value = newVal;
if (newVal === 'createRun') {
pageTitle.value = '创建算例';
}
if (newVal === 'createChildRun') {
pageTitle.value = '创建子算例';
runAllVersion.value = [
{
id: props.divInfo?.uuid,
label: props.divInfo?.runName,
nodeType: 'run',
},
];
runInfoFormData.taskVersion = props.divInfo?.uuid;
}
if (newVal === 'copyRun') {
pageTitle.value = '复制算例';
}
if (newVal === 'editRun') {
pageTitle.value = '编辑算例信息';
}
// 如果是新增算例
if (props.divInfo && props.divInfo?.nodeType === NODE_TYPE.TASK) {
if (runInfoFormData.isJointProjectInfo) {
runInfoFormData.runNames = props.divInfo.nodeName + '_算例' + new Date().getTime();
}
runInfoFormData.templateName = props.divInfo.flowTemplateName;
}
// 如果是新增子算例或者复制算例
if (props.divInfo && props.divInfo?.nodeType === NODE_TYPE.RUN) {
}
}
}, {
immediate: true,
});
const geTemplateListFn = async () => {
const res:any = await queryFlowTemplateApi({
current: 1,
size: 999,
type: 1,
});
if (res && res.code === 200) {
templateNameList.value = res.data.data;
}
};
// 获取任务下所有的算例信息
onMounted(async () => {
await geTemplateListFn();
console.log(props.divInfo);
});
</script>
<style lang="scss" scoped></style>

View File

@@ -1,12 +1,337 @@
<template>
<div class="run-detail-page">
算例详情
<div class="run-title-box">
<div class="task-info">
<div class="task-name">{{ currentRunNodeInfo?.runName }}</div>
<!-- <div class="task-executor">
执行人
<el-icon class="blue">
<UserFilled />
</el-icon>
<span class="name">
{{ '执行人' }}</span>
</div> -->
<div class="task-status">
任务状态
<div class="status">
<el-icon class="info" title="未开始" v-if="currentRunNodeInfo?.status === 0">
<InfoFilled />
</el-icon>
<el-icon class="upload" title="进行中" v-else-if="currentRunNodeInfo?.status === 1">
<HelpFilled />
</el-icon>
<el-icon class="success" title="已完成" v-else-if="currentRunNodeInfo?.status === 2">
<SuccessFilled />
</el-icon>
<el-icon class="upload" title="回传中" v-else-if="currentRunNodeInfo?.status === 3">
<UploadFilled />
</el-icon>
<el-icon class="warn" title="异常" v-else-if="currentRunNodeInfo?.status === 4">
<WarningFilled />
</el-icon>
<el-icon class="info" title="未开始" v-else>
<InfoFilled />
</el-icon>
<span class="status-title">{{ currentRunNodeInfo?.status? statusList[currentRunNodeInfo?.status]:'未开始' }}</span>
</div>
</div>
<div class="task-time">
创建时间
<el-icon class="blue">
<Odometer />
</el-icon>
<span class="name">
{{ currentRunNodeInfo?.createTime }}</span>
</div>
</div>
<div class="task-operate">
<el-button size="small" type="primary">一键执行</el-button>
<el-button size="small" type="danger">停止</el-button>
<el-button size="small">刷新</el-button>
<el-button size="small">查看所有计算</el-button>
</div>
</div>
<div class="run-flow-box">
</div>
<div class="run-info-box">
<div class="info-box-left">
<div class="bottom-title">
<div class="title-name">节点详情</div>
<div class="title-operate"></div>
</div>
<div class="bottom-info-content">
<div class="tabs-box">
<el-tabs v-model="nodeActiveName" class="demo-tabs" @tab-change="handleLeftClickFn">
<el-tab-pane label="参数设置" name="param"></el-tab-pane>
<el-tab-pane label="数据输入" name="input"></el-tab-pane>
<el-tab-pane label="数据输出" name="output"></el-tab-pane>
</el-tabs>
</div>
<div class="tabs-info-content"></div>
</div>
</div>
<div class="info-box-right">
<div class="bottom-title">
<div class="title-name">作业相关</div>
<div class="title-operate"></div>
</div>
<div class="bottom-info-content">
<div class="tabs-box">
<el-tabs v-model="taskActiveName" class="demo-tabs" @tab-click="handleRightClickFn">
<el-tab-pane label="作业列表" name="job-list"></el-tab-pane>
<el-tab-pane label="日志输出" name="job-log"></el-tab-pane>
<el-tab-pane label="关联任务" name="associated-run"></el-tab-pane>
<el-tab-pane label="关键结果" name="result"></el-tab-pane>
<el-tab-pane label="性能指标" name="performance"></el-tab-pane>
<el-tab-pane label="3D模型预览" name="3D-model"></el-tab-pane>
</el-tabs>
</div>
<div class="tabs-info-content">
<resultData v-if="taskActiveName === 'result'" :current-run-ifno="runInfo"></resultData>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, defineProps, defineEmits, watch } from 'vue';
import resultData from './runPagecomponent/resultData.vue';
const props = defineProps({
runInfo: {
type: Object,
default: () => {},
},
});
const statusList = ref([
'未开始', '进行中', '已完成', '回传中', '异常',
]);
const nodeActiveName = ref('param');
const taskActiveName = ref('job-list');
const handleLeftClickFn = () => {
};
const handleRightClickFn = () => {
};
const currentRunNodeInfo = ref<any>({});
watch(() => props.runInfo, (newVal) => {
if (newVal) {
currentRunNodeInfo.value = newVal;
console.log(newVal, 'newVal');
}
}, {
immediate: true,
deep: true,
});
</script>
<style lang="scss" scoped>
.run-detail-page{
.run-detail-page {
width: 100%;
height: 100%;
.run-title-box {
width: 100%;
height: 100%;
height: 50px;
display: flex;
align-items: center;
justify-content: space-between;
background-color: #fff;
padding-right: 10px;
padding-left: 10px;
margin-bottom: 10px;
border-radius: 2px;
.task-info {
height: 100%;
display: flex;
align-items: center;
.task-name {
padding-left: 10px;
border-left: 3px solid var(--el-color-primary);
font-size: 16px;
font-weight: 600;
margin-right: 20px;
}
.task-executor {
height: 100%;
display: flex;
align-items: center;
font-size: 14px;
margin-right: 20px;
}
.task-status {
height: 100%;
display: flex;
align-items: center;
font-size: 14px;
margin-right: 20px;
.status {
height: 100%;
display: flex;
align-items: center;
}
}
.task-time {
height: 100%;
display: flex;
align-items: center;
font-size: 14px;
margin-right: 20px;
}
.name {
font-weight: 600;
}
}
}
.run-flow-box {
width: 100%;
height: 30%;
background-color: #fff;
margin-bottom: 10px;
border-radius: 2px;
}
.run-info-box {
width: 100%;
height: calc(70% - 70px);
display: flex;
align-items: center;
justify-content: space-between;
.info-box-left,.info-box-right {
width: calc(50% - 5px);
height: 100%;
background-color: #fff;
border-radius: 2px;
overflow: hidden;
.bottom-title{
width: 100%;
height: 40px;
display: flex;
align-items: center;
justify-content: space-between;
padding-left: 10px;
.title-name{
padding-left: 10px;
border-left: 3px solid var(--el-color-primary);
font-size: 14px;
font-weight: 600;
}
.title-operate{
height: 100%;
display: flex;
align-items: center;
justify-content: flex-end;
}
}
.bottom-info-content{
width: 100%;
height: calc(100% - 40px);
padding: 0 10px;
.tabs-box{
width: 100%;
height: 40px;
}
.tabs-info-content{
width: 100%;
height: calc(100% - 40px);
}
}
}
}
.blue {
color: var(--el-color-primary);
margin-right: 5px;
}
}
.point {
width: 8px;
height: 8px;
border-radius: 50%;
}
.status-title{
padding-left: 8px;
}
.success {
background-color: #67C23A;
}
.error {
background-color: #F56C6C;
}
.mr5 {
margin-right: 5px;
}
.info {
color: grey;
}
.success {
color: #67c23a;
}
.warn {
color: #f56c6c;
}
.upload {
color: #409eff;
}
</style>

View File

@@ -0,0 +1,149 @@
<!-- 关键结果 -->
<template>
<div class="result-page">
<div class="tab-title-box">
<el-radio-group v-model="currentDirName" >
<el-radio v-for="item in runDirNameList" :key="item.id" :value="item.id">{{ item.name }}</el-radio>
</el-radio-group>
</div>
<div class="dir-content" v-if="runDirNameList.length && currentDirName">
<BaseTable
showIndex
ref="baseTableRef"
tableName="RUN_RESULT_FILE_TABLE"
:api="queryDirDataFn"
:params="{
fileId: currentDirName,
}"
>
<template #leftOptions>
<el-upload :show-file-list="false" :before-upload="beforeUploadFun">
<el-button>上传文件</el-button>
</el-upload>
</template>
</BaseTable>
</div>
</div>
</template>
<script setup lang="ts">
import { queryRunDirApi, uploadRunFilesApi } from '@/api/project/task';
import { ref, defineProps, defineEmits, watch, nextTick, onMounted } from 'vue';
import BaseTable from '@/components/common/table/baseTable.vue';
import { ElMessage } from 'element-plus';
const props = defineProps({
currentRunIfno: {
type: Object,
default: () => {
},
},
});
const baseTableRef = ref();
const runInfo = ref<any>({});
const currentDirName = ref<any>();
const runDirs = ref<any>([]);
const runDirNameList = ref<any>([]);
const showPage = ref(false);
const resultDirId = ref<any>('');
const getRunInfoDirsFn = async () => {
showPage.value = false;
const res: any = await queryRunDirApi({
uuid: runInfo.value.uuid,
size: 10,
current: 1,
});
if (res && res.code === 200) {
runDirs.value = res.data?.data || [];
runDirNameList.value = runDirs.value.map((item: any) => {
return { name: item.originalName, id: item.id };
}) || [];
console.log(runDirNameList.value, 'runDirNameList.value');
console.log(runDirs.value, 'runDirs.value');
if (runDirNameList.value.length) {
currentDirName.value = runDirNameList.value[0].id;
}
}
showPage.value = true;
};
const queryDirDataFn = async (param: any) => {
const res: any = await queryRunDirApi({
...param,
});
if (res && res.code === 200) {
return res;
}
};
const beforeUploadFun = (file: any) => {
if (!resultDirId.value) {
ElMessage.warning('请选择一个目录');
return;
}
const { name } = file;
const params = {
fileName: name,
dirId: resultDirId.value,
file: file,
};
uploadRunFilesApi(params).then((res: any) => {
if (res.code === 200) {
ElMessage.success('上传成功');
reloadFun();
}
});
return false;
};
const reloadFun = () => {
if (baseTableRef.value) {
baseTableRef.value.reloadFun();
}
};
watch(() => props.currentRunIfno, async (newVal) => {
if (newVal) {
runInfo.value = newVal;
nextTick(async () => {
await getRunInfoDirsFn();
});
}
}, {
immediate: true,
deep: true,
});
onMounted(() => {
});
</script>
<style lang="scss" scoped>
.result-page {
width: 100%;
height: 100%;
padding: 0 10px;
.tab-title-box {
width: 100%;
height: 50px;
display: flex;
align-items: center;
justify-content: flex-end;
}
}
</style>

View File

@@ -1,13 +1,105 @@
<template>
<div class="task-info-page">
任务详情界面
<div class="tabs-box">
<el-tabs v-model="activeName" class="demo-tabs" @tab-change="handleClickFn">
<el-tab-pane label="性能指标" name="performance"></el-tab-pane>
<el-tab-pane label="结果图片" name="picture"></el-tab-pane>
<el-tab-pane label="曲线查看" name="canvas"></el-tab-pane>
<el-tab-pane label="交付物" name="deliverable"></el-tab-pane>
<el-tab-pane label="计算模型" name="model"></el-tab-pane>
<el-tab-pane label="仿真报告" name="report"></el-tab-pane>
</el-tabs>
</div>
<div class="task-content">
<div class="tabs-component" v-if="activeName === 'performance'">
<taskPerformance :task-id="currentTaskInfo?.id"></taskPerformance>
</div>
<div class="tabs-component" v-if="activeName === 'picture'">
<resultImage :task-id="currentTaskInfo?.id"></resultImage>
</div>
<div class="tabs-component" v-if="activeName === 'canvas'">
<taskCurve :task-id="currentTaskInfo?.id"></taskCurve>
</div>
<div class="tabs-component" v-if="activeName === 'deliverable'">
<taskDeliverable :task-id="currentTaskInfo?.id"></taskDeliverable>
</div>
<div class="tabs-component" v-if="activeName === 'model'">
<taskModel :task-id="currentTaskInfo?.id"></taskModel>
</div>
<div class="tabs-component" v-if="activeName === 'report'">
<taskReport :task-id="currentTaskInfo?.id"></taskReport>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, defineProps, defineEmits, watch } from 'vue';
import taskPerformance from '@/components/taskDetail/taskPerformance.vue';
import resultImage from '@/components/taskDetail/resultImage.vue';
import taskReport from '@/components/taskDetail/taskReport.vue';
import taskDeliverable from '@/components/taskDetail/taskDeliverable.vue';
import taskModel from '@/components/taskDetail/taskModel.vue';
import taskCurve from '@/components/taskDetail/taskCurve.vue';
const props = defineProps({
taskInfo: {
type: Object,
default: () => {},
},
});
const activeName = ref('performance');
const handleClickFn = () => {
};
const currentTaskInfo = ref<any>(null);
// 监控传入的任务信息
watch(() => props.taskInfo, (newVal) => {
if (newVal) {
currentTaskInfo.value = newVal;
}
}, {
immediate: true,
deep: true,
});
</script>
<style lang="scss" scoped>
.task-info-page{
width: 100%;
height: 100%;
background-color: #fff;
padding: 0 10px;
.tabs-box{
width: 100%;
height: 50px;
}
.task-content{
width: 100%;
height: calc(100% - 50px);
.tabs-component{
width: 100%;
height: 100%;
}
}
}
</style>

View File

@@ -13,7 +13,9 @@
</el-icon>
</div>
<div class="right-content">
<taskDetailPage v-if="treeCurrentNodeInfo?.nodeType === NODE_TYPE.TASK"></taskDetailPage>
<taskDetailPage v-if="treeCurrentNodeInfo?.nodeType === NODE_TYPE.TASK && showPage" :task-info="treeCurrentNodeInfo"></taskDetailPage>
<runDetailPage v-else-if="treeCurrentNodeInfo?.nodeType === NODE_TYPE.RUN && showPage" :run-info="treeCurrentNodeInfo"></runDetailPage>
<el-empty v-else class="empty-style" description="" />
</div>
</div>
@@ -21,30 +23,33 @@
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { ref, defineProps, defineEmits } from 'vue';
import { NODE_TYPE } from '@/utils/enum/node';
import leftTaskTree from './components/leftTaskTree/index.vue';
import taskDetailPage from './components/taskDetailPage/index.vue';
import { NODE_TYPE } from '@/utils/enum/node';
import runDetailPage from './components/runDetailPage/index.vue';
const isToggleShow = ref(true);
const showPage = ref(true);
const toggleFun = () => {
isToggleShow.value = !isToggleShow.value;
};
const treeCurrentNodeInfo = ref<any>(null);
const getTreeCurrentNodeFn = (data:any) => {
const { node }:any = data;
const getTreeCurrentNodeFn = (data: any) => {
showPage.value = false;
treeCurrentNodeInfo.value = {};
const { node }: any = data;
treeCurrentNodeInfo.value = node;
console.log(node);
showPage.value = true;
};
</script>
<style lang="scss" scoped>
.task-execution-page{
.task-execution-page {
width: 100%;
height: 100%;
@@ -52,6 +57,7 @@ const getTreeCurrentNodeFn = (data:any) => {
position: relative;
height: 100%;
display: flex;
.toggle-btn {
position: absolute;
display: flex;
@@ -69,11 +75,13 @@ const getTreeCurrentNodeFn = (data:any) => {
color: var(--el-text-color-regular);
cursor: pointer;
transition: all 0.3s;
&.hide {
left: -14px;
transform: rotateZ(180deg);
}
}
.left-content {
width: 400px;
height: 100%;
@@ -84,29 +92,36 @@ const getTreeCurrentNodeFn = (data:any) => {
padding: var(--padding-normal);
border-right: solid 1px var(--el-border-color-darker);
transition: all 0.3s;
&.hide {
width: 0;
padding: 0;
margin: 0;
}
.filter-tree-content{
width: 100%;
height: 100%;
}
.filter-tree-content {
width: 100%;
height: 100%;
}
}
.right-content {
height: 100%;
flex: 1;
overflow: auto;
background-color: var(--el-bg-color);
border-radius: var(--border-radius-normal);
padding: 0 var(--padding-normal) var(--padding-normal);
background-color: #f2f3f5;
.empty-style {
width: 100%;
height: 100%;
background-color: #fff;
}
}
}
}
</style>