index.vue 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387
  1. <template>
  2. <VueFlow ref="vueFlowRef" v-model:nodes="nodes" v-model:edges="edges" :class="{ dark }"
  3. class="basic-flow"
  4. style="background-image: url('src/assets/flowimg/surromdao.png'); background-position: center; background-repeat: no-repeat;"
  5. :default-viewport="{ zoom: 1.5 }" :min-zoom="0.2" :max-zoom="2.5" @drop="onDrop1"
  6. @node-contextmenu="onNodeContextMenu"
  7. @dragover="onDragOver" @dragleave="onDragLeave" @edge-click="onEdgeClick" @node-double-click="onNodeDoubleClick"
  8. @node-click="onNodeClick" @edge-double-click="onEdgeDoubleClick">
  9. <template #node-default="props">
  10. <eltree :node="props" />
  11. </template>
  12. <Background pattern-color="#aaa" :gap="16"
  13. />
  14. <!-- <MiniMap /> @input="handleUpdate"-->
  15. <Panel :position="'right'" style="display: none;">
  16. <div class="field">
  17. <div>
  18. <label for="label">Label:</label>
  19. <input id="label" v-model.lazy="labelname" /></div>
  20. <button @click="handleUpdate" class="lableaniu">确定</button>
  21. </div>
  22. <!-- <div> -->
  23. <!-- <button class="remove" @click="removeNode(event)">N</button>
  24. <button class="remove" @click="removeEdge(event)">E</button>
  25. <button class="remove" @click="removeall(event)">all</button>
  26. </div> -->
  27. <!-- <button @click="onSelection()" class="lableaniu">获取</button> -->
  28. </Panel>
  29. <Controls position="top-left">
  30. <ControlButton title="重置" @click="resetTransform">
  31. <Icon name="reset" />
  32. </ControlButton>
  33. <ControlButton title="背景切换" @click="toggleDarkMode">
  34. <Icon v-if="dark" name="sun" />
  35. <Icon v-else name="moon" />
  36. </ControlButton>
  37. <ControlButton title="保存" @click="logToObject1">
  38. <!-- <Icon name="log" /> -->
  39. <el-icon :color="iconcolor"><UploadFilled /></el-icon>
  40. </ControlButton>
  41. <ControlButton title="删除节点" @click="removeNode()">
  42. <el-icon :color="iconcolor"><DocumentDelete /></el-icon>
  43. </ControlButton>
  44. <ControlButton title="删除线" @click="removeEdge()">
  45. <el-icon :color="iconcolor"><Crop /></el-icon>
  46. </ControlButton>
  47. <ControlButton title="清空全部" @click="confirmDelete()">
  48. <el-icon :color="iconcolor"><DeleteFilled /></el-icon>
  49. </ControlButton>
  50. </Controls>
  51. <el-dialog v-model="changeNameshow" align-center :modal="false" :close-on-click-modal="false"
  52. :append-to-body="true" draggable :fullscreen="false" :modal-append-to-body="false" modal-class="summary-dlg"
  53. width="400" class="dialog_class bgcolor colortext tianjia sel">
  54. <template #header="{ titleId, titleClass }">
  55. <div class="my-header ">
  56. <h4 :id="titleId" :class="titleClass">修改名称</h4>
  57. </div>
  58. </template>
  59. <div style="margin-top: 20px;padding: 20px;">
  60. <el-form :model="changeName" label-width="100px" class="demo-ruleForm">
  61. <el-form-item label="新名称:" prop="name">
  62. <el-input v-model="changeName.name" placeholder="请输入名称" maxlength="20"></el-input>
  63. </el-form-item>
  64. </el-form>
  65. </div>
  66. <template #footer>
  67. <div class="dialog-footer">
  68. <el-button @click="changeNameshow = false">取 消</el-button>
  69. <el-button type="primary" @click="handleUpdate">确 定</el-button>
  70. </div>
  71. </template>
  72. </el-dialog>
  73. <!-- 双击线段 -->
  74. <el-dialog v-model="dataflowshow" align-center :modal="false" :close-on-click-modal="false"
  75. :append-to-body="true" draggable :fullscreen="false" :modal-append-to-body="false" modal-class="summary-dlg"
  76. width="500" class="dialog_style bgcolor colortext tianjia sel">
  77. <template #header="{ titleId, titleClass }">
  78. <div class="my-header ">
  79. <h4 :id="titleId" :class="titleClass">数据流</h4>
  80. </div>
  81. </template>
  82. <div style="margin-top: 5px;padding: 10px 35px;">
  83. <div v-if="datacontent === '1'">
  84. <el-card :shadow="none" style="min-height: 240px; max-height: 480px;">
  85. <el-checkbox v-model="checkAll"
  86. :indeterminate="isIndeterminate"
  87. @change="handlecheckAllchange">全选</el-checkbox>
  88. <div class="eldesign classtable">
  89. <el-table :data="youhuaFFDtable" border :show-header="false">
  90. <el-table-column
  91. type="index"
  92. label=""
  93. ></el-table-column>
  94. <el-table-column prop="steamflag" width="55">
  95. <template #default="{ row }">
  96. <el-checkbox
  97. :false-label="0"
  98. :true-label="1"
  99. v-model="row.steamflag"
  100. @change="handlecheckFlagchange"></el-checkbox>
  101. </template>
  102. </el-table-column>
  103. <el-table-column prop="name" label="" ></el-table-column>
  104. </el-table>
  105. </div>
  106. </el-card>
  107. </div>
  108. <div v-if="datacontent === '2'">
  109. <el-card :shadow="none" style="min-height: 240px; max-height: 480px;">
  110. <el-checkbox v-model="checkAll"
  111. :indeterminate="isIndeterminate"
  112. @change="handlecheckAllchange">全选</el-checkbox>
  113. <div class="eldesign classtable">
  114. <el-table :data="youhuaCSTtable" border :show-header="false">
  115. <el-table-column
  116. type="index"
  117. label=""
  118. ></el-table-column>
  119. <el-table-column prop="steamflag" width="55">
  120. <template #default="{ row }">
  121. <el-checkbox
  122. :false-label="0"
  123. :true-label="1"
  124. v-model="row.steamflag"
  125. @change="handlecheckFlagchange"></el-checkbox>
  126. </template>
  127. </el-table-column>
  128. <el-table-column prop="name" label="" ></el-table-column>
  129. </el-table>
  130. </div>
  131. </el-card>
  132. </div>
  133. <div v-if="datacontent === '3'">
  134. <el-card :shadow="none" style="min-height: 240px; max-height: 480px;">
  135. <el-checkbox v-model="checkAll"
  136. :indeterminate="isIndeterminate"
  137. @change="handlecheckAllchange">全选</el-checkbox>
  138. <div class="eldesign classtable">
  139. <el-table :data="ADflowyouhuatable" border :show-header="false">
  140. <el-table-column
  141. type="index"
  142. label=""
  143. ></el-table-column>
  144. <el-table-column prop="steamflag" width="55">
  145. <template #default="{ row }">
  146. <el-checkbox
  147. :false-label="0"
  148. :true-label="1"
  149. v-model="row.steamflag"
  150. @change="handlecheckFlagchange"></el-checkbox>
  151. </template>
  152. </el-table-column>
  153. <el-table-column prop="name" label="" ></el-table-column>
  154. <el-table-column prop="steamtype">
  155. <template #default="{ row }">
  156. <el-select v-model="row.steamtype">
  157. <el-option
  158. v-for="item in steamtypeoptions"
  159. :key="item.value"
  160. :label="item.label"
  161. :value="item.value"
  162. />
  163. </el-select>
  164. </template>
  165. </el-table-column>
  166. </el-table>
  167. </div>
  168. </el-card>
  169. </div>
  170. <div v-if="datacontent === '4'">
  171. <el-card :shadow="none" style="min-height: 240px; max-height: 480px;">
  172. <el-checkbox v-model="checkAll"
  173. :indeterminate="isIndeterminate"
  174. @change="handlecheckAllchange">全选</el-checkbox>
  175. <div class="eldesign classtable">
  176. <el-table :data="Xfoilyouhuatable" border :show-header="false">
  177. <el-table-column
  178. type="index"
  179. label=""
  180. ></el-table-column>
  181. <el-table-column prop="steamflag" width="55">
  182. <template #default="{ row }">
  183. <el-checkbox
  184. :false-label="0"
  185. :true-label="1"
  186. v-model="row.steamflag"
  187. @change="handlecheckFlagchange"></el-checkbox>
  188. </template>
  189. </el-table-column>
  190. <el-table-column prop="name" label="" show-overflow-tooltip></el-table-column>
  191. <el-table-column prop="steamtype">
  192. <template #default="{ row }">
  193. <el-select v-model="row.steamtype">
  194. <el-option
  195. v-for="item in steamtypeoptions"
  196. :key="item.value"
  197. :label="item.label"
  198. :value="item.value"
  199. />
  200. </el-select>
  201. </template>
  202. </el-table-column>
  203. </el-table>
  204. </div>
  205. </el-card>
  206. </div>
  207. </div>
  208. <template #footer>
  209. <div class="dialog-footer">
  210. <el-button @click="dataflowshow = false">取 消</el-button>
  211. <el-button type="primary" @click="confirmselection();dataflowshow = false ">确 定</el-button>
  212. </div>
  213. </template>
  214. </el-dialog>
  215. </VueFlow>
  216. <div class="dnd-flow">
  217. <!-- <div id="contextMenu" @click="deleteItemConfirm">删除</div> -->
  218. </div>
  219. </template>
  220. <script setup>
  221. import { ref, markRaw,inject } from 'vue'
  222. import { VueFlow,Panel, useVueFlow, MarkerType} from '@vue-flow/core'
  223. import { ElMessage, ElButton, ElDialog, ElSelect, ElMessageBox} from 'element-plus'
  224. import {
  225. DocumentDelete,
  226. Delete,
  227. UploadFilled,
  228. Histogram,
  229. DeleteFilled,
  230. Crop,
  231. } from '@element-plus/icons-vue'
  232. import { useRoute } from 'vue-router';
  233. import { request, uploadFile } from "@/utils/request";
  234. import { Background } from '@vue-flow/background'
  235. import { ControlButton, Controls } from '@vue-flow/controls'
  236. import { initialEdges, initialNodes } from './modeljs.js'
  237. import { MiniMap } from '@vue-flow/minimap'
  238. import "./main.css";//重置样式
  239. import DropzoneBackground from './DropzoneBackground.vue'
  240. import eltree from './eltree.vue'
  241. import CustomEdge from './CustomEdge.vue';
  242. import useDragAndDrop from './useDnD';
  243. import f11 from '@/assets/img/f11.png'
  244. import r2 from '@/assets/img/r2.png'
  245. import html2canvas from 'html2canvas';
  246. import Icon from './Icon.vue'
  247. import { formatTime } from '@/js/lindex.js';
  248. import emitter from "@/utils/emitter";
  249. // import func from 'vue-temp/vue-editor-bridge.js';
  250. const dark = ref(false)
  251. let datatree=ref();
  252. const route = useRoute();
  253. const { onInit, onNodeDragStop, onNodeContextMenu, onConnect, addEdges, setViewport, toObject,addNodes,updateEdgeData,onConnectStart} = useVueFlow()
  254. let vueFlowRef = ref();
  255. let emit = defineEmits(['optimizerfalse']);
  256. let mergedObj=ref();
  257. let labelname=ref();
  258. let iconcolor=ref('#000')
  259. const props = defineProps({
  260. optimizer: {
  261. type: Boolean,
  262. },
  263. jboptimizer: {
  264. type: Boolean,
  265. },
  266. Xfoil: {
  267. type: Boolean,
  268. },
  269. // color1: {
  270. // type: String,
  271. // },
  272. })
  273. let newobj=ref({
  274. name:'',
  275. description:'',
  276. })
  277. let nodesitem=ref([]);
  278. let linenum=ref(1);
  279. let bgcolor=ref();
  280. let linecolor=ref('#b1b1b7')
  281. let pid=ref('');
  282. let newroter=ref();
  283. let vueflowimg=ref('');
  284. const shopShow = ref(false);
  285. // 选中节点
  286. let noid = ref([]);
  287. let Edgeid = ref();
  288. let seledge=ref(null);
  289. let djshow=ref(false);
  290. let node = ref();
  291. let contextMenu = ref({
  292. position: { x: 0, y: 0 },
  293. target: 'kong',
  294. })
  295. let Nested=ref([]);
  296. let Nested2=ref([]);
  297. let nnum=ref(0);
  298. const { onDragOver, onDrop, onDragLeave, isDragOver } = useDragAndDrop();
  299. const edges = ref([]);
  300. const nodes = ref([]);
  301. const changeNameshow = ref(false);
  302. const changeName = ref({
  303. name: '',
  304. })
  305. // 旧数据存储
  306. let prevNodes = [...nodes.value];
  307. let prevEdges = [...edges.value];
  308. // 监听节点变化
  309. watch(nodes, (newNodes) => {
  310. const deletedNodes = prevNodes.filter((node) => !newNodes.some((n) => n.id === node.id));
  311. if (deletedNodes.length > 0) {
  312. console.log("Deleted Nodes:", deletedNodes);
  313. // 处理节点删除逻辑
  314. }
  315. prevNodes = [...newNodes];
  316. }, { deep: true });
  317. // 监听连线变化
  318. watch(edges, (newEdges) => {
  319. const deletedEdges = prevEdges.filter((edge) => !newEdges.some((e) => e.id === edge.id));
  320. if (deletedEdges.length > 0) {
  321. console.log("Deleted Edges:", deletedEdges);
  322. // 处理连线删除逻辑
  323. }
  324. prevEdges = [...newEdges];
  325. }, { deep: true });
  326. onNodeContextMenu((e) => {
  327. noid.value = e.node;
  328. changeName.value.name = e.node.data.label;
  329. changeNameshow.value = true;
  330. })
  331. // 监听连接开始,提前取消选中的线段
  332. onConnectStart(() => {
  333. cleanEdgeselect();
  334. });
  335. // 线的类型 process-逻辑线 data-数据线
  336. let lineType = ref('process');
  337. // 线序号
  338. let linecount = ref(0);
  339. onConnect((connection) => {
  340. console.log('线连接',connection);
  341. // 创建唯一的边ID(由源节点和目标节点组成)
  342. const edgeId = `${lineType.value}-${connection.source}-${connection.sourceHandle}-${connection.target}-${connection.targetHandle}`;
  343. connection.id = edgeId; // 自定义 ID
  344. connection.type = 'smoothstep';// smoothstep straight
  345. connection.markerEnd = lineType.value === "data" ? "" : MarkerType.ArrowClosed;
  346. connection.color=linecolor.value;
  347. // connection.label = '这是一条注释';
  348. connection.style = { strokeWidth:linenum.value ,stroke:linecolor.value};
  349. // 连接数据流线前应先连接逻辑流
  350. if(lineType.value === 'data'){
  351. const processEdgeId = `process-${connection.source}-${connection.sourceHandle}-${connection.target}-${connection.targetHandle}`;
  352. const hasProcessEdge = edges.value.some(edge => edge.id === processEdgeId);
  353. if(!hasProcessEdge){
  354. ElMessage({
  355. message:'请先连接逻辑流连线!',
  356. type:'error'
  357. })
  358. return;
  359. }
  360. }
  361. //
  362. const sameEdge = edges.value.find(edge => edge.id === edgeId);
  363. if(sameEdge){
  364. deleteflow(sameEdge.data.wid);
  365. }
  366. addEdges(connection);
  367. seledge.value=null;
  368. linecount.value++;
  369. const newName = `Seg${linecount.value}`;
  370. const sourceNode = vueFlowRef.value.getNode(connection.source);
  371. const targetNode = vueFlowRef.value.getNode(connection.target);
  372. // 调用 saveflow 保存数据并获取 wid
  373. saveflow(pid.value, '', newName, lineType.value, sourceNode.data.uid, targetNode.data.uid)
  374. .then((wid) => {
  375. // 更新连接线的数据
  376. const updatedData = {
  377. wid: wid,
  378. uid: newName,
  379. type: lineType.value,
  380. fromuid: sourceNode.data.uid,
  381. touid: targetNode.data.uid,
  382. };
  383. updateEdgeData(connection.id, updatedData);
  384. })
  385. .catch((error) => {
  386. console.error('保存流程失败:', error);
  387. });
  388. })
  389. //修改名称
  390. const handleUpdate = () => {
  391. if (noid.value && noid.value.data) {
  392. noid.value.data.label = changeName.value.name; // 更新名称
  393. console.log(noid.value.data.label); // 打印更新后的值
  394. } else {
  395. console.error("noid.value 或 noid.value.data 未定义"); // 错误日志
  396. }
  397. changeNameshow.value = false; // 更新后关闭对话框
  398. // noid.value.data.label = labelname;
  399. };
  400. emitter.on('child2Data', data => {
  401. datatree.value = data;
  402. console.log("datatree的值:",datatree.value);
  403. })
  404. function onNodeClick(e) {
  405. noid.value = e.node;
  406. changeName.value.name=e.node.data.label;
  407. console.log("shuju:",e.node.data);
  408. console.log("noid.value:",noid.value);
  409. console.log("changeName.value:",changeName.value.name);
  410. djshow.value = !djshow.value;
  411. // if(djshow.value){
  412. // console.log('选中');
  413. // }else{
  414. // console.log('取消选中');
  415. // }
  416. }
  417. //模块化
  418. const bgcolorfunc= (color)=>{
  419. bgcolor.value=color;
  420. if(noid.value.style!=undefined){
  421. console.log(noid.value.style);
  422. noid.value.style.backgroundColor=color;
  423. }
  424. }
  425. function onSelection(){
  426. let positionX=[];
  427. let positiony=[];
  428. for(let i=0;i<Nested.value.length;i++){
  429. // Nested2.value.push(Nested.value[i]);
  430. positionX.push(Nested.value[i].position.x)
  431. positiony.push(Nested.value[i].position.y)
  432. }
  433. let xmin=Math.min(...positionX);
  434. let ymax=Math.max(...positiony);
  435. console.log(positionX);
  436. // console.log( positionX)
  437. // console.log(44444)
  438. // console.log( positiony)
  439. nnum.value++;
  440. // let x=Math.floor(Math.random() * 91) + 10;
  441. // let y=Math.floor(Math.random() * 91) + 10;
  442. let name='模块'+nnum.value
  443. let item= {
  444. id:nnum.value.toString(),
  445. data: { label:name },
  446. position: { x:xmin , y:ymax},
  447. style: { backgroundColor: bgcolor.value, width: '200px',height: '200px' },
  448. //children: [],
  449. }
  450. if(Nested.value.length!=0){
  451. Nested2.value=[];
  452. for(let i=0;i<Nested.value.length;i++){
  453. Nested2.value.push(Nested.value[i]);
  454. }
  455. console.log(Nested2.value);
  456. nodesitem.value= Nested2.value.map(node => {
  457. if(node.parentNode==undefined){
  458. node.isParent=false;
  459. node.parentNode=item.id;
  460. console.log( node.parentNode)
  461. node.position.x= node.position.x /2;
  462. node.position.y= node.position.y/2;
  463. node.expandParent=true;
  464. //positionxy=node.position;
  465. // node.extent='parent';
  466. // return node;
  467. }
  468. return node;
  469. })
  470. }
  471. nodes.value.push(item)
  472. for(let i=0;i<nodesitem.value.length;i++){
  473. console.log(nodesitem.value[i]);
  474. nodes.value.push(nodesitem.value[i])
  475. }
  476. console.log( nodes.value);
  477. }
  478. function onNodeDoubleClick(e) {
  479. noid.value = e.node;
  480. const nowid = e.node.data.wid;
  481. console.log( e.node.data.name);
  482. if (e.node.data.name == 'optimizer') {
  483. emit('optimizerfalse',{name:'优化器',wid:nowid});
  484. }else if(e.node.data.name=="optimizer1"){
  485. emit('optimizerfalse',{name:'进化优化器',wid:nowid});
  486. }else if(e.node.data.name=="optimizer3"){
  487. emit('optimizerfalse',{name:'代理优化器',wid:nowid});
  488. }else if(e.node.data.name=="Xfoil"){
  489. emit('optimizerfalse',{name:'Xfoil',wid:nowid});
  490. }else if(e.node.data.name=="optimizer2"){
  491. emit('optimizerfalse',{name:'梯度优化器',wid:nowid});
  492. }else if(e.node.data.name=="CST"){
  493. emit('optimizerfalse',{name:'CST',wid:nowid});
  494. }else if(e.node.data.name=="ADflow"|| e.node.data.name=="RAE2822"){
  495. emit('optimizerfalse',{name:'ADflow',wid:nowid});
  496. }else if(e.node.data.name=="FFD"){
  497. emit('optimizerfalse',{name:'FFD',wid:nowid});
  498. }else if(e.node.data.name=="TACS"){
  499. emit('optimizerfalse',{name:'TACS',wid:nowid});
  500. }else if(e.node.data.name=="参数化"){
  501. emit('optimizerfalse',{name:'参数化',wid:nowid});
  502. }else if(e.node.data.name=="气动分析"){
  503. emit('optimizerfalse',{name:'气动分析',wid:nowid});
  504. }else if(onPythonlist.value.some(item => e.node.data.name.includes(item))){
  505. emit('optimizerfalse',{name:e.node.data.name,wid:nowid});
  506. }else if(e.node.data.name=="CATIA"){
  507. emit('optimizerfalse',{name:'CATIA',wid:nowid});
  508. }else if(e.node.data.name=="FSI"){
  509. emit('optimizerfalse',{name:'FSI',wid:nowid});
  510. }else if(e.node.data.name=="Flight"){
  511. emit('optimizerfalse',{name:'Flight',wid:nowid});
  512. }
  513. }
  514. let onPythonlist=ref(['Python','Branin','Rosenbrock','Rastrigin','G9','Forrester']);
  515. let previousEdge = null; // 用于保存上一个选中的边缘
  516. // 监听线
  517. function onEdgeClick(e) {
  518. console.log('Edge Click', e.edge);
  519. console.log('所有线段:',edges.value);
  520. // 如果已经有选中的边缘
  521. if (seledge.value) {
  522. // 恢复上一个选中边缘的样式
  523. if (previousEdge) {
  524. previousEdge.style = {
  525. ...previousEdge.style,
  526. stroke: previousEdge.originalColor, // 恢复原始颜色
  527. strokeWidth: previousEdge.originalWidth,// 恢复原始宽度
  528. };
  529. }
  530. }
  531. // 保存当前点击的边缘为选中边缘
  532. Edgeid.value = e.edge.id;
  533. seledge.value = e.edge;
  534. // 暂时更改当前选中边缘的样式
  535. seledge.value.originalColor = seledge.value.style.stroke; // 保存当前边缘的原始颜色
  536. seledge.value.originalWidth = seledge.value.style.strokeWidth; // 保存当前边缘的原始宽度
  537. const isProcess = e.edge.data.type === 'process';
  538. seledge.value.style = {
  539. ...seledge.value.style,
  540. stroke: isProcess ? '#2267B1' : 'rgba(255, 255, 0, 0.3)',// 设置选中边缘的颜色
  541. strokeWidth: isProcess ? 2 : 6,// 设置选中边缘的宽度
  542. };
  543. // 保存当前选中的边缘作为上一个选中边缘
  544. previousEdge = seledge.value;
  545. }
  546. let dataflowshow=ref(false);
  547. let youhuaFFDtable = ref([
  548. { name:'FFD参数(sample)', steamflag:1 }
  549. ])
  550. let youhuaCSTtable = ref([
  551. { name:"上表面CST参数(upper)", steamflag:1 },
  552. { name:'下表面CST参数(lower)', steamflag:1 }
  553. ])
  554. let steamtypeoptions = ref([
  555. { label:'约束条件', value:1 },
  556. { label:'优化目标', value:2 }
  557. ])
  558. let ADflowyouhuatable = ref([
  559. { code: "cl", name:'升力系数Cl', comtype:2 , steamflag:1, steamtype:1 },
  560. { code: "cd", name:'阻力系数Cd', comtype:2 , steamflag:1, steamtype:1 },
  561. { code: "cm", name:'力矩系数Cm', comtype:2 , steamflag:1, steamtype:1 },
  562. ])
  563. let Xfoilyouhuatable = ref([
  564. // { code:'', name:'升力系数Cl', comtype:2 , steamflag:1, steamtype:1 },
  565. // { code:'', name:'阻力系数Cd', comtype:2 , steamflag:1, steamtype:1 },
  566. // { code:'', name:'压阻力系数Cdp', comtype:2 , steamflag:1, steamtype:1 },
  567. // { code:'', name:'力矩系数Cm', comtype:2 , steamflag:1, steamtype:1 },
  568. // { code:'', name:'上表面转换点位置xtr-upper', comtype:2 , steamflag:1, steamtype:1 },
  569. // { code:'', name:'下表面转换点位置xtr-lower', comtype:2 , steamflag:1, steamtype:1 },
  570. ])
  571. let checkAll = ref(false);
  572. let isIndeterminate = ref(false);
  573. const dataTables = {
  574. '1': youhuaFFDtable,
  575. '2': youhuaCSTtable,
  576. '3': ADflowyouhuatable,
  577. '4': Xfoilyouhuatable
  578. };
  579. const handlecheckFlagchange = () => {
  580. const table = dataTables[datacontent.value];
  581. if (!table) return;
  582. let checkedCount = table.value.filter(item => Boolean(item.steamflag)).length;
  583. checkAll.value = checkedCount === table.value.length;
  584. isIndeterminate.value = checkedCount > 0 && checkedCount < table.value.length;
  585. };
  586. const handlecheckAllchange = (val) => {
  587. const table = dataTables[datacontent.value];
  588. if (!table) return;
  589. table.value.forEach(item => item.steamflag = val ? 1 : 0);
  590. isIndeterminate.value = false;
  591. };
  592. // 双击线段弹窗确认
  593. const confirmselection=()=>{
  594. const table = dataTables[datacontent.value];
  595. let checkedData = table.value.filter((item) => item.steamflag).map((item) => item.name);
  596. console.log('xuanzhongshuju:',checkedData);
  597. console.log('seledge:',seledge.value);
  598. seledge.value.label=checkedData.join('\n');
  599. // 保存数据流
  600. dataFlowsave();
  601. dataflowshow.value = false;
  602. }
  603. const xfid = ref('')
  604. const adid = ref('')
  605. // 监听组件xfoil返回的xfid
  606. const handleXfid = (xfidFromB) => {
  607. xfid.value = xfidFromB.value;
  608. noid.value.data.xfid = xfid.value;
  609. };
  610. const handleAdid = (adidFromB) => {
  611. adid.value = adidFromB.value;
  612. noid.value.data.adid = adid.value;
  613. }
  614. let datacontent = ref('')
  615. // 判定是哪种线段
  616. function onEdgeDoubleClick(e) {
  617. console.log('Edge Double Click', e)
  618. if(e.edge.data.type==='process'){
  619. console.log('逻辑流不打开弹窗');
  620. return ;
  621. }
  622. seledge.value = e.edge;
  623. // dataflowshow.value = true
  624. console.log('qidian:',e.edge.sourceNode.data.name);
  625. console.log('zhongdian:',e.edge.targetNode.data.name);
  626. let qidian = e.edge.sourceNode.data.name;
  627. let zhongdian = e.edge.targetNode.data.name;
  628. let youhualist = ['optimizer','optimizer3','optimizer1','optimizer2'];
  629. if( youhualist.includes(qidian) && zhongdian ==='FFD' ){
  630. datacontent.value = '1';
  631. dataflowshow.value = true;
  632. }else if( youhualist.includes(qidian) && zhongdian ==='CST') {
  633. datacontent.value = '2';
  634. dataflowshow.value = true;
  635. }else if( qidian === 'ADflow' && youhualist.includes(zhongdian) ) {
  636. datacontent.value = '3';
  637. // emitter.emit('requestGetadid',pid.value);
  638. adid.value = e.edge.sourceNode.data.adid;
  639. // console.log('adid:',adid.value)
  640. if(adid.value) {
  641. querydataFlow(adid);
  642. dataflowshow.value = true;
  643. }else{
  644. ElMessage.error('ADflow未初始化!')
  645. }
  646. }else if ( qidian === 'Xfoil' && youhualist.includes(zhongdian) ) {
  647. datacontent.value = '4';
  648. // emitter.emit('requestGetxfid',pid.value);
  649. xfid.value = e.edge.sourceNode.data.xfid;
  650. // console.log('xfid:',xfid.value)
  651. if(xfid.value) {
  652. querydataFlow(xfid);
  653. dataflowshow.value = true;
  654. }else{
  655. ElMessage.error('Xfoil未初始化!')
  656. }
  657. }
  658. console.log('leixing:',datacontent.value);
  659. nextTick(() => {
  660. handlecheckFlagchange();
  661. });
  662. }
  663. const querydataFlow = (comid) => {
  664. const params = {
  665. transCode: "MDO0052",
  666. pid: pid.value,
  667. comid: comid.value
  668. }
  669. request(params).then((res) => {
  670. if(datacontent.value === '3'){
  671. ADflowyouhuatable.value = res.params;
  672. handlecheckFlagchange();
  673. }
  674. if(datacontent.value === '4'){
  675. Xfoilyouhuatable.value = res.params;
  676. handlecheckFlagchange();
  677. }
  678. })
  679. .catch((err) => {
  680. ElMessage.error(err.returnMsg)
  681. })
  682. }
  683. const dataFlowsave = () => {
  684. let stringArray = '';
  685. if(datacontent.value === '3'){
  686. stringArray = convertToStringArray([],ADflowyouhuatable.value);
  687. }else if(datacontent.value === '4'){
  688. stringArray = convertToStringArray([],Xfoilyouhuatable.value);
  689. }
  690. const params = {
  691. transCode: "MDO0053",
  692. paramstr: stringArray,
  693. };
  694. request(params).then((res) => {
  695. ElMessage({
  696. message: '数据流保存成功',
  697. type: 'success',
  698. })
  699. })
  700. .catch((err) => {
  701. ElMessage.error('数据流保存失败')
  702. })
  703. }
  704. const convertToStringArray = (result, Data) => {
  705. console.log('Data:', Data);
  706. // 安全检查 Data,确保它是一个数组
  707. if (!Array.isArray(Data)) {
  708. console.error('Data should be an array');
  709. return result; // 返回原 result 或者根据需要返回其他默认值
  710. }
  711. result = Data.map(row => {
  712. // 获取每一行的 `code`, `name`, `value` 和 `flag`
  713. const paramid = row.paramid ?? ' ';
  714. const steamflag = row.steamflag ?? '';
  715. const steamtype = row.steamtype ?? ' ';
  716. // 将字段连接为一个以逗号分隔的字符串
  717. return `${paramid},${steamflag},${steamtype}`;
  718. }).join(';'); // 每行之间用分号分隔
  719. return result;
  720. }
  721. // 右键更改名字
  722. // const onContextMenu = (e) => {
  723. // e.preventDefault(); // 阻止浏览器默认的右键菜单
  724. // const node = e.target.closest(".vue-flow__node");
  725. // console.log("nodes:",nodes);
  726. // console.log("node:",node);
  727. // if (node) {
  728. // // 获取当前右键点击的节点
  729. // const nodeId = node.getAttribute("data-id");
  730. // const clickedNode = nodes.value.find((n) => n.id === nodeId);
  731. // console.log("clickedNode:",clickedNode);
  732. // if (clickedNode) {
  733. // noid.value = clickedNode;
  734. // changeName.value.name = clickedNode.label; // 将当前节点的label放入弹窗中
  735. // changeNameshow.value = true; // 显示弹窗
  736. // }
  737. // }
  738. // };
  739. onInit((vueFlowInstance) => {
  740. vueFlowInstance.fitView()
  741. })
  742. onNodeDragStop(({ event, nodes, node }) => {
  743. console.log(nodes)
  744. Nested.value=nodes;
  745. console.log('Node Drag Stop', { event, nodes, node })
  746. })
  747. // onConnect((connection) => {
  748. // addEdges(connection)
  749. // console.log('Connection', connection)
  750. // })
  751. function updatePos() {
  752. nodes.value = nodes.value.map((node) => {
  753. return {
  754. ...node,
  755. position: {
  756. x: Math.random() * 400,
  757. y: Math.random() * 400,
  758. },
  759. }
  760. })
  761. }
  762. function removeEdge(id) {
  763. if(!seledge.value){
  764. return;
  765. }
  766. id = Edgeid.value;
  767. const wid = seledge.value.data.wid;
  768. vueFlowRef.value.removeEdges(id);
  769. deleteflow(wid);
  770. seledge.value=null;
  771. console.log('msg:',datatree.value);
  772. }
  773. // 触摸
  774. const onDrop1=(event)=>{
  775. onDrop(event);
  776. emitter.emit('doSomethingEvent');
  777. }
  778. function removeNode(id) {
  779. id = noid.value.id;
  780. const wid = noid.value.data.wid;
  781. console.log('removeNodewid:',wid);
  782. if(datatree.value==undefined){
  783. if(nodes.value.length>0){
  784. for (let i = 0; i <nodes.value.length; i++) {
  785. if(id==nodes.value[i].id){
  786. console.log(44444)
  787. console.log( nodes.value[i]);
  788. nodes.value.splice(i, 1)
  789. deleteflow(wid);
  790. }
  791. }
  792. console.log( nodes.value);
  793. }
  794. }else{
  795. if(nodes.value.length>0){
  796. for (let i = 0; i <nodes.value.length; i++) {
  797. if(id==nodes.value[i].id){
  798. console.log( nodes.value[i]);
  799. nodes.value.splice(i, 1)
  800. }
  801. }
  802. }
  803. for (let i = 0; i <datatree.value[0].children.length; i++) {
  804. if(id.includes(datatree.value[0].children[i].Text)){
  805. for (let j = 0; j <datatree.value[0].children[i].children.length; j++) {
  806. if(id==datatree.value[0].children[i].children[j].id){
  807. //datatree.value[0].children.splice(datatree.value[0].children[i].children[j], 1);
  808. datatree.value[0].children[i].children.splice(j, 1);
  809. deleteflow(wid);
  810. vueFlowRef.value.removeNodes(id);
  811. removeRelatedEdges(id);
  812. }
  813. }
  814. }
  815. }
  816. }
  817. }
  818. function removeRelatedEdges(nodeId) {
  819. //过滤出与该节点相关的连线
  820. const relatedEdges = edges.value.filter(
  821. (edge) => edge.source === nodeId || edge.target === nodeId
  822. );
  823. // 遍历删除关联的连线
  824. relatedEdges.forEach((edge) => {
  825. if (edge.data && edge.data.wid) {
  826. deleteflow(edge.data.wid);
  827. }
  828. });
  829. }
  830. // 删除提示
  831. const confirmDelete = () => {
  832. ElMessageBox.confirm(
  833. '确定要删除全部吗?删除后不可恢复!',
  834. '删除确认',
  835. {
  836. confirmButtonText: '确定',
  837. cancelButtonText: '取消',
  838. type: 'warning',
  839. }
  840. )
  841. .then(() => {
  842. removeall();
  843. })
  844. .catch(() => {
  845. ElMessage({
  846. type: 'info',
  847. message: '已取消删除',
  848. })
  849. })
  850. }
  851. function removeall() {
  852. try {
  853. const allnodes = nodes.value;
  854. const allEdges = edges.value;
  855. for (let i = 0; i < allnodes.length; i++) {
  856. if (allnodes[i].data.wid) {
  857. deleteflow(allnodes[i].data.wid);
  858. }
  859. }
  860. for (let i = 0; i < allEdges.length; i++) {
  861. if (allEdges[i].data.wid) {
  862. deleteflow(allEdges[i].data.wid);
  863. }
  864. }
  865. nodes.value = []
  866. edges.value = []
  867. Nested2.value = []
  868. Nested.value = []
  869. // 判断 datatree 是否为空或未定义
  870. if (!datatree.value || datatree.value.length === 0 || !datatree.value[0]?.children) {
  871. console.warn('datatree 数据为空或未定义')
  872. ElMessage({
  873. type: 'warning',
  874. message: '没有数据可以删除'
  875. })
  876. return
  877. }
  878. // 清空 datatree 的 children
  879. for (let i = 0; i < datatree.value[0].children.length; i++) {
  880. if (datatree.value[0]?.children[i]?.children) {
  881. datatree.value[0].children[i].children = []
  882. }
  883. }
  884. } catch (error) {
  885. console.error('删除失败:', error)
  886. ElMessage({
  887. type: 'error',
  888. message: '删除过程中出错'
  889. })
  890. }
  891. }
  892. // 流查询
  893. const queryflow = () => {
  894. const params = {
  895. transCode: 'MDO0057',
  896. pid: pid.value,
  897. }
  898. request(params)
  899. .then((res) => {
  900. console.log(res);
  901. })
  902. .catch((err) => {
  903. ElMessage.error(err.returnMsg)
  904. })
  905. }
  906. // 保存流
  907. const saveflow = async (pid,wid, uid, type, fromuid, touid) => {
  908. const params = {
  909. transCode: 'MDO0058',
  910. pid: pid || '',
  911. wid: wid || '', // 流ID
  912. uid: uid || '',
  913. type: type || '',
  914. fromuid: fromuid || '',
  915. touid: touid || '',
  916. };
  917. try {
  918. // 直接使用 await 等待 request 返回
  919. const res = await request(params);
  920. return res.wid; // 返回 wid
  921. } catch (err) {
  922. // 处理错误
  923. ElMessage.error(err.returnMsg || '保存流程失败');
  924. }
  925. };
  926. // async function saveFlowExample() {
  927. // try {
  928. // const wid = await saveflow('flow123', 'user001', 'process', 'fromA', 'toB');
  929. // console.log('返回的 wid:', wid);
  930. // } catch (err) {
  931. // console.error('保存流程失败:', err.message);
  932. // }
  933. // }
  934. // saveFlowExample();
  935. // 删除流
  936. const deleteflow = (nowid) => {
  937. const params = {
  938. transCode: 'MDO0059',
  939. wid: nowid,
  940. }
  941. request(params)
  942. .then((res) => {
  943. console.log(res);
  944. })
  945. .catch((err) => {
  946. ElMessage.error('删除流程失败')
  947. })
  948. }
  949. async function logToObject1() {
  950. let obj = { nodes: toObject().nodes,edges:toObject().edges };
  951. mergedObj.value=JSON.stringify(obj);
  952. try {
  953. const container = vueFlowRef.value.$el;
  954. const canvas = await html2canvas(container);
  955. const img = canvas.toDataURL('image/png');
  956. // 创建一个图片元素并设置src属性为转换后的图片数据
  957. vueflowimg.value=img
  958. if(vueflowimg.value!=''){
  959. console.log("进入了")
  960. addflow();
  961. }
  962. // 添加到DOM中或者做其他操作
  963. } catch (error) {
  964. console.error('转换出错:', error);
  965. }
  966. }
  967. //添加接口
  968. const addflow = () => {
  969. const savedObj = JSON.parse(sessionStorage.getItem("objlist"));
  970. const stypeValue = savedObj ? savedObj.stype : '';
  971. // 用于首页主界面切换数据一致
  972. const updateobjlist = {
  973. pid: pid.value,
  974. name: newobj.value.name,
  975. remark: newobj.value.description,
  976. image: vueflowimg.value,
  977. isshare: '1',
  978. flow: mergedObj.value,
  979. stype: stypeValue,
  980. }
  981. sessionStorage.setItem("objlist",JSON.stringify(updateobjlist));
  982. console.log("打印stypeValue:",stypeValue);
  983. const params = {
  984. transCode: 'MDO0002',
  985. pid: pid.value,
  986. name: newobj.value.name,
  987. remark:newobj.value.description,
  988. image:vueflowimg.value,
  989. isshare:'1',
  990. flow:mergedObj.value ,
  991. stype:stypeValue,
  992. }
  993. console.log(params);
  994. request(params)
  995. .then((res) => {
  996. console.log(res);
  997. ElMessage({
  998. message: '工程保存成功',
  999. type: 'success',
  1000. })
  1001. })
  1002. .catch((err) => {
  1003. ElMessage.error(err.returnMsg)
  1004. })
  1005. }
  1006. /**
  1007. * Resets the current viewport transformation (zoom & pan)
  1008. */
  1009. function resetTransform() {
  1010. setViewport({ x: 0, y: 0, zoom: 1 })
  1011. }
  1012. function toggleDarkMode() {
  1013. dark.value = !dark.value;
  1014. if(dark.value){
  1015. iconcolor.value='#fff'
  1016. }else{
  1017. iconcolor.value='#000'
  1018. }
  1019. }
  1020. // 禁用右键菜单的函数
  1021. const onNodeContextMenu1 = (event) => {
  1022. event.preventDefault();
  1023. };
  1024. onMounted(() => {
  1025. setTimeout(function() {
  1026. getroter();
  1027. }, 1500);
  1028. // childfun();
  1029. // 点击其他区域取消线段选中
  1030. if (vueFlowRef.value) {
  1031. vueFlowRef.value.$el.addEventListener('click', (event) => {
  1032. // 确保点击的不是边缘
  1033. if (seledge.value && !event.target.closest('.vue-flow__edge')) {
  1034. cleanEdgeselect();
  1035. }
  1036. });
  1037. }
  1038. document.addEventListener('contextmenu', onNodeContextMenu1);
  1039. emitter.on("xfidFromxfoil", handleXfid);
  1040. emitter.on("adidFromadflow", handleAdid);
  1041. });
  1042. const cleanEdgeselect = () => {
  1043. if(seledge.value) {
  1044. // 恢复选中边缘的原始样式
  1045. seledge.value.style = {
  1046. ...seledge.value.style,
  1047. stroke: seledge.value.originalColor,
  1048. strokeWidth: previousEdge?.originalWidth || 1, // 恢复原始宽度
  1049. };
  1050. // 清空选中的边缘
  1051. seledge.value = null;
  1052. Edgeid.value = null;
  1053. previousEdge = null;
  1054. }
  1055. }
  1056. // 在组件销毁前移除右键菜单禁用
  1057. onBeforeUnmount(() => {
  1058. document.removeEventListener('contextmenu', onNodeContextMenu1);
  1059. });
  1060. onUnmounted(() => {
  1061. emitter.off('child2Data');
  1062. emitter.off("xfidFromxfoil", handleXfid);
  1063. emitter.off("adidFromadflow", handleAdid);
  1064. });
  1065. // 获取链接
  1066. const getroter=()=>{
  1067. //datatree.value[0].children=[];
  1068. let objlist=JSON.parse(sessionStorage.getItem("objlist"));
  1069. if(objlist.flow!=''){
  1070. let nodesflow=JSON.parse(objlist.flow)
  1071. nodes.value=nodesflow.nodes;
  1072. edges.value=nodesflow.edges;
  1073. }
  1074. newobj.value.name=objlist.name;
  1075. newobj.value.description=objlist.remark;
  1076. pid.value=objlist.pid;
  1077. // let item={
  1078. // id:'1-0',
  1079. // label: objlist.name,
  1080. // img:r2,
  1081. // }
  1082. // console.log( datatree.value[0].children);
  1083. // datatree.value[0].children.push(item);
  1084. }
  1085. //改变线的粗
  1086. const linestrokeWidth=(type)=>{
  1087. if(type=='process'){
  1088. linenum.value=1;
  1089. linecolor.value = '#b1b1b7';
  1090. lineType.value = 'process';
  1091. }else if(type=='data'){
  1092. linenum.value=6;
  1093. linecolor.value = "rgba(150, 150, 150, 0.2)";
  1094. lineType.value = 'data';
  1095. }
  1096. }
  1097. //改变线的颜色
  1098. const changeAllEdgesColor = (color1) => {
  1099. console.log('yanse:', color1);
  1100. linecolor.value = color1;
  1101. // 找到当前选中的边缘
  1102. if (seledge.value) {
  1103. // 更新该边缘的颜色
  1104. let newColor = linecolor.value;
  1105. // 如果选中的线 `linetype` 是 `data`,则增加透明度 0.3
  1106. if (seledge.value.data.type === 'data') {
  1107. newColor = convertToRGBA(linecolor.value, 0.3);
  1108. }
  1109. const updatedEdge = {
  1110. ...seledge.value,
  1111. style: {
  1112. ...seledge.value.style,
  1113. stroke: newColor, // 只修改颜色
  1114. }
  1115. };
  1116. // 更新 edges 数组
  1117. const updatedEdges = edges.value.map(edge =>
  1118. edge.id === seledge.value.id ? updatedEdge : edge
  1119. );
  1120. edges.value = updatedEdges; // 持久化修改后的边缘
  1121. }
  1122. };
  1123. // 颜色转换函数:将 Hex / RGB 转换为 RGBA
  1124. const convertToRGBA = (color, alpha) => {
  1125. if (color.startsWith('#')) {
  1126. // 处理 Hex 颜色(例如 #ff0000 转换为 rgba(255, 0, 0, 0.3))
  1127. const r = parseInt(color.substring(1, 3), 16);
  1128. const g = parseInt(color.substring(3, 5), 16);
  1129. const b = parseInt(color.substring(5, 7), 16);
  1130. return `rgba(${r}, ${g}, ${b}, ${alpha})`;
  1131. } else if (color.startsWith('rgb')) {
  1132. // 处理 RGB 颜色,替换透明度
  1133. return color.replace(/rgb(a?)\(([^)]+)\)/, `rgba($2, ${alpha})`);
  1134. }
  1135. return color; // 默认返回原始颜色(避免报错)
  1136. };
  1137. watch(() => seledge.value, (newItems, oldItems) => {
  1138. if(seledge.value!=null){
  1139. // seledge.value.style.stroke = linecolor.value;
  1140. }
  1141. });
  1142. defineExpose({changeAllEdgesColor,linestrokeWidth,getroter,onSelection,bgcolorfunc,logToObject1});
  1143. </script>
  1144. <style>
  1145. /* .vue-flow__edge.selected .vue-flow__edge-path, .vue-flow__edge:focus .vue-flow__edge-path, .vue-flow__edge:focus-visible .vue-flow__edge-path {
  1146. stroke: #555 !important;
  1147. } */
  1148. .vue-flow__edge:focus .vue-flow__edge-path, .vue-flow__edge:focus-visible .vue-flow__edge-path {
  1149. stroke: #555 !important;
  1150. }
  1151. .vue-flow__edge {
  1152. text-align: left;
  1153. /* 设置edges的左对齐 */
  1154. }
  1155. .vue-flow__edge-text {
  1156. transform: translateY(-10px); /* 将 label 向上偏移 */
  1157. background: transparent !important;
  1158. font-size: 8px;
  1159. font-family: 'Microsoft YaHei';
  1160. color: #333333;
  1161. }
  1162. .vue-flow__edge-textbg {
  1163. fill: transparent !important; /* 将背景设置为透明 */
  1164. }
  1165. #contextMenu {
  1166. display: none;
  1167. position: absolute;
  1168. background-color: #fff;
  1169. border-radius: 5px;
  1170. padding: 10px;
  1171. text-align: center;
  1172. color: black;
  1173. font-size: 14px;
  1174. font-weight: 400;
  1175. cursor: pointer;
  1176. z-index: 99999;
  1177. }
  1178. .vue-flow__node-default.selectable:hover,
  1179. .vue-flow__node-input.selectable:hover,
  1180. .vue-flow__node-output.selectable:hover {
  1181. box-shadow: none;
  1182. }
  1183. panel {
  1184. cursor: pointer;
  1185. position: absolute;
  1186. z-index: 100000;
  1187. }
  1188. .remove {
  1189. background: #fff;
  1190. color: #666;
  1191. margin: 0 10px;
  1192. font-size: 12px;
  1193. }
  1194. .vue-flow__node-default, .vue-flow__node-input, .vue-flow__node-output{
  1195. /* width: auto !important; */
  1196. border: none;
  1197. background-color: rgba(0,0,0,0);
  1198. }
  1199. .node-content {
  1200. cursor: move; /* 更改鼠标光标表示可拖动 */
  1201. }
  1202. .vue-flow__node {
  1203. cursor: move;
  1204. }
  1205. /* 禁用文本选中效果 */
  1206. .left_main * {
  1207. -webkit-user-select: none; /* Safari */
  1208. -moz-user-select: none; /* Firefox */
  1209. -ms-user-select: none; /* IE10+/Edge */
  1210. user-select: none; /* Standard syntax */
  1211. }
  1212. .lableaniu{
  1213. font-size: 12px;
  1214. background-color: #ddd;
  1215. padding: 4px 16px;
  1216. /* margin-top: -17px; */
  1217. margin-left: 5px;
  1218. margin-top: 0px;
  1219. border-radius: 1px;
  1220. }
  1221. .vue-flow__controls-button svg{
  1222. max-width: 16px;
  1223. max-height: 16px;
  1224. }
  1225. .field{
  1226. display: flex;
  1227. }
  1228. </style>