update:任务执行,算例的流程节点相关
This commit is contained in:
@@ -140,3 +140,11 @@ export const queryKeyResultAndTaskInfoApi = (params: any) => {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询流程节点列表
|
||||||
|
* @param params runId 算例的uuid
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const listSimulationFlowNodeApi = (params: any) => {
|
||||||
|
return post(`${PREFIX}run/listFlowNodes`, params);
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<!-- <el-button @click="exportJson">导出json</el-button>
|
<!-- <el-button @click="exportJson">导出json</el-button>
|
||||||
<el-button @click="importJson">导入json</el-button> -->
|
<el-button @click="importJson">导入json</el-button> -->
|
||||||
<div class="header-box" id="header-box" v-if="showConfigPage">
|
<div class="header-box" id="header-box">
|
||||||
<div class="left-box">
|
<div class="left-box">
|
||||||
<span class="name">{{ flowName }}</span>
|
<span class="name">{{ flowName }}</span>
|
||||||
<!-- <span class="line">|</span>
|
<!-- <span class="line">|</span>
|
||||||
@@ -22,12 +22,12 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div :class="showConfigPage? 'flow-view-box' : 'flow-view-box-all'" v-loading="contentLoading">
|
<div class="flow-view-box" v-loading="contentLoading">
|
||||||
<div id="flow-view-content">
|
<div id="flow-view-content">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<TeleportContainer />
|
<TeleportContainer />
|
||||||
<FlowConfig v-model="drawerVisible" :nodeAttribute="nodeAttribute" @update:drawer-visible="drawerVisible = false"></FlowConfig>
|
<FlowConfig v-model="drawerVisible" :nodeAttribute="nodeAttribute"></FlowConfig>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
|
||||||
@@ -58,14 +58,8 @@ const props = defineProps({
|
|||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
showConfigPage: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const emits = defineEmits(['detail']);
|
|
||||||
|
|
||||||
const flowName = ref('');
|
const flowName = ref('');
|
||||||
|
|
||||||
const currentVersion = ref<any>();
|
const currentVersion = ref<any>();
|
||||||
@@ -161,12 +155,7 @@ const initGraph = async() => {
|
|||||||
console.log('click node', node);
|
console.log('click node', node);
|
||||||
if (node.data.isApp) {
|
if (node.data.isApp) {
|
||||||
nodeAttribute.value = node.data;
|
nodeAttribute.value = node.data;
|
||||||
if (props.showConfigPage) {
|
drawerVisible.value = true;
|
||||||
drawerVisible.value = true;
|
|
||||||
} else {
|
|
||||||
emits('detail', node);
|
|
||||||
}
|
|
||||||
;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -203,10 +192,6 @@ onMounted(async() => {
|
|||||||
.flow-view-box {
|
.flow-view-box {
|
||||||
height: calc(100% - 40px);
|
height: calc(100% - 40px);
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.flow-view-box-all{
|
|
||||||
height:100%
|
|
||||||
}
|
}
|
||||||
#header-box {
|
#header-box {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
class="numInput flex-div"
|
class="numInput flex-div"
|
||||||
v-if="(row.type === WIDGET_TYPE.INPUTS || row.type === WIDGET_TYPE.INPUT) && row.englishLabel"
|
v-if="(row.tagType === WIDGET_TYPE.INPUTS || row.tagType === WIDGET_TYPE.INPUT) && row.englishLabel"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="input-grid"
|
class="input-grid"
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<!-- 2下拉框-->
|
<!-- 2下拉框-->
|
||||||
<el-select
|
<el-select
|
||||||
v-if="row.type === WIDGET_TYPE.SELECT"
|
v-if="row.tagType === WIDGET_TYPE.SELECT"
|
||||||
:multiple="row.isMultiple === '1'"
|
:multiple="row.isMultiple === '1'"
|
||||||
:title="row.value"
|
:title="row.value"
|
||||||
v-model="row.value"
|
v-model="row.value"
|
||||||
@@ -50,9 +50,9 @@
|
|||||||
/>
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
<!-- 4单选框 -->
|
<!-- 4单选框 -->
|
||||||
<el-checkbox v-if="row.type === WIDGET_TYPE.CHECKBOX" v-model="row.value" true-value="1" false-value="0" />
|
<el-checkbox v-if="row.tagType === WIDGET_TYPE.CHECKBOX" v-model="row.value" true-value="1" false-value="0" />
|
||||||
<!-- 多选框 -->
|
<!-- 多选框 -->
|
||||||
<div v-if="row.type === WIDGET_TYPE.CHECKBOXS">
|
<div v-if="row.tagType === WIDGET_TYPE.CHECKBOXS">
|
||||||
<div
|
<div
|
||||||
class="input-grid"
|
class="input-grid"
|
||||||
:style="{
|
:style="{
|
||||||
@@ -75,7 +75,7 @@
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
class="numInput flex-div"
|
class="numInput flex-div"
|
||||||
v-if="row.type === WIDGET_TYPE.NUMBER_INPUTS || row.type === WIDGET_TYPE.NUMBER_INPUT"
|
v-if="row.tagType === WIDGET_TYPE.NUMBER_INPUTS || row.tagType === WIDGET_TYPE.NUMBER_INPUT"
|
||||||
>
|
>
|
||||||
<!-- <el-input-number :precision="row.decimals" controls-position="right"
|
<!-- <el-input-number :precision="row.decimals" controls-position="right"
|
||||||
v-model="row.value"></el-input-number> -->
|
v-model="row.value"></el-input-number> -->
|
||||||
@@ -120,14 +120,14 @@
|
|||||||
<span class="ml10" v-else>{{ row.unit }}</span>
|
<span class="ml10" v-else>{{ row.unit }}</span>
|
||||||
</div>
|
</div>
|
||||||
<!-- 6单纯显示内容,无法编辑 -->
|
<!-- 6单纯显示内容,无法编辑 -->
|
||||||
<div v-if="row.type === WIDGET_TYPE.VIEW">
|
<div v-if="row.tagType === WIDGET_TYPE.VIEW">
|
||||||
<el-icon class="colorIcon" v-if="isLoadingBaseInfo">
|
<el-icon class="colorIcon" v-if="isLoadingBaseInfo">
|
||||||
<Loading />
|
<Loading />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
{{ row.value }}
|
{{ row.value }}
|
||||||
</div>
|
</div>
|
||||||
<!-- 滑块 -->
|
<!-- 滑块 -->
|
||||||
<div v-if="row.type === WIDGET_TYPE.SLIDER" class="slider">
|
<div v-if="row.tagType === WIDGET_TYPE.SLIDER" class="slider">
|
||||||
<span class="value">{{ row.value }}</span>
|
<span class="value">{{ row.value }}</span>
|
||||||
<input
|
<input
|
||||||
class="slider-input"
|
class="slider-input"
|
||||||
@@ -143,7 +143,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 批量选择框控件 -->
|
<!-- 批量选择框控件 -->
|
||||||
<div v-if="row.type === WIDGET_TYPE.BATCH_LOADCASE" class="INCLFileList loadcaseList">
|
<div v-if="row.tagType === WIDGET_TYPE.BATCH_LOADCASE" class="INCLFileList loadcaseList">
|
||||||
<el-checkbox v-model="row.isAllChecked" @change="changeBatchLoadcase($event, row)">全选</el-checkbox>
|
<el-checkbox v-model="row.isAllChecked" @change="changeBatchLoadcase($event, row)">全选</el-checkbox>
|
||||||
<el-checkbox-group v-model="row.checkedList" @change="changeBatchLoadcaseNum(row)">
|
<el-checkbox-group v-model="row.checkedList" @change="changeBatchLoadcaseNum(row)">
|
||||||
<el-checkbox
|
<el-checkbox
|
||||||
@@ -161,7 +161,7 @@
|
|||||||
<div
|
<div
|
||||||
class="localServer"
|
class="localServer"
|
||||||
v-if="
|
v-if="
|
||||||
row.type === WIDGET_TYPE.FILE || row.type === NODE_TYPE.SCRIPT || row.type === NODE_TYPE.PPT
|
row.tagType === WIDGET_TYPE.FILE || row.tagType === NODE_TYPE.SCRIPT || row.tagType === NODE_TYPE.PPT
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<!-- <server-local-file
|
<!-- <server-local-file
|
||||||
@@ -268,6 +268,9 @@ const changeBatchLoadcaseNum = (record: any) => {
|
|||||||
watch(() => props.nodeParams, (newVal) => {
|
watch(() => props.nodeParams, (newVal) => {
|
||||||
if (newVal) {
|
if (newVal) {
|
||||||
tableData.value = newVal;
|
tableData.value = newVal;
|
||||||
|
|
||||||
|
console.log(tableData.value, 'tableData.value');
|
||||||
|
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
baseTableRef.value.setDataFun(tableData.value);
|
baseTableRef.value.setDataFun(tableData.value);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -35,7 +35,8 @@
|
|||||||
<InfoFilled />
|
<InfoFilled />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
|
|
||||||
<span class="status-title">{{ currentRunNodeInfo?.status? statusList[currentRunNodeInfo?.status]:'未开始' }}</span>
|
<span class="status-title">{{ currentRunNodeInfo?.status ? statusList[currentRunNodeInfo?.status] : '未开始'
|
||||||
|
}}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -59,7 +60,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="run-flow-box">
|
<div class="run-flow-box">
|
||||||
<FlowView v-if="runInfo.flowTemplate" :show-config-page="false" :flow-uuid="runInfo.flowTemplate" @detail="getNodeTailFun"></FlowView>
|
<runFlowPage v-if="runInfo.flowTemplate" :run-info="runInfo" @change="changeCurrentFlowNodeFun"></runFlowPage>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="run-info-box">
|
<div class="run-info-box">
|
||||||
@@ -80,8 +81,16 @@
|
|||||||
</el-tabs>
|
</el-tabs>
|
||||||
</div>
|
</div>
|
||||||
<div class="tabs-info-content">
|
<div class="tabs-info-content">
|
||||||
<paramSetting v-if="nodeActiveName === 'param'"></paramSetting>
|
<paramSetting
|
||||||
<runDataPage v-else></runDataPage>
|
v-if="nodeActiveName === 'param'"
|
||||||
|
:current-run-flow-node="flowNode"
|
||||||
|
:node-param-data="nodeParamDataList"
|
||||||
|
></paramSetting>
|
||||||
|
<runDataPage
|
||||||
|
v-else
|
||||||
|
:file-id="nodeActiveName === 'input' ? flowNodeData?.inputDirId : flowNodeData?.outputDirId"
|
||||||
|
:node-info="flowNodeData"
|
||||||
|
></runDataPage>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -106,7 +115,12 @@
|
|||||||
<div class="tabs-info-content">
|
<div class="tabs-info-content">
|
||||||
<resultData v-if="taskActiveName === 'result'" :current-run-ifno="runInfo"></resultData>
|
<resultData v-if="taskActiveName === 'result'" :current-run-ifno="runInfo"></resultData>
|
||||||
<jobList v-if="taskActiveName === 'job-list'"></jobList>
|
<jobList v-if="taskActiveName === 'job-list'"></jobList>
|
||||||
<taskPerformance v-if="taskActiveName === 'performance'" :param-type="'run'" :run-info="runInfo" :show-save-button="true"></taskPerformance>
|
<taskPerformance
|
||||||
|
v-if="taskActiveName === 'performance'"
|
||||||
|
:param-type="'run'"
|
||||||
|
:run-info="runInfo"
|
||||||
|
:show-save-button="true"
|
||||||
|
></taskPerformance>
|
||||||
<runLogs v-if="taskActiveName === 'job-log'"></runLogs>
|
<runLogs v-if="taskActiveName === 'job-log'"></runLogs>
|
||||||
<ModelReview v-if="taskActiveName === '3D-model'"></ModelReview>
|
<ModelReview v-if="taskActiveName === '3D-model'"></ModelReview>
|
||||||
<runVersionTree v-if="taskActiveName === 'associated-run'" :current-task-info="runInfo"></runVersionTree>
|
<runVersionTree v-if="taskActiveName === 'associated-run'" :current-task-info="runInfo"></runVersionTree>
|
||||||
@@ -131,12 +145,12 @@ import taskPerformance from '@/components/taskDetail/taskPerformance.vue';
|
|||||||
import runLogs from './runPagecomponent/runLogs.vue';
|
import runLogs from './runPagecomponent/runLogs.vue';
|
||||||
import ModelReview from './runPagecomponent/3DModelReview.vue';
|
import ModelReview from './runPagecomponent/3DModelReview.vue';
|
||||||
import runVersionTree from './runPagecomponent/runVersionTree.vue';
|
import runVersionTree from './runPagecomponent/runVersionTree.vue';
|
||||||
import FlowView from '@/components/common/flow/flowView.vue';
|
import runFlowPage from './runPagecomponent/flow/runFlowPage.vue';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
runInfo: {
|
runInfo: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => {},
|
default: () => { },
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -155,8 +169,17 @@ const handleRightClickFun = () => {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const getNodeTailFun = (node:any) => {
|
const nodeParamDataList = ref<any>([]);
|
||||||
|
|
||||||
|
const flowNode = ref<any>({});
|
||||||
|
const flowNodeData = ref<any>({});
|
||||||
|
const changeCurrentFlowNodeFun = (info: any) => {
|
||||||
|
const { node, data }: any = info;
|
||||||
console.log(node, 'node');
|
console.log(node, 'node');
|
||||||
|
console.log(data, 'data');
|
||||||
|
flowNode.value = node;
|
||||||
|
flowNodeData.value = data;
|
||||||
|
nodeParamDataList.value = flowNode.value?.store?.data?.data?.pageConfigList || [];
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -261,14 +284,15 @@ watch(() => props.runInfo, (newVal) => {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|
||||||
.info-box-left,.info-box-right {
|
.info-box-left,
|
||||||
|
.info-box-right {
|
||||||
width: calc(50% - 5px);
|
width: calc(50% - 5px);
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
.bottom-title{
|
.bottom-title {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -276,34 +300,34 @@ watch(() => props.runInfo, (newVal) => {
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
padding-left: 10px;
|
padding-left: 10px;
|
||||||
|
|
||||||
.title-name{
|
.title-name {
|
||||||
padding-left: 10px;
|
padding-left: 10px;
|
||||||
border-left: 3px solid var(--el-color-primary);
|
border-left: 3px solid var(--el-color-primary);
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.title-operate{
|
.title-operate {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.bottom-info-content{
|
.bottom-info-content {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: calc(100% - 40px);
|
height: calc(100% - 40px);
|
||||||
padding: 0 10px;
|
padding: 0 10px;
|
||||||
|
|
||||||
.tabs-box{
|
.tabs-box {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tabs-info-content{
|
.tabs-info-content {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: calc(100% - 40px);
|
height: calc(100% - 40px);
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
@@ -327,7 +351,7 @@ watch(() => props.runInfo, (newVal) => {
|
|||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-title{
|
.status-title {
|
||||||
padding-left: 8px;
|
padding-left: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,152 @@
|
|||||||
|
<template>
|
||||||
|
<div class="custom-node">
|
||||||
|
<img class="app-icon" v-if="appProperty.iconUrl" :src="appProperty.iconUrl" alt="">
|
||||||
|
<div class="app-icon app-text" v-else>{{ appProperty?.name.split('')[0] }}</div>
|
||||||
|
<div class="app-info">
|
||||||
|
<div class="app-name" :title="appProperty.name">{{ appProperty.name }}</div>
|
||||||
|
<div class="app-tag">{{ appProperty.type }}</div>
|
||||||
|
</div>
|
||||||
|
<div class="app-status">
|
||||||
|
|
||||||
|
<div class="round" :style="{ background:getStyleFun(appProperty.status).color}"></div>
|
||||||
|
<div class="text" >{{ getStyleFun(appProperty.status).title }}</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<!-- <div>
|
||||||
|
<span @click="attributeFun">属性</span>
|
||||||
|
<span @click="paramFun">参数</span>
|
||||||
|
</div> -->
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { inject, onMounted, reactive } from 'vue';
|
||||||
|
// import { setNodeAttribute } from './nodeEvents';
|
||||||
|
|
||||||
|
// const emits = defineEmits(['attribute', 'param']);
|
||||||
|
|
||||||
|
const appProperty = reactive({
|
||||||
|
name: '',
|
||||||
|
iconUrl: '',
|
||||||
|
type: '',
|
||||||
|
status: '',
|
||||||
|
});
|
||||||
|
|
||||||
|
const getNode:any = inject('getNode');
|
||||||
|
|
||||||
|
// const attributeFun = () => {
|
||||||
|
// console.log('click attributeFun');
|
||||||
|
// setNodeAttribute(appProperty);
|
||||||
|
// };
|
||||||
|
|
||||||
|
// const paramFun = () => {
|
||||||
|
// emits('param', appProperty);
|
||||||
|
// };
|
||||||
|
|
||||||
|
const getStyleFun = (flag:any) => {
|
||||||
|
const styles:any = {
|
||||||
|
active: {
|
||||||
|
color: '#409eff',
|
||||||
|
title: '进行中',
|
||||||
|
},
|
||||||
|
finished: {
|
||||||
|
color: '#67c23a',
|
||||||
|
title: '已完成',
|
||||||
|
},
|
||||||
|
pending: {
|
||||||
|
color: '#909399',
|
||||||
|
title: '未开始',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (styles[flag]) {
|
||||||
|
return styles[flag];
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
color: '#f56c6c',
|
||||||
|
title: '异常',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (getNode) {
|
||||||
|
|
||||||
|
const node = getNode();
|
||||||
|
console.log('getNode()', node, node.getData());
|
||||||
|
const data = node.getData();
|
||||||
|
if (data?.label) {
|
||||||
|
appProperty.name = data.label;
|
||||||
|
appProperty.iconUrl = data.iconUrl;
|
||||||
|
appProperty.type = data.type;
|
||||||
|
appProperty.status = data.flowNodeInfo.nodeStatus || 'pending';
|
||||||
|
// console.log('data', data, appProperty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<style lang="scss">
|
||||||
|
.custom-node {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: #fff;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 4px;
|
||||||
|
.app-icon {
|
||||||
|
width: 36px;
|
||||||
|
height: 36px;
|
||||||
|
margin-right: 8px;
|
||||||
|
background-color: #F2F2F2;
|
||||||
|
border-radius: 4px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: white;
|
||||||
|
font-weight: bold;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.app-text {
|
||||||
|
|
||||||
|
}
|
||||||
|
.app-info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100px;
|
||||||
|
}
|
||||||
|
.app-status{
|
||||||
|
width: 60px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.round{
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: #191919;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text{
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.app-name {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #191919;
|
||||||
|
width: 83px;
|
||||||
|
white-space: nowrap; /* 防止文本换行 */
|
||||||
|
overflow: hidden; /* 隐藏溢出的内容 */
|
||||||
|
text-overflow: ellipsis; /* 显示省略号 */
|
||||||
|
}
|
||||||
|
.app-tag {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #595959;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,146 @@
|
|||||||
|
import { register } from '@antv/x6-vue-shape';
|
||||||
|
import AppNode from './registerAppNode.vue';
|
||||||
|
import { Graph } from '@antv/x6';
|
||||||
|
|
||||||
|
export const registerCustomNode = () => {
|
||||||
|
|
||||||
|
const ports = {
|
||||||
|
groups: {
|
||||||
|
top: {
|
||||||
|
position: 'top',
|
||||||
|
attrs: {
|
||||||
|
circle: {
|
||||||
|
r: 4,
|
||||||
|
magnet: true,
|
||||||
|
stroke: '#5F95FF',
|
||||||
|
strokeWidth: 1,
|
||||||
|
fill: '#fff',
|
||||||
|
style: {
|
||||||
|
visibility: 'hidden',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
right: {
|
||||||
|
position: 'right',
|
||||||
|
attrs: {
|
||||||
|
circle: {
|
||||||
|
r: 4,
|
||||||
|
magnet: true,
|
||||||
|
stroke: '#5F95FF',
|
||||||
|
strokeWidth: 1,
|
||||||
|
fill: '#fff',
|
||||||
|
style: {
|
||||||
|
visibility: 'hidden',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
bottom: {
|
||||||
|
position: 'bottom',
|
||||||
|
attrs: {
|
||||||
|
circle: {
|
||||||
|
r: 4,
|
||||||
|
magnet: true,
|
||||||
|
stroke: '#5F95FF',
|
||||||
|
strokeWidth: 1,
|
||||||
|
fill: '#fff',
|
||||||
|
style: {
|
||||||
|
visibility: 'hidden',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
left: {
|
||||||
|
position: 'left',
|
||||||
|
attrs: {
|
||||||
|
circle: {
|
||||||
|
r: 4,
|
||||||
|
magnet: true,
|
||||||
|
stroke: '#5F95FF',
|
||||||
|
strokeWidth: 1,
|
||||||
|
fill: '#fff',
|
||||||
|
style: {
|
||||||
|
visibility: 'hidden',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
group: 'top',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
group: 'right',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
group: 'bottom',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
group: 'left',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
// 自定义的画布中的显示节点
|
||||||
|
register({
|
||||||
|
shape: 'custom-app-vue-node',
|
||||||
|
type: 'app',
|
||||||
|
width: 220,
|
||||||
|
height: 56,
|
||||||
|
component: AppNode,
|
||||||
|
ports: ports,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 自定义的左侧拖拽的节点
|
||||||
|
Graph.registerNode(
|
||||||
|
'custom-stencil-node',
|
||||||
|
{
|
||||||
|
inherit: 'rect',
|
||||||
|
width: 50,
|
||||||
|
height: 70,
|
||||||
|
markup: [
|
||||||
|
{
|
||||||
|
tagName: 'rect',
|
||||||
|
selector: 'body',
|
||||||
|
attrs: {
|
||||||
|
fill: '#333',
|
||||||
|
textAnchor: 'middle',
|
||||||
|
textVerticalAnchor: 'middle',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tagName: 'image',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tagName: 'text',
|
||||||
|
selector: 'label',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
attrs: {
|
||||||
|
body: {
|
||||||
|
stroke: '#fff',
|
||||||
|
fill: '#fff',
|
||||||
|
},
|
||||||
|
image: { // 图片布局设置
|
||||||
|
width: 50,
|
||||||
|
height: 50,
|
||||||
|
fill: '#F0F0F0',
|
||||||
|
// refX: 5,
|
||||||
|
// refY: 5,
|
||||||
|
},
|
||||||
|
label: { // 文本布局设置
|
||||||
|
dominantBaseline: 'middle',
|
||||||
|
y: 20,
|
||||||
|
// textAnchor: 'center',
|
||||||
|
// textVerticalAnchor: 'bottom',
|
||||||
|
fontSize: 10,
|
||||||
|
// fill: '#1F1F1F',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// ports: { ...ports },
|
||||||
|
},
|
||||||
|
true
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,266 @@
|
|||||||
|
<template>
|
||||||
|
<div class="run-flow-page" >
|
||||||
|
<div class="flow-content" id="flow-view-content" v-loading="contentLoading"></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, defineProps, defineEmits, watch, onMounted, nextTick } from 'vue';
|
||||||
|
import { ElMessage } from 'element-plus';
|
||||||
|
import { Graph } from '@antv/x6';
|
||||||
|
import { queryFlowTemplateDetailApi } from '@/api/capability/flow';
|
||||||
|
import { createNode, getNodeList } from '@/views/simulation/creation/components/stencil';
|
||||||
|
import { objectTypeArrayRemovesDuplicates } from '@/utils/common';
|
||||||
|
import { registerCustomNode } from './registerNode';
|
||||||
|
import { listSimulationFlowNodeApi } from '@/api/project/run';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
runInfo: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const emits = defineEmits(['change']);
|
||||||
|
|
||||||
|
const contentLoading = ref(false);
|
||||||
|
|
||||||
|
const graph = ref<any>();
|
||||||
|
const flowName = ref<any>();
|
||||||
|
|
||||||
|
const nodeDataList = ref<any>([]);
|
||||||
|
const querLlistSimulationFlowNode = async (id:any) => {
|
||||||
|
const res:any = await listSimulationFlowNodeApi({
|
||||||
|
runId: id,
|
||||||
|
});
|
||||||
|
if (res && res.code === 200) {
|
||||||
|
nodeDataList.value = res.data;
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getFlowDetail = async(uuid:string) => {
|
||||||
|
contentLoading.value = true;
|
||||||
|
const res:any = await queryFlowTemplateDetailApi({ uuid: uuid, status: 1 });
|
||||||
|
if (res.code === 200) {
|
||||||
|
if (res.data.viewContent.length > 50) {
|
||||||
|
const dataJson = JSON.parse(res.data.viewContent);
|
||||||
|
const beginandend = dataJson.cells.filter((item:any) => {
|
||||||
|
return item.type === 'local' || item?.data?.label === '起始节点' || item?.data?.label === '结束节点';
|
||||||
|
});
|
||||||
|
const ids = beginandend.map((item:any) => {
|
||||||
|
return item.id;
|
||||||
|
});
|
||||||
|
dataJson.cells = dataJson.cells.filter((item:any) => {
|
||||||
|
return !ids.includes(item.id) && !ids.includes(item?.source?.cell) && !ids.includes(item?.target?.cell);
|
||||||
|
});
|
||||||
|
const nodes = dataJson.cells.filter((item:any) => {
|
||||||
|
return item?.type;
|
||||||
|
});
|
||||||
|
let position = nodes.map((item:any) => {
|
||||||
|
return item?.position?.x;
|
||||||
|
});
|
||||||
|
position = objectTypeArrayRemovesDuplicates(position, 2);
|
||||||
|
for (let i = 0;i < position.length;i++) {
|
||||||
|
|
||||||
|
for (let j = 0;j < dataJson.cells.length;j++) {
|
||||||
|
if (dataJson.cells[j]?.position?.x === position[i]) {
|
||||||
|
dataJson.cells[j].rank = i + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0;i < dataJson.cells.length;i++) {
|
||||||
|
if (dataJson.cells[i].type ) {
|
||||||
|
dataJson.cells[i].size.width = 220;
|
||||||
|
dataJson.cells[i].position.x = dataJson.cells[i].position.x + dataJson.cells[i].rank * 70;
|
||||||
|
|
||||||
|
for (let j = 0;j < nodeDataList.value.length;j++) {
|
||||||
|
if (dataJson.cells[i].id === nodeDataList.value[j].nodeId) {
|
||||||
|
dataJson.cells[i].data.flowNodeInfo = nodeDataList.value[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// console.log(dataJson, 'dataJson');
|
||||||
|
// console.log(nodeDataList.value, 'nodeDataList');
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
graph.value.fromJSON(dataJson);
|
||||||
|
graph.value.centerContent();
|
||||||
|
contentLoading.value = false;
|
||||||
|
}, 1000);
|
||||||
|
} else {
|
||||||
|
contentLoading.value = false;
|
||||||
|
}
|
||||||
|
flowName.value = res.data.templateName;
|
||||||
|
} else {
|
||||||
|
ElMessage.error(res.msg);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const selectNode = ref<any>({});
|
||||||
|
const initGraph = async() => {
|
||||||
|
graph.value = new Graph({
|
||||||
|
panning: {
|
||||||
|
enabled: true,
|
||||||
|
},
|
||||||
|
interacting: {
|
||||||
|
// 禁用画布拖拽
|
||||||
|
nodeMovable: false,
|
||||||
|
},
|
||||||
|
container: document.getElementById('flow-view-content') as HTMLElement,
|
||||||
|
autoResize: true,
|
||||||
|
// 画布的最小最大缩放级别
|
||||||
|
scaling: { min: 0.5, max: 3 },
|
||||||
|
grid: true,
|
||||||
|
// width: 800,
|
||||||
|
// height: 800,
|
||||||
|
background: {
|
||||||
|
color: '#F2F7FA',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
registerCustomNode();
|
||||||
|
const nodeList = await getNodeList();
|
||||||
|
createNode(nodeList, graph.value);
|
||||||
|
|
||||||
|
graph.value.on('node:click', ({ node }:any) => {
|
||||||
|
selectNode.value = node;
|
||||||
|
const allNodes = graph.value.getNodes();
|
||||||
|
for (let i = 0;i < allNodes.length;i++) {
|
||||||
|
if (selectNode.value.id === allNodes[i].id) {
|
||||||
|
allNodes[i].addTools({
|
||||||
|
name: 'boundary',
|
||||||
|
args: {
|
||||||
|
padding: 0,
|
||||||
|
attrs: {
|
||||||
|
// fill: '#7c68fc',
|
||||||
|
stroke: '#0366FF ',
|
||||||
|
'stroke-width': 2,
|
||||||
|
'stroke-dasharray': '',
|
||||||
|
rx: 4,
|
||||||
|
ry: 4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
localStorage.setItem('CURRENT_RUN_FLOW_NODE_INFO', allNodes[i].id);
|
||||||
|
} else {
|
||||||
|
allNodes[i].removeTools();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = nodeDataList.value.find((item:any) => {
|
||||||
|
return item.nodeId === node.id;
|
||||||
|
});
|
||||||
|
|
||||||
|
emits('change', {
|
||||||
|
node,
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// 设置默认点击节点
|
||||||
|
const setCurrentNodeFun = () => {
|
||||||
|
|
||||||
|
const allNodes = graph.value.getNodes();
|
||||||
|
const currentId = localStorage.getItem('CURRENT_RUN_FLOW_NODE_INFO') || '';
|
||||||
|
if (currentId) {
|
||||||
|
const currentNodes = allNodes.find((item:any) => {
|
||||||
|
return item.id === currentId;
|
||||||
|
});
|
||||||
|
if (currentNodes) {
|
||||||
|
currentNodes.addTools({
|
||||||
|
name: 'boundary',
|
||||||
|
args: {
|
||||||
|
padding: 0,
|
||||||
|
attrs: {
|
||||||
|
// fill: '#7c68fc',
|
||||||
|
stroke: '#0366FF ',
|
||||||
|
'stroke-width': 2,
|
||||||
|
'stroke-dasharray': '',
|
||||||
|
rx: 4,
|
||||||
|
ry: 4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
allNodes[0].addTools({
|
||||||
|
name: 'boundary',
|
||||||
|
args: {
|
||||||
|
padding: 0,
|
||||||
|
attrs: {
|
||||||
|
// fill: '#7c68fc',
|
||||||
|
stroke: '#0366FF ',
|
||||||
|
'stroke-width': 2,
|
||||||
|
'stroke-dasharray': '',
|
||||||
|
rx: 4,
|
||||||
|
ry: 4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
allNodes[0].addTools({
|
||||||
|
name: 'boundary',
|
||||||
|
args: {
|
||||||
|
padding: 0,
|
||||||
|
attrs: {
|
||||||
|
// fill: '#7c68fc',
|
||||||
|
stroke: '#0366FF ',
|
||||||
|
'stroke-width': 2,
|
||||||
|
'stroke-dasharray': '',
|
||||||
|
rx: 4,
|
||||||
|
ry: 4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(() => props.runInfo, async (newVal) => {
|
||||||
|
|
||||||
|
if (newVal) {
|
||||||
|
|
||||||
|
// currentRunNodeInfo.value = newVal;
|
||||||
|
// await initGraph();
|
||||||
|
// await getFlowDetail(currentRunNodeInfo.value.flowTemplate);
|
||||||
|
// await querLlistSimulationFlowNode(currentRunNodeInfo.value.uuid);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
immediate: true,
|
||||||
|
deep: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted( async() => {
|
||||||
|
setTimeout( async() => {
|
||||||
|
if (props.runInfo) {
|
||||||
|
await initGraph();
|
||||||
|
await querLlistSimulationFlowNode(props.runInfo.uuid);
|
||||||
|
await getFlowDetail(props.runInfo.flowTemplate);
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
|
||||||
|
.run-flow-page{
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.flow-content{
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="param-set-page">
|
<div class="param-set-page">
|
||||||
<flowNodeParamTable></flowNodeParamTable>
|
{{ nodeParamData }}
|
||||||
|
<flowNodeParamTable :node-params="nodeParamData"></flowNodeParamTable>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -9,21 +10,24 @@ import { ref, watch } from 'vue';
|
|||||||
import flowNodeParamTable from '@/components/flow/flowNodeParamTable.vue';
|
import flowNodeParamTable from '@/components/flow/flowNodeParamTable.vue';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
currentNodeInfo: {
|
currentRunFlowNode: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => {
|
default: () => {
|
||||||
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
nodeParamData: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const nodeParamInfo = ref<any>({});
|
watch(() => props.currentRunFlowNode, (newVal) => {
|
||||||
|
|
||||||
watch(() => props.currentNodeInfo, (newVal) => {
|
|
||||||
|
|
||||||
if (newVal) {
|
if (newVal) {
|
||||||
nodeParamInfo.value = newVal;
|
|
||||||
}
|
}
|
||||||
|
}, {
|
||||||
|
immediate: true,
|
||||||
|
deep: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -7,12 +7,18 @@
|
|||||||
showIndex
|
showIndex
|
||||||
ref="baseTableRef"
|
ref="baseTableRef"
|
||||||
tableName="RUN_RESULT_FILE_TABLE"
|
tableName="RUN_RESULT_FILE_TABLE"
|
||||||
|
:api="queryRunDirFun"
|
||||||
|
:params="{
|
||||||
|
fileId:fileId,
|
||||||
|
// uuid:nodeInfo.uuid
|
||||||
|
}"
|
||||||
|
:show-checkbox="true"
|
||||||
>
|
>
|
||||||
<template #leftOptions>
|
<template #leftOptions>
|
||||||
<el-upload :show-file-list="false" :before-upload="beforeUploadFun">
|
<el-upload :show-file-list="false" :before-upload="beforeUploadFun">
|
||||||
<el-button>上传文件</el-button>
|
<el-button>上传文件</el-button>
|
||||||
</el-upload>
|
</el-upload>
|
||||||
<el-button type="primary" class="ml10">下载文件</el-button>
|
<el-button type="primary" class="ml10" @click="downLoadFileFun">下载文件</el-button>
|
||||||
</template>
|
</template>
|
||||||
</BaseTable>
|
</BaseTable>
|
||||||
</div>
|
</div>
|
||||||
@@ -21,23 +27,85 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, watch } from 'vue';
|
import { ref, watch } from 'vue';
|
||||||
import BaseTable from '@/components/common/table/baseTable.vue';
|
import BaseTable from '@/components/common/table/baseTable.vue';
|
||||||
|
import { queryRunDirApi, uploadRunFilesApi } from '@/api/project/run';
|
||||||
|
import { ElMessage } from 'element-plus';
|
||||||
|
|
||||||
|
const env = import.meta.env;
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
currentNodeInfo: {
|
nodeInfo: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => {},
|
default: () => {},
|
||||||
},
|
},
|
||||||
|
fileId: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const baseTableRef = ref();
|
const baseTableRef = ref();
|
||||||
|
<<<<<<< Updated upstream
|
||||||
const nodeInfo = ref<any>({});
|
const nodeInfo = ref<any>({});
|
||||||
const beforeUploadFun = () => {
|
const beforeUploadFun = () => {
|
||||||
|
=======
|
||||||
|
const beforeUploadFun = async (file:any) => {
|
||||||
|
|
||||||
|
if (!props.fileId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { name } = file;
|
||||||
|
|
||||||
|
const param = {
|
||||||
|
file,
|
||||||
|
dirId: props.fileId,
|
||||||
|
fileName: name,
|
||||||
|
fileType: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
await uploadRunFilesApi(param).then(async (res:any) => {
|
||||||
|
if (res.code === 200) {
|
||||||
|
ElMessage.success('上传成功');
|
||||||
|
await reloadFun();
|
||||||
|
}
|
||||||
|
}).finally(() => {
|
||||||
|
|
||||||
|
});
|
||||||
|
>>>>>>> Stashed changes
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
watch(() => props.currentNodeInfo, (newVal) => {
|
const queryRunDirFun = async (param:any) => {
|
||||||
|
if (param.fileId) {
|
||||||
|
const res:any = await queryRunDirApi(param);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const downLoadFileFun = async () => {
|
||||||
|
|
||||||
|
const ckeckData = baseTableRef.value.tableRef.getCheckboxRecords();
|
||||||
|
|
||||||
|
for (let i = 0;i < ckeckData.length;i++) {
|
||||||
|
|
||||||
|
const downloadUrl = `${env.VITE_API_FILE_URL}/data/downloadFile?fileId=${ckeckData[i].id}`;
|
||||||
|
window.open(downloadUrl, '_blank');
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(ckeckData, 'ckeckData');
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
const reloadFun = async () => {
|
||||||
|
if (baseTableRef.value) {
|
||||||
|
await baseTableRef.value.resetFun();
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(() => props.nodeInfo, (newVal) => {
|
||||||
if (newVal) {
|
if (newVal) {
|
||||||
nodeInfo.value = newVal;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}, {
|
}, {
|
||||||
|
|||||||
Reference in New Issue
Block a user