<template>
  <div>
    <!-- <el-button type="primary" @click="saveFlow">测试</el-button> -->
    <div style="display: flex;margin-left: 1%;padding-top: 0.5%;position: absolute;z-index: 1000;justify-content: space-between;width: 98%;align-items: center;"> 
      <el-icon size="large" style="cursor: pointer" @click="back"><Back /></el-icon>
      <el-button @click="delWholeFlow" style="margin-left: auto;" type="danger" size="mini">删除</el-button>
      <!-- <el-button style="margin-left: 1%;" type="info" size="mini" plain @click="toImage">导出为图片</el-button> -->
      <el-button style="margin-left: 1%;" type="primary" size="mini" @click="saveFlow">保存</el-button>
      <el-button style="margin-left: 1%;" type="primary" size="mini" @click="startTest">试运行</el-button>
    </div>
    <div v-if="nodeDeSer" 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>
        <div style="margin-left: 4%;">
          {{servieName}}
        </div> 
        <el-icon @click="closeDe" 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-input v-model="serviceUrl" style="width: 90%;" placeholder="Please input" disabled>
          <template #prepend>
            <div v-if="serviceRqtype==='GET'" style="color: #67C23A;background-color: transparent;">
              GET
            </div>
            <div v-if="serviceRqtype==='POST'" style="color: #409EFF;background-color: transparent;">
              POST
            </div>
          </template>
        </el-input>
        <svg-icon @click="testOne" icon-class="startTest" style="margin-left: auto;width: 50px;height: 25px;cursor: pointer;"/>
      </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="handleSelectChange"
                    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: 90%;margin-left: 5%;margin-top:10%;align-items: center;justify-content: space-between;">
        <el-form ref="deptRef" :model="form" label-width="80px" label-position="top">
          <el-form-item label="BODY">
            <el-radio-group v-model="form.bodyType">
              <el-radio value="none">none</el-radio>
              <el-radio value="form-data">form-data</el-radio>
              <el-radio value="x-www-form-urlencoded">x-www-form-urlencoded</el-radio>
              <el-radio value="JSON">JSON</el-radio>
              <el-radio value="raw">raw</el-radio>
            </el-radio-group>
          </el-form-item>
          <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>
        <el-icon @click="saveStartNode" style="margin-left: auto;cursor: pointer;"><Close /></el-icon>
      </div>
      <div>
        <el-button  @click="addStart" style="margin-top: 5%;margin-left: 1%;" type="success" size="mini" :disabled="isEdit" plain>新增参数</el-button>
        <div style="display: flex;width: 98%;margin-left: 1%;margin-top:2%;align-items: center;justify-content: space-between;">
        <el-table 
        style="margin-top: 1%;width: 100%;"
        :data="tableDataCanStart" 
        :cell-style="{ textAlign: 'center',padding:'2px 0' }"
        :header-cell-style="{ textAlign: 'center'}"
        :row-style="{ height: heightAll*0.01+'px',fontSize: '16px',textAlign:'center'  }"
        border >
            <el-table-column prop="itemName" label="参数名称(必填)">
                <template #default="scope">
                    <div style="width: 100%;">
                        <el-input  placeholder="请填写参数名称" type="primary" class="noBor" v-model="scope.row.name" size="mini" text style="margin-left: 0%;"></el-input>
                    </div>
                </template>
            </el-table-column>
            <el-table-column prop="itemName" label="参数类型(必填)" width="200">
                <template #default="scope">
                    <div style="width: 100%;">
                        <el-select
                        v-model="scope.row.dataType"
                        class="noBorSel"
                        
                        placeholder=""
                        style="width: 100%;margin-left: 0%;"
                        >
                            <el-option
                            v-for="item in optionsType"
                            :key="item.value"
                            :label="item.label"
                            :value="item.value"
                            />
                </el-select>
                    </div>
                </template>
            </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.description" size="mini" text style="margin-left: 0%;"></el-input>
                    </div>
                </template>
            </el-table-column>
            <el-table-column prop="itemName" label="是否必填" >
                <template #default="scope">
                    <div style="width: 100%;">
                        <el-checkbox v-model="scope.row.required" size="large" />
                    </div>
                </template>
            </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>
                </template>
            </el-table-column>
            <el-table-column prop="address" label="操作" width="100">
                <template #default="scope">
                    <div style="width: 100%;">
                        <el-button type="danger" @click="delCanStart(scope.$index)" size="mini" text style="margin-left: 0%;">删除</el-button>
                    </div>
                </template>
            </el-table-column>
        </el-table>
      </div>
      </div>
    </div>
    <div v-show="nodeEnd" style="height: 82vh;overflow-y: auto;width: 25vw;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="saveEndNode" style="margin-left: auto;cursor: pointer;"><Close /></el-icon>
      </div>
      <div>
        <el-button  @click="addEnd" style="margin-top: 5%;margin-left: 1%;" type="success" size="mini" :disabled="isEdit" plain>新增参数</el-button>
        <div style="display: flex;width: 98%;margin-left: 1%;margin-top:2%;align-items: center;justify-content: space-between;">
        <el-table :data="tableDataCanEnd" border style="width: 100%">
          <el-table-column prop="paramCode" label="参数名(必填)" width="">
           <template #default="scope">
                <div style="width: 100%;">
                    <el-input  placeholder="" type="primary" class="noBor" v-model="scope.row.name" size="mini" text style="margin-left: 0%;"></el-input>
                </div>
            </template>
          </el-table-column>
          <el-table-column prop="itemName" label="参数类型(必填)">
              <template #default="scope">
                  <div style="width: 100%;">
                      <el-select
                      v-model="scope.row.dataType"
                      class="noBorSel"
                      placeholder=""
                      style="width: 100%;margin-left: 0%;"
                      >
                          <el-option
                          v-for="item in optionsType"
                          :key="item.value"
                          :label="item.label"
                          :value="item.value"
                          />
              </el-select>
                  </div>
              </template>
          </el-table-column>
          <el-table-column prop="paramValue" label="参数值" width="">
            <template #default="scope">
              <div style="width:100%;">
                  <el-select
                    v-model="scope.row.paramValue"
                    filterable
                    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-column prop="address" label="操作" width="100">
                <template #default="scope">
                    <div style="width: 100%;">
                        <el-button type="danger" @click="delEnd(scope.$index)" size="mini" text style="margin-left: 0%;">删除</el-button>
                    </div>
                </template>
            </el-table-column>
        </el-table>
      </div>
      </div>
    </div>
    <div style="display: flex;height: 87vh;width: 100%;padding-top:2%;justify-items: center;">
      <div style="width: 20%;margin-left: 1%;overflow-y: auto;margin-top: 0.5%;">
        <el-checkbox-group v-model="checkboxGroup1" size="" style="margin-left: 5%;" @change="oneSel">
          <el-checkbox-button key="service" label="service">
            服务
          </el-checkbox-button>
          <el-checkbox-button key="tool" label="tool">
            工具
          </el-checkbox-button>
      </el-checkbox-group>
        <el-input
          v-if="checkboxGroup1.includes('service')"
          v-model="inputNode"
          style="width:90%;margin-left: 5%;background-color: #ebeef5;margin-top: 1%;"
          class="w-50 m-2"
          :prefix-icon="Search" 
        />
        <el-tree v-if="checkboxGroup1.includes('service')" :expand-on-click-node="false" ref="treeRef" :filter-node-method="filterNode" :current-node-key="currentNodeKey" class="treeLeft" :data="dataTree" 
        @node-click="handleNodeClick" node-key="id" style="margin-left: 5%;margin-top: 3%;width: 90%;background-color: transparent;" default-expand-all :key="valueKet">
          <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>
              </div>
            </span>
          </template>
        </el-tree>
        <el-tree v-if="!checkboxGroup1.includes('service')" :expand-on-click-node="false" ref="treeRef" :current-node-key="currentNodeKey" class="treeLeft" :data="dataTreeTool" 
        @node-click="handleNodeClick" node-key="id" style="margin-left: 5%;margin-top: 3%;width: 90%;background-color: transparent;" default-expand-all :key="valueKet">
          <template #default="{ node, data }">
            <span  style="justify-content: space-between;display: flex;width: 120%;align-items: center;" :draggable="true" @dragstart="onDragStart($event,data)">
              <div class="custom-tree-node">
                  <svg-icon icon-class="liuchengshuru" style="color: #eebe77;" v-if="data.label=='输入'"/>
                  <svg-icon icon-class="liuchengEx" dstyle="color: #13E03B;" v-if="data.label=='Excel文件输入组件'"/>
                  <svg-icon icon-class="liuchengbiao" dstyle="color: #13E03B;" v-if="data.label=='表输入组件'"/>
                  <svg-icon icon-class="liuchengcsv" dstyle="color: #13E03B;" v-if="data.label=='csv输入组件'"/>
                  <svg-icon icon-class="lczh" dstyle="color: #13E03B;" v-if="data.label=='转换'"/>
                  <svg-icon icon-class="lczhzj" dstyle="color: #13E03B;" v-if="data.label=='转换组件'"/>
                  <svg-icon icon-class="lcpx" dstyle="color: #13E03B;" v-if="data.label=='排序记录'"/>
                  <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=='表输出组件'"/>
                <span style="margin-left: 2%;">&nbsp;{{ node.label }}</span>
              </div>
            </span>
          </template>
        </el-tree>
      </div>
      <div ref="flowContainer" style="width: 80%;">
        <VueFlow  ref="vueFlowRef" style="background-color: #EFEFF4;margin-top: 0.5%;" :nodes="nodes" :viewport="zoom" :edges="edges" @drop="onDrop" @dragover="onDragOver" @dragleave="onDragLeave"
          @node-click="onNodeClick"   @connect="onConnect" fit-view-on-init>
          <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">
              <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=='输入'"/>
                  <svg-icon icon-class="liuchengEx" style="color: #13E03B;height:20px;width:20px;" v-if="specialNodeProps.data.label=='Excel文件输入组件'"/>
                  <svg-icon icon-class="liuchengbiao" style="color: #13E03B;height:20px;width:20px;" v-if="specialNodeProps.data.label=='表输入组件'"/>
                  <svg-icon icon-class="liuchengcsv" style="color: #13E03B;height:20px;width:20px;" v-if="specialNodeProps.data.label=='csv输入组件'"/>
                  <svg-icon icon-class="lczh" style="color: #13E03B;height:20px;width:20px;" v-if="specialNodeProps.data.label=='转换'"/>
                  <svg-icon icon-class="lczhzj" style="color: #13E03B;height:20px;width:20px;" v-if="specialNodeProps.data.label=='转换组件'"/>
                  <svg-icon icon-class="lcpx" style="color: #13E03B;height:20px;width:20px;" v-if="specialNodeProps.data.label=='排序记录'"/>
                  <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=='表输出组件'"/>
                </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 
                  style="margin-left: -20%;font-size: 15px;height: 15px;width: 100%;" ></el-input>
                </div>
              </div>
                <Handle type="source" :position="Position.Right"/>
                <Handle type="target" :position="Position.Left"/>
            </div>
            <div v-if="specialNodeProps.data.label=='开始'" class="vue-flow__node-default" style="border: 0.2px solid #c8c9cc;border-radius: 6px;min-height: 6vh;min-width: 11vw">
              <div style='width:100%;font-size:10px;display:flex;align-items:flex-end;height: 10px;margin-top: 2%;'>
                <img style="width: 15px;height:15px;border-radius: 12px;" src="@/assets/images/icon-Start-v2.jpg" alt="">
                <div style="margin-left: 3%;font-weight: 500;">
                  开始
                </div>
                <el-tag class="ml-2" style="width: 30px;height: 15px;font-size: 7px;margin-left: 6%;" type="info">触发器</el-tag>
              </div>
                <Handle type="source" :position="Position.Right"/>
            </div>
            <div v-if="specialNodeProps.data.label=='结束'" class="vue-flow__node-default" style="border: 0.2px solid #c8c9cc;border-radius: 6px;min-height: 6vh;min-width: 11vw">
              <div style='width:100%;font-size:10px;display:flex;align-items:flex-end;height: 10px;margin-top: 2%;'>
                <img style="width: 15px;height:15px;border-radius: 12px;" src="@/assets/images/icon-Start-v2.jpg" alt="">
                <div style="margin-left: 3%;font-weight: 500;">
                  结束
                </div>
                <div>

                </div>
              </div>
                <Handle type="target" :position="Position.Left"/>
            </div>
            <div v-if="specialNodeProps.data.nodeType=='SERVICE'" 
            class="vue-flow__node-default" 
            v-loading="specialNodeProps.data.loading"
            style="border: 0.5px solid #c8c9cc;border-radius: 6px;border-radius: 6px;min-height: 8vh;min-width: 13vw">
              <div style='width:100%;font-size:10px;display:flex;align-items:flex-end;height: 10px;margin-top: 2%;justify-content: space-between;'>
                <img style="width: 15px;height:15px;border-radius: 12px;" src="@/assets/images/icon-HTTP.png" alt="">
                <div style="margin-left:3%;font-weight: 500;"> 
                  <el-input class="custom-no-border" placeholder="" type="primary" v-model="specialNodeProps.data.label" size="mini" text 
                  style="margin-left: 0%;font-size: 10px;height: 15px;width: 100%;" ></el-input>
                  <!-- {{ specialNodeProps.data.label}} -->
                </div>
                <el-icon v-if="specialNodeProps.data.isSuccess"  style="cursor: pointer;margin-left: auto;color: #67C23A;"><SuccessFilled /></el-icon>
                <el-tooltip :content="specialNodeProps.data.erMsg" placement="top" effect="light">
                  <el-icon v-if="specialNodeProps.data.isFail"  style="cursor: pointer;margin-left: auto;color: #F56C6C;"><CircleCloseFilled /></el-icon>
                </el-tooltip>
                <!-- <el-icon @click.stop="testNode(specialNodeProps)" style="cursor: pointer;margin-left: 2%;"><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%;">
                <el-tag class="ml-2" style="width: 35px;height: 20px;font-size: 10px;" type="warning">服务</el-tag>
              </div>
              <div style="display: flex;margin-top: 3%;font-size: 9px;color: #b1b3b8;flex-wrap: wrap;align-items: flex-start;">
                <div style="word-break: break-all;min-width: 0;width: 100%;text-align: left;">
                  {{ specialNodeProps.data.service.rqtype+ ':' }}{{ specialNodeProps.data.service.url }}
                </div>
              </div>
              <div style="display: flex;margin-top: 3%;font-size: 9px;color: #b1b3b8;align-items: center;">
                <div>
                  说明:
                </div>
                <div>
                  {{ specialNodeProps.data.service.intro }}
                </div>
              </div>
                <Handle type="source" :position="Position.Right"/>
                <Handle type="target" :position="Position.Left"/>
            </div>
          </template>
          <template #edge-custom="specialEdgeProps">
            <div style="height: 1px;color: red;">

            </div>
          </template> 
        </VueFlow>
      </div>
      <el-dialog @close="clearFromLev" title="" v-model="dialogVisibleBiao" width="50%" destroy-on-close :key="tableKey">
        <el-form size="mini" :key="tableKey" style="margin-top: 1%;width: 98%;"  :model="formJi" label-position="right" ref="formRefJi" label-width="120px" :rules="rulesJi">
          <el-form-item label="连接方式:" prop="" style="display: flex; align-items: center;">
            <el-radio-group  v-model="formJi.rptype" class="ml-4" style="display: inline-flex; align-items: center;">
              <el-radio label="1" size="large" style="display: inline-flex; align-items: center;">
                <span style="position: relative; top: -1px">资产表</span>
              </el-radio>
              <el-radio label="2" size="large" style="display: inline-flex; align-items: center;">
                <span style="position: relative; top: -1px">sql</span>
              </el-radio>
              <el-radio label="3" size="large" style="display: inline-flex; align-items: center;">
                <span style="position: relative; top: -1px">数据连接</span>
              </el-radio>
            </el-radio-group>
          </el-form-item>
          <el-form-item label="数据源:" prop="" style="">
            <div style="display: flex;width: 30%;justify-content: space-between;">
              <el-select
                v-model="formJi.type"
                
                    style="width: 100%;margin-left: 0%;"
                >
                    <el-option
                    v-for="item in optionsType"
                    :key="item.value"
                    :label="item.label"
                    :value="item.value"
                    />
                </el-select>
            </div>
            </el-form-item>
            <el-form-item label="读取模式:" prop="" style="display: flex; align-items: center;">
            <el-radio-group  v-model="formJi.rptype" class="ml-4" style="display: inline-flex; align-items: center;">
              <el-radio label="1" size="large" style="display: inline-flex; align-items: center;">
                <span style="position: relative; top: -1px">全量</span>
              </el-radio>
              <el-radio label="2" size="large" style="display: inline-flex; align-items: center;">
                <span style="position: relative; top: -1px">id增量</span>
              </el-radio>
              <el-radio label="3" size="large" style="display: inline-flex; align-items: center;">
                <span style="position: relative; top: -1px">时间范围增量</span>
              </el-radio>
            </el-radio-group>
            </el-form-item>  
            <el-form-item label="where条件:">
                <el-input v-model="formJi.intro" style="width: 100%;" :rows="3" resize="none" type="textarea"/>
            </el-form-item>
          </el-form>
          <div style="font-size: 16px;margin-left: 1%">
            属性字段
          </div>
          <el-table 
          style="margin-top: 2%;width: 100%;margin-left: 1%;overflow: auto;"
          :data="tableDataCan" 
          :cell-style="{ textAlign: 'center',padding:'3px 0px' }"
          :header-cell-style="{ textAlign: 'center', }"
          max-height="45vh"
          :row-style="{ height: heightAll*0.01+'px',fontSize: '16px',textAlign:'center'  }"
          border>
              <el-table-column prop="parName" label="参数英文名">
                <template #default="scope" style="width: 120%;">
                    <el-input  v-model="scope.row.parEnname" style="width: 120%;margin-left: -10%;"/>
                </template>
              </el-table-column>
              <el-table-column prop="parName" label="参数名称">
                <template #default="scope">
                    <el-input  v-model="scope.row.parName" style="width: 120%;margin-left: -10%;"/>
                </template>
              </el-table-column>
              <el-table-column prop="parType" label="参数类型" >
                <template #default="scope">
                    <el-input  v-model="scope.row.parType" style="width: 120%;margin-left: -10%;"/>
                </template>
              </el-table-column>
              <el-table-column prop="parNote" label="操作" width="85">
                <template #default="scope">
                    <el-button type="danger" @click="delCan(scope.$index, scope.row)" text size="mini" style="margin-left: 0%;">删除</el-button>
                </template> 
              </el-table-column>
          </el-table>
        <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>
      <el-dialog
        :title="title"
        v-model="dialogVisibleExcel"
        width="50%">
        <div>
            <el-form ref="formAddref" :model="formAdd" label-width="100px" class="coz-mg-card" :rules="rulesAdd">
              <el-row :gutter="24">
            <el-col :span="8">
              <el-form-item label="选择附件:">
                  <el-upload
                    ref="uploadRef"
                    style="margin-top: 0%;"
                    :limit="1"
                    :show-file-list="false"
                    :file-list="fileList"
                    :headers="upload.headers"
                    :on-progress="handlepro"
                    :on-success="handleFileSuccess"
                    :on-change="handleChange"
                    :action="upload.url + '?file=' + upload.updateSupport"
                    :auto-upload="false">
                      <el-button @click="clearDefault" plain type="primary" size="mini" style="margin-left:auto;width: 80px;" :icon="Upload">上传文件</el-button>
                  </el-upload>
              </el-form-item>
            </el-col>
            <el-col :span="8">
              <el-form-item label="起始行:" prop="appTitle">
                <el-input-number
                    v-model="num"
                    class="mx-4"
                    :min="1"
                    controls-position="right"
                    @change="handleChange"
                  />
                </el-form-item>
            </el-col>
            <el-col :span="8">
              <el-form-item label="起始列:" prop="appNote">
                <el-input-number
                    v-model="num"
                    class="mx-4"
                    :min="1"
                    controls-position="right"
                    @change="handleChange"
                  />
                </el-form-item>
            </el-col>
            </el-row>
            </el-form>
        </div>
        <div style="font-size: 16px;margin-left: 1%">
            属性字段
          </div>
          <el-table 
          style="margin-top: 2%;width: 100%;margin-left: 1%;overflow: auto;"
          :data="tableDataCan" 
          :cell-style="{ textAlign: 'center',padding:'3px 0px' }"
          :header-cell-style="{ textAlign: 'center', }"
          max-height="45vh"
          :row-style="{ height: heightAll*0.01+'px',fontSize: '16px',textAlign:'center'  }"
          border>
              <el-table-column prop="parName" label="参数英文名">
                <template #default="scope" style="width: 120%;">
                    <el-input  v-model="scope.row.parEnname" style="width: 120%;margin-left: -10%;"/>
                </template>
              </el-table-column>
              <el-table-column prop="parName" label="参数名称">
                <template #default="scope">
                    <el-input  v-model="scope.row.parName" style="width: 120%;margin-left: -10%;"/>
                </template>
              </el-table-column>
              <el-table-column prop="parType" label="参数类型" >
                <template #default="scope">
                    <el-input  v-model="scope.row.parType" style="width: 120%;margin-left: -10%;"/>
                </template>
              </el-table-column>
              <el-table-column prop="parNote" label="操作" width="85">
                <template #default="scope">
                    <el-button type="danger" @click="delCan(scope.$index, scope.row)" text size="mini" style="margin-left: 0%;">删除</el-button>
                </template> 
              </el-table-column>
          </el-table>
        <template #footer>
            <el-button @click="dialogVisibleExcel = false">取消</el-button>
            <el-button v-if="isAdd" type="primary" @click="submitAdd">确定</el-button>
            <el-button v-if="!isAdd" type="primary" @click="subEdit">确定</el-button>
        </template>
    </el-dialog>
    <el-dialog @close="clearFromLev" title="" v-model="dialogVisibleCsv" width="50%" destroy-on-close :key="tableKey">
        <el-form ref="formAddref" :model="formAdd" label-width="100px" class="coz-mg-card" :rules="rulesAdd">
              <el-row :gutter="24">
            <el-col :span="8">
              <el-form-item label="上传附件：">
                  <el-upload
                    ref="uploadRef"
                    style="margin-top: 0%;"
                    :limit="1"
                    :show-file-list="false"
                    :file-list="fileList"
                    :headers="upload.headers"
                    :on-progress="handlepro"
                    :on-success="handleFileSuccess"
                    :on-change="handleChange"
                    :action="upload.url + '?file=' + upload.updateSupport"
                    :auto-upload="false">
                      <el-button @click="clearDefault" plain type="primary" size="mini" style="margin-left:auto;width: 80px;" :icon="Upload">选择文件</el-button>
                  </el-upload>
                  <el-button @click="clearDefault" plain type="primary" size="mini" style="margin-left:auto;width: 80px;" :icon="Upload">解析文件</el-button>
              </el-form-item>
            </el-col>
            <el-col :span="8">
              <el-form-item label="" prop="">
                
                </el-form-item>
            </el-col>
            <el-col :span="8">
            </el-col>
            </el-row>
            </el-form>
          <div style="font-size: 16px;margin-left: 1%">
            属性字段
          </div>
          <el-table 
          style="margin-top: 2%;width: 100%;margin-left: 1%;overflow: auto;"
          :data="tableDataCan" 
          :cell-style="{ textAlign: 'center',padding:'3px 0px' }"
          :header-cell-style="{ textAlign: 'center', }"
          max-height="45vh"
          :row-style="{ height: heightAll*0.01+'px',fontSize: '16px',textAlign:'center'  }"
          border>
              <el-table-column prop="parName" label="参数英文名">
                <template #default="scope" style="width: 120%;">
                    <el-input  v-model="scope.row.parEnname" style="width: 120%;margin-left: -10%;"/>
                </template>
              </el-table-column>
              <el-table-column prop="parName" label="参数名称">
                <template #default="scope">
                    <el-input  v-model="scope.row.parName" style="width: 120%;margin-left: -10%;"/>
                </template>
              </el-table-column>
              <el-table-column prop="parType" label="参数类型" >
                <template #default="scope">
                    <el-input  v-model="scope.row.parType" style="width: 120%;margin-left: -10%;"/>
                </template>
              </el-table-column>
              <el-table-column prop="parNote" label="操作" width="85">
                <template #default="scope">
                    <el-button type="danger" @click="delCan(scope.$index, scope.row)" text size="mini" style="margin-left: 0%;">删除</el-button>
                </template> 
              </el-table-column>
          </el-table>
        <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>
      <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>
      <el-dialog @close="" title="试运行结果" v-model="dialogVisibleSart" width="50%" destroy-on-close :key="tableKey">
         <el-input
          v-model="outputData"
          :autosize="{ minRows: 10, maxRows: 15 }"
          type="textarea"
          placeholder="Please input"
        />
        <template #footer>
            <span class="dialog-footer">
              <el-button type="primary" @click="dialogVisibleSart = false" size="mini">
                确定
              </el-button>
          </span>
        </template>
      </el-dialog>
    </div>

  </div>
</template>
<script setup>
import html2canvas from 'html2canvas';
import { Controls } from '@vue-flow/controls'
import '@vue-flow/controls/dist/style.css'
import '@vue-flow/core/dist/theme-default.css';
import { Plus,Search } from '@element-plus/icons-vue'
import { toRaw, isReactive, isProxy,onUnmounted  } from 'vue';
import beautify from 'json-beautify'; 
import DynamicMap from '@/components/DynamicMap/index.vue'
import {Promotion} from '@element-plus/icons-vue'
import { onMounted, ref,onBeforeUnmount } from 'vue'
import {useVueFlow, VueFlow ,MarkerType } from '@vue-flow/core'
import SpecialNode from './components/SpecialNode.vue'
import SpecialEdge from './components/SpecialEdge.vue'
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,runflow} from "@/api/standardization/modeling.js";
import { useStore } from 'vuex';
import {Handle, Position} from '@vue-flow/core'
import { computed } from 'vue';
import { modelTreeSelect,testService } from "@/api/service/info";
// import { toRaw, isReactive, isProxy } from 'vue';
const {
  snapToGrid,
  addEdges,
  onEdgeClick,
  addNodes,
  removeNodes,
  updateNodeInternals,
  screenToFlowCoordinate,
  onNodesInitialized,
  updateNode,
  onNodeClick,
  getNodes,
  zoomTo,
  toObject,
  getEdges,
  findNode
} = useVueFlow()
snapToGrid.value = true
const parNodeid = ref('')
const formAdd = ref({
    appTitle: '',
    appNote: '',
});
const parSerList = ref([])
const tableDataCanStart = ref([])
const dialogVisibleSart = ref(false)
const testAttention = ref()
const tableDataCanEnd = ref([])
const outputData = ref()
const dialogVisibleTest = ref(false)
const dialogVisibleCsv = ref(false)
const formAddref = ref()
const dialogVisibleExcel = ref(false)
const rulesAdd = reactive({
  appTitle: [{ required: true, message: '必填', trigger: 'blur' }], 
  appNote: [{ required: true, message: '必填', trigger: 'blur' }], 
});
const titleTest = ref('')
const upload = reactive({
  // 是否显示弹出层（用户导入）
  open: false,
  // 弹出层标题（用户导入）
  title: "",
  // 是否禁用上传
  isUploading: false,
  // 是否更新已经存在的用户数据
  updateSupport: '',
  // 设置上传的请求头部
  headers: { Authorization: "Bearer " + getToken() },
  // 上传的地址
  url: import.meta.env.VITE_APP_BASE_API + "/common/upload"
});
const dialogVisibleBiao = ref(false)
const vueFlowModel = ref();
const formJi = ref({
  name:'',
  cateCode:'',
  type:'',
  url:'',
  rqtype:'',
  rptype:'',
  intro:'',
});
const nodeEnd = ref(false)
const nodeStart = ref(false)
const optionsCan = ref()
const parTitle = ref()
const rulesJi = reactive({
  name: [{ required: true, message: '必填', trigger: 'blur' }],
  url: [{ required: true, message: '必填', trigger: 'blur' }],
  cateCode: [{ required: true, message: '必填', trigger: 'blur' }],
});
const optionsType = ref([
  {
    label:"string",
    value:'string'
  },
  {
    label:"int",
    value:'int'
  },
  {
    label:"boolean",
    value:'boolean'
  },
  {
    label:"array",
    value:'array'
  },
  {
    label:"object",
    value:'object'
  },
  {
    label:"number",
    value:'number'
  },
  {
    label:"null",
    value:'null'
  },
  {
    label:"any",
    value:'any'
  },
  
])
const dataTreeTool = ref([
  {
    label:'输入',
    value:'输入',
    children:[
      {
        label:'表输入组件',
        nodeType:'tool',
        value:'表输入组件',
      },
      {
        label:'Excel文件输入组件',
        value:'Excel文件输入组件',
        nodeType:'tool',
      },
      {
        label:'csv输入组件',
        nodeType:'tool',
        value:'csv输入组件',
      },
    ]
  },
  {
    label:'转换',
    value:'转换',
    children:[
      {
        label:'转换组件',
        nodeType:'tool',
        value:'转换组件',
      },
      {
        label:'排序记录',
        nodeType:'tool',
        value:'排序记录',
      },
      {
        label:'字段派生器',
        nodeType:'tool',
        value:'字段派生器',
      },
    ]
  },
  {
    label:'输出',
    value:'输出',
    children:[
      {
        label:'表输出组件',
        nodeType:'tool',
        value:'表输出组件',
      },
    ]
  },
])
const tableDataCanOut = ref([]);
const flowContainer = ref(null);
const status = ref('就绪');
const zoom = ref();
const inputNode = ref('');
const vueFlowRef = ref(null);
const treeRef = ref(null);
const servieName = ref()
const serviceRqtype = ref()
const serviceUrl = ref()
const parFlowId = ref()
const tableDataCan = ref()
const nodeDeSer = ref(false)
const isAdd = ref(false)
const {proxy} = getCurrentInstance();
const modelQueryParams = ref({
  name: undefined,
  isPublic: '0',
});
const toolQueryParams = ref({
  name: undefined,
});
const dataTree = ref([]);
const modelOptions = ref(undefined);
const modelId = ref(undefined);
const loading = ref(true);
const checkboxGroup1 = ref(['service'])
const toolType = ref('0');
const serviceList = ref([]);
const serInfo = ref()
const defaultEdgeStyle = {
  style: { 
    stroke: '#79bbff', 
    strokeWidth: 2,
    type: 'bezier', 
    fill: 'none' // 避免截图时出现黑色背景 [4](@ref)
  },
  markerEnd: {
    type: MarkerType.Arrow,
    color: '#79bbff', // 箭头颜色
    width: 15,        // 箭头宽度
    height: 15        // 箭头高度
  }
};
const draggedData = ref(undefined);
const isDragging = ref(false);
const isDragOver = ref(false);
const nodes = ref([
  { id: '1', position: { x: -600, y: -300 }, data: { label: '开始' }, type: 'special' },
  { id: '2', position: { x: 150, y: 100 }, data: { label: '结束' }, type: 'special' },
]);
const edges =  ref([]);
const form = ref({
  bodyType: 'none',
  errorPolicy: 'ABORT',
  retryCount: 0,
});
const title = ref('')
const open = ref(false)
const store = useStore();

watch(inputNode, (val) => {
  treeRef.value?.filter(val); // 调用树的过滤方法
});
function clearSt(){
  tableDataCanStart.value = []
}
function showData(){
  dialogVisibleSart.value = true
}
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);
  
  if (isNewOption) {
    const newValue = `${lastValue}:fixed`; // 生成新值
    // 1. 更新数据源
    optionsCan.value.push({ name: lastValue, ref: newValue });
    // 2. ⭐ 关键：手动更新 v-model 绑定值
    scope.row.paramValue = newValue; // 同步更新绑定值[10](@ref)
  }
  saveNode()
};
function addEnd(){
  console.log(tableDataCanEnd.value)
  tableDataCanEnd.value.push({})
}
function delEnd(index){
  tableDataCanEnd.value.splice(index,1)
}
function testOne(){
  var par = serInfo.value
  par.params = tableDataCan.value
  testService(par).then(res=>{
    dialogVisibleSart.value = true
    outputData.value = res.msg
  })
}
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));

function saveStartNode(){
  nodeStart.value = false
  
}
function saveEndNode(){
  nodeEnd.value = false
  var par = tableDataCanEnd.value
  const node = findNode('2')
  node.data.data = par
  console.log(nodes)
}
function addStart(){
  tableDataCanStart.value.push({})
}
function delCanStart(index){
  tableDataCanStart.value.splice(index,1)
}
function closeDe(){
  nodeDeSer.value = false
}
function saveNode(){
  // console.log(tableDataCan.value)
  var par = {
    title:parTitle.value, 
    parameters:[]
  }
  tableDataCan.value.forEach(item=>{
    if(item.paramValue!==null){
      var parSplit = item.paramValue.split('.')
      if(parSplit[1]==='fixed'){
        var par1 = {
          name:item.paramCode,
          value:parSplit[0],
          dataType:item.paramType,
          refType:'fixed'
        }
        par.parameters.push(par1)
      }
      else{
        var par1 = {
          name:item.paramCode,
          ref:item.paramValue,
          dataType:item.paramType,
          refType:'ref'
        }
        par.parameters.push(par1)
      }
    }
    else{
      var par1 = {
        name:item.paramCode,
        value:null,
        dataType:item.paramType,
        refType:'fixed'
      }
      par.parameters.push(par1)
    }
    
  })
  nodes.value.forEach(item=>{
    if(item.id===parNodeid.value){
      // console.log(item.id)
      item.data.parameters = par.parameters
      item.data.service = serInfo.value
      item.data.service.params = parSerList.value
    }
  })
  console.log(toObject())
  // nodeDeSer.value = false
  // const node = findNode(parNodeid.value)
  // node.data.data = par
  // updateNode(node.id, { data: { ...node.data, ...par } });
  // updateNodeInternals(node.id);
  // updateNode(parNodeid.value, {
  //   data: par
  // });
}
function delWholeFlow(){
  proxy.$confirm('是否删除该模型流程？', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        delFlow(parFlowId.value).then(res => {
            if(res.code === 200){
                proxy.$message({
                    message: '删除成功',
                    type: 'success'
                });
                getList();
            } else {
                proxy.$message.error('删除失败');
            }
        })
      })
}
const toImage = async () => {
  console.log(flowContainer.value)
  await nextTick(); 
  status.value = '生成图片中...';
  try {
    const canvas = await html2canvas(flowContainer.value, {
      backgroundColor: '#fff',
      scale: 2,
      useCORS: true,
    });
    
    // 生成下载链接
    const dataUrl = canvas.toDataURL('image/png');
    const link = document.createElement('a');
    link.href = dataUrl;
    link.download = 'vueflow-diagram.png'; // 文件名
    link.click();
    
    status.value = '导出成功！';
    setTimeout(() => status.value = '就绪', 3000); // 重置状态
  } catch (error) {
    status.value = `导出失败: ${error.message}`;
    console.error('导出错误:', error);
  }
};
function testNode(node){
  dialogVisibleTest.value = true
}
function oneSel(){
  if(checkboxGroup1.value.length>1){
    checkboxGroup1.value.splice(0,1)
  }
}
async function delNode(node){
  removeNodes([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)
});
async function getTreeLeft(){
  var par = {
    params:{
      serviceState:'1'
    }
  }
  await modelTreeSelect(par).then(res=>{
    dataTree.value = (res.data)
  })
}
function flatArrayToTree(flatArray, rootPid = '1') {
  if (!Array.isArray(flatArray) || flatArray.length === 0) {
    return [];
  }

  const nodeMap = new Map();
  const tree = [];

  // 第一遍循环：建立id到节点的映射，并添加children属性
  flatArray.forEach(item => {
    nodeMap.set(item.id, {
      ...item,
      children: []
    });
  });

  // 第二遍循环：建立父子关系
  flatArray.forEach(item => {
    const currentNode = nodeMap.get(item.id);
    
    if (item.pid === rootPid) {
      // 根节点直接加入结果数组
      tree.push(currentNode);
    } else {
      // 非根节点：找到父节点并加入其children数组
      const parentNode = nodeMap.get(item.pid);
      if (parentNode) {
        parentNode.children.push(currentNode);
      } else {
        // 如果找不到父节点，作为孤儿节点直接放在根级
        tree.push(currentNode);
      }
    }
  });

  return tree;
}
function deepToRaw(obj) {
  // 如果是数组，遍历每个元素并递归处理
  if (Array.isArray(obj)) {
    return obj.map(item => deepToRaw(item));
  }
  // 如果是对象且可能是响应式代理，获取其原始对象并递归处理其属性
  else if (obj !== null && typeof obj === 'object' && (isProxy(obj) || isReactive(obj))) {
    const rawObj = toRaw(obj);
    return Object.fromEntries(
      Object.entries(rawObj).map(([key, value]) => [key, deepToRaw(value)])
    );
  }
  // 如果是普通对象，直接返回
  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;
  ws.value = new WebSocket('ws://' + '192.168.2.119:8082/websocket/message'); 
  ws.value.onopen = () => {
    connected.value = true;
  };
  
  ws.value.onmessage = (event) => {
    messages.value.push(event.data); // 存储接收到的消息
  };
  await delay(1000)
  if(messages.value.length>0){
    var param = []
    var paramEnd = []
    if(tableDataCanStart.value.length>0&&tableDataCanEnd.value.length>0){
      tableDataCanStart.value.forEach(item=>{
        var par = {
          name:item.name,
          dataType:item.dataType,
          refType:'input',
          description:item.description,
          required:item.required
        }
        param.push(par)
      })
      tableDataCanEnd.value.forEach(item=>{
        var par = {
          name:item.name,
          dataType:item.dataType,
          refType:'ref',
          ref:item.paramValue
        }
        paramEnd.push(par)
      })
      nodes.value.forEach(item=>{
        if(item.id==='1'){
          item.data.parameters = param 
        }
        if(item.id==='2'){
          item.data.outputDefs = paramEnd 
        }
      })
      var a = JSON.parse(JSON.stringify(toObject()))
      a.nodes.forEach(item=>{
        if(item.id==='1'){
          item.type = 'startNode'
        }
        else if(item.id==='2'){
          item.type = 'endNode'
        }
        else{
          item.type = 'serviceNode'
        }
      })
      var par = {}
      par.flowGraph = JSON.stringify(a)
      par.params = {}
      par.webSocketId = messages.value[0]
      tableDataCanStart.value.forEach(item=>{
        // 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
        }
      })
    }
    else if(tableDataCanStart.value.length===0){
      proxy.$message({
          message: '请设置输入值！',
          type: 'warning'
      });
    }
    else if(tableDataCanEnd.value.length===0){
      proxy.$message({
          message: '请设置输出值！',
          type: 'warning'
      });
    }
  }
  
  
}
async function saveFlow(){
  if(tableDataCanStart.value.length>0&&tableDataCanEnd.value.length>0){
    var param = []
    var paramEnd = []
    tableDataCanStart.value.forEach(item=>{
      var par = {
        name:item.name,
        dataType:item.dataType,
        refType:'input',
        description:item.description,
        required:item.required,
        // paramValue:item.paramValue
      }
      param.push(par)
    })
    tableDataCanEnd.value.forEach(item=>{
      var par = {
        name:item.name,
        dataType:item.dataType,
        refType:'ref',
        ref:item.paramValue,
        paramValue:item.paramValue
      }
      paramEnd.push(par)
    })
    nodes.value.forEach(item=>{
      if(item.id==='1'){
        item.data.parameters = param
        if(item.erMsg){
          delete item.erMsg
        }
      }
      if(item.id==='2'){
        item.data.outputDefs = paramEnd 
        if(item.erMsg){
          delete item.erMsg
        }
      }
    })
    var a = JSON.parse(JSON.stringify(toObject()))
    a.nodes.forEach(item=>{
      if(item.id==='1'){
        item.type = 'startNode'
      }
      else if(item.id==='2'){
        item.type = 'endNode'
      }
      else{
        item.type = 'serviceNode'
      }
    })
    if(isAdd.value){
      const count = computed(() => store.getters.id)
      var par = {
        appId: count.value,
        flowName:'default',
        flowGraph: JSON.stringify(a)
      }
      addModelingFlow(par).then(res=>{
        if(res.code===200){
          proxy.$message({
            message: '保存成功',
            type: 'success'
          });
        }
        getList()
      })
    }
    else{
      const count = computed(() => store.getters.id)
      var par = {
        flowId: parFlowId.value,
        appId: count.value,
        flowName:'default',
        flowGraph: JSON.stringify(a)
      }
      console.log(par)
      editModelingFlow(par).then(res=>{
        if(res.code===200){
          proxy.$message({
            message: '保存成功',
            type: 'success'
          });
          getList()
        }
      }) 
    }
  }
  else if(tableDataCanStart.value.length===0){
    proxy.$message({
        message: '请设置输入值！',
        type: 'warning'
    });
  }
  else if(tableDataCanEnd.value.length===0){
    proxy.$message({
        message: '请设置输出值！',
        type: 'warning'
    });
  }
  var parFlow = toRaw(toObject())
  parFlow.nodes.forEach(item => {
    if(item.id==='1'){
      item.type='startNode'
      item.data.parameters = tableDataCanStart.value;
    }
    if(item.id==='2'){
      item.type='endNode'
      item.data.parameters = tableDataCanEnd.value;
      console.log(item)
    }
    item.title = item.label
  });
  
}
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;
  });
}
function parseJSONWithComments(jsonString) {
    // 移除单行注释（//）和多行注释（/* */）
    const cleanedJson = jsonString.replace(/\/\/.*|\/\*[\s\S]*?\*\//g, '');
    try {
        return JSON.parse(cleanedJson);
    } catch (error) {
        console.error("解析失败：", error.message);
        return null;
    }
}
onNodeClick(({event, node}) => {
  nodeEnd.value = false
  nodeStart.value = false
  nodeDeSer.value = false
  parNodeid.value = node.id
  parTitle.value = node.data.name
  tableDataCan.value = []
  optionsCan.value = []
  tableDataCanOut.value = []
  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){
      item.data.service.rpcontent = parseJSONWithComments(item.data.service.rpcontent)
      console.log((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)
      })
    }
    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
  }
  if(node.data.label==='开始'){
    nodeStart.value = true

  }
  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:''
        }
        tableDataCanOut.value.push(par)
      })
      // 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)
    if(node.data.value==='表输入组件'){
      dialogVisibleBiao.value = true
    }
    if(node.data.value==='Excel文件输入组件'){
      dialogVisibleExcel.value = true
    }
    if(node.data.value==='csv输入组件'){
      dialogVisibleCsv.value = true
    }
  }
  
});

/**
 * 开始拖拽选项的事件
 * @param event
 * @param data
 */
function onDragStart(event, data) {
  if(data.nodeType==='SERVICE'||data.nodeType==='tool'){
    if (event.dataTransfer) {
      event.dataTransfer.setData('application/vueflow', data)
      event.dataTransfer.effectAllowed = 'move'
    }

    draggedData.value = data
    isDragging.value = true
    
    document.addEventListener('drop', onDragEnd)
  }
  
}

/**
 * 拖拽到画布vueflow的事件
 * @param event
 */
function onDragOver(event) {
  event.preventDefault()
  
  if (draggedData.value) {
    isDragOver.value = true

    if (event.dataTransfer) {
      event.dataTransfer.dropEffect = 'move'
    }
  }
}

/**
 * 拖拽放下的事件
 * @param event
 */

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: copyObject(draggedData.value) // 先使用本地数据
  };
  addNodes(newNode);

  // 2. 异步获取数据并更新
  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)
});
  // console.log(toObject())
}

/**
 * 拖拽到画布外面的的事件
 */
function onDragLeave() {
  isDragOver.value = false
}

/**
 * 拖拽结束
 */
function onDragEnd() {
  isDragging.value = false
  isDragOver.value = false
  draggedData.value = null
  document.removeEventListener('drop', onDragEnd)
}

function onConnect(params) {
  addEdges({ ...params, ...defaultEdgeStyle })
}
function back(){
  proxy.$router.push({ path: '/standardization/modelUsing' });
}
/** 查询模型列表 */
function getModelList() {
  getModelList2(modelQueryParams.value).then(res => {
    loading.value = false;
    modelOptions.value = res.data;
  });
}

/** 通过条件过滤节点  */
const filterNode = (value, data) => {
  if (!value) return true;
  return data.label.indexOf(value) !== -1;
};


/** 查询流程图 */
function getList() {
  const count = computed(() => store.getters.id)
  console.log(count.value);
  var par = {
    appId: count.value
  }
  getModelingDe(par).then(res => {
    if(res.data.length===0){
      isAdd.value = true
      nodes.value = [
        { id: '1', position: { x: -600, y: -300 }, data: { label: '开始' }, type: 'special' },
        { id: '2', position: { x: 150, y: 100 }, data: { label: '结束' }, type: 'special' },
      ]
    }
    else{
      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'
        if(item.id==='2'&&item.data){
          tableDataCanEnd.value = item.data.outputDefs
        }
        if(item.id==='1'&&item.data.parameters){
          tableDataCanStart.value = item.data.parameters
        }
      })
      nodes.value = a.nodes
      edges.value = a.edges
      zoom.value = a.zoom
      zoomTo(zoom.value) 
      parFlowId.value = res.data[0].flowId
    }
    if(tableDataCanEnd.value.length===0){
      tableDataCanEnd.value = []
    }
  });
  
}
const ws = ref(null);
const connected = ref(false);
const messages = ref([]);
const connect = () => {
  ws.value = new WebSocket('ws://127.0.0.1:8082/websocket/message'); // 替换为你的 WS 地址
  
  ws.value.onopen = () => {
    connected.value = true;
  };
  
  ws.value.onmessage = (event) => {
    messages.value.push(event.data); // 存储接收到的消息
  };
  
  ws.value.onerror = (error) => {
    console.error('WebSocket 错误:', error);
  };
  
  ws.value.onclose = () => {
    connected.value = false;
    console.log('WebSocket 连接已关闭');
  };
};

const sendMessage = () => {
  if (ws.value && ws.value.readyState === WebSocket.OPEN) {
    const message = 'Hello, Server!'; // 实际发送的消息内容或格式可与后端约定
    ws.value.send(message);
  }
};

const disconnect = () => {
  if (ws.value) {
    ws.value.close();
    ws.value = null;
  }
};

// 组件卸载时自动断开连接
onUnmounted(() => {
  disconnect();
});
onMounted(() => {
  // connect()
  getTreeLeft()
  getList();
})
watch(messages, (newMessages) => {
  newMessages.forEach(item=>{
    item = JSON.parse(item)
    nodes.value.forEach(item1=>{
      if(item1.id===item.id){
        if(item.nodeState&&item.nodeState==='START'){
          item1.data.loading = true
          item1.data.isSuccess = true
          item1.data.isFail = false
        }
        if(item.nodeState&&item.nodeState==='ERROR'){
          console.log(3)
          item1.data.loading = false
          item1.data.isSuccess = false
          item1.data.isFail = true
          item1.data.erMsg = item.errorMessage
          // throw new TypeError(`期望传入一个数字，但收到的是`)
        }
        if(item.nodeState&&item.nodeState==='END'){
          console.log(2)
          item1.data.loading = false
          // item1.data.isSuccess = true
          // item1.data.isFail = false
        }
      }
    })
  })
}, { deep: true })
// watch(nodes, (newNodes) => {
//   console.log('当前节点列表:', newNodes) // 实时输出最新数据
// }, { deep: true })
</script>
<style>
@import '@vue-flow/core/dist/style.css';
@import '@vue-flow/core/dist/theme-default.css';
</style>
<style scoped>
.custom-no-border :deep(.el-input__wrapper) {
  box-shadow: none !important; /* 移除默认阴影（即边框） */
  border: none !important;     /* 双重保障 */
}
/* 处理悬停和聚焦状态 */
.custom-no-border :deep(.el-input__wrapper:hover),
.custom-no-border :deep(.el-input__wrapper:focus-within) {
  box-shadow: none !important;
  border: none !important;
}
:deep(.treeLeft) .el-tree-node__content {
  display: flex !important;
  height: 28px;                  /* 按设计稿调整高度 */
  align-items: center;
  padding-top: 0 !important;
}
:deep(.treeLeft) .el-tree-node__content:hover {
  background-color: #e9e9eb;
}
:deep(.treeLeft) .el-tree-node__content:active {
    background-color: rgka(69,157,255,0.1) !important;
  }

  /* 选中态（Active） */
:deep(.treeLeft) .el-tree-node.is-current > .el-tree-node__content {
    background-color: #c6e2ff !important;
  }
</style>