修复bug

This commit is contained in:
weibl
2025-11-25 10:22:25 +08:00
parent 846870ab99
commit 2a6779d87b
15 changed files with 261 additions and 69 deletions

View File

@@ -3,10 +3,13 @@
v-model="dialogVisible"
diaTitle="流程预览"
width="80%"
height="80vh"
height="500"
@close="closeFun"
>
<FlowView type="review" :flowUuid="flowUuid"></FlowView>
<div class="flow-box">
<FlowView type="review" :flowUuid="flowUuid"></FlowView>
</div>
</Dialog>
</template>
<script setup lang="ts">
@@ -46,3 +49,8 @@ onMounted(async() => {
});
</script>
<style lang="scss" scoped>
.flow-box {
height: 70vh;
}
</style>

View File

@@ -161,6 +161,7 @@
:operationType="operationType"
:nodeType="modalNodeType"
:detail="modalDetail"
:belongProject="belongProject"
@confirm="onNodeDetailConfirmFun"
/>
<!-- <userSelectTable
@@ -179,9 +180,8 @@ import TreeCaseTable from '@/components/common/treeCaseTable/treeTable.vue';
import { getTagKeyMap, NODE_TYPE } from '@/utils/enum/node';
import { canAddChild } from '@/utils/node';
import nodeDetailDialog from './nodeDetailDialog.vue';
import { random } from 'lodash-es';
import { TASK_CALCULATE_STATUS, TASK_PROCESS_STATUS } from '@/utils/enum/task';
import { disposeMemberList, disposeTagKey } from '@/views/task/projectDetail/components/project';
import { disposeTagKey } from '@/views/task/projectDetail/components/project';
import { ElMessage } from 'element-plus';
import { generateFakeId } from '@/utils/node';
import i18n from '@/utils/i18n';
@@ -212,6 +212,7 @@ interface Props {
phaseUuid?: string; // 阶段uuid
exportBtnVisible?: boolean; // 阶段uuid
showCheckBox?: boolean;
belongProject?: boolean;
}
const props = withDefaults(defineProps<Props>(), {
@@ -233,6 +234,7 @@ const props = withDefaults(defineProps<Props>(), {
phaseUuid: '',
exportBtnVisible: false,
showCheckBox: true,
belongProject: false, // 属于项目还是工况库
});
const tagKeyMap = getTagKeyMap();
const disposeTreeData = (treeData: any[]) => {

View File

@@ -60,6 +60,7 @@ interface Props {
operationType: OPERATION_TYPE | string;
nodeType?: string;
modalTableNameList?: string[];
belongProject?: boolean;
}
const props = withDefaults(defineProps<Props>(), {
@@ -69,6 +70,7 @@ const props = withDefaults(defineProps<Props>(), {
nodeType: '',
modalTableNameList: () => (['TASK_POOL_CATEGORY', 'TASK_POOL_TASK', 'TASK_POOL_PERFORMANCE']),
detail: null,
belongProject: false,
});
const emits = defineEmits(['update:modelValue', 'confirm']);
@@ -159,7 +161,11 @@ const prepareFromProps = () => {
targetTableName = props.modalTableNameList?.[0] || targetTableName;
break;
case NODE_TYPE.TASK:
text += '工况';
if (props.belongProject) {
text += '任务';
} else {
text += '工况';
}
targetTableName = props.modalTableNameList?.[1] || targetTableName;
break;
case NODE_TYPE.PERFORMANCE:

View File

@@ -1,8 +1,8 @@
import { createRouter, createWebHistory } from 'vue-router';
import { CommonStore } from '@/stores/common';
import EmptyLayout from '@/layouts/empty.vue';
// import DefaultLayout from '@/layouts/default.vue';
import CidLayout from '@/layouts/cid.vue';
import DefaultLayout from '@/layouts/default.vue';
// import CidLayout from '@/layouts/cid.vue';
import routerData from '@/router/routerData';
const router = createRouter({
@@ -22,7 +22,8 @@ const router = createRouter({
},
{
path: '/',
component: CidLayout,
component: DefaultLayout,
// component: CidLayout,
children: routerData,
},
{

View File

@@ -47,8 +47,8 @@ import { releaseFlowTemplateApi, upgradeFlowTemplateDraftApi } from '@/api/capab
const props = defineProps<{
showDialog: boolean;
uuid: string;
versionType:string;
uuid?: string;
// versionType:string;
graph: any;
nodeRelation: any[];
flowDetail: any;
@@ -116,7 +116,7 @@ const upgradeDraftFun = async (params:any) => {
};
const submitApproveFun = async (uuid:string = props.uuid) => {
const submitApproveFun = async (uuid:string = props.uuid || '') => {
const res:any = await releaseFlowTemplateApi({
uuid: uuid,
// versionType: props.versionType,

View File

@@ -1,7 +1,7 @@
<template>
<div class="script-manager">
<!-- 应用版本选择 -->
<div class="item-box">
<!-- <div class="item-box">
<div class="title">应用版本</div>
<el-select v-model="appVersion" placeholder="请选择" class="select-version">
<el-option
@@ -11,7 +11,7 @@
:value="version.value"
/>
</el-select>
</div>
</div> -->
<div class="item-box">
<div class="title">
<span>
@@ -31,6 +31,25 @@
<el-radio value="or"></el-radio>
</el-radio-group>
</div>
<div class="item-box">
<div class="title">
<span>
执行方式
<el-tooltip
class="box-item"
effect="dark"
content="节点的执行方式,是后台自动执行或者手动执行"
placement="top-start"
>
<el-icon color="#606266"><QuestionFilled /></el-icon>
</el-tooltip>
</span>
</div>
<el-radio-group v-model="exeMethod">
<el-radio value="serviceTask">自动</el-radio>
<el-radio value="userTask">手动</el-radio>
</el-radio-group>
</div>
<div class="item-box">
<div class="title">
<span>节点前脚本</span>
@@ -147,14 +166,14 @@ const props = defineProps({
const env = import.meta.env;
const PREFIX = env.VITE_API_PREFIX_DATA;
const appVersion = computed({
get() {
return props.nodeAttribute.appVersion;
},
set(val) {
updateNodeAttribute({ appVersion: val });
},
});
// const appVersion = computed({
// get() {
// return props.nodeAttribute.appVersion;
// },
// set(val) {
// updateNodeAttribute({ appVersion: val });
// },
// });
const inputFormat = computed({
get() {
@@ -192,6 +211,15 @@ const nodeCondition = computed({
},
});
const exeMethod = computed({
get() {
return props.nodeAttribute.exeMethod;
},
set(val) {
updateNodeAttribute({ exeMethod: val });
},
});
const showCodeEdit = ref(false);
// 应用版本数据

View File

@@ -5,7 +5,7 @@ import { ElMessage } from 'element-plus';
* 校验流程合理性
* @param cells
*/
export const getRelationNodeAndVerifyFlowFun = (cells:any) => {
export const getRelationNodeAndVerifyFlowFun = (cells:any, templateName:string, uuid:string) => {
console.log('cells', cells);
const nodeArr = [];
const edgeArr = [];
@@ -32,7 +32,16 @@ export const getRelationNodeAndVerifyFlowFun = (cells:any) => {
if (!relationNode) {
return false;
}
return [relationNode];
const formatElementArr = formatNodeAndEdge(edgeArr, nodeArr);
const formatElementOjb = {
process: {
id: uuid,
name: templateName,
},
flowElements: formatElementArr,
};
console.log('formatElementArr', formatElementArr);
return formatElementOjb;
};
const sortNodeAndEdge = (nodeArr: any, edgeArr: any) => {
try {
@@ -74,8 +83,14 @@ const sortNodeAndEdge = (nodeArr: any, edgeArr: any) => {
console.log('开始向node里插入preNode');
insertRepeatToNode([relationNode], repeatNodeArr, nodeArr);
const includeIds:string[] = [];
console.log('校验流程尾部是否都为结束节点');
if (!verifyEndNode([relationNode])) {
if (!verifyEndNode([relationNode], includeIds)) {
return false;
}
if (includeIds.length !== nodeArr.length) {
ElMessage.error('存在连接不完整的节点!');
return false;
}
@@ -124,12 +139,15 @@ const insertRepeatToNode = (relationNode:any, repeatNodeArr:any, nodeArr:any) =>
}
};
const verifyEndNode = (nodeArr:any):boolean => {
const verifyEndNode = (nodeArr:any, includeIds:string[]):boolean => {
let isEnd = true;
for (let index = 0; index < nodeArr.length; index++) {
if (!includeIds.includes(nodeArr[index].id)) {
includeIds.push(nodeArr[index].id);
}
if (nodeArr[index].children.length > 0 ) {
if (isEnd) {
isEnd = verifyEndNode(nodeArr[index].children);
isEnd = verifyEndNode(nodeArr[index].children, includeIds);
}
} else {
if (nodeArr[index].nodeType !== FLOW_NODE_TYPE_ENUM.END) {
@@ -158,3 +176,64 @@ const checkStartEndNode = (nodeArr: any) => {
}
return true;
};
const formatNodeAndEdge = (edgeArr:any[], nodeArr:any[]) => {
console.log('edgeArr', edgeArr);
console.log('nodeArr', nodeArr);
const edgeFormatArr:any = [];
const nodeFormatArr:any = [];
edgeArr.forEach((item:any) => {
edgeFormatArr.push({
id: item.id,
type: 'sequenceFlow',
sourceRef: item.source,
targetRef: item.target,
});
});
nodeArr.forEach((node:any) => {
const formatItem:any = {
id: node.id, type: node.type,
nodeType: node.nodeType,
name: node.label,
};
edgeArr.forEach((edge:any) => {
if (node.id === edge.source) {
formatItem['incomingFlows'] = [edge.id];
}
if (node.id === edge.target) {
formatItem['outgoingFlows'] = [edge.id];
}
});
formatItem['extensionElements'] = { executeConfig: {} };
formatItem['extensionElements']['executeConfig'] = { ...node, executeType: '', children: [], preNode: [] };
delete formatItem['extensionElements']['executeConfig']['iconUrl'];
delete formatItem['extensionElements']['executeConfig']['children'];
delete formatItem.iconUrl;
delete formatItem.pageConfigList;
delete formatItem.children;
delete formatItem.preNode;
if (formatItem.nodeType === FLOW_NODE_TYPE_ENUM.START) {
formatItem.type = 'startEvent';
}
if (formatItem.nodeType === FLOW_NODE_TYPE_ENUM.END) {
formatItem.type = 'endEvent';
}
if (node.exeMethod === 'userTask') {
formatItem.type = 'userTask';
}
if (node.exeMethod === 'serviceTask') {
formatItem.type = 'serviceTask';
}
if (node.type === '本地应用') {
formatItem.type = 'localApp';
}
if (node.type === '云应用') {
formatItem.type = 'cloudApp';
}
if (node.type === 'HPC') {
formatItem.type = 'HPC';
}
nodeFormatArr.push(formatItem);
});
return [...nodeFormatArr, ...edgeFormatArr];
};

View File

@@ -110,9 +110,9 @@ export const nodeAttribute = reactive<any>({
iconUrl: '',
preScripts: [],
postScripts: [],
appVersion: '',
exeCommand: '', // 执行命令
nodeCondition: 'and', // 节点条件
exeMethod: 'serviceTask', // 执行方式
inputFormat: '', // 输入文件格式
outputFormat: '', // 输出文件格式
pageConfigList: [],

View File

@@ -113,7 +113,6 @@ export const createNode = (nodeListObj:any, graph:any, stencil?:any) => {
iconUrl: item.isLocal ? item.appImage : FileUtil.getFilePreviewImgPathUrl(item.appImage),
preScripts: [],
postScripts: [],
appVersion: '',
pageConfigList: [],
},
})

View File

@@ -152,7 +152,7 @@ const saveDraftFun = async(callback?: () => void) => {
const dataJson = graph.value.toJSON();
console.log('dataJson', dataJson);
if (!callback) {
nodeRelation.value = getRelationNodeAndVerifyFlowFun(graph.value.model.collection.cells);
nodeRelation.value = getRelationNodeAndVerifyFlowFun(graph.value.model.collection.cells, flowDetail.templateName, flowDetail.uuid);
}
const res:any = await updateFlowTemplateDraftApi({ ...flowDetail, uuid: props.flowUuid, viewContent: JSON.stringify(dataJson), templateContent: JSON.stringify(nodeRelation.value) });
if (!callback) {
@@ -174,9 +174,9 @@ const nodeRelation = ref<any>([]);
const openApproveDiaFun = () => {
console.log('graph.value', graph.value);
nodeRelation.value = getRelationNodeAndVerifyFlowFun(graph.value.model.collection.cells);
nodeRelation.value = getRelationNodeAndVerifyFlowFun(graph.value.model.collection.cells, flowDetail.templateName, flowDetail.uuid);
console.log('nodeRelation.value', nodeRelation.value);
if (Array.isArray(nodeRelation.value)) {
if (nodeRelation.value) {
showApproveDia.value = true;
}
};

View File

@@ -94,11 +94,24 @@ const createFlow = async(params: any) => {
};
const editFlow = async(params: any) => {
const res:any = await updateFlowTemplateDraftApi(params);
if (res && res.code === 200) {
ElMessage.success('编辑流程基本属性成功!');
} else {
ElMessage.error(res.msg || '编辑流程基本属性失败!');
console.log('oldFormData', oldFormData.value);
console.log('params', params);
console.log('json', JSON.stringify(oldFormData.value) === JSON.stringify(params));
let editFlag = false;
for (const key in oldFormData.value) {
if (oldFormData.value[key] !== params[key]) {
console.log('oldFormData.value[key]', key, oldFormData.value[key], params[key]);
editFlag = true;
break;
}
}
if (editFlag) {
const res:any = await updateFlowTemplateDraftApi(params);
if (res && res.code === 200) {
ElMessage.success('编辑流程基本属性成功!');
} else {
ElMessage.error(res.msg || '编辑流程基本属性失败!');
}
}
};
@@ -113,8 +126,11 @@ const closeFun = () => {
// emits('nextPageFun', 'basePage');
// };
const oldFormData = ref<any>({});
const setEditForm = (val: any) => {
console.log('val', val, tableFormRef.value);
oldFormData.value = val;
nextTick(() => {
tableFormRef.value.setFormDataFun({ ...val });
});

View File

@@ -40,9 +40,13 @@
<el-dropdown-menu>
<el-dropdown-item @click="openDiaFun('edit', flow)">重命名</el-dropdown-item>
<el-dropdown-item @click="goFlowDetailFun(flow.uuid)">编辑</el-dropdown-item>
<el-dropdown-item v-if="flow.templateStatus === FLOW_USE_STATUS.USED" @click="changeFlowStatusMessageBox(flow.uuid,FLOW_USE_STATUS.STOP)">弃用</el-dropdown-item>
<el-dropdown-item v-if="flow.templateStatus === FLOW_USE_STATUS.USED" @click="changeFlowStatusMessageBox(flow.uuid,FLOW_USE_STATUS.STOP)">
<span class="flow-delete-btn">弃用</span>
</el-dropdown-item>
<el-dropdown-item v-if="flow.templateStatus === FLOW_USE_STATUS.STOP" @click="changeFlowStatusMessageBox(flow.uuid,FLOW_USE_STATUS.USED)">启用</el-dropdown-item>
<el-dropdown-item @click="deleteFlowMessageBox(flow.uuid)">删除</el-dropdown-item>
<el-dropdown-item @click="deleteFlowMessageBox(flow.uuid)">
<span class="flow-delete-btn">删除</span>
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
@@ -446,6 +450,9 @@ const copyFlowFun = (flow:any) => {
margin-right: 0;
}
}
.flow-delete-btn {
color: var(--el-color-danger);
}
}
.flow-grid {

View File

@@ -25,8 +25,13 @@
<template #tableActions="{ row }">
<div class="gl-table-actions">
<el-link type="primary" @click="openTabReviewFile(row.id)">预览</el-link>
<el-link type="primary" @click="downloadFile(row.id)">下载</el-link>
<el-link type="primary" @click="openDialog('edit',row)">编辑</el-link>
<el-link type="danger" @click="deleteFileFun(row.id)">删除</el-link>
<el-popconfirm title="确认删除?" @confirm="deleteFileFun(row.id)">
<template #reference>
<el-link type="danger">删除</el-link>
</template>
</el-popconfirm>
</div>
</template>
</BaseTable>
@@ -107,36 +112,63 @@ const confirmUploadFun = async() => {
const valid = tableFormRef.value.validateFun();
if (valid) {
const fromData = tableFormRef.value.getFormDataFun();
const form = new FormData();
if (fromData.remarks) {
form.append('remarks', fromData.remarks );
}
if (fromData.fileType) {
form.append('fileType', fromData.fileType);
}
if (fromData.files?.length > 0) {
// 选了新文件上传
if (fromData.files[0]?.raw) {
form.append('fileName ', fromData.files[0].name);
form.append('file ', fromData.files[0].raw);
}
}
if (isEditDialog.value) {
console.log('编辑文件', fromData);
if (fromData.id) {
form.append('id', fromData.id);
}
await dataUpdateFileApi(form);
} else {
console.log('上传文件', fromData);
form.append('nodeId ', String(props.projectId));
form.append('projectId ', String(props.projectId));
form.append('uuid ', String(props.projectUuid));
form.append('projectName ', props.projectName);
// form.append('fileName ', fromData.files[0].name);
// form.append('file ', fromData.files[0].raw);
await upload(`${PREFIX}node/uploadProjectFiles`, form);
// 有文件更新
if (fromData.files?.length > 0) {
for (let index = 0; index < fromData.files.length; index++) {
const form = new FormData();
if (fromData.remarks) {
form.append('remarks', fromData.remarks );
}
if (fromData.fileType) {
form.append('fileType', fromData.fileType);
}
// 选了新文件上传
if (fromData.files[index]?.raw) {
form.append('fileName ', fromData.files[index].name);
form.append('file ', fromData.files[index].raw);
}
if (isEditDialog.value) {
console.log('编辑文件', fromData);
if (fromData.id) {
form.append('id', fromData.id);
}
await dataUpdateFileApi(form);
} else {
console.log('上传文件', fromData);
form.append('nodeId ', String(props.projectId));
form.append('projectId ', String(props.projectId));
form.append('uuid ', String(props.projectUuid));
form.append('projectName ', props.projectName);
// form.append('fileName ', fromData.files[0].name);
// form.append('file ', fromData.files[0].raw);
await upload(`${PREFIX}node/uploadProjectFiles`, form);
}
}
} else {// 无文件更新
const form = new FormData();
if (fromData.remarks) {
form.append('remarks', fromData.remarks );
}
if (fromData.fileType) {
form.append('fileType', fromData.fileType);
}
if (isEditDialog.value) {
console.log('编辑文件', fromData);
if (fromData.id) {
form.append('id', fromData.id);
}
await dataUpdateFileApi(form);
} else {
console.log('上传文件', fromData);
form.append('nodeId ', String(props.projectId));
form.append('projectId ', String(props.projectId));
form.append('uuid ', String(props.projectUuid));
form.append('projectName ', props.projectName);
// form.append('fileName ', fromData.files[0].name);
// form.append('file ', fromData.files[0].raw);
await upload(`${PREFIX}node/uploadProjectFiles`, form);
}
}
tableRef.value.resetFun();
dialogVisible.value = false;
@@ -150,6 +182,10 @@ const deleteFileFun = async(id:number) => {
tableRef.value.resetFun();
}
};
const downloadFile = (id:string) => {
const downloadUrl = `${env.VITE_API_FILE_URL}/data/downloadFile?fileId=${id}`;
window.open(downloadUrl, '_blank');
};
// const fileSearchFun = async(params:any) => {
// const res:any = await fileSearchApi({
// 'searchType': '1',

View File

@@ -132,6 +132,7 @@
:projectUuid="nodeLevel1Uuid"
:phaseUuid="nodeLevel2Uuid"
:editMode="true"
:belongProject="true"
>
</loadCaseTable>
<!-- <loadcase-pro-table

View File

@@ -69,6 +69,7 @@ import TableForm from '@/components/common/table/tableForm.vue';
import { tableActionsLength } from '@/utils/common';
import dayjs from 'dayjs';
import { getMemberListIds } from '@/utils/task';
import { isNumber } from 'lodash-es';
const exeTableRef = ref();
@@ -166,8 +167,16 @@ const disposeDisabledAchieveStatus = (status: string, option: { value: TASK_CALC
const confirmFun = async() => {
if (await tableFormRef.value.validateFun()) {
loadingInterface.value = true;
const fromData:any = tableFormRef.value.getFormDataFun();
console.log('fromData', fromData);
if (fromData.exeStatus === TASK_PROCESS_STATUS.COMPLETED && !isNumber(fromData.difficult)) {
ElMessage({
message: '关闭任务时需要填写难度系数!',
type: 'warning',
});
return false;
}
loadingInterface.value = true;
// console.log('tableFormRef.value.getFormDataFun()', fromData);
const params:any = {
taskIds: [fromData.uuid],