index.vue 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284
  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="logEvent('contextmenu', $event)"
  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="请输入名称"></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 } = 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. let noid = ref([]);
  286. let Edgeid = ref();
  287. let seledge=ref(null);
  288. let djshow=ref(false);
  289. let node = ref();
  290. let contextMenu = ref({
  291. position: { x: 0, y: 0 },
  292. target: 'kong',
  293. })
  294. let Nested=ref([]);
  295. let Nested2=ref([]);
  296. let nnum=ref(0);
  297. const { onDragOver, onDrop, onDragLeave, isDragOver } = useDragAndDrop();
  298. const edges = ref([]);
  299. const nodes = ref([]);
  300. const changeNameshow = ref(false);
  301. const changeName = ref({
  302. name: '',
  303. })
  304. onNodeContextMenu((e) => {
  305. noid.value = e.node;
  306. changeName.value.name = e.node.data.label;
  307. changeNameshow.value = true;
  308. })
  309. // 线的类型 process-逻辑线 data-数据线
  310. let lineType = ref('process');
  311. // 线序号
  312. let linecount = ref(0);
  313. onConnect((connection) => {
  314. console.log('线连接',connection);
  315. // 创建唯一的边ID(由源节点和目标节点组成)
  316. const edgeId = `${connection.source}-${connection.target}`;
  317. connection.id = edgeId; // 自定义 ID
  318. connection.type = 'smoothstep';// smoothstep straight
  319. connection.markerEnd = MarkerType.ArrowClosed;
  320. connection.color=linecolor.value;
  321. // connection.label = '这是一条注释';
  322. connection.style = { strokeWidth:linenum.value ,stroke:linecolor.value};
  323. addEdges(connection)
  324. seledge.value=null;
  325. linecount.value++;
  326. const newName = `Seg${linecount.value}`;
  327. const sourceNode = vueFlowRef.value.getNode(connection.source);
  328. const targetNode = vueFlowRef.value.getNode(connection.target);
  329. // 调用 saveflow 保存数据并获取 wid
  330. saveflow(pid.value, '', newName, lineType.value, sourceNode.data.uid, targetNode.data.uid)
  331. .then((wid) => {
  332. // 更新连接线的数据
  333. const updatedData = {
  334. wid: wid,
  335. uid: newName,
  336. type: lineType.value,
  337. fromuid: sourceNode.data.uid,
  338. touid: targetNode.data.uid,
  339. };
  340. updateEdgeData(connection.id, updatedData);
  341. })
  342. .catch((error) => {
  343. console.error('保存流程失败:', error);
  344. });
  345. })
  346. //修改名称
  347. const handleUpdate = () => {
  348. if (noid.value && noid.value.data) {
  349. noid.value.data.label = changeName.value.name; // 更新名称
  350. console.log(noid.value.data.label); // 打印更新后的值
  351. } else {
  352. console.error("noid.value 或 noid.value.data 未定义"); // 错误日志
  353. }
  354. changeNameshow.value = false; // 更新后关闭对话框
  355. // noid.value.data.label = labelname;
  356. };
  357. emitter.on('child2Data', data => {
  358. datatree.value = data;
  359. console.log("datatree的值:",datatree.value);
  360. })
  361. function onNodeClick(e) {
  362. noid.value = e.node;
  363. changeName.value.name=e.node.data.label;
  364. console.log("shuju:",e.node.data);
  365. console.log("noid.value:",noid.value);
  366. console.log("changeName.value:",changeName.value.name);
  367. djshow.value = !djshow.value;
  368. // if(djshow.value){
  369. // console.log('选中');
  370. // }else{
  371. // console.log('取消选中');
  372. // }
  373. }
  374. //模块化
  375. const bgcolorfunc= (color)=>{
  376. bgcolor.value=color;
  377. if(noid.value.style!=undefined){
  378. console.log(noid.value.style);
  379. noid.value.style.backgroundColor=color;
  380. }
  381. }
  382. function onSelection(){
  383. let positionX=[];
  384. let positiony=[];
  385. for(let i=0;i<Nested.value.length;i++){
  386. // Nested2.value.push(Nested.value[i]);
  387. positionX.push(Nested.value[i].position.x)
  388. positiony.push(Nested.value[i].position.y)
  389. }
  390. let xmin=Math.min(...positionX);
  391. let ymax=Math.max(...positiony);
  392. console.log(positionX);
  393. // console.log( positionX)
  394. // console.log(44444)
  395. // console.log( positiony)
  396. nnum.value++;
  397. // let x=Math.floor(Math.random() * 91) + 10;
  398. // let y=Math.floor(Math.random() * 91) + 10;
  399. let name='模块'+nnum.value
  400. let item= {
  401. id:nnum.value.toString(),
  402. data: { label:name },
  403. position: { x:xmin , y:ymax},
  404. style: { backgroundColor: bgcolor.value, width: '200px',height: '200px' },
  405. //children: [],
  406. }
  407. if(Nested.value.length!=0){
  408. Nested2.value=[];
  409. for(let i=0;i<Nested.value.length;i++){
  410. Nested2.value.push(Nested.value[i]);
  411. }
  412. console.log(Nested2.value);
  413. nodesitem.value= Nested2.value.map(node => {
  414. if(node.parentNode==undefined){
  415. node.isParent=false;
  416. node.parentNode=item.id;
  417. console.log( node.parentNode)
  418. node.position.x= node.position.x /2;
  419. node.position.y= node.position.y/2;
  420. node.expandParent=true;
  421. //positionxy=node.position;
  422. // node.extent='parent';
  423. // return node;
  424. }
  425. return node;
  426. })
  427. }
  428. nodes.value.push(item)
  429. for(let i=0;i<nodesitem.value.length;i++){
  430. console.log(nodesitem.value[i]);
  431. nodes.value.push(nodesitem.value[i])
  432. }
  433. console.log( nodes.value);
  434. }
  435. function onNodeDoubleClick(e) {
  436. noid.value = e.node;
  437. const nowid = e.node.data.wid;
  438. console.log( e.node.data.name);
  439. if (e.node.data.name == '优化器') {
  440. emit('optimizerfalse',{name:'优化器',wid:nowid});
  441. }else if(e.node.data.name=="进化优化器"){
  442. emit('optimizerfalse',{name:'进化优化器',wid:nowid});
  443. }else if(e.node.data.name=="代理优化器"){
  444. emit('optimizerfalse',{name:'代理优化器',wid:nowid});
  445. }else if(e.node.data.name=="Xfoil"){
  446. emit('optimizerfalse',{name:'Xfoil',wid:nowid});
  447. }else if(e.node.data.name=="梯度优化器"){
  448. emit('optimizerfalse',{name:'梯度优化器',wid:nowid});
  449. }else if(e.node.data.name=="CST"){
  450. emit('optimizerfalse',{name:'CST',wid:nowid});
  451. }else if(e.node.data.name=="ADflow"){
  452. emit('optimizerfalse',{name:'ADflow',wid:nowid});
  453. }else if(e.node.data.name=="FFD"){
  454. emit('optimizerfalse',{name:'FFD',wid:nowid});
  455. }else if(e.node.data.name=="TACS"){
  456. emit('optimizerfalse',{name:'TACS',wid:nowid});
  457. }else if(e.node.data.name=="参数化"){
  458. emit('optimizerfalse',{name:'参数化',wid:nowid});
  459. }else if(e.node.data.name=="气动分析"){
  460. emit('optimizerfalse',{name:'气动分析',wid:nowid});
  461. }else if(onPythonlist.value.some(item => e.node.data.name.includes(item))){
  462. emit('optimizerfalse',{name:e.node.data.name,wid:nowid});
  463. }else if(e.node.data.name=="CATIA"){
  464. emit('optimizerfalse',{name:'CATIA',wid:nowid});
  465. }else if(e.node.data.name=="FSI"){
  466. emit('optimizerfalse',{name:'FSI',wid:nowid});
  467. }else if(e.node.data.name=="Flight"){
  468. emit('optimizerfalse',{name:'Flight',wid:nowid});
  469. }
  470. }
  471. let onPythonlist=ref(['Python','Branin','Rosenbrock','Rastrigin','G9','Forrester']);
  472. let previousEdge = null; // 用于保存上一个选中的边缘
  473. // 监听线
  474. function onEdgeClick(e) {
  475. console.log('Edge Click', e.edge);
  476. // 如果已经有选中的边缘
  477. if (seledge.value) {
  478. // 恢复上一个选中边缘的样式
  479. if (previousEdge) {
  480. previousEdge.style = {
  481. ...previousEdge.style,
  482. stroke: previousEdge.originalColor, // 恢复原始颜色
  483. strokeWidth: previousEdge.originalWidth,// 恢复原始宽度
  484. };
  485. }
  486. }
  487. // 保存当前点击的边缘为选中边缘
  488. Edgeid.value = e.edge.id;
  489. seledge.value = e.edge;
  490. // 暂时更改当前选中边缘的样式
  491. seledge.value.originalColor = seledge.value.style.stroke; // 保存当前边缘的原始颜色
  492. seledge.value.originalWidth = seledge.value.style.strokeWidth; // 保存当前边缘的原始宽度
  493. seledge.value.style = {
  494. ...seledge.value.style,
  495. stroke: '#2267B1', // 设置选中边缘的颜色
  496. strokeWidth: 2, // 设置选中边缘的宽度
  497. };
  498. // 保存当前选中的边缘作为上一个选中边缘
  499. previousEdge = seledge.value;
  500. }
  501. let dataflowshow=ref(false);
  502. let youhuaFFDtable = ref([
  503. { name:'FFD参数(sample)', steamflag:1 }
  504. ])
  505. let youhuaCSTtable = ref([
  506. { name:"上表面CST参数(upper)", steamflag:1 },
  507. { name:'下表面CST参数(lower)', steamflag:1 }
  508. ])
  509. let steamtypeoptions = ref([
  510. { label:'约束条件', value:1 },
  511. { label:'优化目标', value:2 }
  512. ])
  513. let ADflowyouhuatable = ref([
  514. { code: "cl", name:'升力系数Cl', comtype:2 , steamflag:1, steamtype:1 },
  515. { code: "cd", name:'阻力系数Cd', comtype:2 , steamflag:1, steamtype:1 },
  516. { code: "cm", name:'力矩系数Cm', comtype:2 , steamflag:1, steamtype:1 },
  517. { code: " ", name:'体积', comtype:2 , steamflag:1, steamtype:1 },
  518. ])
  519. let Xfoilyouhuatable = ref([
  520. // { code:'', name:'升力系数Cl', comtype:2 , steamflag:1, steamtype:1 },
  521. // { code:'', name:'阻力系数Cd', comtype:2 , steamflag:1, steamtype:1 },
  522. // { code:'', name:'压阻力系数Cdp', comtype:2 , steamflag:1, steamtype:1 },
  523. // { code:'', name:'力矩系数Cm', comtype:2 , steamflag:1, steamtype:1 },
  524. // { code:'', name:'上表面转换点位置xtr-upper', comtype:2 , steamflag:1, steamtype:1 },
  525. // { code:'', name:'下表面转换点位置xtr-lower', comtype:2 , steamflag:1, steamtype:1 },
  526. ])
  527. let checkAll = ref(false);
  528. let isIndeterminate = ref(false);
  529. const dataTables = {
  530. '1': youhuaFFDtable,
  531. '2': youhuaCSTtable,
  532. '3': ADflowyouhuatable,
  533. '4': Xfoilyouhuatable
  534. };
  535. const handlecheckFlagchange = () => {
  536. const table = dataTables[datacontent.value];
  537. if (!table) return;
  538. let checkedCount = table.value.filter(item => Boolean(item.steamflag)).length;
  539. checkAll.value = checkedCount === table.value.length;
  540. isIndeterminate.value = checkedCount > 0 && checkedCount < table.value.length;
  541. };
  542. const handlecheckAllchange = (val) => {
  543. const table = dataTables[datacontent.value];
  544. if (!table) return;
  545. table.value.forEach(item => item.steamflag = val ? 1 : 0);
  546. isIndeterminate.value = false;
  547. };
  548. const confirmselection=()=>{
  549. const table = dataTables[datacontent.value];
  550. let checkedData = table.value.filter((item) => item.steamflag).map((item) => item.name);
  551. console.log('xuanzhongshuju:',checkedData);
  552. console.log('seledge:',seledge.value);
  553. seledge.value.label=checkedData.join('\n');
  554. if(datacontent.value === '4') {
  555. dataFlowsave();
  556. }
  557. dataflowshow.value = false;
  558. }
  559. const xfid = ref('')
  560. const adid = ref('')
  561. // 监听组件xfoil返回的xfid
  562. const handleXfid = (xfidFromB) => {
  563. xfid.value = xfidFromB.value;
  564. };
  565. const handleAdid = (adidFromB) => {
  566. adid.value = adidFromB.value;
  567. }
  568. let datacontent = ref('')
  569. function onEdgeDoubleClick(e) {
  570. console.log('Edge Double Click', e)
  571. seledge.value = e.edge;
  572. // dataflowshow.value = true
  573. console.log('qidian:',e.edge.sourceNode.data.name);
  574. console.log('zhongdian:',e.edge.targetNode.data.name);
  575. let qidian = e.edge.sourceNode.data.name;
  576. let zhongdian = e.edge.targetNode.data.name;
  577. let youhualist = ['优化器','代理优化器','进化优化器','梯度优化器'];
  578. if( youhualist.includes(qidian) && zhongdian ==='FFD' ){
  579. datacontent.value = '1';
  580. dataflowshow.value = true;
  581. }else if( youhualist.includes(qidian) && zhongdian ==='CST') {
  582. datacontent.value = '2';
  583. dataflowshow.value = true;
  584. }else if( qidian === 'ADflow' && youhualist.includes(zhongdian) ) {
  585. datacontent.value = '3';
  586. emitter.emit('requestGetadid',pid.value);
  587. console.log('adid:',adid.value)
  588. if(adid.value) {
  589. // querydataFlow(adid);
  590. dataflowshow.value = true;
  591. }else{
  592. ElMessage.error('ADflow未初始化!')
  593. }
  594. }else if ( qidian === 'Xfoil' && youhualist.includes(zhongdian) ) {
  595. datacontent.value = '4';
  596. emitter.emit('requestGetxfid',pid.value);
  597. console.log('xfid:',xfid.value)
  598. if(xfid.value) {
  599. querydataFlow(xfid);
  600. dataflowshow.value = true;
  601. }else{
  602. ElMessage.error('Xfoil未初始化!')
  603. }
  604. }
  605. console.log('leixing:',datacontent.value);
  606. nextTick(() => {
  607. handlecheckFlagchange();
  608. });
  609. }
  610. const querydataFlow = (comid) => {
  611. const params = {
  612. transCode: "MDO0052",
  613. pid: pid.value,
  614. comid: comid.value
  615. }
  616. request(params).then((res) => {
  617. if(datacontent.value === '4'){
  618. Xfoilyouhuatable.value = res.params;
  619. handlecheckFlagchange();
  620. }
  621. })
  622. .catch((err) => {
  623. ElMessage.error(err.returnMsg)
  624. })
  625. }
  626. const dataFlowsave = () => {
  627. const params = {
  628. transCode: "MDO0053",
  629. paramstr: convertToStringArray([],Xfoilyouhuatable.value),
  630. };
  631. request(params).then((res) => {
  632. ElMessage({
  633. message: res.returnMsg,
  634. type: 'success',
  635. })
  636. })
  637. .catch((err) => {
  638. ElMessage.error(err.returnMsg)
  639. })
  640. }
  641. const convertToStringArray = (result, Data) => {
  642. console.log('Data:', Data);
  643. // 安全检查 Data,确保它是一个数组
  644. if (!Array.isArray(Data)) {
  645. console.error('Data should be an array');
  646. return result; // 返回原 result 或者根据需要返回其他默认值
  647. }
  648. result = Data.map(row => {
  649. // 获取每一行的 `code`, `name`, `value` 和 `flag`
  650. const paramid = row.paramid ?? ' ';
  651. const steamflag = row.steamflag ?? '';
  652. const steamtype = row.steamtype ?? ' ';
  653. // 将字段连接为一个以逗号分隔的字符串
  654. return `${paramid},${steamflag},${steamtype}`;
  655. }).join(';'); // 每行之间用分号分隔
  656. return result;
  657. }
  658. function logEvent(name, event) {
  659. console.log(2222)
  660. }
  661. // 右键更改名字
  662. // const onContextMenu = (e) => {
  663. // e.preventDefault(); // 阻止浏览器默认的右键菜单
  664. // const node = e.target.closest(".vue-flow__node");
  665. // console.log("nodes:",nodes);
  666. // console.log("node:",node);
  667. // if (node) {
  668. // // 获取当前右键点击的节点
  669. // const nodeId = node.getAttribute("data-id");
  670. // const clickedNode = nodes.value.find((n) => n.id === nodeId);
  671. // console.log("clickedNode:",clickedNode);
  672. // if (clickedNode) {
  673. // noid.value = clickedNode;
  674. // changeName.value.name = clickedNode.label; // 将当前节点的label放入弹窗中
  675. // changeNameshow.value = true; // 显示弹窗
  676. // }
  677. // }
  678. // };
  679. onInit((vueFlowInstance) => {
  680. vueFlowInstance.fitView()
  681. })
  682. onNodeDragStop(({ event, nodes, node }) => {
  683. console.log(nodes)
  684. Nested.value=nodes;
  685. console.log('Node Drag Stop', { event, nodes, node })
  686. })
  687. // onConnect((connection) => {
  688. // addEdges(connection)
  689. // console.log('Connection', connection)
  690. // })
  691. function updatePos() {
  692. nodes.value = nodes.value.map((node) => {
  693. return {
  694. ...node,
  695. position: {
  696. x: Math.random() * 400,
  697. y: Math.random() * 400,
  698. },
  699. }
  700. })
  701. }
  702. function removeEdge(id) {
  703. id = Edgeid.value;
  704. const wid = seledge.value.data.wid;
  705. vueFlowRef.value.removeEdges(id);
  706. deleteflow(wid);
  707. seledge.value=null;
  708. console.log('msg:',datatree.value);
  709. }
  710. // 触摸
  711. const onDrop1=(event)=>{
  712. onDrop(event);
  713. emitter.emit('doSomethingEvent');
  714. }
  715. function removeNode(id) {
  716. id = noid.value.id;
  717. const wid = noid.value.data.wid;
  718. console.log('removeNodewid:',wid);
  719. if(datatree.value==undefined){
  720. if(nodes.value.length>0){
  721. for (let i = 0; i <nodes.value.length; i++) {
  722. if(id==nodes.value[i].id){
  723. console.log(44444)
  724. console.log( nodes.value[i]);
  725. nodes.value.splice(i, 1)
  726. deleteflow(wid);
  727. }
  728. }
  729. console.log( nodes.value);
  730. }
  731. }else{
  732. if(nodes.value.length>0){
  733. for (let i = 0; i <nodes.value.length; i++) {
  734. if(id==nodes.value[i].id){
  735. console.log( nodes.value[i]);
  736. nodes.value.splice(i, 1)
  737. }
  738. }
  739. }
  740. for (let i = 0; i <datatree.value[0].children.length; i++) {
  741. if(id.includes(datatree.value[0].children[i].Text)){
  742. for (let j = 0; j <datatree.value[0].children[i].children.length; j++) {
  743. if(id==datatree.value[0].children[i].children[j].id){
  744. //datatree.value[0].children.splice(datatree.value[0].children[i].children[j], 1);
  745. datatree.value[0].children[i].children.splice(j, 1);
  746. deleteflow(wid);
  747. vueFlowRef.value.removeNodes(id);
  748. removeRelatedEdges(id);
  749. }
  750. }
  751. }
  752. }
  753. }
  754. }
  755. function removeRelatedEdges(nodeId) {
  756. //过滤出与该节点相关的连线
  757. const relatedEdges = edges.value.filter(
  758. (edge) => edge.source === nodeId || edge.target === nodeId
  759. );
  760. // 遍历删除关联的连线
  761. relatedEdges.forEach((edge) => {
  762. if (edge.data && edge.data.wid) {
  763. deleteflow(edge.data.wid);
  764. }
  765. });
  766. }
  767. // 删除提示
  768. const confirmDelete = () => {
  769. ElMessageBox.confirm(
  770. '确定要删除全部吗?删除后不可恢复!',
  771. '删除确认',
  772. {
  773. confirmButtonText: '确定',
  774. cancelButtonText: '取消',
  775. type: 'warning',
  776. }
  777. )
  778. .then(() => {
  779. removeall();
  780. })
  781. .catch(() => {
  782. ElMessage({
  783. type: 'info',
  784. message: '已取消删除',
  785. })
  786. })
  787. }
  788. function removeall() {
  789. try {
  790. const allnodes = nodes.value;
  791. const allEdges = edges.value;
  792. for (let i = 0; i < allnodes.length; i++) {
  793. if (allnodes[i].data.wid) {
  794. deleteflow(allnodes[i].data.wid);
  795. }
  796. }
  797. for (let i = 0; i < allEdges.length; i++) {
  798. if (allEdges[i].data.wid) {
  799. deleteflow(allEdges[i].data.wid);
  800. }
  801. }
  802. nodes.value = []
  803. edges.value = []
  804. Nested2.value = []
  805. Nested.value = []
  806. // 判断 datatree 是否为空或未定义
  807. if (!datatree.value || datatree.value.length === 0 || !datatree.value[0]?.children) {
  808. console.warn('datatree 数据为空或未定义')
  809. ElMessage({
  810. type: 'warning',
  811. message: '没有数据可以删除'
  812. })
  813. return
  814. }
  815. // 清空 datatree 的 children
  816. for (let i = 0; i < datatree.value[0].children.length; i++) {
  817. if (datatree.value[0]?.children[i]?.children) {
  818. datatree.value[0].children[i].children = []
  819. }
  820. }
  821. // 删除成功
  822. ElMessage({
  823. type: 'success',
  824. message: '删除成功'
  825. })
  826. } catch (error) {
  827. console.error('删除失败:', error)
  828. ElMessage({
  829. type: 'error',
  830. message: '删除过程中出错'
  831. })
  832. }
  833. }
  834. // 流查询
  835. const queryflow = () => {
  836. const params = {
  837. transCode: 'MDO0057',
  838. pid: pid.value,
  839. }
  840. request(params)
  841. .then((res) => {
  842. console.log(res);
  843. })
  844. .catch((err) => {
  845. ElMessage.error(err.returnMsg)
  846. })
  847. }
  848. // 保存流
  849. const saveflow = async (pid,wid, uid, type, fromuid, touid) => {
  850. const params = {
  851. transCode: 'MDO0058',
  852. pid: pid || '',
  853. wid: wid || '', // 流ID
  854. uid: uid || '',
  855. type: type || '',
  856. fromuid: fromuid || '',
  857. touid: touid || '',
  858. };
  859. try {
  860. // 直接使用 await 等待 request 返回
  861. const res = await request(params);
  862. return res.wid; // 返回 wid
  863. } catch (err) {
  864. // 处理错误
  865. ElMessage.error(err.returnMsg || '保存流程失败');
  866. }
  867. };
  868. // async function saveFlowExample() {
  869. // try {
  870. // const wid = await saveflow('flow123', 'user001', 'process', 'fromA', 'toB');
  871. // console.log('返回的 wid:', wid);
  872. // } catch (err) {
  873. // console.error('保存流程失败:', err.message);
  874. // }
  875. // }
  876. // saveFlowExample();
  877. // 删除流
  878. const deleteflow = (nowid) => {
  879. const params = {
  880. transCode: 'MDO0059',
  881. wid: nowid,
  882. }
  883. request(params)
  884. .then((res) => {
  885. console.log(res);
  886. })
  887. .catch((err) => {
  888. ElMessage.error('删除流程失败')
  889. })
  890. }
  891. async function logToObject1() {
  892. let obj = { nodes: toObject().nodes,edges:toObject().edges };
  893. mergedObj.value=JSON.stringify(obj);
  894. try {
  895. const container = vueFlowRef.value.$el;
  896. const canvas = await html2canvas(container);
  897. const img = canvas.toDataURL('image/png');
  898. // 创建一个图片元素并设置src属性为转换后的图片数据
  899. vueflowimg.value=img
  900. if(vueflowimg.value!=''){
  901. console.log("进入了")
  902. addflow();
  903. }
  904. // 添加到DOM中或者做其他操作
  905. } catch (error) {
  906. console.error('转换出错:', error);
  907. }
  908. }
  909. //添加接口
  910. const addflow = () => {
  911. const savedObj = JSON.parse(sessionStorage.getItem("objlist"));
  912. const stypeValue = savedObj ? savedObj.stype : '';
  913. // 用于首页主界面切换数据一致
  914. const updateobjlist = {
  915. pid: pid.value,
  916. name: newobj.value.name,
  917. remark: newobj.value.description,
  918. image: vueflowimg.value,
  919. isshare: '1',
  920. flow: mergedObj.value,
  921. stype: stypeValue,
  922. }
  923. sessionStorage.setItem("objlist",JSON.stringify(updateobjlist));
  924. console.log("打印stypeValue:",stypeValue);
  925. const params = {
  926. transCode: 'MDO0002',
  927. pid: pid.value,
  928. name: newobj.value.name,
  929. remark:newobj.value.description,
  930. image:vueflowimg.value,
  931. isshare:'1',
  932. flow:mergedObj.value ,
  933. stype:stypeValue,
  934. }
  935. console.log(params);
  936. request(params)
  937. .then((res) => {
  938. console.log(res);
  939. ElMessage({
  940. message: '工程保存成功',
  941. type: 'success',
  942. })
  943. })
  944. .catch((err) => {
  945. ElMessage.error(err.returnMsg)
  946. })
  947. }
  948. /**
  949. * Resets the current viewport transformation (zoom & pan)
  950. */
  951. function resetTransform() {
  952. setViewport({ x: 0, y: 0, zoom: 1 })
  953. }
  954. function toggleDarkMode() {
  955. dark.value = !dark.value;
  956. if(dark.value){
  957. iconcolor.value='#fff'
  958. }else{
  959. iconcolor.value='#000'
  960. }
  961. }
  962. onMounted(() => {
  963. setTimeout(function() {
  964. getroter();
  965. }, 1500);
  966. // childfun();
  967. if (vueFlowRef.value) {
  968. vueFlowRef.value.$el.addEventListener('click', (event) => {
  969. // 确保点击的不是边缘
  970. if (seledge.value && !event.target.closest('.vue-flow__edge')) {
  971. // 恢复选中边缘的原始样式
  972. seledge.value.style = {
  973. ...seledge.value.style,
  974. stroke: seledge.value.originalColor,
  975. strokeWidth: previousEdge?.originalWidth || 1, // 恢复原始宽度
  976. };
  977. // 清空选中的边缘
  978. seledge.value = null;
  979. Edgeid.value = null;
  980. previousEdge = null;
  981. }
  982. });
  983. }
  984. emitter.on("xfidFromxfoil", handleXfid);
  985. emitter.on("adidFromadflow", handleAdid);
  986. });
  987. onUnmounted(() => {
  988. emitter.off('child2Data');
  989. emitter.off("xfidFromxfoil", handleXfid);
  990. emitter.off("adidFromadflow", handleAdid);
  991. });
  992. // 获取链接
  993. const getroter=()=>{
  994. //datatree.value[0].children=[];
  995. let objlist=JSON.parse(sessionStorage.getItem("objlist"));
  996. if(objlist.flow!=''){
  997. let nodesflow=JSON.parse(objlist.flow)
  998. nodes.value=nodesflow.nodes;
  999. edges.value=nodesflow.edges;
  1000. }
  1001. newobj.value.name=objlist.name;
  1002. newobj.value.description=objlist.remark;
  1003. pid.value=objlist.pid;
  1004. // let item={
  1005. // id:'1-0',
  1006. // label: objlist.name,
  1007. // img:r2,
  1008. // }
  1009. // console.log( datatree.value[0].children);
  1010. // datatree.value[0].children.push(item);
  1011. }
  1012. //改变线的粗
  1013. const linestrokeWidth=(num)=>{
  1014. if(seledge.value){
  1015. seledge.value.style.strokeWidth = num;
  1016. }
  1017. linenum.value=num;
  1018. // console.log(seledge.value);
  1019. // let edgearr= toObject().edges;
  1020. // for (let i = 0; i <= edgearr.length-1; i++) {
  1021. // edgearr[i].style.strokeWidth = num;
  1022. // }
  1023. console.log(num)
  1024. //addEdges(edgearr);
  1025. }
  1026. //改变线的颜色
  1027. const changeAllEdgesColor = (color1) => {
  1028. console.log('yanse:', color1);
  1029. linecolor.value = color1;
  1030. // 找到当前选中的边缘
  1031. if (seledge.value) {
  1032. // 更新该边缘的颜色,不修改宽度
  1033. const updatedEdge = {
  1034. ...seledge.value,
  1035. style: {
  1036. ...seledge.value.style,
  1037. stroke: linecolor.value, // 只修改颜色
  1038. strokeWidth: 1, // 保持选中样式的宽度(如果想要恢复原始宽度,设置为 1)
  1039. }
  1040. };
  1041. // 更新 edges 数组
  1042. const updatedEdges = edges.value.map(edge =>
  1043. edge.id === seledge.value.id ? updatedEdge : edge
  1044. );
  1045. edges.value = updatedEdges; // 持久化修改后的边缘
  1046. }
  1047. };
  1048. watch(() => seledge.value, (newItems, oldItems) => {
  1049. if(seledge.value!=null){
  1050. // seledge.value.style.stroke = linecolor.value;
  1051. }
  1052. });
  1053. defineExpose({changeAllEdgesColor,linestrokeWidth,getroter,onSelection,bgcolorfunc,logToObject1});
  1054. </script>
  1055. <style>
  1056. /* .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 {
  1057. stroke: #555 !important;
  1058. } */
  1059. .vue-flow__edge:focus .vue-flow__edge-path, .vue-flow__edge:focus-visible .vue-flow__edge-path {
  1060. stroke: #555 !important;
  1061. }
  1062. .vue-flow__edge {
  1063. text-align: left;
  1064. /* 设置edges的左对齐 */
  1065. }
  1066. .vue-flow__edge-text {
  1067. transform: translateY(-10px); /* 将 label 向上偏移 */
  1068. background: transparent !important;
  1069. font-size: 8px;
  1070. font-family: 'Microsoft YaHei';
  1071. color: #333333;
  1072. }
  1073. .vue-flow__edge-textbg {
  1074. fill: transparent !important; /* 将背景设置为透明 */
  1075. }
  1076. #contextMenu {
  1077. display: none;
  1078. position: absolute;
  1079. background-color: #fff;
  1080. border-radius: 5px;
  1081. padding: 10px;
  1082. text-align: center;
  1083. color: black;
  1084. font-size: 14px;
  1085. font-weight: 400;
  1086. cursor: pointer;
  1087. z-index: 99999;
  1088. }
  1089. .vue-flow__node-default.selectable:hover,
  1090. .vue-flow__node-input.selectable:hover,
  1091. .vue-flow__node-output.selectable:hover {
  1092. box-shadow: none;
  1093. }
  1094. panel {
  1095. cursor: pointer;
  1096. position: absolute;
  1097. z-index: 100000;
  1098. }
  1099. .remove {
  1100. background: #fff;
  1101. color: #666;
  1102. margin: 0 10px;
  1103. font-size: 12px;
  1104. }
  1105. .vue-flow__node-default, .vue-flow__node-input, .vue-flow__node-output{
  1106. /* width: auto !important; */
  1107. border: none;
  1108. background-color: rgba(0,0,0,0);
  1109. }
  1110. .node-content {
  1111. cursor: move; /* 更改鼠标光标表示可拖动 */
  1112. }
  1113. .vue-flow__node {
  1114. cursor: move;
  1115. }
  1116. /* 禁用文本选中效果 */
  1117. .left_main * {
  1118. -webkit-user-select: none; /* Safari */
  1119. -moz-user-select: none; /* Firefox */
  1120. -ms-user-select: none; /* IE10+/Edge */
  1121. user-select: none; /* Standard syntax */
  1122. }
  1123. .lableaniu{
  1124. font-size: 12px;
  1125. background-color: #ddd;
  1126. padding: 4px 16px;
  1127. /* margin-top: -17px; */
  1128. margin-left: 5px;
  1129. margin-top: 0px;
  1130. border-radius: 1px;
  1131. }
  1132. .vue-flow__controls-button svg{
  1133. max-width: 16px;
  1134. max-height: 16px;
  1135. }
  1136. .field{
  1137. display: flex;
  1138. }
  1139. </style>