index.vue 40 KB

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