| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177 |
- <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>
- <div style="margin-left:1% ;">{{flowName}}</div>
- <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="(newValue) => handleSelectChange(newValue, scope.row)"
- 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="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%;line-height: 1.5;align-items: center;margin-top: 5%;">
- <div style="width: 20%;margin-left: 5%;">
- 名称:
- </div>
- <el-input placeholder="" type="primary" class="noBor" v-model="saveName" size="mini" text style="margin-left: 0%;"></el-input>
- </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>
- <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="{fontSize: '14px', textAlign: 'center'}"
- :row-style="{ height: heightAll*0.01+'px',fontSize: '17px',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="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">
- <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">
- <svg-icon icon-class="model2" style="color: #eebe77;" v-if="data.nodeType=='MODEL'"/>
- <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=='表输出组件'"/>
- <svg-icon icon-class="lcbsc" dstyle="color: #13E03B;" v-if="data.label=='存储节点'"/>
- <span style="margin-left: 2%;"> {{ 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">
- <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=='输入'"/>
- <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=='表输出组件'"/>
- <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="{fontSize: '14px', textAlign: 'center', }"
- max-height="45vh"
- :row-style="{ height: heightAll*0.01+'px',fontSize: '17px',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="{fontSize: '14px', textAlign: 'center', }"
- max-height="45vh"
- :row-style="{ height: heightAll*0.01+'px',fontSize: '17px',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="{fontSize: '14px', textAlign: 'center', }"
- max-height="45vh"
- :row-style="{ height: heightAll*0.01+'px',fontSize: '17px',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 { getWebSocketUrl } from '@/utils/websocket'
- 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 {getModellist} from '@/api/standardization/modeling'
- 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 saveName = 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:"json",
- value:'json'
- },
- {
- label:"number",
- value:'number'
- },
-
- ])
- const dataTreeTool = ref([
- {
- label:'输入',
- value:'输入',
- children:[
- {
- label:'表输入组件',
- nodeType:'tool',
- value:'表输入组件',
- },
- {
- label:'Excel文件输入组件',
- value:'Excel文件输入组件',
- nodeType:'tool',
- },
- {
- label:'csv输入组件',
- nodeType:'tool',
- value:'csv输入组件',
- },
- {
- label:'存储节点',
- nodeType:'tool',
- value:'存储节点',
- },
- ]
- },
- {
- 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 saveDeSer = 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 = (newValue, rowData) => {
- if (!newValue || newValue.trim() === '') {
- return; // 空值不处理
- }
-
- // 检查新值是否已存在于预设选项中
- 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()
- };
- 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 closeSaveDe(){
- saveDeSer.value = false
- }
- function closeDe(){
- nodeDeSer.value = false
- servieName.value = null
- }
- 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]==='input'){
- 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)
- }
- })
- // 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)
- item.data.parameters = par.parameters
- item.data.service = serInfo.value
- if(item.data.service){
- item.data.service.params = parSerList.value
- }
- }
- })
- console.log(toObject())
- }
- 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 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位随机数
- 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(){
- console.log(tableDataCanStart.value)
- messages.value = []
- 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')
- // ws.value = new WebSocket('wss://' + host + '/websocket/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,
- ref:item.paramValue
- }
- 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()))
- console.log(a)
- a.nodes.forEach(item=>{
- if(item.data.value==="存储节点"){
- item.type = 'saveNode'
- if(item.data.parameters){
- 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 if(item.data.value!=="存储节点"&&item.id!=='1'&&item.id!=='2'){
- 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
- })
- 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({
- 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()))
- console.log(a)
- a.nodes.forEach(item=>{
- if(item.data.label==="存储节点"){
- const count = computed(() => store.getters.id)
- item.data.appId = count.value
- item.name = saveName.value
- }
- 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;
- }
- }
- const parNodeAll = ref([])
- onNodeClick(({event, node}) => {
- console.log(parNodeAll.value)
- 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: ''
- },
- {
- paramCode: 'name',
- 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
- 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(item.data.label==='存储节点'){
- item.data.tableDataCanOut.forEach(item2=>{
- var par = {
- 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
- }
- if(node.data.label==='开始'){
- nodeStart.value = true
- }
- if(node.data.nodeType==='SERVICE'){
- 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
- }
- 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
- })
- }
- }
- 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
- }
- if(item.data.parameters!==null){
- item.list = []
- if(item.data.parameters){
- item.data.parameters.forEach(item1=>{
- var par = {
- paramCode:item1.name,
- paramValue:item1.ref,
- paramType:item1.dataType,
- refType:item1.refType,
- }
- item.list.push(par)
- })
- }
- item.ptService = item.data.service
- }
- if(item.id!=='2'&&item.id!=='1'&&item.data){
- parNodeAll.value.push(item)
- }
- })
- console.log(parNodeAll.value)
- 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;
- }
- };
- const flowName = ref()
- function getName() {
- const count = computed(() => store.getters.id)
- getModellist().then(res => {
- res.rows.forEach(item=>{
- console.log(item.appId,count)
- if(item.appId === count.value){
- flowName.value = item.appTitle
- }
- })
- })
- }
- // 组件卸载时自动断开连接
- onUnmounted(() => {
- disconnect();
- });
- onMounted(() => {
- // connect()
- getTreeLeft()
- getList();
- getName()
- })
- 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>
|