1624 lines
45 KiB
Vue
1624 lines
45 KiB
Vue
<template>
|
||
<div class="run-detail-page">
|
||
<div class="run-title-box" v-show="!leftFullScreen && !rightFullScreen">
|
||
<div class="task-info">
|
||
<div class="task-name">{{ currentRunNodeInfo?.runName }}</div>
|
||
<div class="task-status">
|
||
任务状态:
|
||
<div class="status">
|
||
<el-icon class="upload" title="进行中" v-if="runFlowPocesInfo?.status === 'running'">
|
||
<HelpFilled />
|
||
</el-icon>
|
||
<el-icon
|
||
class="success"
|
||
title="已完成"
|
||
v-else-if="runFlowPocesInfo?.status === 'completed'"
|
||
>
|
||
<SuccessFilled />
|
||
</el-icon>
|
||
<el-icon
|
||
class="upload"
|
||
title="挂起中"
|
||
v-else-if="runFlowPocesInfo?.status === 'suspended'"
|
||
>
|
||
<UploadFilled />
|
||
</el-icon>
|
||
<el-icon
|
||
class="upload"
|
||
title="等待操作"
|
||
v-else-if="runFlowPocesInfo?.status === 'waiting_for_user'"
|
||
>
|
||
<UploadFilled />
|
||
</el-icon>
|
||
<el-icon class="warn" title="异常" v-else-if="runFlowPocesInfo?.status === 'error'">
|
||
<WarningFilled />
|
||
</el-icon>
|
||
<el-icon class="info" title="未开始" v-else>
|
||
<InfoFilled />
|
||
</el-icon>
|
||
<span class="status-title">{{
|
||
runFlowPocesInfo?.status ? statusList[runFlowPocesInfo?.status] : '未开始'
|
||
}}</span>
|
||
</div>
|
||
</div>
|
||
<div class="task-time">
|
||
作业流执行时间:
|
||
<el-icon class="blue">
|
||
<Odometer />
|
||
</el-icon>
|
||
<span class="name"> {{ runFlowPocesInfo?.durationFormatted || '--' }}</span>
|
||
</div>
|
||
</div>
|
||
<div class="task-operate">
|
||
<!-- runInfo.status === RUN_STATUS.UNSTART -->
|
||
<el-button
|
||
type="primary"
|
||
v-if="!runInfo.status"
|
||
:disabled="uploadFileFlag"
|
||
@click="startTaskRunJobFun"
|
||
>开始</el-button
|
||
>
|
||
<el-button type="primary" @click="visible = true">HPC列表</el-button>
|
||
|
||
<el-button @click="refreshFun">刷新</el-button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="run-flow-box" v-show="!leftFullScreen && !rightFullScreen">
|
||
<div class="flow-box-inner" v-if="runInfo.flowTemplate && showPage">
|
||
<runFlowPage
|
||
:run-info="runInfo"
|
||
@change="changeCurrentFlowNodeFun"
|
||
@update="updateFlowPageParamListFun"
|
||
@execute="executeFun"
|
||
>
|
||
</runFlowPage>
|
||
</div>
|
||
</div>
|
||
|
||
<div :class="leftFullScreen || rightFullScreen ? 'run-info-box is-all-page' : 'run-info-box'">
|
||
<div
|
||
v-if="!rightFullScreen"
|
||
:class="leftFullScreen ? 'info-box-left allpage ' : 'info-box-left'"
|
||
>
|
||
<div class="bottom-title">
|
||
<div class="title-name">节点详情</div>
|
||
<div class="title-operate">
|
||
<el-icon
|
||
v-if="!leftFullScreen"
|
||
@click="leftFullScreen = !leftFullScreen"
|
||
class="icon-style"
|
||
><FullScreen
|
||
/></el-icon>
|
||
<el-icon v-else @click="leftFullScreen = !leftFullScreen" class="icon-style"
|
||
><Close
|
||
/></el-icon>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="bottom-info-content">
|
||
<div class="tabs-box left-tab">
|
||
<el-tabs v-model="nodeActiveName" class="demo-tabs" @tab-change="handleLeftClickFun">
|
||
<el-tab-pane label="节点信息" name="info"></el-tab-pane>
|
||
<el-tab-pane label="输入数据" name="input"></el-tab-pane>
|
||
<el-tab-pane label="仿真参数" name="param"></el-tab-pane>
|
||
<el-tab-pane label="输出数据" name="output"></el-tab-pane>
|
||
</el-tabs>
|
||
</div>
|
||
<div class="operate-box">
|
||
<!-- <el-switch
|
||
v-model="executeMode"
|
||
class="mr10"
|
||
active-value="AUTO"
|
||
inactive-value="MANUAL"
|
||
active-text="自动执行"
|
||
inactive-text="手动执行"
|
||
@change="FlowNodeExecuteModeChangeFun"
|
||
/> -->
|
||
<!-- <el-button
|
||
type=""
|
||
v-if="flowNodeParamData?.nodeTypeValue === '1'"
|
||
@click="startLocalAppFun"
|
||
>启动</el-button
|
||
> -->
|
||
<!-- <el-button type="primary" @click="startLocalAppFun">执行</el-button> -->
|
||
<!-- <el-button
|
||
type="primary"
|
||
v-if="flowNodeData.nodeStatus === RUN_NODE_STATUS.WAITING_FOR_USER"
|
||
@click="continueStartRunJobFun"
|
||
>执行手动节点</el-button
|
||
> -->
|
||
<!-- <el-button
|
||
type="primary"
|
||
@click="skipCurrentNodeFlowFun"
|
||
v-if="flowNodeParamData?.nodeTypeValue === '1'"
|
||
>跳过当前本地节点</el-button
|
||
> -->
|
||
</div>
|
||
<div class="tabs-info-content">
|
||
<!-- <paramSetting
|
||
:current-run-flow-node="flowNode"
|
||
:node-param-data="nodeParamDataList"
|
||
:node-data="flowNodeParamData"
|
||
:node-info="flowNodeData"
|
||
:run-info="runInfo"
|
||
:online-file-param="onlineFileParam"
|
||
v-if="nodeActiveName === 'param' && showPage"
|
||
@update="refreshFlowNodeParamFun"
|
||
>
|
||
</paramSetting> -->
|
||
<!-- v-if="nodeActiveName === 'param' && showPage" -->
|
||
|
||
<flowNodeParamTable
|
||
ref="flowNodeParamTableRef"
|
||
v-show="nodeActiveName === 'param' && showPage"
|
||
:node-params="nodeParamDataList"
|
||
:current-node="flowNode"
|
||
:page-info="flowNodeData"
|
||
:run-info="runInfo"
|
||
:online-file-param="onlineFileParam"
|
||
:flow-node-param-data="flowNodeParamData"
|
||
:flow-node-data="flowNodeData"
|
||
@confirm="refreshFlowNodeParamFun"
|
||
@update="updateFlowNodeParamFun"
|
||
@flowclick="flowclickFun"
|
||
></flowNodeParamTable>
|
||
<runDataPage
|
||
v-show="nodeActiveName === 'input' || nodeActiveName === 'output'"
|
||
:file-id="
|
||
nodeActiveName === 'input' ? flowNodeData?.inputDirId : flowNodeData?.outputDirId
|
||
"
|
||
:node-info="flowNodeData"
|
||
></runDataPage>
|
||
|
||
<div class="bottom-info-content-tab" v-show="nodeActiveName === 'info'">
|
||
<div class="node-img">
|
||
<img :src="flowNodeParamData.iconUrl" alt="" />
|
||
</div>
|
||
<div class="node-content">
|
||
<!-- <div class="button-box">
|
||
<el-button
|
||
type="primary"
|
||
v-if="flowNodeParamData.nodeTypeValue === '1'"
|
||
@click="justStartLocalAppFun"
|
||
>启动</el-button
|
||
>
|
||
<el-button type="primary" v-else @click="startOtherNodeFun">启动</el-button>
|
||
<el-button
|
||
type="primary"
|
||
v-if="
|
||
flowNodeData.nodeStatus === 'waiting_for_user' ||
|
||
flowNodeData.nodeStatus === 'active'
|
||
"
|
||
@click="continueStartRunJobFun"
|
||
>完成</el-button
|
||
>
|
||
</div> -->
|
||
<el-form>
|
||
<el-form-item label="节点名称">
|
||
<span>{{ flowNodeData.nodeName }}</span>
|
||
</el-form-item>
|
||
<el-form-item label="节点类型">
|
||
<el-tag v-if="flowNodeParamData.nodeTypeValue === '3'" type="primary">{{
|
||
getTypeNameFun(flowNodeParamData.nodeTypeValue)
|
||
}}</el-tag>
|
||
<el-tag v-else-if="flowNodeParamData.nodeTypeValue === '2'" type="success">{{
|
||
getTypeNameFun(flowNodeParamData.nodeTypeValue)
|
||
}}</el-tag>
|
||
<el-tag v-else-if="flowNodeParamData.nodeTypeValue === '1'" type="warning">{{
|
||
getTypeNameFun(flowNodeParamData.nodeTypeValue)
|
||
}}</el-tag>
|
||
<el-tag v-else type="primary">{{
|
||
getTypeNameFun(flowNodeParamData.nodeTypeValue)
|
||
}}</el-tag>
|
||
|
||
<!-- {{ flowNodeParamData?.nodeTypeValue }} -->
|
||
</el-form-item>
|
||
<el-form-item label="节点状态">
|
||
<div class="app-status">
|
||
<div
|
||
class="round"
|
||
:style="{
|
||
background: getStyleFun(flowNodeData?.nodeStatus).color,
|
||
}"
|
||
></div>
|
||
<div class="text">
|
||
{{ getStyleFun(flowNodeData?.nodeStatus).title }}
|
||
</div>
|
||
</div>
|
||
|
||
<!-- {{ flowNodeData?.nodeDetailInfo?.status }} -->
|
||
</el-form-item>
|
||
<el-form-item label="执行时间">
|
||
<el-icon class="icon-style mr5"><Timer /></el-icon>
|
||
<span class="gl-text-ellipsis">
|
||
{{ flowNodeData?.nodeDetailInfo?.durationFormatted || '--' }}
|
||
</span>
|
||
</el-form-item>
|
||
<el-form-item label="开始时间">
|
||
<el-icon class="icon-style mr5"><Calendar /></el-icon>
|
||
<span class="gl-text-ellipsis">
|
||
{{ flowNodeData?.nodeDetailInfo?.startTime || '--' }}
|
||
</span>
|
||
</el-form-item>
|
||
<el-form-item label="完成时间">
|
||
<el-icon class="icon-style mr5"><Calendar /></el-icon>
|
||
<span class="gl-text-ellipsis">
|
||
{{ flowNodeData?.nodeDetailInfo?.endTime || '--' }}
|
||
</span>
|
||
</el-form-item>
|
||
</el-form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<!-- </template> -->
|
||
<!-- <template #right> -->
|
||
<div
|
||
v-if="!leftFullScreen"
|
||
:class="rightFullScreen ? 'info-box-right allpage ' : 'info-box-right'"
|
||
>
|
||
<div class="bottom-title">
|
||
<div class="title-name">作业相关</div>
|
||
<div class="title-operate">
|
||
<el-icon
|
||
v-if="!rightFullScreen"
|
||
class="icon-style"
|
||
@click="rightFullScreen = !rightFullScreen"
|
||
><FullScreen
|
||
/></el-icon>
|
||
<el-icon v-else class="icon-style" @click="rightFullScreen = !rightFullScreen"
|
||
><Close
|
||
/></el-icon>
|
||
</div>
|
||
</div>
|
||
<div class="bottom-info-content">
|
||
<div class="tabs-box">
|
||
<el-tabs v-model="taskActiveName" class="demo-tabs" @tab-click="handleRightClickFun">
|
||
<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="报告结果" name="report"></el-tab-pane>
|
||
<el-tab-pane label="标准规范" name="standard"></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>
|
||
<jobList v-if="taskActiveName === 'job-list'" :current-run-info="runInfo"></jobList>
|
||
<taskPerformance
|
||
v-if="taskActiveName === 'performance'"
|
||
:param-type="'run'"
|
||
:run-info="runInfo"
|
||
:show-save-button="true"
|
||
:full-height="true"
|
||
></taskPerformance>
|
||
<runLogs v-if="taskActiveName === 'job-log'"></runLogs>
|
||
<ModelReview v-if="taskActiveName === '3D-model'"></ModelReview>
|
||
<runVersionTree
|
||
v-if="taskActiveName === 'associated-run'"
|
||
:current-task-info="runInfo"
|
||
></runVersionTree>
|
||
<runStandard v-if="taskActiveName === 'standard'" :run-info="runInfo"></runStandard>
|
||
<reportResult
|
||
v-if="taskActiveName === 'report'"
|
||
:current-run-ifno="runInfo"
|
||
></reportResult>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<!-- </template>
|
||
</DragSplit> -->
|
||
</div>
|
||
<HpcList v-model="visible" />
|
||
</div>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { onActivated, onBeforeUnmount, onDeactivated, onMounted, ref, watch } from 'vue';
|
||
import resultData from './runPagecomponent/resultData.vue';
|
||
import runDataPage from './runPagecomponent/runDataPage.vue';
|
||
import jobList from './runPagecomponent/jobList.vue';
|
||
import taskPerformance from '@/components/taskDetail/taskPerformance.vue';
|
||
import runLogs from './runPagecomponent/runLogs.vue';
|
||
import ModelReview from './runPagecomponent/3DModelReview.vue';
|
||
import runVersionTree from './runPagecomponent/runVersionTree.vue';
|
||
import runFlowPage from './runPagecomponent/flow/runFlowPage.vue';
|
||
import HpcList from '@/components/task/hpcList.vue';
|
||
import {
|
||
queryRunDirApi,
|
||
retryFailedNodeApi,
|
||
saveNodeParamsApi,
|
||
startProcessInstanceApi,
|
||
uploadRunFilesApi,
|
||
} from '@/api/project/run';
|
||
import {
|
||
checklocalresourceApi,
|
||
getdeviceuuidApi,
|
||
startupPlugin,
|
||
submittaskApi,
|
||
} from '@/api/application/application';
|
||
import { ElMessage } from 'element-plus';
|
||
import { asyncCallbackApi, continueServiceTaskApi } from '@/api/flowable/process';
|
||
import runStandard from './runPagecomponent/runStandard.vue';
|
||
import { RUN_NODE_STATUS, RUN_STATUS } from '@/utils/enum/run';
|
||
import { addApplicationCallRecordApi, queryAllApplicationApi } from '@/api/system/application';
|
||
import flowNodeParamTable from '@/components/flow/flowNodeParamTable.vue';
|
||
import { cloneDeep } from 'lodash-es';
|
||
import { WIDGET_TYPE } from '@/utils/enum/flow';
|
||
import emitter from '@/utils/eventBus';
|
||
import { getDictionaryDataApi } from '@/api/system/systemData';
|
||
import { getUserData, getUserId, getUserTenantId } from '@/utils/user';
|
||
import reportResult from './runPagecomponent/reportResult.vue';
|
||
import dayjs from 'dayjs';
|
||
import { base64ToStrFun, isJSONFun } from '@/utils/file';
|
||
|
||
const props = defineProps({
|
||
runInfo: {
|
||
type: Object,
|
||
default: () => {},
|
||
},
|
||
});
|
||
|
||
const emits = defineEmits(['update']);
|
||
|
||
const statusList = ref<any>({
|
||
running: '进行中',
|
||
completed: '已完成',
|
||
suspended: '挂起中',
|
||
error: '异常',
|
||
waiting_for_user: '待操作',
|
||
});
|
||
const flowNodeParamTableRef = ref();
|
||
const executeMode = ref('MANUAL');
|
||
const visible = ref(false);
|
||
const nodeActiveName = ref('info');
|
||
const taskActiveName = ref('job-list');
|
||
|
||
const leftFullScreen = ref(false);
|
||
const rightFullScreen = ref(false);
|
||
const showPage = ref(true);
|
||
const refreshPage = ref(true);
|
||
const handleLeftClickFun = () => {};
|
||
|
||
const handleRightClickFun = () => {};
|
||
|
||
const nodeParamDataList = ref<any>([]);
|
||
|
||
const flowNode = ref<any>({});
|
||
const flowNodeData = ref<any>({});
|
||
const flowNodeParamData = ref<any>({});
|
||
const runFlowPocesInfo = ref<any>({});
|
||
const onlineFileParam = ref<any>({});
|
||
const changeCurrentFlowNodeFun = (info: any) => {
|
||
refreshPage.value = false;
|
||
const { node, data, process }: any = info;
|
||
|
||
flowNode.value = node;
|
||
flowNodeData.value = data;
|
||
flowNodeData.value.copyNodeStatus = data?.nodeStatus;
|
||
// nodeParamDataList.value = flowNode.value?.store?.data?.data?.pageConfigList || [];
|
||
nodeParamDataList.value = cloneDeep(pageParamInfo.value[data.nodeName]) || [];
|
||
flowNodeParamData.value = flowNode.value?.store?.data?.data || {};
|
||
runFlowPocesInfo.value = process;
|
||
onlineFileParam.value = {
|
||
processDefinitionId: process.processDefinitionId,
|
||
runId: data.runId,
|
||
nodeId: data.uuid,
|
||
beforeNodeId: flowNodeParamData.value?.beforeNodeId,
|
||
regexConfig: {
|
||
masterFileRegularStr: '^aa\\.xml$',
|
||
inputFilesRegularStr: '^.+\\.json$',
|
||
},
|
||
};
|
||
const params = data.userParams;
|
||
if (params?.executeMode) {
|
||
executeMode.value = params?.executeMode;
|
||
} else {
|
||
executeMode.value = 'MANUAL';
|
||
}
|
||
refreshPage.value = true;
|
||
// taskActiveName.value = 'job-list';
|
||
// nodeActiveName.value = 'info';
|
||
};
|
||
|
||
const pageParamInfo = ref<any>({});
|
||
const pageUserParam = ref<any>({});
|
||
const pageNodeDatas = ref<any>({});
|
||
const pageFlowNodeInfos = ref<any>({});
|
||
// 获取流程的每个节点的用户配置参数
|
||
const updateFlowPageParamListFun = (data: any) => {
|
||
const { list, param, nodeDatas, flowNodeInfos }: any = data;
|
||
pageParamInfo.value = list;
|
||
pageUserParam.value = param;
|
||
pageNodeDatas.value = nodeDatas;
|
||
pageFlowNodeInfos.value = flowNodeInfos;
|
||
for (const key in pageParamInfo.value) {
|
||
resetTableDataFun(pageUserParam.value[key], pageParamInfo.value[key]);
|
||
}
|
||
};
|
||
|
||
const resetTableDataFun = (obj: any, list: any) => {
|
||
for (let i = 0; i < list.length; i++) {
|
||
if (!list[i]?.englishLabel) {
|
||
if (obj[list[i].vModel] && list[i]?.children?.length) {
|
||
resetTableDataFun(obj[list[i].vModel], list[i].children);
|
||
}
|
||
} else {
|
||
for (const key in obj) {
|
||
if (list[i]?.englishLabel === key) {
|
||
list[i].defaultValue = obj[key];
|
||
}
|
||
}
|
||
}
|
||
}
|
||
};
|
||
|
||
const currentRunNodeInfo = ref<any>({});
|
||
|
||
// 开始执行任务
|
||
const startTaskRunJobFun = async () => {
|
||
// 在开始执行任务之前,保存每个节点的参数后再调用执行任务的接口
|
||
|
||
// 检查每个节点的参数
|
||
uploadFileFlag.value = 0;
|
||
|
||
for (const key in pageParamInfo.value) {
|
||
const params = pageUserParam.value[key];
|
||
const list = pageParamInfo.value[key];
|
||
const data = pageNodeDatas.value.find((item: any) => {
|
||
return item.nodeName === key;
|
||
});
|
||
const node = pageFlowNodeInfos.value.find((item: any) => {
|
||
return item.data.label === key;
|
||
})?.data;
|
||
await saveParamsFun(params, list, data, node);
|
||
}
|
||
|
||
// if (!uploadFileFlag.value) {
|
||
const res: any = await startProcessInstanceApi({
|
||
runId: props.runInfo.uuid,
|
||
});
|
||
if (res && res.code === 200) {
|
||
ElMessage.success(res.message);
|
||
showPage.value = false;
|
||
refreshRunFlowInfo();
|
||
emits('update', { status: RUN_STATUS.RUNNING });
|
||
// }
|
||
} else {
|
||
// ElMessage.success('文件正在上传中,请勿进行其他操作!');
|
||
}
|
||
};
|
||
|
||
const saveNodesParamFun = async () => {
|
||
for (const key in pageParamInfo.value) {
|
||
const params = pageUserParam.value[key];
|
||
const list = pageParamInfo.value[key];
|
||
const data = pageNodeDatas.value.find((item: any) => {
|
||
return item.nodeName === key;
|
||
});
|
||
const node = pageFlowNodeInfos.value.find((item: any) => {
|
||
return item.data.label === key;
|
||
})?.data;
|
||
await saveParamsFun(params, list, data, node);
|
||
}
|
||
};
|
||
|
||
const saveParamsFun = async (params: any, list: any, data: any, node: any) => {
|
||
const newParams: any = list;
|
||
const inputParams: any = { ...params };
|
||
const runNodeData = node;
|
||
let result: any = false;
|
||
result = checkParamRequiredFun(newParams);
|
||
|
||
if (result) {
|
||
inputParams.executeMode = 'MANUAL';
|
||
} else {
|
||
inputParams.executeMode = 'AUTO';
|
||
}
|
||
|
||
for (const key in node) {
|
||
if (['inputFormat', 'outputFormat', 'slaveFormat'].includes(key)) {
|
||
if (node[key]?.length) {
|
||
inputParams[key] = base64ToStrFun(node[key]);
|
||
} else {
|
||
inputParams[key] = '';
|
||
}
|
||
}
|
||
}
|
||
|
||
await setDataToParam(newParams, inputParams, true, data.inputDirId);
|
||
|
||
if (node.nodeType === 'HPC') {
|
||
setSpecialParamData(inputParams, runNodeData);
|
||
}
|
||
|
||
if (runNodeData.nodeType === '脚本节点' && runNodeData.label.includes('报告')) {
|
||
setReportSpecialParamDataFun(inputParams);
|
||
}
|
||
|
||
// 本地应用全部为手动节点
|
||
if (node.nodeType === '本地应用') {
|
||
inputParams.executeMode = 'MANUAL';
|
||
}
|
||
|
||
const param: any = {
|
||
nodeUuid: data.uuid,
|
||
runId: data.runId,
|
||
inputParams,
|
||
};
|
||
|
||
const res: any = await saveNodeParamsApi(param);
|
||
if (res && res.code === 200) {
|
||
}
|
||
};
|
||
|
||
const uploadFileFlag = ref(0);
|
||
const setDataToParam = async (list: any, obj: any, isUpload?: any, inputDirId?: any) => {
|
||
for (let i = 0; i < list.length; i++) {
|
||
if (list[i]?.englishLabel) {
|
||
if (list[i].tagType === WIDGET_TYPE.FILE && list[i]?.fileList?.length) {
|
||
const fileList = list[i]?.fileList || [];
|
||
let arrs: any = [];
|
||
if (fileList.length) {
|
||
uploadFileFlag.value++;
|
||
const fileData = await runUploadRunFilesFun(fileList, inputDirId);
|
||
arrs = fileData;
|
||
}
|
||
|
||
list[i].defaultValue = arrs;
|
||
}
|
||
obj[list[i].englishLabel] = list[i].defaultValue || '';
|
||
} else {
|
||
if (list[i].tagType === WIDGET_TYPE.VIEW && list[i].tagIcon === 'row') {
|
||
if (list[i]?.children?.length) {
|
||
obj[list[i].vModel] = {};
|
||
setDataToParam(list[i]?.children, obj[list[i].vModel], isUpload);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
};
|
||
|
||
const runUploadRunFilesFun = async (list: any, inputDirId: any) => {
|
||
const sourceFiles = list.map((item: any) => {
|
||
return {
|
||
fileName: item.name,
|
||
size: item.size,
|
||
fileType: '',
|
||
};
|
||
});
|
||
|
||
const param = {
|
||
sourceFiles,
|
||
uploadTaskId: new Date().getTime(),
|
||
dirId: inputDirId,
|
||
};
|
||
|
||
const res: any = await uploadRunFilesApi(param);
|
||
|
||
if (res && res.code === 200) {
|
||
res.data.forEach((item: any, index: any) => {
|
||
item.isSaveLocal = 'Y';
|
||
emitter.emit('ADD_UPLOAD_FILE', {
|
||
file: list[index].raw,
|
||
data: {
|
||
// 接口返回的文件目录信息,包括配置信息
|
||
...item,
|
||
isApprove: 0, // 0否 1是
|
||
taskType: 4, // 4交付物
|
||
callbackFlag: 'START_FLOW',
|
||
},
|
||
});
|
||
});
|
||
}
|
||
|
||
if (res.code === 200) {
|
||
const result = res.data.map((item: any) => {
|
||
// return item.objectKey;
|
||
const path = item.objectKey.split('/').slice(0, -1).concat(item.sourceFileName).join('/');
|
||
return path;
|
||
});
|
||
|
||
return result;
|
||
}
|
||
};
|
||
|
||
// 检查是否必填参数都填写
|
||
const checkParamRequiredFun = (list: any) => {
|
||
for (let i = 0; i < list.length; i++) {
|
||
if (list[i].required) {
|
||
if (list[i].tagType === WIDGET_TYPE.FILE) {
|
||
if (!list[i]?.fileList?.length && !list[i].defaultValue?.length) {
|
||
return true;
|
||
}
|
||
} else {
|
||
if (!list[i].defaultValue) {
|
||
return true;
|
||
}
|
||
}
|
||
} else {
|
||
if (list[i]?.children?.length) {
|
||
checkParamRequiredFun(list[i]?.children);
|
||
}
|
||
}
|
||
}
|
||
};
|
||
|
||
// 设置特殊的参数信息
|
||
const setSpecialParamData = (param: any, data: any) => {
|
||
param.taskId = props.runInfo.taskId;
|
||
param.taskName = props.runInfo.parentName;
|
||
param.runId = props.runInfo.uuid;
|
||
param.runName = props.runInfo.runName;
|
||
param.projectname = props.runInfo.projectName;
|
||
// param.software = '电池仿真';
|
||
// param.jobName = '测试任务' + new Date().getTime();
|
||
if (!param.jobName) {
|
||
param.jobName = '测试任务' + new Date().getTime();
|
||
}
|
||
param.software = data.label;
|
||
const keys = Object.keys(param);
|
||
if (keys.includes('masterFileRegularStr') && keys.includes('inputFilesRegularStr')) {
|
||
param.explicitInputFiles = {
|
||
masterFileRegularStr: param.masterFileRegularStr.length ? param.masterFileRegularStr : [],
|
||
inputFilesRegularStr: param.inputFilesRegularStr.length ? param.inputFilesRegularStr : [],
|
||
};
|
||
}
|
||
};
|
||
|
||
// 报告脚本生成参数填写
|
||
const setReportSpecialParamDataFun = (param: any) => {
|
||
const projectInfo = JSON.parse(
|
||
localStorage.getItem('CURRENT_FILTER_RUN_TASK_TREE_PARAM') as string
|
||
);
|
||
|
||
param.reportName = '算例报告_' + dayjs().format('YYYY_MM_DD_HH_mm');
|
||
param.applicants = getUserData().nickname;
|
||
param.date = dayjs().format('YYYY-MM-DD HH:mm:ss');
|
||
param.loadcaseName = props.runInfo.parentName;
|
||
param.projectNum = projectInfo?.projectCode;
|
||
param.formulateTime = dayjs().format('YYYY-MM-DD HH:mm:ss');
|
||
param.checkTime = dayjs().format('YYYY-MM-DD HH:mm:ss');
|
||
param.approveTime = dayjs().format('YYYY-MM-DD HH:mm:ss');
|
||
param.workspace = '';
|
||
param.workspaceNum = '';
|
||
};
|
||
|
||
const continueStartRunJobFun = async () => {
|
||
if (uploadFileFlag.value) {
|
||
ElMessage.warning('等待文件上传完毕后再执行流程!');
|
||
return;
|
||
}
|
||
|
||
if (flowNodeData.value.nodeStatus === 'active') {
|
||
await skipCurrentNodeFlowFun();
|
||
}
|
||
|
||
const res: any = await continueServiceTaskApi({
|
||
processInstanceId: flowNodeData.value.processInstanceId,
|
||
taskDefinitionKey: flowNodeData.value.nodeId,
|
||
flowelementType: flowNodeData.value.nodeDetailInfo.type,
|
||
});
|
||
if (res && res.code === 200) {
|
||
showPage.value = false;
|
||
refreshRunFlowInfo();
|
||
}
|
||
};
|
||
|
||
// 启动应用
|
||
const startLocalAppFun = async () => {
|
||
if (flowNodeData.value?.nodeStatus === RUN_NODE_STATUS.WAITING_FOR_USER) {
|
||
continueStartRunJobFun();
|
||
} else if (flowNodeData.value?.nodeStatus === RUN_NODE_STATUS.ERROR) {
|
||
// 重新执行失败的流程节点
|
||
// 重新保存该流程节点的参数
|
||
await flowNodeParamTableRef.value.saveNodeParamFun('RESTART_FLOW_NODE');
|
||
// 调用重新执行的接口
|
||
} else {
|
||
// 本地节点拉起应用
|
||
if (flowNodeParamData.value?.nodeTypeValue === '1') {
|
||
await justStartLocalAppFun();
|
||
}
|
||
}
|
||
};
|
||
|
||
const getAppInfo = async (uuid: any) => {
|
||
const param = {
|
||
appName: '',
|
||
current: 1,
|
||
size: 999,
|
||
};
|
||
try {
|
||
const res: any = await queryAllApplicationApi(param);
|
||
if (res && res.code === 200) {
|
||
for (let i = 0; i < res.data.data.length; i++) {
|
||
const paths = isJSONFun(res.data.data[i].appPath)
|
||
? JSON.parse(res.data.data[i].appPath as string)
|
||
: res.data.data[i].appPath;
|
||
|
||
if (paths && paths instanceof Object) {
|
||
const keys = Object.keys(paths);
|
||
if (keys.includes(getUserId())) {
|
||
res.data.data[i].appPath = paths[getUserId()];
|
||
} else {
|
||
res.data.data[i].appPath = '';
|
||
}
|
||
}
|
||
}
|
||
|
||
const appPath = res.data.data.find((item: any) => {
|
||
return item.uuid === uuid;
|
||
})?.appPath;
|
||
return appPath;
|
||
} else {
|
||
return '';
|
||
}
|
||
} catch {
|
||
return '';
|
||
}
|
||
};
|
||
|
||
const justStartLocalAppFun = async () => {
|
||
if (uploadFileFlag.value) {
|
||
ElMessage.success('等待文件传输完成后再进行操作');
|
||
return;
|
||
}
|
||
|
||
// if (flowNodeParamData.value?.nodeTypeValue === '1') {
|
||
// const appPath = flowNodeParamData.value.appPath || '';
|
||
|
||
const appUuid = flowNodeParamData.value.uuid;
|
||
const appPath = (await getAppInfo(appUuid)) || '';
|
||
|
||
await getdeviceuuidFun();
|
||
const uuid = localStorage.getItem('USER_UUID');
|
||
|
||
if (uuid) {
|
||
const result: any = await checklocalresourceFun(appPath);
|
||
if (result) {
|
||
const params = await getSubmitParamFun(appPath);
|
||
const res: any = await submittaskApi(params);
|
||
if (res && res.code === 200) {
|
||
const res2: any = await addApplicationCallRecordApi({
|
||
appName: flowNodeParamData.value.label,
|
||
appType: flowNodeParamData.value.nodeTypeValue,
|
||
creator: flowNodeParamData.value.creator,
|
||
});
|
||
if (res2 && res2.code === 200) {
|
||
}
|
||
ElMessage.success('应用正在启动中,请等待');
|
||
refreshFun();
|
||
} else {
|
||
}
|
||
}
|
||
} else {
|
||
return;
|
||
}
|
||
// }
|
||
};
|
||
|
||
// 启动其他应用
|
||
const startOtherNodeFun = async () => {
|
||
if (uploadFileFlag.value) {
|
||
ElMessage.success('等待文件传输完成后再进行操作');
|
||
return;
|
||
}
|
||
if (flowNodeData.value?.nodeStatus === RUN_NODE_STATUS.WAITING_FOR_USER) {
|
||
continueStartRunJobFun();
|
||
} else if (flowNodeData.value?.nodeStatus === RUN_NODE_STATUS.ERROR) {
|
||
await flowNodeParamTableRef.value.saveNodeParamFun('RESTART_FLOW_NODE');
|
||
}
|
||
};
|
||
|
||
// 重新执行节点按钮
|
||
const retryFailedNodeFun = async () => {
|
||
const param = {
|
||
processInstanceId: flowNodeData.value.processInstanceId,
|
||
failNodeId: flowNodeData.value.nodeId,
|
||
};
|
||
|
||
try {
|
||
const res: any = await retryFailedNodeApi(param);
|
||
if (res && res.code === 200) {
|
||
ElMessage.success('节点已重新执行!');
|
||
showPage.value = false;
|
||
refreshRunFlowInfo();
|
||
}
|
||
} catch (error) {
|
||
console.error(error);
|
||
}
|
||
};
|
||
|
||
// 获取插件提交计算的参数信息
|
||
const getSubmitParamFun = async (appPath: any) => {
|
||
const taskName = props.runInfo?.parentName;
|
||
const taskId = props.runInfo?.taskId;
|
||
const taskCmd = appPath;
|
||
const taskPreCmd = flowNodeParamData.value.preExeCommand;
|
||
const taskPostCmd = flowNodeParamData.value.postExeCommand;
|
||
const runId = props.runInfo?.uuid;
|
||
const runName = props.runInfo?.runName;
|
||
const taskPreCmdParam = {
|
||
'load.py': '',
|
||
};
|
||
const taskPostCmdParam = {
|
||
'pptx.py': '',
|
||
};
|
||
const { fileIds, fileNames, taskCmdParam }: any = await getNodeFileIdAndNames();
|
||
|
||
const fileType = await getfileTypeList();
|
||
const uploadId = flowNodeData.value.userParams.outputDirId.toString();
|
||
const owner = getUserData()?.nickname;
|
||
const tenantId = getUserTenantId().toString();
|
||
const userId = getUserId().toString();
|
||
const localAppName = flowNodeData.value.nodeName;
|
||
const localAppVersion = '';
|
||
const creatorId = getUserId().toString();
|
||
const subRunId = flowNodeData.value.nodeId;
|
||
const asyncTaskId = flowNodeData.value.nodeDetailInfo?.asyncTaskId;
|
||
const outputFormat = flowNodeParamData.value.outputFormat;
|
||
return {
|
||
runId,
|
||
runName,
|
||
taskName,
|
||
taskId,
|
||
taskCmd,
|
||
taskPreCmd,
|
||
taskPostCmd,
|
||
taskCmdParam,
|
||
taskPostCmdParam,
|
||
taskPreCmdParam,
|
||
fileIds,
|
||
fileNames,
|
||
fileType,
|
||
uploadId,
|
||
owner,
|
||
tenantId,
|
||
userId,
|
||
localAppName,
|
||
localAppVersion,
|
||
creatorId,
|
||
subRunId,
|
||
asyncTaskId,
|
||
outputFormat,
|
||
};
|
||
};
|
||
|
||
const getNodeFileIdAndNames = async () => {
|
||
const dirId = flowNodeData.value.userParams.inputDirId;
|
||
const fileIds: any = [];
|
||
const fileNames: any = [];
|
||
const taskCmdParam: any = {};
|
||
|
||
// 本地应用执行的脚本也需要下载下来
|
||
if (flowNodeParamData.value?.postScripts?.length) {
|
||
for (let i = 0; i < flowNodeParamData.value?.postScripts?.length; i++) {
|
||
fileIds.push(flowNodeParamData.value?.postScripts[i].fileId);
|
||
fileNames.push(flowNodeParamData.value?.postScripts[i].name);
|
||
}
|
||
}
|
||
|
||
if (flowNodeParamData.value?.preScripts?.length) {
|
||
for (let i = 0; i < flowNodeParamData.value?.preScripts?.length; i++) {
|
||
fileIds.push(flowNodeParamData.value?.preScripts[i].fileId);
|
||
fileNames.push(flowNodeParamData.value?.preScripts[i].name);
|
||
}
|
||
}
|
||
|
||
try {
|
||
const res: any = await queryRunDirApi({
|
||
current: 1,
|
||
fileId: dirId,
|
||
size: 999,
|
||
});
|
||
|
||
if (res && res.code === 200) {
|
||
const list = res.data.data;
|
||
for (let i = 0; i < list.length; i++) {
|
||
fileIds.push(list[i].id.toString());
|
||
fileNames.push(list[i].originalName);
|
||
}
|
||
// if (flowNodeParamData.value.nodeExeCommand) {
|
||
// taskCmdParam[flowNodeParamData.value.nodeExeCommand] = './' + fileNames.join(',');
|
||
// // = fileNames.map((item: any) => {
|
||
// // return { [flowNodeParamData.value.nodeExeCommand]: item };
|
||
// // });
|
||
// } else {
|
||
// taskCmdParam = {};
|
||
// }
|
||
|
||
if (Object.keys(flowNodeData.value.userParams).includes('--export')) {
|
||
taskCmdParam['--export'] = flowNodeData.value.userParams['--export'];
|
||
}
|
||
if (Object.keys(flowNodeData.value.userParams).includes('--import')) {
|
||
taskCmdParam['--import'] = './' + fileNames.join(',');
|
||
}
|
||
return {
|
||
fileIds,
|
||
fileNames,
|
||
taskCmdParam,
|
||
};
|
||
} else {
|
||
return {
|
||
fileIds,
|
||
fileNames,
|
||
taskCmdParam,
|
||
};
|
||
}
|
||
} catch {
|
||
return {
|
||
fileIds,
|
||
fileNames,
|
||
taskCmdParam,
|
||
};
|
||
}
|
||
};
|
||
|
||
const getfileTypeList = async () => {
|
||
try {
|
||
const res: any = await getDictionaryDataApi({ dictClass: 'FILE_UPLOAD_ALLOCATION_TYPE' });
|
||
if (res && res.code === 200) {
|
||
// const types: any = res.data.map((item: any) => {
|
||
// const obj: any = {};
|
||
// obj[item.dictName] = item.dictValue.split(',');
|
||
// return obj;
|
||
// });
|
||
const obj: any = {};
|
||
for (let i = 0; i < res.data.length; i++) {
|
||
obj[res.data[i].dictName] = res.data[i].dictValue.split(',');
|
||
}
|
||
|
||
const outPutFile = flowNodeData.value?.userParams?.outputFileType?.split(',') || [];
|
||
if (outPutFile?.length) {
|
||
const list: any = [];
|
||
for (let i = 0; i < outPutFile.length; i++) {
|
||
let isReturnFile = true;
|
||
for (const key in obj) {
|
||
if (obj[key].includes(outPutFile[i])) {
|
||
isReturnFile = false;
|
||
}
|
||
}
|
||
|
||
if (isReturnFile) {
|
||
list.push(outPutFile[i]);
|
||
}
|
||
}
|
||
|
||
obj['1'] = obj['1'].concat(list);
|
||
}
|
||
|
||
return obj;
|
||
} else {
|
||
return {};
|
||
}
|
||
} catch {
|
||
return {};
|
||
}
|
||
};
|
||
|
||
// 检查资源是否合法
|
||
const checklocalresourceFun = async (path: any) => {
|
||
try {
|
||
const res: any = await checklocalresourceApi({ resource: [path] });
|
||
if (res && res.code === 200) {
|
||
if (res.data.returnCode.includes('Operate Success')) {
|
||
return true;
|
||
} else {
|
||
return false;
|
||
}
|
||
}
|
||
} catch {
|
||
return false;
|
||
}
|
||
};
|
||
|
||
const getdeviceuuidFun = async () => {
|
||
try {
|
||
const res: any = await getdeviceuuidApi();
|
||
if (res && res.code === 200) {
|
||
const uuid = res.data.returnCode
|
||
.replace('UUID', '')
|
||
.replace(/\ +/g, '')
|
||
.replace(/[\r\n]/g, '');
|
||
|
||
localStorage.setItem('USER_UUID', uuid);
|
||
}
|
||
} catch {
|
||
startupPlugin();
|
||
}
|
||
};
|
||
|
||
// 刷新节点页面信息
|
||
const refreshRunFlowInfo = () => {
|
||
setTimeout(() => {
|
||
showPage.value = true;
|
||
});
|
||
};
|
||
|
||
const refreshFun = () => {
|
||
showPage.value = false;
|
||
refreshRunFlowInfo();
|
||
};
|
||
|
||
// const FlowNodeExecuteModeChangeFun = async () => {
|
||
// const inputParams = {
|
||
// ...flowNodeData.value.userParams,
|
||
// executeMode: executeMode.value,
|
||
// };
|
||
// const params = {
|
||
// nodeUuid: flowNodeParamData.value?.flowNodeInfo?.uuid,
|
||
// runId: props.runInfo.uuid,
|
||
// inputParams,
|
||
// };
|
||
// try {
|
||
// const res: any = await saveNodeParamsApi(params);
|
||
// if (res && res.code === 200) {
|
||
// ElMessage.success('操作成功');
|
||
// refreshFun();
|
||
// } else {
|
||
// }
|
||
// } catch {}
|
||
// };
|
||
|
||
const refreshFlowNodeParamFun = async (data: any) => {
|
||
const { flag }: any = data;
|
||
if (flag === false) {
|
||
await retryFailedNodeFun();
|
||
showPage.value = false;
|
||
refreshRunFlowInfo();
|
||
}
|
||
|
||
if (flag === true) {
|
||
ElMessage.success('文件正在上传中,请等待文件上传完成后再操作');
|
||
}
|
||
};
|
||
const newNodeData = ref<any>({});
|
||
const updateFlowNodeParamFun = (data: any) => {
|
||
for (let i = 0; i < pageParamInfo.value[flowNodeData.value.nodeName].length; i++) {
|
||
for (const key in data[i]) {
|
||
pageParamInfo.value[flowNodeData.value.nodeName][i][key] = data[i][key];
|
||
}
|
||
}
|
||
newNodeData.value[flowNodeData.value.nodeName] = data;
|
||
// nodeParamDataList.value = data;
|
||
};
|
||
|
||
const getStyleFun = (flag: any) => {
|
||
const styles: any = {
|
||
active: {
|
||
color: '#409eff',
|
||
title: '进行中',
|
||
},
|
||
waiting_for_user: {
|
||
color: '#409eff',
|
||
title: '进行中',
|
||
},
|
||
finished: {
|
||
color: '#67c23a',
|
||
title: '已完成',
|
||
},
|
||
pending: {
|
||
color: '#909399',
|
||
title: '未开始',
|
||
},
|
||
};
|
||
|
||
if (styles[flag]) {
|
||
return styles[flag];
|
||
} else {
|
||
return {
|
||
color: '#f56c6c',
|
||
title: '异常',
|
||
};
|
||
}
|
||
};
|
||
|
||
const getTypeNameFun = (type: any) => {
|
||
const str =
|
||
appTypeList.value.find((item: any) => {
|
||
return item.dictValue === type;
|
||
})?.dictName || '';
|
||
|
||
return str;
|
||
};
|
||
|
||
const appTypeList = ref<any>([]);
|
||
const getDictionaryDataFun = async () => {
|
||
const res: any = await getDictionaryDataApi({
|
||
dictClass: 'APP_TYPE',
|
||
});
|
||
if (res && res.code === 200) {
|
||
appTypeList.value = res.data;
|
||
}
|
||
};
|
||
|
||
const skipCurrentNodeFlowFun = async () => {
|
||
const params = {
|
||
asyncTaskId: flowNodeData.value?.nodeDetailInfo.asyncTaskId,
|
||
resultJson: 'success',
|
||
status: 'SUCCESS',
|
||
};
|
||
|
||
try {
|
||
const res: any = await asyncCallbackApi(params);
|
||
if (res && res.code === 200) {
|
||
// refreshFun();
|
||
}
|
||
} catch (error) {
|
||
console.error(error);
|
||
}
|
||
};
|
||
|
||
// 双击两次执行当前应用节点
|
||
const executeFun = () => {
|
||
if (uploadFileFlag.value) {
|
||
ElMessage.success('文件未上传完整,请等待稍后再进行操作');
|
||
return;
|
||
}
|
||
|
||
startLocalAppFun();
|
||
};
|
||
|
||
// 文件上传完成后的回调事件
|
||
const uploadFinishedFun = async (data: any) => {
|
||
// 开始任务执行
|
||
if (data.callbackFlag === 'START_FLOW') {
|
||
uploadFileFlag.value--;
|
||
|
||
// const res: any = await startProcessInstanceApi({
|
||
// runId: props.runInfo.uuid,
|
||
// });
|
||
// if (res && res.code === 200) {
|
||
// ElMessage.success(res.message);
|
||
// showPage.value = false;
|
||
// refreshRunFlowInfo();
|
||
// emits('update', { status: RUN_STATUS.RUNNING });
|
||
// }
|
||
}
|
||
|
||
// 重复执行失败节点
|
||
if (data.callbackFlag === 'RESTART_FLOW_NODE') {
|
||
await retryFailedNodeFun();
|
||
}
|
||
};
|
||
|
||
const flowclickFun = async (flag: any) => {
|
||
await saveNodesParamFun();
|
||
|
||
if (flag === 'justStartLocalAppFun') {
|
||
await justStartLocalAppFun();
|
||
}
|
||
if (flag === 'startOtherNodeFun') {
|
||
await startOtherNodeFun();
|
||
}
|
||
if (flag === 'continueStartRunJobFun') {
|
||
await continueStartRunJobFun();
|
||
}
|
||
};
|
||
|
||
watch(
|
||
() => props.runInfo,
|
||
(newVal) => {
|
||
if (newVal) {
|
||
currentRunNodeInfo.value = newVal;
|
||
}
|
||
},
|
||
{
|
||
immediate: true,
|
||
deep: true,
|
||
}
|
||
);
|
||
|
||
const timer = ref<any>(null);
|
||
|
||
onMounted(async () => {
|
||
await getDictionaryDataFun();
|
||
emitter.on('UPLOAD_FINISHED', uploadFinishedFun);
|
||
// 5分钟自动刷新一次流程信息
|
||
timer.value = setInterval(
|
||
() => {
|
||
refreshFun();
|
||
},
|
||
5 * 60 * 1000
|
||
);
|
||
});
|
||
|
||
onBeforeUnmount(() => {
|
||
emitter.off('UPLOAD_FINISHED', uploadFinishedFun);
|
||
clearInterval(timer.value);
|
||
});
|
||
|
||
onActivated(() => {
|
||
emitter.on('UPLOAD_FINISHED', uploadFinishedFun);
|
||
});
|
||
|
||
onDeactivated(() => {
|
||
emitter.off('UPLOAD_FINISHED', uploadFinishedFun);
|
||
});
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.run-detail-page {
|
||
width: 100%;
|
||
height: 100%;
|
||
position: relative;
|
||
|
||
.run-title-box {
|
||
width: 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: 200px;
|
||
background-color: #fff;
|
||
margin-bottom: 10px;
|
||
border-radius: 2px;
|
||
overflow: hidden;
|
||
|
||
.flow-box-inner {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
}
|
||
|
||
.run-info-box {
|
||
width: 100%;
|
||
height: calc(100% - 270px);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
|
||
.run-flow-info-box {
|
||
width: 100%;
|
||
height: 180px;
|
||
margin-bottom: 10px;
|
||
border-radius: 2px;
|
||
background-color: #fff;
|
||
|
||
.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;
|
||
padding-right: 10px;
|
||
|
||
.icon-style {
|
||
font-size: 16px;
|
||
color: var(--el-color-primary);
|
||
cursor: pointer;
|
||
}
|
||
}
|
||
}
|
||
|
||
.bottom-info-content {
|
||
width: 100%;
|
||
height: calc(100% - 40px);
|
||
padding: 0 10px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
|
||
.node-img {
|
||
width: 100px;
|
||
height: 100%;
|
||
display: flex;
|
||
justify-content: center;
|
||
|
||
img {
|
||
width: 100px;
|
||
height: 100px;
|
||
background-color: #f2f2f2;
|
||
border-radius: 5px;
|
||
}
|
||
}
|
||
|
||
.node-content {
|
||
width: calc(100% - 140px);
|
||
height: 100%;
|
||
|
||
// .el-form {
|
||
// width: 100%;
|
||
// height: 100%;
|
||
// flex-wrap: wrap;
|
||
|
||
// .el-form-item {
|
||
// // width: calc(100% / 4);
|
||
// }
|
||
// }
|
||
}
|
||
}
|
||
}
|
||
|
||
.info-box-left,
|
||
.info-box-right {
|
||
width: calc(50% - 5px);
|
||
// width: 100%;
|
||
// height: 500px;
|
||
height: 100%;
|
||
background-color: #fff;
|
||
border-radius: 2px;
|
||
// margin-bottom: 10px;
|
||
// 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;
|
||
padding-right: 10px;
|
||
|
||
.icon-style {
|
||
font-size: 16px;
|
||
color: var(--el-color-primary);
|
||
cursor: pointer;
|
||
}
|
||
}
|
||
}
|
||
|
||
.bottom-info-content {
|
||
width: 100%;
|
||
height: calc(100% - 40px);
|
||
padding: 0 10px;
|
||
position: relative;
|
||
|
||
.operate-box {
|
||
position: absolute;
|
||
top: 0;
|
||
right: 20px;
|
||
}
|
||
|
||
.tabs-box {
|
||
// width: calc(100% - 220px);
|
||
height: 40px;
|
||
}
|
||
|
||
// .left-tab {
|
||
// width: calc(100% - 140px);
|
||
// }
|
||
|
||
.tabs-info-content {
|
||
width: 100%;
|
||
height: calc(100% - 50px);
|
||
padding: 10px;
|
||
overflow: auto;
|
||
}
|
||
}
|
||
}
|
||
|
||
.allpage {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
}
|
||
|
||
.is-all-page {
|
||
width: 100%;
|
||
height: 100%;
|
||
left: 0;
|
||
top: 0;
|
||
z-index: 20;
|
||
position: absolute;
|
||
}
|
||
|
||
.blue {
|
||
color: var(--el-color-primary);
|
||
margin-right: 5px;
|
||
}
|
||
}
|
||
|
||
.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;
|
||
}
|
||
}
|
||
|
||
.point {
|
||
width: 8px;
|
||
height: 8px;
|
||
border-radius: 50%;
|
||
}
|
||
|
||
.status-title {
|
||
padding-left: 8px;
|
||
}
|
||
|
||
.success {
|
||
color: #67c23a;
|
||
}
|
||
|
||
.error {
|
||
color: #f56c6c;
|
||
}
|
||
|
||
.mr5 {
|
||
margin-right: 5px;
|
||
}
|
||
|
||
.info {
|
||
color: grey;
|
||
}
|
||
|
||
.success {
|
||
color: #67c23a;
|
||
}
|
||
|
||
.warn {
|
||
color: #f56c6c;
|
||
}
|
||
|
||
.upload {
|
||
color: #409eff;
|
||
}
|
||
|
||
.mr10 {
|
||
margin-right: 10px;
|
||
}
|
||
|
||
.icon-style {
|
||
font-size: 16px;
|
||
color: var(--el-color-primary);
|
||
cursor: pointer;
|
||
}
|
||
|
||
.mr5 {
|
||
margin-right: 5px;
|
||
}
|
||
|
||
.bottom-info-content-tab {
|
||
width: 100%;
|
||
// height: calc(100% - 40px);
|
||
height: 100%;
|
||
padding: 0 10px;
|
||
padding-right: 0;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
// padding: 20px;
|
||
|
||
.node-img {
|
||
width: 100px;
|
||
height: 100%;
|
||
display: flex;
|
||
justify-content: center;
|
||
|
||
img {
|
||
width: 100px;
|
||
height: 100px;
|
||
background-color: #f2f2f2;
|
||
border-radius: 5px;
|
||
}
|
||
}
|
||
|
||
.node-content {
|
||
width: calc(100% - 140px);
|
||
height: 100%;
|
||
padding: 0 20px;
|
||
padding-right: 0;
|
||
padding-bottom: 0;
|
||
|
||
.el-form {
|
||
width: 100%;
|
||
// height: 100%;
|
||
height: calc(100% - 50px);
|
||
overflow: auto;
|
||
flex-wrap: wrap;
|
||
|
||
.el-form-item {
|
||
// width: calc(100% / 3);
|
||
}
|
||
}
|
||
|
||
.button-box {
|
||
width: 100%;
|
||
height: 50px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: flex-end;
|
||
}
|
||
}
|
||
}
|
||
</style>
|