index.vue 47 KB

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