|
|
@@ -13,8 +13,8 @@
|
|
|
<el-tag class="ml-2" style="" type="warning">服务</el-tag>
|
|
|
<div style="margin-left: 4%;">
|
|
|
{{servieName}}
|
|
|
- </div>
|
|
|
- <el-icon @click="nodeDeSer = false" style="margin-left: auto;cursor: pointer;"><Close /></el-icon>
|
|
|
+ </div>
|
|
|
+ <el-icon @click="saveNode" style="margin-left: auto;cursor: pointer;"><Close /></el-icon>
|
|
|
</div>
|
|
|
<div>
|
|
|
<div style="display: flex;width: 90%;margin-left: 5%;margin-top:10%;align-items: center;justify-content: space-between;">
|
|
|
@@ -35,8 +35,22 @@
|
|
|
<el-table-column prop="paramCode" label="参数名" width="" />
|
|
|
<el-table-column prop="paramValue" label="参数值" width="">
|
|
|
<template #default="scope">
|
|
|
- <div style="width: 100%;">
|
|
|
- <el-input placeholder="" type="primary" class="noBor" v-model="scope.row.paramValue" size="mini" text style="margin-left: 0%;"></el-input>
|
|
|
+ <div style="width:100%;">
|
|
|
+ <el-select
|
|
|
+ v-model="scope.row.paramValue"
|
|
|
+ multiple
|
|
|
+ filterable
|
|
|
+ allow-create
|
|
|
+ default-first-option
|
|
|
+ :reserve-keyword="false"
|
|
|
+ style="width: 100%"
|
|
|
+ >
|
|
|
+ <el-option
|
|
|
+ v-for="item in optionsCan"
|
|
|
+ :label="item.paramCode"
|
|
|
+ :value="item.paramValue"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
</div>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
@@ -193,7 +207,7 @@
|
|
|
style="margin-left: 0%;font-size: 10px;height: 15px;width: 150%;" ></el-input>
|
|
|
<!-- {{ specialNodeProps.data.label}} -->
|
|
|
</div>
|
|
|
- <el-icon style="cursor: pointer;margin-left: auto;"><CaretRight /></el-icon>
|
|
|
+ <el-icon @click.stop="testNode(specialNodeProps)" style="cursor: pointer;margin-left: auto;"><CaretRight /></el-icon>
|
|
|
<el-icon @click.stop="delNode(specialNodeProps)" style="cursor: pointer;color: #F56C6C;margin-left: 2%;"><Delete /></el-icon>
|
|
|
</div>
|
|
|
<div style="display: flex;margin-top: 3%;">
|
|
|
@@ -478,6 +492,27 @@
|
|
|
</span>
|
|
|
</template>
|
|
|
</el-dialog>
|
|
|
+ <el-dialog @close="clearFromLev" :title="titleTest" v-model="dialogVisibleTest" width="50%" destroy-on-close :key="tableKey">
|
|
|
+ <el-form ref="formAddref" :model="formAdd" label-width="100px" class="coz-mg-card" :rules="rulesAdd">
|
|
|
+ <el-form-item label="输入测试值:">
|
|
|
+ <el-input v-model="formJi.intro" :placeholder="testAttention" style="width: 100%;" :rows="15" resize="none" type="textarea"/>
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+ <div style="font-size: 16px;margin-left: 1%">
|
|
|
+ 属性字段
|
|
|
+ </div>
|
|
|
+ <template #footer>
|
|
|
+ <span class="dialog-footer">
|
|
|
+ <el-button size="mini" @click="dialogVisibleBiao = false">取消</el-button>
|
|
|
+ <el-button type="primary" @click="saveAdd1Level" size="mini" v-if="show1Lev">
|
|
|
+ 提交
|
|
|
+ </el-button>
|
|
|
+ <el-button type="primary" @click="saveAddNextLevel" size="mini" v-if="!show1Lev">
|
|
|
+ 提交
|
|
|
+ </el-button>
|
|
|
+ </span>
|
|
|
+ </template>
|
|
|
+ </el-dialog>
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
@@ -498,7 +533,7 @@ import {getPtServiceList,getSerDe} from "@/api/service/info.js";
|
|
|
import { getToken } from '@/utils/auth'
|
|
|
import {getModelList2} from "@/api/register/regCom.js";
|
|
|
import {copyObject} from "@/utils/index.js";
|
|
|
-import {getModelingDe,addModelingFlow,editModelingFlow,delFlow} from "@/api/standardization/modeling.js";
|
|
|
+import {getModelingDe,addModelingFlow,editModelingFlow,delFlow,runflow} from "@/api/standardization/modeling.js";
|
|
|
import { useStore } from 'vuex';
|
|
|
import {Handle, Position} from '@vue-flow/core'
|
|
|
import { computed } from 'vue';
|
|
|
@@ -509,6 +544,7 @@ const {
|
|
|
onEdgeClick,
|
|
|
addNodes,
|
|
|
removeNodes,
|
|
|
+ updateNodeInternals,
|
|
|
screenToFlowCoordinate,
|
|
|
onNodesInitialized,
|
|
|
updateNode,
|
|
|
@@ -517,12 +553,16 @@ const {
|
|
|
zoomTo,
|
|
|
toObject,
|
|
|
getEdges,
|
|
|
+ findNode
|
|
|
} = useVueFlow()
|
|
|
snapToGrid.value = true
|
|
|
+const parNodeid = ref('')
|
|
|
const formAdd = ref({
|
|
|
appTitle: '',
|
|
|
appNote: '',
|
|
|
});
|
|
|
+const testAttention = ref("{\n \"data\": [\n {\n \"typhoonId\": \"202317\",\n \"typhoonName\": \"杰拉华\",\n \"test\": \"1123\"\n },\n {\n \"typhoonId\": \"202316\",\n \"typhoonName\": \"三巴\",\n \"test\": \"1123\"\n \n }\n ],\n \"succeeded\": true,\n \"statusCode\": 200,\n \"remark\": \"获取该年台风信息成功\",\n \"callParameters\": null\n}")
|
|
|
+const dialogVisibleTest = ref(false)
|
|
|
const dialogVisibleCsv = ref(false)
|
|
|
const formAddref = ref()
|
|
|
const dialogVisibleExcel = ref(false)
|
|
|
@@ -530,6 +570,7 @@ const rulesAdd = reactive({
|
|
|
appTitle: [{ required: true, message: '必填', trigger: 'blur' }],
|
|
|
appNote: [{ required: true, message: '必填', trigger: 'blur' }],
|
|
|
});
|
|
|
+const titleTest = ref('')
|
|
|
const upload = reactive({
|
|
|
// 是否显示弹出层(用户导入)
|
|
|
open: false,
|
|
|
@@ -555,6 +596,7 @@ const formJi = ref({
|
|
|
rptype:'',
|
|
|
intro:'',
|
|
|
});
|
|
|
+const optionsCan = ref()
|
|
|
const rulesJi = reactive({
|
|
|
name: [{ required: true, message: '必填', trigger: 'blur' }],
|
|
|
url: [{ required: true, message: '必填', trigger: 'blur' }],
|
|
|
@@ -684,6 +726,14 @@ function showData(){
|
|
|
function handleInputClick(){
|
|
|
console.log(nodes.value)
|
|
|
}
|
|
|
+function saveNode(){
|
|
|
+ nodeDeSer.value = false
|
|
|
+ const node = findNode(parNodeid.value)
|
|
|
+ node.data.returnList = tableDataCanOut.value
|
|
|
+ updateNode(parNodeid.value, {
|
|
|
+ data: node.data
|
|
|
+ });
|
|
|
+}
|
|
|
function delWholeFlow(){
|
|
|
proxy.$confirm('是否删除该模型流程?', '提示', {
|
|
|
confirmButtonText: '确定',
|
|
|
@@ -728,6 +778,9 @@ const toImage = async () => {
|
|
|
console.error('导出错误:', error);
|
|
|
}
|
|
|
};
|
|
|
+function testNode(node){
|
|
|
+ dialogVisibleTest.value = true
|
|
|
+}
|
|
|
function oneSel(){
|
|
|
if(checkboxGroup1.value.length>1){
|
|
|
checkboxGroup1.value.splice(0,1)
|
|
|
@@ -738,6 +791,11 @@ async function delNode(node){
|
|
|
await nextTick()
|
|
|
|
|
|
}
|
|
|
+function generateTimestampId() {
|
|
|
+ const timestamp = Date.now(); // 13位毫秒时间戳
|
|
|
+ const randomNum = Math.floor(Math.random() * 1000); // 3位随机数
|
|
|
+ return parseInt(`${timestamp}${randomNum}`); // 拼接后转为整数
|
|
|
+}
|
|
|
onEdgeClick(({ edge }) => {
|
|
|
console.log(edges.value,edge)
|
|
|
edges.value = edges.value.filter(item => item.id !== edge.id)
|
|
|
@@ -748,14 +806,23 @@ async function getTreeLeft(){
|
|
|
})
|
|
|
}
|
|
|
function saveFlow(){
|
|
|
+ var parFlow = toRaw(toObject())
|
|
|
+ parFlow.nodes.forEach(item => {
|
|
|
+ if(item.id==='1'){
|
|
|
+ item.type='startNode'
|
|
|
+ }
|
|
|
+ if(item.id==='2'){
|
|
|
+ item.type='endNode'
|
|
|
+ }
|
|
|
+ });
|
|
|
+ console.log(parFlow)
|
|
|
if(isAdd.value){
|
|
|
const count = computed(() => store.getters.id)
|
|
|
var par = {
|
|
|
appId: count.value,
|
|
|
flowName:'default',
|
|
|
- flowGraph: JSON.stringify(toRaw(toObject()))
|
|
|
+ flowGraph: JSON.stringify(parFlow)
|
|
|
}
|
|
|
- console.log(par)
|
|
|
addModelingFlow(par).then(res=>{
|
|
|
if(res.code===200){
|
|
|
proxy.$message({
|
|
|
@@ -772,7 +839,7 @@ function saveFlow(){
|
|
|
flowId: parFlowId.value,
|
|
|
appId: count.value,
|
|
|
flowName:'default',
|
|
|
- flowGraph: JSON.stringify(toRaw(toObject()))
|
|
|
+ flowGraph: JSON.stringify(parFlow)
|
|
|
}
|
|
|
console.log(par)
|
|
|
editModelingFlow(par).then(res=>{
|
|
|
@@ -783,12 +850,71 @@ function saveFlow(){
|
|
|
});
|
|
|
getList()
|
|
|
}
|
|
|
- })
|
|
|
+ })
|
|
|
}
|
|
|
}
|
|
|
+function getPredecessorsNodes(nodeId, edges = getEdges.value, allNodes = getNodes.value){
|
|
|
+ // 1. 找到所有直接指向目标节点的边(即 target 为 nodeId 的边)
|
|
|
+ const incomingEdges = edges.filter(edge => edge.target === nodeId);
|
|
|
+
|
|
|
+ // 2. 从这些边中提取所有源节点的 ID
|
|
|
+ const sourceNodeIds = incomingEdges.map(edge => edge.source);
|
|
|
+
|
|
|
+ // 3. 根据源节点 ID 获取完整的节点对象
|
|
|
+ const directPredecessors = allNodes.filter(node => sourceNodeIds.includes(node.id));
|
|
|
+
|
|
|
+ // 4. 递归获取这些直接前置节点的前置节点
|
|
|
+ const allPredecessors = [];
|
|
|
+ for (const predecessor of directPredecessors) {
|
|
|
+ // 将直接前置节点加入结果数组
|
|
|
+ allPredecessors.push(predecessor);
|
|
|
+ // 递归获取该前置节点的前置节点,并合并到结果数组中
|
|
|
+ const predecessorsOfPredecessor = getPredecessorsNodes(predecessor.id, edges, allNodes);
|
|
|
+ allPredecessors.push(...predecessorsOfPredecessor);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 5. 使用 Set 或其他方法去重(根据节点 ID),因为一个节点可能通过不同路径被多次访问
|
|
|
+ const uniquePredecessors = Array.from(new Map(allPredecessors.map(node => [node.id, node])).values());
|
|
|
+
|
|
|
+ return uniquePredecessors;
|
|
|
+};
|
|
|
+function removeDuplicatesAndEmptyItems(arr) {
|
|
|
+ const map = new Map();
|
|
|
+ return arr.filter(item => {
|
|
|
+ // 过滤 null 和 undefined
|
|
|
+ if (item === null || item === undefined) return false;
|
|
|
+
|
|
|
+ // 处理对象类型:转为字符串标识去重
|
|
|
+ const key = typeof item === 'object'
|
|
|
+ ? JSON.stringify(item)
|
|
|
+ : item;
|
|
|
+
|
|
|
+ // 若标识不存在于 Map 中,则保留并记录
|
|
|
+ if (!map.has(key)) {
|
|
|
+ map.set(key, true);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
onNodeClick(({event, node}) => {
|
|
|
+ console.log(node)
|
|
|
+ parNodeid.value = node.id
|
|
|
tableDataCan.value = []
|
|
|
+ optionsCan.value = []
|
|
|
+ var parNode = getPredecessorsNodes(node.id)
|
|
|
+ var parOp = []
|
|
|
+ parNode.forEach(item => {
|
|
|
+ parOp = parOp.concat(item.data.returnList)
|
|
|
+ // console.log(item.data.returnList)
|
|
|
+ })
|
|
|
+ var a = JSON.parse(JSON.stringify(parOp));
|
|
|
+ optionsCan.value = removeDuplicatesAndEmptyItems(a)
|
|
|
+ console.log(a)
|
|
|
+ console.log(parNode)
|
|
|
if(node.data.nodeType==='SERVICE'){
|
|
|
+ // console.log(getPredecessorsNodes(node.id))
|
|
|
getSerDe(node.data.id).then(res=>{
|
|
|
serviceRqtype.value = res.data.ptService.rqtype
|
|
|
servieName.value = res.data.ptService.name
|
|
|
@@ -855,35 +981,32 @@ function onDragOver(event) {
|
|
|
* @param event
|
|
|
*/
|
|
|
|
|
|
-function onDrop(event) {
|
|
|
- getSerDe(draggedData.value.id).then(res=>{
|
|
|
- draggedData.value = res.data.ptService
|
|
|
- })
|
|
|
- const position = screenToFlowCoordinate({
|
|
|
- x: event.clientX,
|
|
|
- y: event.clientY,
|
|
|
- })
|
|
|
-
|
|
|
- const nodeId = Math.random() + "id";
|
|
|
- const data = copyObject(draggedData.value)
|
|
|
+async function onDrop(event) {
|
|
|
+ const position = screenToFlowCoordinate({ x: event.clientX, y: event.clientY });
|
|
|
+ const nodeId = generateTimestampId();
|
|
|
+
|
|
|
+ // 1. 同步创建节点
|
|
|
const newNode = {
|
|
|
id: nodeId,
|
|
|
type: 'special',
|
|
|
position,
|
|
|
- data,
|
|
|
- }
|
|
|
-
|
|
|
- // 更新位置到鼠标中心
|
|
|
- const {off} = onNodesInitialized(() => {
|
|
|
- updateNode(nodeId, (node) => ({
|
|
|
- position: {x: node.position.x - node.dimensions.width / 2, y: node.position.y - node.dimensions.height / 2},
|
|
|
- }))
|
|
|
+ data: copyObject(draggedData.value) // 先使用本地数据
|
|
|
+ };
|
|
|
+ addNodes(newNode);
|
|
|
|
|
|
- off()
|
|
|
- })
|
|
|
+ // 2. 异步获取数据并更新
|
|
|
+ const res = await getSerDe(draggedData.value.id);
|
|
|
+ const fullData = {
|
|
|
+ ...res.data.ptService,
|
|
|
+ returnList: res.data.returnList
|
|
|
+ };
|
|
|
|
|
|
- addNodes(newNode)
|
|
|
- // nodes.value.push(newNode)
|
|
|
+ // 3. 等待节点渲染完成后再修正位置
|
|
|
+ nextTick(() => {
|
|
|
+ updateNode(nodeId, { data: { ...newNode.data, ...fullData } });
|
|
|
+ updateNodeInternals(nodeId); // 强制更新节点布局[1](@ref)
|
|
|
+});
|
|
|
+ // console.log(toObject())
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -943,6 +1066,9 @@ function getList() {
|
|
|
isAdd.value = false
|
|
|
var a = JSON.parse(JSON.parse(JSON.stringify(res.data[0].flowGraph)))
|
|
|
console.log(a)
|
|
|
+ a.nodes.forEach(item=>{
|
|
|
+ item.type = 'special'
|
|
|
+ })
|
|
|
nodes.value = a.nodes
|
|
|
edges.value = a.edges
|
|
|
zoom.value = a.zoom
|