| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499 |
- <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="saveNode" style="margin-left: auto;cursor: pointer;"><Close /></el-icon>
- </div>
- <div>
- <div style="display: flex;width: 90%;margin-left: 5%;margin-top:10%;align-items: center;justify-content: space-between;">
- <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 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-form-item label="失败处理">
- <el-select v-model="form.errorPolicy" style="width: 50%">
- <el-option label="报错" value="ABORT"></el-option>
- <el-option label="忽视" value="IGNORE"></el-option>
- <el-option label="重连" value="RETRY"></el-option>
- </el-select>
- </el-form-item>
- <el-form-item label="失败重连次数">
- <el-input-number v-model="form.retryCount" :min="1" style="width: 50%" :max="30"/>
- </el-form-item>
- <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.value" 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-if="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%;"> {{ 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"
- 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: 150%;" ></el-input>
- <!-- {{ specialNodeProps.data.label}} -->
- </div>
- <el-icon @click.stop="testNode(specialNodeProps)" style="cursor: pointer;margin-left: auto;"><CaretRight /></el-icon>
- <el-icon @click.stop="delNode(specialNodeProps)" style="cursor: pointer;color: #F56C6C;margin-left: 2%;"><Delete /></el-icon>
- </div>
- <div style="display: flex;margin-top: 3%;">
- <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: 2, maxRows: 4 }"
- 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 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 } from "@/api/service/info";
- 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 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 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)
- }
- };
- function addEnd(){
- tableDataCanEnd.value.push([])
- }
- function delEnd(index){
- tableDataCanEnd.value.splice(index,1)
- }
- function startTest(){
- 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 = 'printNode'
- }
- })
- var par = {}
- par.flowGraph = JSON.stringify(a)
- par.params = {}
- tableDataCanStart.value.forEach(item=>{
- // par.set(item.name,item.value)
- par.params[item.name] = item.value
- })
- console.log(a)
- runflow(par).then(res=>{
- if(res.code === 200){
- proxy.$message({
- message: res.msg,
- type: 'success'
- });
- dialogVisibleSart.value = true
- outputData.value = JSON.stringify(res.data)
- }
- })
-
- }
- else if(tableDataCanStart.value.length===0){
- proxy.$message({
- message: '请设置输入值!',
- type: 'warning'
- });
- }
- else if(tableDataCanEnd.value.length===0){
- proxy.$message({
- message: '请设置输出值!',
- type: 'warning'
- });
- }
-
- }
- function saveStartNode(){
- nodeStart.value = false
- }
- function saveEndNode(){
- nodeEnd.value = false
- }
- function addStart(){
- tableDataCanStart.value.push([])
- }
- function delCanStart(index){
- tableDataCanStart.value.splice(index,1)
- }
- 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.paramName,
- value:parSplit[0],
- dataType:item.paramType,
- refType:'fixed'
- }
- par.parameters.push(par1)
- }
- else{
- var par1 = {
- name:item.paramName,
- ref:item.paramValue,
- dataType:item.paramType,
- refType:'ref'
- }
- par.parameters.push(par1)
- }
- }
- else{
- var par1 = {
- name:item.paramName,
- value:null,
- dataType:item.paramType,
- refType:'fixed'
- }
- par.parameters.push(par1)
- }
-
- })
- 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(){
- await modelTreeSelect().then(res=>{
- dataTree.value = res.data
- })
- }
- function saveFlow(){
- var parFlow = toRaw(toObject())
- parFlow.nodes.forEach(item => {
- if(item.id==='1'){
- item.type='startNode'
- }
- if(item.id==='2'){
- item.type='endNode'
- }
- });
- console.log(parFlow)
- if(isAdd.value){
- const count = computed(() => store.getters.id)
- var par = {
- appId: count.value,
- flowName:'default',
- flowGraph: JSON.stringify(parFlow)
- }
- 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(parFlow)
- }
- console.log(par)
- editModelingFlow(par).then(res=>{
- if(res.code===200){
- proxy.$message({
- message: '保存成功',
- type: 'success'
- });
- getList()
- }
- })
- }
- }
- function getPredecessorsNodes(nodeId, edges = getEdges.value, allNodes = getNodes.value){
- // 1. 找到所有直接指向目标节点的边(即 target 为 nodeId 的边)
- const incomingEdges = edges.filter(edge => edge.target === nodeId);
-
- // 2. 从这些边中提取所有源节点的 ID
- const sourceNodeIds = incomingEdges.map(edge => edge.source);
-
- // 3. 根据源节点 ID 获取完整的节点对象
- const directPredecessors = allNodes.filter(node => sourceNodeIds.includes(node.id));
-
- // 4. 递归获取这些直接前置节点的前置节点
- const allPredecessors = [];
- for (const predecessor of directPredecessors) {
- // 将直接前置节点加入结果数组
- allPredecessors.push(predecessor);
- // 递归获取该前置节点的前置节点,并合并到结果数组中
- const predecessorsOfPredecessor = getPredecessorsNodes(predecessor.id, edges, allNodes);
- allPredecessors.push(...predecessorsOfPredecessor);
- }
- // 5. 使用 Set 或其他方法去重(根据节点 ID),因为一个节点可能通过不同路径被多次访问
- const uniquePredecessors = Array.from(new Map(allPredecessors.map(node => [node.id, node])).values());
-
- return uniquePredecessors;
- };
- function removeDuplicatesAndEmptyItems(arr) {
- const map = new Map();
- return arr.filter(item => {
- // 过滤 null 和 undefined
- if (item === null || item === undefined) return false;
-
- // 处理对象类型:转为字符串标识去重
- const key = typeof item === 'object'
- ? JSON.stringify(item)
- : item;
-
- // 若标识不存在于 Map 中,则保留并记录
- if (!map.has(key)) {
- map.set(key, true);
- return true;
- }
- return false;
- });
- }
- 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
- console.log(node)
- parNodeid.value = node.id
- parTitle.value = node.data.name
- tableDataCan.value = []
- optionsCan.value = []
- var parNode = getPredecessorsNodes(node.id)
- console.log((JSON.parse(JSON.stringify(parNode))))
- var a = JSON.parse(JSON.stringify(parNode))
- 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 count = index+1
- var par = {
- ref:count.toString() + ':' + item1,
- name:item.data.label + ':' + item1
- }
- 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
- tableDataCanOut.value = res.data.returnList
- 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'
- })
- nodes.value = a.nodes
- edges.value = a.edges
- zoom.value = a.zoom
- zoomTo(zoom.value)
- parFlowId.value = res.data[0].flowId
- }
- });
- }
- onMounted(() => {
- getTreeLeft()
- getList();
- })
- 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>
|