index.vue 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086
  1. <template>
  2. <VueFlow ref="vueFlowRef" :nodes="nodes" :edges="edges" :class="{ dark }"
  3. class="basic-flow"
  4. :default-viewport="{ zoom: 1.5 }" :min-zoom="0.2" :max-zoom="2.5" @drop="onDrop1"
  5. @contextmenu.prevent="onContextMenu" @node-contextmenu="logEvent('contextmenu', $event)"
  6. @dragover="onDragOver" @dragleave="onDragLeave" @edge-click="onEdgeClick" @node-double-click="onNodeDoubleClick"
  7. @node-click="onNodeClick" @edge-double-click="onEdgeDoubleClick">
  8. <template #node-default="props">
  9. <eltree :node="props" />
  10. </template>
  11. <Background pattern-color="#aaa" :gap="16" />
  12. <!-- <MiniMap /> @input="handleUpdate"-->
  13. <Panel :position="'right'" style="display: none;">
  14. <div class="field">
  15. <div>
  16. <label for="label">Label:</label>
  17. <input id="label" v-model.lazy="labelname" /></div>
  18. <button @click="handleUpdate" class="lableaniu">确定</button>
  19. </div>
  20. <!-- <div> -->
  21. <!-- <button class="remove" @click="removeNode(event)">N</button>
  22. <button class="remove" @click="removeEdge(event)">E</button>
  23. <button class="remove" @click="removeall(event)">all</button>
  24. </div> -->
  25. <!-- <button @click="onSelection()" class="lableaniu">获取</button> -->
  26. </Panel>
  27. <Controls position="top-left">
  28. <ControlButton title="重置" @click="resetTransform">
  29. <Icon name="reset" />
  30. </ControlButton>
  31. <ControlButton title="背景切换" @click="toggleDarkMode">
  32. <Icon v-if="dark" name="sun" />
  33. <Icon v-else name="moon" />
  34. </ControlButton>
  35. <ControlButton title="保存" @click="logToObject1">
  36. <!-- <Icon name="log" /> -->
  37. <el-icon :color="iconcolor"><UploadFilled /></el-icon>
  38. </ControlButton>
  39. <ControlButton title="删除节点" @click="removeNode()">
  40. <el-icon :color="iconcolor"><DocumentDelete /></el-icon>
  41. </ControlButton>
  42. <ControlButton title="删除线" @click="removeEdge()">
  43. <el-icon :color="iconcolor"><Crop /></el-icon>
  44. </ControlButton>
  45. <ControlButton title="清空全部" @click="removeall()">
  46. <el-icon :color="iconcolor"><DeleteFilled /></el-icon>
  47. </ControlButton>
  48. </Controls>
  49. <el-dialog v-model="changeNameshow" align-center :modal="false" :close-on-click-modal="false"
  50. :append-to-body="true" draggable :fullscreen="false" :modal-append-to-body="false" modal-class="summary-dlg"
  51. width="400" class="dialog_class bgcolor colortext tianjia sel">
  52. <template #header="{ titleId, titleClass }">
  53. <div class="my-header ">
  54. <h4 :id="titleId" :class="titleClass">修改名称</h4>
  55. </div>
  56. </template>
  57. <div style="margin-top: 20px;padding: 20px;">
  58. <el-form :model="changeName" label-width="100px" class="demo-ruleForm">
  59. <el-form-item label="新名称:" prop="name">
  60. <el-input v-model="changeName.name" placeholder="请输入名称"></el-input>
  61. </el-form-item>
  62. </el-form>
  63. </div>
  64. <template #footer>
  65. <div class="dialog-footer">
  66. <el-button @click="changeNameshow = false">取 消</el-button>
  67. <el-button type="primary" @click="handleUpdate">确 定</el-button>
  68. </div>
  69. </template>
  70. </el-dialog>
  71. <!-- 双击线段 -->
  72. <el-dialog v-model="dataflowshow" align-center :modal="false" :close-on-click-modal="false"
  73. :append-to-body="true" draggable :fullscreen="false" :modal-append-to-body="false" modal-class="summary-dlg"
  74. width="500" class="dialog_style bgcolor colortext tianjia sel">
  75. <template #header="{ titleId, titleClass }">
  76. <div class="my-header ">
  77. <h4 :id="titleId" :class="titleClass">数据流</h4>
  78. </div>
  79. </template>
  80. <div style="margin-top: 5px;padding: 10px 35px;">
  81. <div v-if="datacontent === '1'">
  82. <el-card :shadow="none" style="min-height: 240px; max-height: 480px;">
  83. <el-checkbox v-model="checkAll"
  84. :indeterminate="isIndeterminate"
  85. @change="handlecheckAllchange">全选</el-checkbox>
  86. <div class="eldesign classtable">
  87. <el-table :data="youhuaFFDtable" border :show-header="false">
  88. <el-table-column
  89. type="index"
  90. label=""
  91. ></el-table-column>
  92. <el-table-column prop="steamflag" width="55">
  93. <template #default="{ row }">
  94. <el-checkbox
  95. :false-label="0"
  96. :true-label="1"
  97. v-model="row.steamflag"
  98. @change="handlecheckFlagchange"></el-checkbox>
  99. </template>
  100. </el-table-column>
  101. <el-table-column prop="name" label="" ></el-table-column>
  102. </el-table>
  103. </div>
  104. </el-card>
  105. </div>
  106. <div v-if="datacontent === '2'">
  107. <el-card :shadow="none" style="min-height: 240px; max-height: 480px;">
  108. <el-checkbox v-model="checkAll"
  109. :indeterminate="isIndeterminate"
  110. @change="handlecheckAllchange">全选</el-checkbox>
  111. <div class="eldesign classtable">
  112. <el-table :data="youhuaCSTtable" border :show-header="false">
  113. <el-table-column
  114. type="index"
  115. label=""
  116. ></el-table-column>
  117. <el-table-column prop="steamflag" width="55">
  118. <template #default="{ row }">
  119. <el-checkbox
  120. :false-label="0"
  121. :true-label="1"
  122. v-model="row.steamflag"
  123. @change="handlecheckFlagchange"></el-checkbox>
  124. </template>
  125. </el-table-column>
  126. <el-table-column prop="name" label="" ></el-table-column>
  127. </el-table>
  128. </div>
  129. </el-card>
  130. </div>
  131. <div v-if="datacontent === '3'">
  132. <el-card :shadow="none" style="min-height: 240px; max-height: 480px;">
  133. <el-checkbox v-model="checkAll"
  134. :indeterminate="isIndeterminate"
  135. @change="handlecheckAllchange">全选</el-checkbox>
  136. <div class="eldesign classtable">
  137. <el-table :data="ADflowyouhuatable" border :show-header="false">
  138. <el-table-column
  139. type="index"
  140. label=""
  141. ></el-table-column>
  142. <el-table-column prop="steamflag" width="55">
  143. <template #default="{ row }">
  144. <el-checkbox
  145. :false-label="0"
  146. :true-label="1"
  147. v-model="row.steamflag"
  148. @change="handlecheckFlagchange"></el-checkbox>
  149. </template>
  150. </el-table-column>
  151. <el-table-column prop="name" label="" ></el-table-column>
  152. <el-table-column prop="steamtype">
  153. <template #default="{ row }">
  154. <el-select v-model="row.steamtype">
  155. <el-option
  156. v-for="item in steamtypeoptions"
  157. :key="item.value"
  158. :label="item.label"
  159. :value="item.value"
  160. />
  161. </el-select>
  162. </template>
  163. </el-table-column>
  164. </el-table>
  165. </div>
  166. </el-card>
  167. </div>
  168. <div v-if="datacontent === '4'">
  169. <el-card :shadow="none" style="min-height: 240px; max-height: 480px;">
  170. <el-checkbox v-model="checkAll"
  171. :indeterminate="isIndeterminate"
  172. @change="handlecheckAllchange">全选</el-checkbox>
  173. <div class="eldesign classtable">
  174. <el-table :data="Xfoilyouhuatable" border :show-header="false">
  175. <el-table-column
  176. type="index"
  177. label=""
  178. ></el-table-column>
  179. <el-table-column prop="steamflag" width="55">
  180. <template #default="{ row }">
  181. <el-checkbox
  182. :false-label="0"
  183. :true-label="1"
  184. v-model="row.steamflag"
  185. @change="handlecheckFlagchange"></el-checkbox>
  186. </template>
  187. </el-table-column>
  188. <el-table-column prop="name" label="" show-overflow-tooltip></el-table-column>
  189. <el-table-column prop="steamtype">
  190. <template #default="{ row }">
  191. <el-select v-model="row.steamtype">
  192. <el-option
  193. v-for="item in steamtypeoptions"
  194. :key="item.value"
  195. :label="item.label"
  196. :value="item.value"
  197. />
  198. </el-select>
  199. </template>
  200. </el-table-column>
  201. </el-table>
  202. </div>
  203. </el-card>
  204. </div>
  205. </div>
  206. <template #footer>
  207. <div class="dialog-footer">
  208. <el-button @click="dataflowshow = false">取 消</el-button>
  209. <el-button type="primary" @click="confirmselection();dataflowshow = false ">确 定</el-button>
  210. </div>
  211. </template>
  212. </el-dialog>
  213. </VueFlow>
  214. <div class="dnd-flow">
  215. <!-- <div id="contextMenu" @click="deleteItemConfirm">删除</div> -->
  216. </div>
  217. </template>
  218. <script setup>
  219. import { ref, markRaw,inject } from 'vue'
  220. import { VueFlow,Panel, useVueFlow, MarkerType} from '@vue-flow/core'
  221. import { ElMessage, ElButton, ElDialog, ElSelect } from 'element-plus'
  222. import {
  223. DocumentDelete,
  224. Delete,
  225. UploadFilled,
  226. Histogram,
  227. DeleteFilled,
  228. Crop,
  229. } from '@element-plus/icons-vue'
  230. import { useRoute } from 'vue-router';
  231. import { request, uploadFile } from "@/utils/request";
  232. import { Background } from '@vue-flow/background'
  233. import { ControlButton, Controls } from '@vue-flow/controls'
  234. import { initialEdges, initialNodes } from './modeljs.js'
  235. import { MiniMap } from '@vue-flow/minimap'
  236. import "./main.css";//重置样式
  237. import DropzoneBackground from './DropzoneBackground.vue'
  238. import eltree from './eltree.vue'
  239. import CustomEdge from './CustomEdge.vue';
  240. import useDragAndDrop from './useDnD';
  241. import f11 from '@/assets/img/f11.png'
  242. import r2 from '@/assets/img/r2.png'
  243. import html2canvas from 'html2canvas';
  244. import Icon from './Icon.vue'
  245. import { formatTime } from '@/js/lindex.js';
  246. import emitter from "@/utils/emitter";
  247. // import func from 'vue-temp/vue-editor-bridge.js';
  248. const dark = ref(false)
  249. let datatree=ref();
  250. const route = useRoute();
  251. const { onInit, onNodeDragStop, onNodeContextMenu, onConnect, addEdges, setViewport, toObject,addNode } = useVueFlow()
  252. let vueFlowRef = ref();
  253. let emit = defineEmits(['optimizerfalse']);
  254. let mergedObj=ref();
  255. let labelname=ref();
  256. let iconcolor=ref('#000')
  257. const props = defineProps({
  258. optimizer: {
  259. type: Boolean,
  260. },
  261. jboptimizer: {
  262. type: Boolean,
  263. },
  264. Xfoil: {
  265. type: Boolean,
  266. },
  267. // color1: {
  268. // type: String,
  269. // },
  270. })
  271. let newobj=ref({
  272. name:'',
  273. description:'',
  274. })
  275. let nodesitem=ref([]);
  276. let linenum=ref(1);
  277. let bgcolor=ref();
  278. let linecolor=ref('#b1b1b7')
  279. let pid=ref('');
  280. let newroter=ref();
  281. let vueflowimg=ref('');
  282. const shopShow = ref(false);
  283. let noid = ref([]);
  284. let Edgeid = ref();
  285. let seledge=ref(null);
  286. let djshow=ref(false);
  287. let node = ref();
  288. let contextMenu = ref({
  289. position: { x: 0, y: 0 },
  290. target: 'kong',
  291. })
  292. let Nested=ref([]);
  293. let Nested2=ref([]);
  294. let nnum=ref(0);
  295. const { onDragOver, onDrop, onDragLeave, isDragOver } = useDragAndDrop();
  296. const edges = ref([]);
  297. const nodes = ref([]);
  298. const changeNameshow = ref(false);
  299. const changeName = ref({
  300. name: '',
  301. })
  302. onNodeContextMenu((e) => {
  303. noid.value = e.node;
  304. changeName.value.name = e.node.data.label;
  305. changeNameshow.value = true;
  306. })
  307. onConnect((connection) => {
  308. console.log(connection);
  309. connection.type = 'smoothstep';// smoothstep straight
  310. connection.markerEnd = MarkerType.ArrowClosed;
  311. connection.color=linecolor.value;
  312. // connection.label = '这是一条注释';
  313. connection.style = { strokeWidth:linenum.value ,stroke:linecolor.value};
  314. addEdges(connection)
  315. seledge.value=null;
  316. })
  317. //修改名称
  318. const handleUpdate = () => {
  319. if (noid.value && noid.value.data) {
  320. noid.value.data.label = changeName.value.name; // 更新名称
  321. console.log(noid.value.data.label); // 打印更新后的值
  322. } else {
  323. console.error("noid.value 或 noid.value.data 未定义"); // 错误日志
  324. }
  325. changeNameshow.value = false; // 更新后关闭对话框
  326. // noid.value.data.label = labelname;
  327. };
  328. emitter.on('child2Data', data => {
  329. datatree.value = data;
  330. console.log(datatree.value);
  331. })
  332. function onNodeClick(e) {
  333. noid.value = e.node;
  334. changeName.value.name=e.node.data.label;
  335. console.log("shuju:",e.node.data);
  336. console.log("noid.value:",noid.value);
  337. console.log("changeName.value:",changeName.value.name);
  338. djshow.value = !djshow.value;
  339. // if(djshow.value){
  340. // console.log('选中');
  341. // }else{
  342. // console.log('取消选中');
  343. // }
  344. }
  345. //模块化
  346. const bgcolorfunc= (color)=>{
  347. bgcolor.value=color;
  348. if(noid.value.style!=undefined){
  349. console.log(noid.value.style);
  350. noid.value.style.backgroundColor=color;
  351. }
  352. }
  353. function onSelection(){
  354. let positionX=[];
  355. let positiony=[];
  356. for(let i=0;i<Nested.value.length;i++){
  357. // Nested2.value.push(Nested.value[i]);
  358. positionX.push(Nested.value[i].position.x)
  359. positiony.push(Nested.value[i].position.y)
  360. }
  361. let xmin=Math.min(...positionX);
  362. let ymax=Math.max(...positiony);
  363. console.log(positionX);
  364. // console.log( positionX)
  365. // console.log(44444)
  366. // console.log( positiony)
  367. nnum.value++;
  368. // let x=Math.floor(Math.random() * 91) + 10;
  369. // let y=Math.floor(Math.random() * 91) + 10;
  370. let name='模块'+nnum.value
  371. let item= {
  372. id:nnum.value.toString(),
  373. data: { label:name },
  374. position: { x:xmin , y:ymax},
  375. style: { backgroundColor: bgcolor.value, width: '200px',height: '200px' },
  376. //children: [],
  377. }
  378. if(Nested.value.length!=0){
  379. Nested2.value=[];
  380. for(let i=0;i<Nested.value.length;i++){
  381. Nested2.value.push(Nested.value[i]);
  382. }
  383. console.log(Nested2.value);
  384. nodesitem.value= Nested2.value.map(node => {
  385. if(node.parentNode==undefined){
  386. node.isParent=false;
  387. node.parentNode=item.id;
  388. console.log( node.parentNode)
  389. node.position.x= node.position.x /2;
  390. node.position.y= node.position.y/2;
  391. node.expandParent=true;
  392. //positionxy=node.position;
  393. // node.extent='parent';
  394. // return node;
  395. }
  396. return node;
  397. })
  398. }
  399. nodes.value.push(item)
  400. for(let i=0;i<nodesitem.value.length;i++){
  401. console.log(nodesitem.value[i]);
  402. nodes.value.push(nodesitem.value[i])
  403. }
  404. console.log( nodes.value);
  405. }
  406. function onNodeDoubleClick(e) {
  407. noid.value = e.node;
  408. console.log( e.node.data.name);
  409. if (e.node.data.name == '优化器') {
  410. emit('optimizerfalse','优化器');
  411. }else if(e.node.data.name=="进化优化器"){
  412. emit('optimizerfalse','进化优化器');
  413. }else if(e.node.data.name=="代理优化器"){
  414. emit('optimizerfalse','代理优化器');
  415. }else if(e.node.data.name=="Xfoil"){
  416. emit('optimizerfalse','Xfoil');
  417. }else if(e.node.data.name=="梯度优化器"){
  418. emit('optimizerfalse','梯度优化器');
  419. }else if(e.node.data.name=="CST"){
  420. emit('optimizerfalse','CST');
  421. }else if(e.node.data.name=="ADflow"){
  422. emit('optimizerfalse','ADflow');
  423. }else if(e.node.data.name=="FFD"){
  424. emit('optimizerfalse','FFD');
  425. }else if(e.node.data.name=="TACS"){
  426. emit('optimizerfalse','TACS');
  427. }else if(e.node.data.name=="参数化"){
  428. emit('optimizerfalse','参数化');
  429. }else if(e.node.data.name=="气动分析"){
  430. emit('optimizerfalse','气动分析');
  431. }else if(onPythonlist.value.some(item => e.node.data.name.includes(item))){
  432. emit('optimizerfalse','Python');
  433. }else if(e.node.data.name=="CATIA"){
  434. emit('optimizerfalse','CATIA');
  435. }else if(e.node.data.name=="FSI"){
  436. emit('optimizerfalse','FUM to FEM');
  437. }else if(e.node.data.name=="Flight"){
  438. emit('optimizerfalse','Flight');
  439. }
  440. }
  441. let onPythonlist=ref(['Python','Branin','Rosenbrock','Rastrigin','G9','Forrester']);
  442. let previousEdge = null; // 用于保存上一个选中的边缘
  443. // 监听线
  444. function onEdgeClick(e) {
  445. // 如果已经有选中的边缘
  446. if (seledge.value) {
  447. // 恢复上一个选中边缘的样式
  448. if (previousEdge) {
  449. previousEdge.style = {
  450. ...previousEdge.style,
  451. stroke: previousEdge.originalColor, // 恢复原始颜色
  452. strokeWidth: previousEdge.originalWidth,// 恢复原始宽度
  453. };
  454. }
  455. }
  456. // 保存当前点击的边缘为选中边缘
  457. Edgeid.value = e.edge.id;
  458. seledge.value = e.edge;
  459. // 暂时更改当前选中边缘的样式
  460. seledge.value.originalColor = seledge.value.style.stroke; // 保存当前边缘的原始颜色
  461. seledge.value.originalWidth = seledge.value.style.strokeWidth; // 保存当前边缘的原始宽度
  462. seledge.value.style = {
  463. ...seledge.value.style,
  464. stroke: '#2267B1', // 设置选中边缘的颜色
  465. strokeWidth: 2, // 设置选中边缘的宽度
  466. };
  467. // 保存当前选中的边缘作为上一个选中边缘
  468. previousEdge = seledge.value;
  469. }
  470. let dataflowshow=ref(false);
  471. let youhuaFFDtable = ref([
  472. { name:'FFD参数(sample)', steamflag:1 }
  473. ])
  474. let youhuaCSTtable = ref([
  475. { name:"上表面CST参数(upper)", steamflag:1 },
  476. { name:'下表面CST参数(lower)', steamflag:1 }
  477. ])
  478. let steamtypeoptions = ref([
  479. { label:'约束条件', value:1 },
  480. { label:'优化目标', value:2 }
  481. ])
  482. let ADflowyouhuatable = ref([
  483. { code: "cl", name:'升力系数Cl', comtype:2 , steamflag:1, steamtype:1 },
  484. { code: "cd", name:'阻力系数Cd', comtype:2 , steamflag:1, steamtype:1 },
  485. { code: "cm", name:'力矩系数Cm', comtype:2 , steamflag:1, steamtype:1 },
  486. { code: " ", name:'体积', comtype:2 , steamflag:1, steamtype:1 },
  487. ])
  488. let Xfoilyouhuatable = ref([
  489. // { code:'', name:'升力系数Cl', comtype:2 , steamflag:1, steamtype:1 },
  490. // { code:'', name:'阻力系数Cd', comtype:2 , steamflag:1, steamtype:1 },
  491. // { code:'', name:'压阻力系数Cdp', comtype:2 , steamflag:1, steamtype:1 },
  492. // { code:'', name:'力矩系数Cm', comtype:2 , steamflag:1, steamtype:1 },
  493. // { code:'', name:'上表面转换点位置xtr-upper', comtype:2 , steamflag:1, steamtype:1 },
  494. // { code:'', name:'下表面转换点位置xtr-lower', comtype:2 , steamflag:1, steamtype:1 },
  495. ])
  496. let checkAll = ref(false);
  497. let isIndeterminate = ref(false);
  498. const dataTables = {
  499. '1': youhuaFFDtable,
  500. '2': youhuaCSTtable,
  501. '3': ADflowyouhuatable,
  502. '4': Xfoilyouhuatable
  503. };
  504. const handlecheckFlagchange = () => {
  505. const table = dataTables[datacontent.value];
  506. if (!table) return;
  507. let checkedCount = table.value.filter(item => Boolean(item.steamflag)).length;
  508. checkAll.value = checkedCount === table.value.length;
  509. isIndeterminate.value = checkedCount > 0 && checkedCount < table.value.length;
  510. };
  511. const handlecheckAllchange = (val) => {
  512. const table = dataTables[datacontent.value];
  513. if (!table) return;
  514. table.value.forEach(item => item.steamflag = val ? 1 : 0);
  515. isIndeterminate.value = false;
  516. };
  517. const confirmselection=()=>{
  518. const table = dataTables[datacontent.value];
  519. let checkedData = table.value.filter((item) => item.steamflag).map((item) => item.name);
  520. console.log('xuanzhongshuju:',checkedData);
  521. console.log('seledge:',seledge.value);
  522. seledge.value.label=checkedData.join('\n');
  523. if(datacontent.value === '4') {
  524. dataFlowsave();
  525. }
  526. dataflowshow.value = false;
  527. }
  528. const xfid = ref('')
  529. const adid = ref('')
  530. // 监听组件xfoil返回的xfid
  531. const handleXfid = (xfidFromB) => {
  532. xfid.value = xfidFromB.value;
  533. };
  534. const handleAdid = (adidFromB) => {
  535. adid.value = adidFromB.value;
  536. }
  537. let datacontent = ref('')
  538. function onEdgeDoubleClick(e) {
  539. console.log('Edge Double Click', e)
  540. seledge.value = e.edge;
  541. // dataflowshow.value = true
  542. console.log('qidian:',e.edge.sourceNode.data.name);
  543. console.log('zhongdian:',e.edge.targetNode.data.name);
  544. let qidian = e.edge.sourceNode.data.name;
  545. let zhongdian = e.edge.targetNode.data.name;
  546. let youhualist = ['优化器','代理优化器','进化优化器','梯度优化器'];
  547. if( youhualist.includes(qidian) && zhongdian ==='FFD' ){
  548. datacontent.value = '1';
  549. dataflowshow.value = true;
  550. }else if( youhualist.includes(qidian) && zhongdian ==='CST') {
  551. datacontent.value = '2';
  552. dataflowshow.value = true;
  553. }else if( qidian === 'ADflow' && youhualist.includes(zhongdian) ) {
  554. datacontent.value = '3';
  555. emitter.emit('requestGetadid',pid.value);
  556. console.log('adid:',adid.value)
  557. if(adid.value) {
  558. // querydataFlow(adid);
  559. dataflowshow.value = true;
  560. }else{
  561. ElMessage.error('ADflow未初始化!')
  562. }
  563. }else if ( qidian === 'Xfoil' && youhualist.includes(zhongdian) ) {
  564. datacontent.value = '4';
  565. emitter.emit('requestGetxfid',pid.value);
  566. console.log('xfid:',xfid.value)
  567. if(xfid.value) {
  568. querydataFlow(xfid);
  569. dataflowshow.value = true;
  570. }else{
  571. ElMessage.error('Xfoil未初始化!')
  572. }
  573. }
  574. console.log('leixing:',datacontent.value);
  575. nextTick(() => {
  576. handlecheckFlagchange();
  577. });
  578. }
  579. const querydataFlow = (comid) => {
  580. const params = {
  581. transCode: "MDO0052",
  582. pid: pid.value,
  583. comid: comid.value
  584. }
  585. request(params).then((res) => {
  586. if(datacontent.value === '4'){
  587. Xfoilyouhuatable.value = res.params;
  588. handlecheckFlagchange();
  589. }
  590. })
  591. .catch((err) => {
  592. ElMessage.error(err.returnMsg)
  593. })
  594. }
  595. const dataFlowsave = () => {
  596. const params = {
  597. transCode: "MDO0053",
  598. paramstr: convertToStringArray([],Xfoilyouhuatable.value),
  599. };
  600. request(params).then((res) => {
  601. ElMessage({
  602. message: res.returnMsg,
  603. type: 'success',
  604. })
  605. })
  606. .catch((err) => {
  607. ElMessage.error(err.returnMsg)
  608. })
  609. }
  610. const convertToStringArray = (result, Data) => {
  611. console.log('Data:', Data);
  612. // 安全检查 Data,确保它是一个数组
  613. if (!Array.isArray(Data)) {
  614. console.error('Data should be an array');
  615. return result; // 返回原 result 或者根据需要返回其他默认值
  616. }
  617. result = Data.map(row => {
  618. // 获取每一行的 `code`, `name`, `value` 和 `flag`
  619. const paramid = row.paramid ?? ' ';
  620. const steamflag = row.steamflag ?? '';
  621. const steamtype = row.steamtype ?? ' ';
  622. // 将字段连接为一个以逗号分隔的字符串
  623. return `${paramid},${steamflag},${steamtype}`;
  624. }).join(';'); // 每行之间用分号分隔
  625. return result;
  626. }
  627. function logEvent(name, event) {
  628. console.log(2222)
  629. }
  630. // 右键更改名字
  631. // const onContextMenu = (e) => {
  632. // e.preventDefault(); // 阻止浏览器默认的右键菜单
  633. // const node = e.target.closest(".vue-flow__node");
  634. // console.log("nodes:",nodes);
  635. // console.log("node:",node);
  636. // if (node) {
  637. // // 获取当前右键点击的节点
  638. // const nodeId = node.getAttribute("data-id");
  639. // const clickedNode = nodes.value.find((n) => n.id === nodeId);
  640. // console.log("clickedNode:",clickedNode);
  641. // if (clickedNode) {
  642. // noid.value = clickedNode;
  643. // changeName.value.name = clickedNode.label; // 将当前节点的label放入弹窗中
  644. // changeNameshow.value = true; // 显示弹窗
  645. // }
  646. // }
  647. // };
  648. onInit((vueFlowInstance) => {
  649. vueFlowInstance.fitView()
  650. })
  651. onNodeDragStop(({ event, nodes, node }) => {
  652. console.log(nodes)
  653. Nested.value=nodes;
  654. console.log('Node Drag Stop', { event, nodes, node })
  655. })
  656. onConnect((connection) => {
  657. addEdges(connection)
  658. })
  659. function updatePos() {
  660. nodes.value = nodes.value.map((node) => {
  661. return {
  662. ...node,
  663. position: {
  664. x: Math.random() * 400,
  665. y: Math.random() * 400,
  666. },
  667. }
  668. })
  669. }
  670. function removeEdge(id) {
  671. id = Edgeid.value;
  672. vueFlowRef.value.removeEdges(id);
  673. console.log('msg:',datatree.value);
  674. }
  675. // 触摸
  676. const onDrop1=(event)=>{
  677. onDrop(event);
  678. emitter.emit('doSomethingEvent');
  679. }
  680. function removeNode(id) {
  681. id = noid.value.id;
  682. if(datatree.value==undefined){
  683. if(nodes.value.length>0){
  684. for (let i = 0; i <nodes.value.length; i++) {
  685. if(id==nodes.value[i].id){
  686. console.log(44444)
  687. console.log( nodes.value[i]);
  688. nodes.value.splice(i, 1)
  689. }
  690. }
  691. console.log( nodes.value);
  692. }
  693. }else{
  694. if(nodes.value.length>0){
  695. for (let i = 0; i <nodes.value.length; i++) {
  696. if(id==nodes.value[i].id){
  697. console.log( nodes.value[i]);
  698. nodes.value.splice(i, 1)
  699. }
  700. }
  701. }
  702. for (let i = 0; i <datatree.value[0].children.length; i++) {
  703. if(id.includes(datatree.value[0].children[i].Text)){
  704. for (let j = 0; j <datatree.value[0].children[i].children.length; j++) {
  705. if(id==datatree.value[0].children[i].children[j].id){
  706. //datatree.value[0].children.splice(datatree.value[0].children[i].children[j], 1);
  707. datatree.value[0].children[i].children.splice(j, 1)
  708. vueFlowRef.value.removeNodes(id);
  709. }
  710. }
  711. }
  712. }
  713. }
  714. }
  715. function removeall(){
  716. nodes.value=[];
  717. edges.value=[];
  718. Nested2.value=[];
  719. Nested.value=[];
  720. for (let i = 0; i <datatree.value[0].children.length; i++) {
  721. for (let j = 0; j <datatree.value[0].children[i].children.length; j++) {
  722. datatree.value[0].children[i].children=[];
  723. }
  724. }
  725. }
  726. async function logToObject1() {
  727. let obj = { nodes: toObject().nodes,edges:toObject().edges };
  728. mergedObj.value=JSON.stringify(obj);
  729. try {
  730. const container = vueFlowRef.value.$el;
  731. const canvas = await html2canvas(container);
  732. const img = canvas.toDataURL('image/png');
  733. // 创建一个图片元素并设置src属性为转换后的图片数据
  734. vueflowimg.value=img
  735. if(vueflowimg.value!=''){
  736. console.log("进入了")
  737. addflow();
  738. }
  739. // 添加到DOM中或者做其他操作
  740. } catch (error) {
  741. console.error('转换出错:', error);
  742. }
  743. }
  744. //添加接口
  745. const addflow = () => {
  746. const savedObj = JSON.parse(sessionStorage.getItem("objlist"));
  747. const stypeValue = savedObj ? savedObj.stype : '';
  748. console.log(stypeValue);
  749. const params = {
  750. transCode: 'MDO0002',
  751. pid: pid.value,
  752. name: newobj.value.name,
  753. remark:newobj.value.description,
  754. image:vueflowimg.value,
  755. isshare:'1',
  756. flow:mergedObj.value ,
  757. stype:stypeValue,
  758. }
  759. console.log(params);
  760. request(params)
  761. .then((res) => {
  762. console.log(res);
  763. ElMessage({
  764. message: res.returnMsg,
  765. type: 'success',
  766. })
  767. })
  768. .catch((err) => {
  769. ElMessage.error(err.returnMsg)
  770. })
  771. }
  772. /**
  773. * Resets the current viewport transformation (zoom & pan)
  774. */
  775. function resetTransform() {
  776. setViewport({ x: 0, y: 0, zoom: 1 })
  777. }
  778. function toggleDarkMode() {
  779. dark.value = !dark.value;
  780. if(dark.value){
  781. iconcolor.value='#fff'
  782. }else{
  783. iconcolor.value='#000'
  784. }
  785. }
  786. onMounted(() => {
  787. setTimeout(function() {
  788. getroter();
  789. }, 1500);
  790. // childfun();
  791. if (vueFlowRef.value) {
  792. vueFlowRef.value.$el.addEventListener('click', (event) => {
  793. // 确保点击的不是边缘
  794. if (seledge.value && !event.target.closest('.vue-flow__edge')) {
  795. // 恢复选中边缘的原始样式
  796. seledge.value.style = {
  797. ...seledge.value.style,
  798. stroke: seledge.value.originalColor,
  799. strokeWidth: previousEdge?.originalWidth || 1, // 恢复原始宽度
  800. };
  801. // 清空选中的边缘
  802. seledge.value = null;
  803. Edgeid.value = null;
  804. previousEdge = null;
  805. }
  806. });
  807. }
  808. emitter.on("xfidFromxfoil", handleXfid);
  809. emitter.on("adidFromadflow", handleAdid);
  810. });
  811. onUnmounted(() => {
  812. emitter.off('child2Data');
  813. emitter.off("xfidFromxfoil", handleXfid);
  814. emitter.off("adidFromadflow", handleAdid);
  815. });
  816. // 获取链接
  817. const getroter=()=>{
  818. //datatree.value[0].children=[];
  819. let objlist=JSON.parse(sessionStorage.getItem("objlist"));
  820. if(objlist.flow!=''){
  821. let nodesflow=JSON.parse(objlist.flow)
  822. nodes.value=nodesflow.nodes;
  823. edges.value=nodesflow.edges;
  824. }
  825. newobj.value.name=objlist.name;
  826. newobj.value.description=objlist.remark;
  827. pid.value=objlist.pid;
  828. // let item={
  829. // id:'1-0',
  830. // label: objlist.name,
  831. // img:r2,
  832. // }
  833. // console.log( datatree.value[0].children);
  834. // datatree.value[0].children.push(item);
  835. }
  836. //改变线的粗
  837. const linestrokeWidth=(num)=>{
  838. if(seledge.value){
  839. seledge.value.style.strokeWidth = num;
  840. }
  841. linenum.value=num;
  842. // console.log(seledge.value);
  843. // let edgearr= toObject().edges;
  844. // for (let i = 0; i <= edgearr.length-1; i++) {
  845. // edgearr[i].style.strokeWidth = num;
  846. // }
  847. console.log(num)
  848. //addEdges(edgearr);
  849. }
  850. //改变线的颜色
  851. const changeAllEdgesColor = (color1) => {
  852. console.log('yanse:', color1);
  853. linecolor.value = color1;
  854. // 找到当前选中的边缘
  855. if (seledge.value) {
  856. // 更新该边缘的颜色,不修改宽度
  857. const updatedEdge = {
  858. ...seledge.value,
  859. style: {
  860. ...seledge.value.style,
  861. stroke: linecolor.value, // 只修改颜色
  862. strokeWidth: 1, // 保持选中样式的宽度(如果想要恢复原始宽度,设置为 1)
  863. }
  864. };
  865. // 更新 edges 数组
  866. const updatedEdges = edges.value.map(edge =>
  867. edge.id === seledge.value.id ? updatedEdge : edge
  868. );
  869. edges.value = updatedEdges; // 持久化修改后的边缘
  870. }
  871. };
  872. watch(() => seledge.value, (newItems, oldItems) => {
  873. if(seledge.value!=null){
  874. // seledge.value.style.stroke = linecolor.value;
  875. }
  876. });
  877. defineExpose({changeAllEdgesColor,linestrokeWidth,getroter,onSelection,bgcolorfunc});
  878. </script>
  879. <style>
  880. /* .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 {
  881. stroke: #555 !important;
  882. } */
  883. .vue-flow__edge:focus .vue-flow__edge-path, .vue-flow__edge:focus-visible .vue-flow__edge-path {
  884. stroke: #555 !important;
  885. }
  886. .vue-flow__edge {
  887. text-align: left;
  888. /* 设置edges的左对齐 */
  889. }
  890. .vue-flow__edge-text {
  891. transform: translateY(-10px); /* 将 label 向上偏移 */
  892. background: transparent !important;
  893. font-size: 8px;
  894. font-family: 'Source Sans Pro-Regular';
  895. color: #333333;
  896. }
  897. .vue-flow__edge-textbg {
  898. fill: transparent !important; /* 将背景设置为透明 */
  899. }
  900. #contextMenu {
  901. display: none;
  902. position: absolute;
  903. background-color: #fff;
  904. border-radius: 5px;
  905. padding: 10px;
  906. text-align: center;
  907. color: black;
  908. font-size: 14px;
  909. font-weight: 400;
  910. cursor: pointer;
  911. z-index: 99999;
  912. }
  913. .vue-flow__node-default.selectable:hover,
  914. .vue-flow__node-input.selectable:hover,
  915. .vue-flow__node-output.selectable:hover {
  916. box-shadow: none;
  917. }
  918. panel {
  919. cursor: pointer;
  920. position: absolute;
  921. z-index: 100000;
  922. }
  923. .remove {
  924. background: #fff;
  925. color: #666;
  926. margin: 0 10px;
  927. font-size: 12px;
  928. }
  929. .vue-flow__node-default, .vue-flow__node-input, .vue-flow__node-output{
  930. /* width: auto !important; */
  931. border: none;
  932. background-color: rgba(0,0,0,0);
  933. }
  934. .node-content {
  935. cursor: move; /* 更改鼠标光标表示可拖动 */
  936. }
  937. .vue-flow__node {
  938. cursor: move;
  939. }
  940. /* 禁用文本选中效果 */
  941. .left_main * {
  942. -webkit-user-select: none; /* Safari */
  943. -moz-user-select: none; /* Firefox */
  944. -ms-user-select: none; /* IE10+/Edge */
  945. user-select: none; /* Standard syntax */
  946. }
  947. .lableaniu{
  948. font-size: 12px;
  949. background-color: #ddd;
  950. padding: 4px 16px;
  951. /* margin-top: -17px; */
  952. margin-left: 5px;
  953. margin-top: 0px;
  954. border-radius: 1px;
  955. }
  956. .vue-flow__controls-button svg{
  957. max-width: 16px;
  958. max-height: 16px;
  959. }
  960. .field{
  961. display: flex;
  962. }
  963. </style>