nanjingliujinyu 4 månader sedan
förälder
incheckning
a7f46aec61

+ 7 - 0
ruoyi-ui/src/api/standardization/modeling.js

@@ -67,4 +67,11 @@ export function delFlow(id) {
     url: '/app/flow/' + id,
     method: 'delete'
   })
+}
+export function runflow(data) {
+  return request({
+    url: "/app/flow/runFlow",
+    method: 'post',
+    data:data
+  });
 }

+ 13 - 13
ruoyi-ui/src/views/service/info/editModel.vue

@@ -1264,18 +1264,18 @@ async function saveEditService(){
         }
       })
       // 处理返回值
-      if(byWhich.value==='input'){
-        var par = JSON.parse(dataJsonXiang.value)
-        var par1 = transformDynamicDataToTree(par)
-        console.log(par1)
-        postReturnlist(par1).then(res=>{
-          if(res.code===200){
-            proxy.$modal.msgSuccess("新增成功");
-            getTreeLeft()
-          }
-        })
-      }
-      if(byWhich.value==='tree'){
+      // if(byWhich.value==='input'){
+      //   var par = JSON.parse(dataJsonXiang.value)
+      //   var par1 = transformDynamicDataToTree(par)
+      //   console.log(par1)
+      //   postReturnlist(par1).then(res=>{
+      //     if(res.code===200){
+      //       proxy.$modal.msgSuccess("新增成功");
+      //       getTreeLeft()
+      //     }
+      //   })
+      // }
+      // if(byWhich.value==='tree'){
         // console.log(dataTreeReturn.value)
         var par = JSON.parse(JSON.stringify(dataTreeReturn.value))
         var par1 = flattenTreeWithArrayIndex(par)
@@ -1286,7 +1286,7 @@ async function saveEditService(){
             getTreeLeft()
           }
         })
-      }
+      // }
     }
   }
 }

+ 159 - 33
ruoyi-ui/src/views/standardization/modeling/index.vue

@@ -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