Przeglądaj źródła

Merge remote-tracking branch 'origin/master'

ZhuDeKang 2 miesięcy temu
rodzic
commit
e77baa8b4b

BIN
ruoyi-ui/src/assets/fonts/AlimamaDongFangDaKai-Regular.ttf


+ 6 - 0
ruoyi-ui/src/assets/fonts/font.css

@@ -0,0 +1,6 @@
+@font-face {
+  font-family: 'DongFangDaKai';
+  src: url(AlimamaDongFangDaKai-Regular.ttf);
+  font-weight: normal;
+  font-style: normal
+}

+ 1 - 0
ruoyi-ui/src/main.js

@@ -4,6 +4,7 @@ import Cookies from "js-cookie";
 
 import ElementPlus from "element-plus";
 import "element-plus/dist/index.css";
+import "@/assets/fonts/font.css";
 import locale from "element-plus/es/locale/lang/zh-cn";
 
 import "@/assets/styles/index.scss"; // global css

+ 1 - 1
ruoyi-ui/src/router/index.js

@@ -65,7 +65,7 @@ export const constantRoutes = [
     {
         path: '',
         component: Layout,
-        redirect: '/datamonitor/monitorservice',
+        redirect: '/shouye',
         // children: [
         //     {
         //         path: '/index',

+ 103 - 78
ruoyi-ui/src/views/shouye.vue

@@ -1,104 +1,129 @@
 <template>
-    <div style="height: 100vh;background-color: #dcecef;">
-        <img style="position: absolute;left: 2%;top: 3%;width: 58%;z-index: 100;height: 6%;"  src="@/assets/上海水务首页图片包/项目标题.png" alt="">
-    <el-carousel 
-    :interval="4000" 
-    height="auto"
-    arrow="always"
-    autoplay
+  <div style="height: 100vh;background-color: #dcecef;">
+    <div style="position: absolute;left: 2%;top: 2%;width: 58%;z-index: 100;height: 6%;">
+      <span style="font-size: 3rem;color: #fff;font-family: DongFangDaKai">上海市水务海洋数字孪生模型服务管理系统</span>
+    </div>
+    <!--        <img  src="@/assets/上海水务首页图片包/项目标题.png" alt="">-->
+    <el-carousel
+        :interval="4000"
+        height="auto"
+        arrow="always"
+        autoplay
     >
-        <el-carousel-item style="height: 80vh">
-            <img style="height: 100%;width: 100%;"  src="@/assets/上海水务首页图片包/上海城区洪涝仿真模型.png" alt="">
-        </el-carousel-item>
-        <el-carousel-item style="height: 80vh">
-            <img style="height: 100%;width: 100%;"  src="@/assets/上海水务首页图片包/风暴潮模型.png" alt="">
-        </el-carousel-item>
-        <el-carousel-item style="height: 80vh">
-            <img style="height: 100%;width: 100%;"  src="@/assets/上海水务首页图片包/黄浦江水系水文分析预报数值模拟模型.png" alt="">
-        </el-carousel-item>
-        <el-carousel-item style="height: 80vh">
-            <img style="height: 100%;width: 100%;"  src="@/assets/上海水务首页图片包/内涝.jpg" alt="">
-        </el-carousel-item>
-        <el-carousel-item style="height: 80vh">
-            <img style="height: 100%;width: 100%;"  src="@/assets/上海水务首页图片包/上海城区洪涝仿真模型.png" alt="">
-        </el-carousel-item>
-        <el-carousel-item style="height: 80vh">
-            <img style="height: 100%;width: 100%;"  src="@/assets/上海水务首页图片包/苏州河水系水情预报模型.png" alt="">
-        </el-carousel-item>
-        <el-carousel-item style="height: 80vh">
-            <img style="height: 100%;width: 100%;"  src="@/assets/上海水务首页图片包/上海市中心城区排水系统模型.png" alt="">
-        </el-carousel-item>
-        <el-carousel-item style="height: 80vh">
-            <img style="height: 100%;width: 100%;"  src="@/assets/上海水务首页图片包/温带风暴潮预报模型.png" alt="">
-        </el-carousel-item>
+      <el-carousel-item style="height: 80vh">
+        <img style="height: 100%;width: 100%;" src="@/assets/上海水务首页图片包/上海城区洪涝仿真模型.png" alt="">
+      </el-carousel-item>
+      <el-carousel-item style="height: 80vh">
+        <img style="height: 100%;width: 100%;" src="@/assets/上海水务首页图片包/风暴潮模型.png" alt="">
+      </el-carousel-item>
+      <el-carousel-item style="height: 80vh">
+        <img style="height: 100%;width: 100%;" src="@/assets/上海水务首页图片包/黄浦江水系水文分析预报数值模拟模型.png"
+             alt="">
+      </el-carousel-item>
+      <el-carousel-item style="height: 80vh">
+        <img style="height: 100%;width: 100%;" src="@/assets/上海水务首页图片包/内涝.jpg" alt="">
+      </el-carousel-item>
+      <el-carousel-item style="height: 80vh">
+        <img style="height: 100%;width: 100%;" src="@/assets/上海水务首页图片包/上海城区洪涝仿真模型.png" alt="">
+      </el-carousel-item>
+      <el-carousel-item style="height: 80vh">
+        <img style="height: 100%;width: 100%;" src="@/assets/上海水务首页图片包/苏州河水系水情预报模型.png" alt="">
+      </el-carousel-item>
+      <el-carousel-item style="height: 80vh">
+        <img style="height: 100%;width: 100%;" src="@/assets/上海水务首页图片包/上海市中心城区排水系统模型.png" alt="">
+      </el-carousel-item>
+      <el-carousel-item style="height: 80vh">
+        <img style="height: 100%;width: 100%;" src="@/assets/上海水务首页图片包/温带风暴潮预报模型.png" alt="">
+      </el-carousel-item>
     </el-carousel>
+  </div>
+  <div style="position: absolute;height: 30vh;z-index: 100;top: 70%;width: 100%;">
+    <div style="display: flex;width: 98%;margin-left: 1%;">
+      <div style="width: 25vw;height: 29vh;margin-left: 1%;cursor: pointer;" class="back1"
+           @click="pushto('platform/componentReg')">
+        <div style="width: 100%;color: #dcecef;text-align: center;font-size: 1.5rem;margin-top:5%;">模型注册管理</div>
+        <img style="height: 80%;width: 80%;margin-left: 10%;margin-top: 2%;"
+             src="@/assets/上海水务首页图片包/模型注册.png" alt="">
+      </div>
+      <div style="width: 25vw;height: 29vh;margin-left: 1%;cursor: pointer;" class="back2"
+           @click="pushto('register/edtiModel')">
+        <div style="width: 100%;color: #dcecef;text-align: center;font-size: 1.5rem;margin-top:5%;">模型服务管理</div>
+        <img style="height: 80%;width: 80%;margin-left: 10%;margin-top: 2%;"
+             src="@/assets/上海水务首页图片包/模型服务管理.png" alt="">
+      </div>
+      <div style="width: 25vw;height: 29vh;margin-left: 1%;cursor: pointer;" class="back1"
+           @click="pushto('standardization/modelUsing')">
+        <div style="width: 100%;color: #dcecef;text-align: center;font-size: 1.5rem;margin-top:5%;">模型标准化开发</div>
+        <img style="height: 80%;width: 80%;margin-left: 10%;margin-top: 2%;"
+             src="@/assets/上海水务首页图片包/模型标准化.png" alt="">
+      </div>
+      <div style="width: 25vw;height: 29vh;margin-left: 1%;cursor: pointer;" class="back2"
+           @click="pushto('datamonitor/model_operation_monitoring')">
+        <div style="width: 100%;color: #dcecef;text-align: center;font-size: 1.5rem;margin-top:5%;">模型监控管理</div>
+        <img style="height: 80%;width: 80%;margin-left: 10%;margin-top: 2%;"
+             src="@/assets/上海水务首页图片包/模型监控.png" alt="">
+      </div>
+      <div style="width: 25vw;height: 29vh;margin-left: 1%;cursor: pointer;" class="back1"
+           @click="pushto('evaluate/score')">
+        <div style="width: 100%;color: #dcecef;text-align: center;font-size: 1.5rem;margin-top:5%;">模型评价管理</div>
+        <img style="height: 80%;width: 80%;margin-left: 10%;margin-top: 2%;"
+             src="@/assets/上海水务首页图片包/模型评价.png" alt="">
+      </div>
+
     </div>
-    <div style="position: absolute;height: 30vh;z-index: 100;top: 70%;width: 100%;">
-        <div style="display: flex;width: 98%;margin-left: 1%;"> 
-            <div style="width: 25vw;height: 29vh;margin-left: 1%;cursor: pointer;" class="back1" @click="pushto('platform/componentReg')">
-                <div style="width: 100%;color: #dcecef;text-align: center;font-size: 1.5rem;margin-top:5%;">模型注册管理</div>
-                <img style="height: 80%;width: 80%;margin-left: 10%;margin-top: 2%;"  src="@/assets/上海水务首页图片包/模型注册.png" alt="">
-            </div>
-            <div style="width: 25vw;height: 29vh;margin-left: 1%;cursor: pointer;" class="back2" @click="pushto('register/edtiModel')">
-                <div style="width: 100%;color: #dcecef;text-align: center;font-size: 1.5rem;margin-top:5%;">模型服务管理</div>
-                <img style="height: 80%;width: 80%;margin-left: 10%;margin-top: 2%;"  src="@/assets/上海水务首页图片包/模型服务管理.png" alt="">
-            </div>
-            <div style="width: 25vw;height: 29vh;margin-left: 1%;cursor: pointer;" class="back1" @click="pushto('standardization/modelUsing')">
-                <div style="width: 100%;color: #dcecef;text-align: center;font-size: 1.5rem;margin-top:5%;">模型标准化开发</div>
-                <img style="height: 80%;width: 80%;margin-left: 10%;margin-top: 2%;"  src="@/assets/上海水务首页图片包/模型标准化.png" alt="">
-            </div>
-            <div style="width: 25vw;height: 29vh;margin-left: 1%;cursor: pointer;" class="back2" @click="pushto('datamonitor/model_operation_monitoring')">
-                <div style="width: 100%;color: #dcecef;text-align: center;font-size: 1.5rem;margin-top:5%;">模型监控管理</div>
-                <img style="height: 80%;width: 80%;margin-left: 10%;margin-top: 2%;"  src="@/assets/上海水务首页图片包/模型监控.png" alt="">
-            </div>
-            <div style="width: 25vw;height: 29vh;margin-left: 1%;cursor: pointer;" class="back1" @click="pushto('evaluate/score')">
-                <div style="width: 100%;color: #dcecef;text-align: center;font-size: 1.5rem;margin-top:5%;">模型评价管理</div>
-                <img style="height: 80%;width: 80%;margin-left: 10%;margin-top: 2%;"  src="@/assets/上海水务首页图片包/模型评价.png" alt="">
-            </div>
-            
-        </div>
-    </div>
+  </div>
 </template>
 <script setup>
-import { useRouter } from 'vue-router'
+import {useRouter} from 'vue-router'
 
 const router = useRouter()
 const carouseData = [
-  { 
-    id: 1, 
-    url: new URL('@/assets/上海水务首页图片包/风暴潮.png', import.meta.url).href 
+  {
+    id: 1,
+    url: new URL('@/assets/上海水务首页图片包/风暴潮.png', import.meta.url).href
   },
-  { 
-    id: 2, 
-    url: new URL('@/assets/上海水务首页图片包/风暴潮.png', import.meta.url).href 
+  {
+    id: 2,
+    url: new URL('@/assets/上海水务首页图片包/风暴潮.png', import.meta.url).href
   },
-  { 
-    id: 3, 
-    url: new URL('@/assets/上海水务首页图片包/风暴潮.png', import.meta.url).href 
+  {
+    id: 3,
+    url: new URL('@/assets/上海水务首页图片包/风暴潮.png', import.meta.url).href
   },
 ]
-function pushto(routers){
-    router.push(routers);
+
+function pushto(routers) {
+  router.push(routers);
 }
 
 </script>
+<!--
+  //background-image:url('@/assets/上海水务首页图片包/浅蓝.png');
+  //background-repeat: no-repeat;
+  //background-position: center center;
+ -->
 <style scoped>
-.back1{
-    background-image:url('@/assets/上海水务首页图片包/浅蓝.png');
-    background-repeat: no-repeat;
-    background-position: center center;
+
+.back1 {
+  background: linear-gradient(45deg, rgba(142, 197, 252, 1.000) 0.000%, rgba(141, 211, 255, 1.000) 25.000%, rgba(161, 216, 255, 1.000) 50.000%, rgba(193, 210, 255, 1.000) 75.000%, rgba(224, 195, 255, 1.000) 100.000%);
+  border-radius: 8px;
+  box-shadow: 0 16px 48px 16px rgba(0, 0, 0, .08), 0 12px 32px rgba(0, 0, 0, .12), 0 8px 16px -8px rgba(0, 0, 0, .16);
+  transition: transform .2s ease-in;
 }
+
 .back1:hover {
   transform: translateY(-20px);
-  box-shadow: 0 8px 15px rgba(0, 0, 0, 0.2);
 }
-.back2{
-    background-image:url('@/assets/上海水务首页图片包/深蓝.png');
-    background-repeat: no-repeat;
-    background-position: center center;
+
+.back2 {
+  background-image: url('@/assets/上海水务首页图片包/深蓝.png');
+  background-repeat: no-repeat;
+  background-position: center center;
+  transition: transform .2s ease-in;
 }
+
 .back2:hover {
   transform: translateY(-20px);
-  box-shadow: 0 8px 15px rgba(0, 0, 0, 0.2);
+  box-shadow: 0 0 6px rgba(0, 0, 0, .12);
 }
 </style>

+ 423 - 83
ruoyi-ui/src/views/standardization/modeling/index.vue

@@ -40,7 +40,7 @@
                   <el-select
                     v-model="scope.row.paramValue"
                     filterable
-                    @change="handleSelectChange"
+                    @change="(newValue) => handleSelectChange(newValue, scope.row)"
                     allow-create
                     default-first-option
                     :reserve-keyword="false"
@@ -106,6 +106,79 @@
       </div>
       </div>
     </div>
+    <div v-if="saveDeSer" style="height: 82vh;overflow-y: auto;width: 20vw;position: absolute;float: right;z-index: 1000;right: 1%;top:6%;border: 0.1px solid #dedfe0;border-radius: 6px;background-color: white;">
+      <div style="display: flex;margin-left: 3%;margin-top: 3%;align-items: center;justify-content: space-between;width: 95%;">
+        <el-tag class="ml-2" style="" type="warning">存储节点</el-tag>
+        <el-icon @click="closeSaveDe" 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;">
+        <el-table :data="tableDataCan" border style="width: 100%">
+          <el-table-column prop="paramCode" label="参数名" width="" />
+          <el-table-column prop="paramValue" label="参数值" width="">
+            <template #default="scope">
+              
+              <div style="width:100%;">
+                  <el-select
+                    v-model="scope.row.paramValue"
+                    filterable
+                    @change="saveNode"
+                    allow-create
+                    default-first-option
+                    :reserve-keyword="false"
+                    style="width: 100%"
+                  >
+                    <el-option
+                      v-for="item in optionsCan"
+                      :label="item.name"
+                      :value="item.ref"
+                    />
+                  </el-select>
+              </div>
+            </template>
+          </el-table-column>
+        </el-table>
+      </div>
+      <div style="display: flex;width: 88%;margin-left: 5%;margin-top:10%;align-items: center;justify-content: space-between;">
+        <el-form ref="deptRef" :model="form" label-width="100px" label-position="top" style="width: 100%;">
+          <el-row :gutter="48">
+            <el-col :span="12">
+              <el-form-item label="失败处理:" prop="name" style="">
+                <div style="display: flex;width: 100%;justify-content: space-between;">
+                  <el-select v-model="form.errorPolicy" style="width: 100%">
+                    <el-option label="报错" value="ABORT"></el-option>
+                    <el-option label="忽视" value="IGNORE"></el-option>
+                    <el-option label="重连" value="RETRY"></el-option>
+                  </el-select>
+                </div>
+              </el-form-item>
+            </el-col>
+            <el-col :span="12">
+              <el-form-item label="失败重连次数:" prop="" style="">
+                <div style="display: flex;width: 100%;justify-content: space-between;">
+                  <el-input-number  v-model="form.retryCount" :min="1" style="width: 100%" :max="30"/>
+                  <div style="display: flex;">
+                  </div>
+                </div>
+              </el-form-item>
+            </el-col>
+          </el-row>
+          <el-form-item  label="输出">
+            <el-table :data="tableDataCanOut" border style="width: 100%">
+              <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>
+                </template>
+              </el-table-column>
+            </el-table>
+          </el-form-item>
+        </el-form>
+      </div>
+      </div>
+    </div>
     <div v-if="nodeStart" style="height: 82vh;overflow-y: auto;width: 40vw;position: absolute;float: right;z-index: 1000;right: 1%;top:6%;border: 0.1px solid #dedfe0;border-radius: 6px;background-color: white;">
       <div style="display: flex;margin-left: 3%;margin-top: 3%;align-items: center;justify-content: space-between;width: 95%;">
         <el-tag class="ml-2" style="" type="warning">开始节点</el-tag>
@@ -164,9 +237,12 @@
             </el-table-column>
             <el-table-column prop="itemName" label="参数值" >
                 <template #default="scope">
-                    <div style="width: 100%;">
-                        <el-input type="primary"  class="noBor" v-model="scope.row.paramValue" size="mini" text style="margin-left: 0%;"></el-input>
-                    </div>
+                  <div style="display: flex;">
+                    <div style="color: red;width: 15%;" v-if="scope.row.inValid">*</div>
+                      <div style="width: 100%;">
+                          <el-input type="primary" @blur="checkValid(scope.row)" class="noBor" v-model="scope.row.paramValue" size="mini" text style="margin-left: 0%;"></el-input>
+                      </div>
+                  </div>
                 </template>
             </el-table-column>
             <el-table-column prop="address" label="操作" width="100">
@@ -251,9 +327,9 @@
           <el-checkbox-button key="service" label="service">
             服务
           </el-checkbox-button>
-          <!-- <el-checkbox-button key="tool" label="tool">
+          <el-checkbox-button key="tool" label="tool">
             工具
-          </el-checkbox-button> -->
+          </el-checkbox-button>
       </el-checkbox-group>
         <el-input
           v-if="checkboxGroup1.includes('service')"
@@ -267,11 +343,7 @@
           <template #default="{ node, data }">
             <span  style="justify-content: space-between;display: flex;width: 100%;align-items: center;" :draggable="true" @dragstart="onDragStart($event,data)">
               <div class="custom-tree-node">
-                  <!-- <el-tag v-if="data.nodeType=='MODEL'" class="ml-2" type="warning">模型</el-tag> -->
                    <svg-icon icon-class="model2" style="color: #eebe77;" v-if="data.nodeType=='MODEL'"/>
-                  <!-- <el-tag  class="ml-2">
-                    服务
-                  </el-tag> -->
                   <svg-icon icon-class="model" dstyle="color: #13E03B;" v-if="data.nodeType=='SERVICE'"/>
                   <svg-icon svg-icon icon-class="cate" style="color: red;" v-if="data.nodeType=='TREE'"/>
                 <span>{{ node.label }}</span>
@@ -294,6 +366,7 @@
                   <svg-icon icon-class="lczd" dstyle="color: #13E03B;" v-if="data.label=='字段派生器'"/>
                   <svg-icon icon-class="lcsc" dstyle="color: #13E03B;" v-if="data.label=='输出'"/>
                   <svg-icon icon-class="lcbsc" dstyle="color: #13E03B;" v-if="data.label=='表输出组件'"/>
+                  <svg-icon icon-class="lcbsc" dstyle="color: #13E03B;" v-if="data.label=='存储节点'"/>
                 <span style="margin-left: 2%;">&nbsp;{{ node.label }}</span>
               </div>
             </span>
@@ -306,6 +379,7 @@
           <Controls :showInteractive="false" :showFitView="false"/>
           <template #node-special="specialNodeProps">
             <div v-if="specialNodeProps.data.nodeType=='tool'" class="vue-flow__node-default" style="border: 0.2px solid #c8c9cc;border-radius: 6px;min-height: 6vh;min-width: 11vw">
+              <el-icon @click.stop="delNode(specialNodeProps)" style="cursor: pointer;color: #F56C6C;position: absolute;right: 5%;top: 10%;"><Delete /></el-icon>
               <div style='width:100%;font-size:15px;display:flex;align-items:center;height: 3vh;margin-top: 2%;'>
                 <div style="margin-left: 0%;font-weight: 500;">
                   <svg-icon icon-class="liuchengshuru" style="color: #eebe77;height:20px;width:20px;" v-if="specialNodeProps.data.label=='输入'"/>
@@ -318,6 +392,7 @@
                   <svg-icon icon-class="lczd" style="color: #13E03B;height:20px;width:20px;" v-if="specialNodeProps.data.label=='字段派生器'"/>
                   <svg-icon icon-class="lcsc" style="color: #13E03B;height:20px;width:20px;" v-if="specialNodeProps.data.label=='输出'"/>
                   <svg-icon icon-class="lcbsc" style="color: #13E03B;height:20px;width:20px;" v-if="specialNodeProps.data.label=='表输出组件'"/>
+                  <svg-icon icon-class="lcbsc" style="color: #13E03B;height:20px;width:20px;" v-if="specialNodeProps.data.label=='存储节点'"/>
                 </div>
                 <div style="margin-left: 10%;">
                   <el-input class="custom-no-border" @click.stop="handleInputClick" type="primary" v-model="specialNodeProps.data.label" size="mini" text 
@@ -805,21 +880,13 @@ const optionsType = ref([
     value:'array'
   },
   {
-    label:"object",
-    value:'object'
+    label:"json",
+    value:'json'
   },
   {
     label:"number",
     value:'number'
   },
-  {
-    label:"null",
-    value:'null'
-  },
-  {
-    label:"any",
-    value:'any'
-  },
   
 ])
 const dataTreeTool = ref([
@@ -842,6 +909,11 @@ const dataTreeTool = ref([
         nodeType:'tool',
         value:'csv输入组件',
       },
+      {
+        label:'存储节点',
+        nodeType:'tool',
+        value:'存储节点',
+      },
     ]
   },
   {
@@ -890,6 +962,7 @@ const serviceUrl = ref()
 const parFlowId = ref()
 const tableDataCan = ref()
 const nodeDeSer = ref(false)
+const saveDeSer = ref(false)
 const isAdd = ref(false)
 const {proxy} = getCurrentInstance();
 const modelQueryParams = ref({
@@ -950,19 +1023,32 @@ function showData(){
 function handleInputClick(){
   console.log(nodes.value)
 }
-const handleSelectChange = (selectedValue) => {
-  const lastValue = Array.isArray(selectedValue) 
-    ? selectedValue[selectedValue.length - 1] 
-    : selectedValue;
-
-  const isNewOption = !optionsCan.value.some(item => item.ref === lastValue);
+const handleSelectChange = (newValue, rowData) => {
+  if (!newValue || newValue.trim() === '') {
+    return; // 空值不处理
+  }
   
-  if (isNewOption) {
-    const newValue = `${lastValue}.input`; // 生成新值
-    // 1. 更新数据源
-    optionsCan.value.push({ name: lastValue, ref: newValue });
-    // 2. ⭐ 关键:手动更新 v-model 绑定值
-    scope.row.paramValue = newValue; // 同步更新绑定值[10](@ref)
+  // 检查新值是否已存在于预设选项中
+  const isExistingOption = optionsCan.value.some(item => 
+    item.ref === newValue || item.name === newValue
+  );
+  
+  // 如果是不存在的新值,且尚未添加过后缀,则添加.input后缀
+  if (!isExistingOption && !newValue.endsWith('.input')) {
+    rowData.paramValue = newValue + '.input';
+  }
+  
+  // 可选:将新值添加到选项列表中供后续选择
+  if (!isExistingOption) {
+    const newOption = {
+      name: newValue.endsWith('.input') ? newValue.replace('.input', '') : newValue,
+      ref: newValue.endsWith('.input') ? newValue : newValue + '.input'
+    };
+    
+    // 避免重复添加
+    if (!optionsCan.value.some(item => item.ref === newOption.ref)) {
+      optionsCan.value.push(newOption);
+    }
   }
   saveNode()
 };
@@ -1000,11 +1086,15 @@ function addStart(){
 function delCanStart(index){
   tableDataCanStart.value.splice(index,1)
 }
+function closeSaveDe(){
+  saveDeSer.value = false
+}
 function closeDe(){
   nodeDeSer.value = false
+  servieName.value = null
 }
 function saveNode(){
-  // console.log(tableDataCan.value)
+  console.log(tableDataCan.value)
   var par = {
     title:parTitle.value, 
     parameters:[]
@@ -1017,7 +1107,7 @@ function saveNode(){
           name:item.paramCode,
           value:parSplit[0],
           dataType:item.paramType,
-          refType:'input'
+          refType:'fixed'
         }
         par.parameters.push(par1)
       }
@@ -1040,14 +1130,38 @@ function saveNode(){
       }
       par.parameters.push(par1)
     }
-    
   })
+  // if(parNodeAll.value.length>0){
+  //   parNodeAll.value.forEach(item=>{
+  //     if(item.id===parNodeid.value){
+  //       parNodeAll.value.tableDataCan.forEach(item1=>{
+  //         par.parameters.forEach(item2=>{
+  //           if(item1.paramCode === item2.name){
+  //             item1.paramValue = item2.value
+  //           }
+  //         })
+  //       })
+  //     }
+  //     if(item.ptService.srvId===parNodeid.value){
+  //       parNodeAll.value.list.forEach(item1=>{
+  //         par.parameters.forEach(item2=>{
+  //           if(item1.paramCode === item2.name){
+  //             item1.paramValue = item2.value
+  //           }
+  //         })
+  //       })
+  //     }
+  //   })
+  // }
+  console.log(nodes.value,parNodeid.value)
   nodes.value.forEach(item=>{
     if(item.id===parNodeid.value){
-      // console.log(item.id)
+      console.log(item.id)
       item.data.parameters = par.parameters
       item.data.service = serInfo.value
-      item.data.service.params = parSerList.value
+      if(item.data.service){
+        item.data.service.params = parSerList.value
+      }
     }
   })
   console.log(toObject())
@@ -1117,6 +1231,93 @@ async function delNode(node){
   await nextTick()
   
 }
+function canConvertToJSONArray(str) {
+  try {
+    const parsed = JSON.parse(str);
+    return Array.isArray(parsed); // 确保解析后的是数组
+  } catch (e) {
+    return false; // 解析失败则不能转换
+  }
+}
+function canConvertToJSONObject(str) {
+  try {
+    const parsed = JSON.parse(str);
+    return typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed);
+  } catch (e) {
+    return false;
+  }
+}
+function canConvertToSpecificBoolean(str) {
+  const lowerCaseStr = str.toLowerCase().trim();
+  return lowerCaseStr === 'true' || lowerCaseStr === 'false';
+}
+function canConvertToInteger(str) {
+  const num = parseInt(str, 10);
+  // 检查不是NaN,并且转换后的整数字符串表示与原始字符串去除空格后一致(避免小数和带单位字符串)
+  return !isNaN(num) && num.toString() === str.trim();
+}
+function canConvertToNumber(str) {
+  const num = parseFloat(str);
+  return !isNaN(num); // 注意:空字符串、纯空白符也会返回false
+}
+var allValid = ref(true)
+function checkValid(row){
+  if(row.paramValue.length>0){
+    if(row.dataType==='number'){
+      if(canConvertToNumber(row.paramValue)===false){
+        row.inValid = true
+        allValid.value = false
+      }
+      else{
+        row.inValid = false
+        row.paramValue = Number(row.paramValue)
+      }
+    }
+    if(row.dataType==='int'){
+      if(canConvertToInteger(row.paramValue)===false){
+        row.inValid = true
+        allValid.value = false
+      }
+      else{
+        row.inValid = false
+        row.paramValue = parseInt(row.paramValue,10)
+      }
+    }
+    if(row.dataType==='boolean'){
+      if(canConvertToSpecificBoolean(row.paramValue)===false){
+        row.inValid = true
+        allValid.value = false
+      }
+      else{
+        row.inValid = false
+        row.paramValue = Boolean(row.paramValue)
+      }
+    }
+    if(row.dataType==='array'){
+      if(canConvertToJSONArray(row.paramValue)===false){
+        row.inValid = true
+        allValid.value = false
+      }
+      else{
+        row.inValid = false
+        row.paramValue = JSON.parse(row.paramValue)
+      }
+    }
+    if(row.dataType==='json'){
+      if(canConvertToJSONObject(row.paramValue)===false){
+        row.inValid = true
+        allValid.value = false
+      }
+      else{
+        row.inValid = false
+        row.paramValue = JSON.parse(row.paramValue)
+      }
+    }
+  }
+  else{
+    row.inValid = false
+  }
+}
 function generateTimestampId() {
   const timestamp = Date.now(); // 13位毫秒时间戳
   const randomNum = Math.floor(Math.random() * 1000); // 3位随机数
@@ -1189,10 +1390,7 @@ function deepToRaw(obj) {
   return obj;
 }
 async function startTest(){ 
-  const baseUrl = window.location.origin.toString().substring(6)
   messages.value = []
-  const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
-  const host = window.location.host;
   console.log('ws:/' + import.meta.env.VITE_APP_WEBSOCKET_PATH + '/websocket/websocket/message')
   ws.value = new WebSocket('/websocket/websocket/message')
   // ws.value = new WebSocket('wss://10.91.9.204:18082/websocket/websocket/message')
@@ -1237,14 +1435,24 @@ async function startTest(){
         }
       })
       var a = JSON.parse(JSON.stringify(toObject()))
+      console.log(a)
       a.nodes.forEach(item=>{
+        if(item.data.value==="存储节点"){
+          item.type = 'saveNode'
+          item.data.parameters.forEach(item1=>{
+            item1.dataType = 'object'
+          })
+          // item.data.parameters = item.data.tableDataCan
+          delete item.data.tableDataCan
+          delete item.data.tableDataCanOut
+        }
         if(item.id==='1'){
           item.type = 'startNode'
         }
         else if(item.id==='2'){
           item.type = 'endNode'
         }
-        else{
+        else if(item.data.value!=="存储节点"&&item.id!=='1'&&item.id!=='2'){
           item.type = 'serviceNode'
         }
       })
@@ -1256,19 +1464,33 @@ async function startTest(){
         // par.set(item.name,item.value)
         par.params[item.name] = item.paramValue
       })
-      console.log(par.params)
-      await runflow(par).then(res=>{
-        if(res.code === 200){
-          proxy.$message({
-              message: res.msg,
-              type: 'success'
-          });
-          dialogVisibleSart.value = true
-          outputData.value = beautify(res.data, null, 2, 80)
-          ws.value.close()
-          ws.value = null
+      allValid.value = true
+      tableDataCanStart.value.forEach(item=>{
+        if(item.inValid===true){
+          allValid.value = false
         }
       })
+      if(allValid.value===false){
+        proxy.$message({
+          message: '请按规则设置输入值!',
+          type: 'warning'
+        });
+      }
+      else{
+        
+        await runflow(par).then(res=>{
+          if(res.code === 200){
+            proxy.$message({
+                message: res.msg,
+                type: 'success'
+            });
+            dialogVisibleSart.value = true
+            outputData.value = beautify(res.data, null, 2, 80)
+            ws.value.close()
+            ws.value = null
+          }
+        })
+      }
     }
     else if(tableDataCanStart.value.length===0){
       proxy.$message({
@@ -1326,7 +1548,12 @@ async function saveFlow(){
       }
     })
     var a = JSON.parse(JSON.stringify(toObject()))
+    console.log(a)
     a.nodes.forEach(item=>{
+      if(item.data.label==="存储节点"){
+        const count = computed(() => store.getters.id)
+        item.data.appId = count.value
+      }
       if(item.id==='1'){
         item.type = 'startNode'
       }
@@ -1455,7 +1682,78 @@ function parseJSONWithComments(jsonString) {
         return null;
     }
 }
+const parNodeAll = ref([])
 onNodeClick(({event, node}) => {
+  saveDeSer.value = false
+  nodeEnd.value = false
+  if(node.data.value==='存储节点'){
+    parNodeid.value = node.id
+    optionsCan.value = []
+    saveDeSer .value = true
+    if(tableDataCanStart.value.length>0){
+      tableDataCanStart.value.forEach(item=>{
+        var par = {
+          ref:'1' + '.' + item.name,
+          name:item.name
+        }
+        optionsCan.value.push(par)
+      })
+    }
+    var parNode = getPredecessorsNodes(node.id)
+    var a = JSON.parse(JSON.stringify(parNode))
+    // console.log(a)
+    a.forEach((item,index) => {
+      console.log(item.data)
+      if(item.data.label!=='开始'&&item.data.service&&item.data.service.rpcontent){
+        console.log(item.data.service.rpcontent)
+        item.data.service.rpcontent = parseJSONWithComments(item.data.service.rpcontent)
+        var parShu = Object.keys((item.data.service.rpcontent))
+        parShu.forEach(item1=>{
+          var par = {
+            ref:item.id + '.' + item1,
+            name:item.data.label + ':' + item1
+          }
+          optionsCan.value.push(par)
+        })
+      }
+    })
+    var haveNode = false
+    for(var i = 0;i<parNodeAll.value.length;i++){
+      if(node.id === parNodeAll.value[i].id){
+        tableDataCan.value = parNodeAll.value[i].data.tableDataCan
+        tableDataCanOut.value = parNodeAll.value[i].data.tableDataCanOut
+        haveNode = true
+      }
+    }
+    if(haveNode === false){
+      tableDataCan.value = [
+        {
+          paramCode: 'data',
+          paramValue: ''
+        },
+        {
+          paramCode: 'timeIenth',
+          paramValue: ''
+        },
+      ]
+      tableDataCanOut.value = [
+        {
+          paramCode: 'code',
+          paramValue: ''
+        },
+        {
+          paramCode: 'msg',
+          paramValue: ''
+        },
+      ]
+      
+      node.data.tableDataCan = tableDataCan.value
+      node.data.tableDataCanOut = tableDataCanOut.value
+      parNodeAll.value.push(node)
+    }
+    console.log(parNodeAll.value)
+    return
+  }
   nodeEnd.value = false
   nodeStart.value = false
   nodeDeSer.value = false
@@ -1466,7 +1764,7 @@ onNodeClick(({event, node}) => {
   tableDataCanOut.value = []
   var parNode = getPredecessorsNodes(node.id)
   var a = JSON.parse(JSON.stringify(parNode))
-  // console.log(a)
+  console.log(a)
   a.forEach((item,index) => {
     console.log(item.data)
     if(item.data.label!=='开始'&&item.data.service&&item.data.service.rpcontent){
@@ -1481,16 +1779,25 @@ onNodeClick(({event, node}) => {
         optionsCan.value.push(par)
       })
     }
-    if(tableDataCanStart.value.length>0){
-      tableDataCanStart.value.forEach(item=>{
+    if(item.data.label==='存储节点'){
+      item.data.tableDataCanOut.forEach(item2=>{
         var par = {
-          ref:'1' + '.' + item.name,
-          name:item.name
+          ref:item.id + '.' + item2.paramCode,
+          name:item.data.label + ':' + item2.paramCode
         }
         optionsCan.value.push(par)
       })
     }
   })
+  if(tableDataCanStart.value.length>0){
+    tableDataCanStart.value.forEach(item=>{
+      var par = {
+        ref:'1' + '.' + item.name,
+        name:item.name
+      }
+      optionsCan.value.push(par)
+    })
+  }
   console.log(optionsCan.value)
   if(node.data.label==='结束'){
     nodeEnd.value = true
@@ -1500,26 +1807,57 @@ onNodeClick(({event, node}) => {
 
   }
   if(node.data.nodeType==='SERVICE'){
-    getSerDe(node.data.id).then(res=>{
-      serviceRqtype.value = res.data.ptService.rqtype
-      servieName.value = res.data.ptService.name
-      tableDataCan.value = res.data.list
-      serInfo.value = res.data.ptService
-      parSerList.value = JSON.parse(JSON.stringify(res.data.list))
-      var par1 =  parseJSONWithComments(res.data.ptService.rpcontent)
-      var parShu = Object.keys((par1))
-      console.log(parShu)
-      parShu.forEach(item1=>{
-        var par = {
-          paramCode:item1,
-          paramValue:''
+    var haveNode = true
+    if(parNodeAll.value.length===0){
+      haveNode = false
+    }
+    for(var i = 0;i<parNodeAll.value.length;i++){
+      if(parNodeAll.value[i].ptService&&parNodeAll.value[i].ptService.srvId===node.data.id){
+          serviceRqtype.value = parNodeAll.value[i].ptService.rqtype
+          servieName.value = parNodeAll.value[i].ptService.name
+          tableDataCan.value = parNodeAll.value[i].list
+          serInfo.value = parNodeAll.value[i].ptService
+          parSerList.value = JSON.parse(JSON.stringify(parNodeAll.value[i].list))
+          var par1 =  parseJSONWithComments(parNodeAll.value[i].ptService.rpcontent)
+          var parShu = Object.keys((par1))
+          parShu.forEach(item1=>{
+            var par = {
+              paramCode:item1,
+              paramValue:''
+            }
+            tableDataCanOut.value.push(par)
+          })
+          serviceUrl.value = parNodeAll.value[i].ptService.url
+          nodeDeSer.value = true
+          haveNode = true
+          break
         }
-        tableDataCanOut.value.push(par)
+        else{
+          haveNode = false
+        }
+      }
+    if(haveNode === false){
+      getSerDe(node.data.id).then(res=>{
+        parNodeAll.value.push(res.data)
+        serviceRqtype.value = res.data.ptService.rqtype
+        servieName.value = res.data.ptService.name
+        tableDataCan.value = res.data.list
+        serInfo.value = res.data.ptService
+        parSerList.value = JSON.parse(JSON.stringify(res.data.list))
+        var par1 =  parseJSONWithComments(res.data.ptService.rpcontent)
+        var parShu = Object.keys((par1))
+        console.log(parShu)
+        parShu.forEach(item1=>{
+          var par = {
+            paramCode:item1,
+            paramValue:''
+          }
+          tableDataCanOut.value.push(par)
+        })
+        serviceUrl.value = res.data.ptService.url
+        nodeDeSer.value = true
       })
-      // tableDataCanOut.value = parseJSONWithComments(res.data.ptService.rpcontent)
-      serviceUrl.value = res.data.ptService.url
-      nodeDeSer.value = true
-    })
+    }
   }
   if(node.data.nodeType==='tool'){
     console.log(node.data.value)
@@ -1591,17 +1929,19 @@ async function onDrop(event) {
   addNodes(newNode);
 
   // 2. 异步获取数据并更新
-  const res = await getSerDe(draggedData.value.id);
-  const fullData = {
-    ...res.data.ptService,
-    returnList: res.data.returnList
-  };
+  
+  // const res = await getSerDe(draggedData.value.id);
+  
+  // const fullData = {
+  //   ...res.data.ptService,
+  //   returnList: res.data.returnList
+  // };
 
   // 3. 等待节点渲染完成后再修正位置
   nextTick(() => {
-  updateNode(nodeId, { data: { ...newNode.data, ...fullData } });
-  updateNodeInternals(nodeId); // 强制更新节点布局[1](@ref)
-});
+    updateNode(nodeId, { data: { ...newNode.data, ...fullData } });
+    updateNodeInternals(nodeId); // 强制更新节点布局[1](@ref)
+  });
   // console.log(toObject())
 }