optimize_monitor.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523
  1. <template>
  2. <!-- 曲线监控 -->
  3. <div style="width: 100%; height: 100%">
  4. <div class="echartitem" style="width: 100%; height: 100%">
  5. <!-- <h3 class="selcal">{{ props.selval }}</h3> -->
  6. <div
  7. id="line"
  8. ref="chartContainer"
  9. style="width: 100%; height: 100%"
  10. ></div>
  11. </div>
  12. </div>
  13. </template>
  14. <script setup>
  15. import { ref, onMounted, reactive, markRaw, inject, watch, nextTick } from "vue"
  16. import { RouterView, RouterLink } from "vue-router"
  17. import { request, uploadFile } from "@/utils/request"
  18. import { ElMessage, ElButton, ElDialog, ElSelect } from "element-plus"
  19. import * as echarts from "echarts"
  20. let vars = ref([])
  21. let vals = ref([])
  22. let series = ref([
  23. ])
  24. let xdata = ref([])
  25. let chartContainer = ref()
  26. let myChart
  27. let chartDom = ref()
  28. let option = ref(null)
  29. let convergeDate = ref([])
  30. let curvedata = ref("")
  31. let state = reactive({
  32. instance: null
  33. })
  34. const props = defineProps({
  35. echartdata: {
  36. type: String
  37. },
  38. curvedata: {
  39. type: String
  40. }
  41. })
  42. let emit = defineEmits([""])
  43. onMounted(() => {
  44. myChart = echarts.init(chartContainer.value)
  45. linechart()
  46. myChart.resize();
  47. })
  48. //初始化
  49. const echatinit = () => {
  50. convergeDate.value = []
  51. series.value = []
  52. xdata.value = []
  53. }
  54. // 从websocket取数据
  55. // const getsockechart = (data) => {
  56. // console.log("曲线数据", data);
  57. // curvedata.value = data;
  58. // // 如果是第一次传入数据,则初始化为空数组;否则保留之前的数据
  59. // if (!xdata.value) {
  60. // xdata.value = [];
  61. // }
  62. // let rows = curvedata.value;
  63. // vars = rows[0].vars.split(" ")
  64. // console.log('变量名:',vars);
  65. // // 继续累加之前的数据
  66. // let convergeDate = {
  67. // "design_var/upperB": [],
  68. // "design_var/lowerB": []
  69. // };
  70. // // 遍历每一行数据
  71. // for (let i = 0; i < rows.length; i++) {
  72. // let vals = rows[i].vals.split(" ");
  73. // let upperB = JSON.parse(vals[3]);
  74. // let lowerB = JSON.parse(vals[4]);
  75. // // 将新的数据追加到对应的数组中
  76. // convergeDate["design_var/upperB"].push(...upperB);
  77. // convergeDate["design_var/lowerB"].push(...lowerB);
  78. // // 将新的 step 值追加到 xdata 数组
  79. // xdata.value.push(rows[i].step);
  80. // }
  81. // // 获取所有的 upperB 和 lowerB 数据
  82. // let upperBData = convergeDate["design_var/upperB"];
  83. // let lowerBData = convergeDate["design_var/lowerB"];
  84. // // 计算每条曲线的数量
  85. // let curveCount = upperBData.length / rows.length;
  86. // console.log('曲线数据测试:',curveCount,upperBData.length,rows.length)
  87. // // 遍历每一条曲线,检查是否已经存在,如果存在,则更新数据;否则,创建新曲线
  88. // for (let i = 0; i < curveCount; i++) {
  89. // let upperBCurveData = [];
  90. // let lowerBCurveData = [];
  91. // // 填充每条曲线的数据
  92. // for (let j = 0; j < rows.length; j++) {
  93. // upperBCurveData.push(upperBData[j * curveCount + i]);
  94. // lowerBCurveData.push(lowerBData[j * curveCount + i]);
  95. // }
  96. // // 查找是否已经存在此曲线
  97. // let upperBSeries = series.value.find(s => s.name === `design_var/upperB${i + 1}`);
  98. // let lowerBSeries = series.value.find(s => s.name === `design_var/lowerB${i + 1}`);
  99. // // 如果存在则更新数据,否则创建新曲线
  100. // if (upperBSeries) {
  101. // upperBSeries.data.push(...upperBCurveData);
  102. // } else {
  103. // series.value.push({
  104. // name: `design_var/upperB${i + 1}`,
  105. // type: "line",
  106. // data: upperBCurveData
  107. // });
  108. // }
  109. // if (lowerBSeries) {
  110. // lowerBSeries.data.push(...lowerBCurveData);
  111. // } else {
  112. // series.value.push({
  113. // name: `design_var/lowerB${i + 1}`,
  114. // type: "line",
  115. // data: lowerBCurveData
  116. // });
  117. // }
  118. // }
  119. // // 使用 myChart 设置图表的配置
  120. // myChart.setOption({
  121. // legend: {
  122. // data: [
  123. // ...Array.from({ length: curveCount }, (_, i) => `design_var/upperB${i + 1}`),
  124. // ...Array.from({ length: curveCount }, (_, i) => `design_var/lowerB${i + 1}`)
  125. // ] // 设置图例数据为曲线名
  126. // },
  127. // xAxis: {
  128. // data: xdata.value // 使用更新后的 xdata
  129. // },
  130. // series: series.value // 使用更新后的 series
  131. // });
  132. // console.log('更新后的 xdata:', xdata.value);
  133. // console.log('更新后的 series:', series.value);
  134. // };
  135. const getsockechart = (data) => {
  136. console.log("曲线数据", data);
  137. curvedata.value = data;
  138. let rows = curvedata.value;
  139. // 获取变量名
  140. let vars = rows[0].vars.split(" ");
  141. console.log('变量名:', vars);
  142. // 继续累加之前的数据
  143. let convergeDate = {};
  144. // 遍历每一行数据
  145. for (let i = 0; i < rows.length; i++) {
  146. let vals = rows[i].vals.split(" ");
  147. // 获取每一列的值
  148. for (let j = 0; j < vars.length; j++) {
  149. let columnName = vars[j];
  150. let value = vals[j];
  151. // 判断值是否是数组
  152. try {
  153. let parsedValue = JSON.parse(value); // 尝试解析为数组
  154. if (Array.isArray(parsedValue)) {
  155. // 如果是数组,分解成每个单独的值,创建多条曲线
  156. parsedValue.forEach((item, index) => {
  157. let curveName = `${columnName}_${index + 1}`;
  158. if (!convergeDate[curveName]) {
  159. convergeDate[curveName] = [];
  160. }
  161. convergeDate[curveName].push(item);
  162. });
  163. } else {
  164. // 如果是单个值,创建单一的曲线
  165. if (!convergeDate[columnName]) {
  166. convergeDate[columnName] = [];
  167. }
  168. convergeDate[columnName].push(parsedValue);
  169. }
  170. } catch (e) {
  171. // 如果解析失败,说明该列不是数组,直接作为单个数值处理
  172. if (!convergeDate[columnName]) {
  173. convergeDate[columnName] = [];
  174. }
  175. convergeDate[columnName].push(parseFloat(value));
  176. }
  177. }
  178. // 将新的 step 值追加到 xdata 数组
  179. xdata.value.push(rows[i].step);
  180. }
  181. // 遍历每一个列名,动态更新或创建曲线
  182. Object.keys(convergeDate).forEach((curveName) => {
  183. if(curveName === 'No'|| curveName === 'Time/s') return;
  184. let curveData = convergeDate[curveName];
  185. // 查找是否已经存在此曲线
  186. let existingSeries = series.value.find(s => s.name === curveName);
  187. if (existingSeries) {
  188. // 如果已存在,更新数据
  189. existingSeries.data.push(...curveData);
  190. } else {
  191. // 否则,创建新的曲线
  192. series.value.push({
  193. name: curveName,
  194. type: "line",
  195. data: curveData
  196. });
  197. }
  198. });
  199. // 使用 myChart 设置图表的配置
  200. myChart.setOption({
  201. legend: {
  202. data: Object.keys(convergeDate) // 设置图例数据为曲线名
  203. },
  204. xAxis: {
  205. data: xdata.value // 使用更新后的 xdata
  206. },
  207. series: series.value // 使用更新后的 series
  208. });
  209. console.log('更新后的 xdata:', xdata.value);
  210. console.log('更新后的 series:', series.value);
  211. };
  212. // 数据转化废弃
  213. // const getshuju = (data) => {
  214. // curvedata.value = data
  215. // convergeDate.value = []
  216. // series.value = []
  217. // xdata.value = []
  218. // let rows = JSON.parse(curvedata.value)
  219. // let num = 0
  220. // for (let i = 0; i < rows.length; i++) {
  221. // num += 1
  222. // vars.value = rows[i].vars.split(",")
  223. // vals.value = rows[i].vals.split(" ")
  224. // let data = vals.value.map((str) => Number(str))
  225. // convergeDate.value.push(data)
  226. // xdata.value.push(num)
  227. // }
  228. // console.log(convergeDate.value)
  229. // // console.log( convergeDate.value);
  230. // for (let j = 0; j < vars.value.length; j++) {
  231. // let firstColumn = convergeDate.value.map((row) => row[j])
  232. // let item = {
  233. // name: vars.value[j],
  234. // type: "line",
  235. // stack: "Total",
  236. // data: firstColumn
  237. // }
  238. // series.value.push(item)
  239. // }
  240. // myChart.setOption({
  241. // legend: {
  242. // data: vars.value
  243. // },
  244. // xAxis: {
  245. // data: xdata.value
  246. // },
  247. // series: series.value
  248. // })
  249. // }
  250. const getshuju = (data) => {
  251. // 初始化变量
  252. curvedata.value = data;
  253. convergeDate.value = [];
  254. series.value = [];
  255. xdata.value = [];
  256. // 解析传入的 JSON 数据
  257. let rows = JSON.parse(curvedata.value);
  258. for (let i = 0; i < rows.length; i++) {
  259. // 解析每一行的列名和列值
  260. vars.value = rows[i].vars.split(" "); // 列名(空格分隔)
  261. vals.value = rows[i].vals.split(" "); // 对应的值(空格分隔)
  262. // 处理 vals 中的数据
  263. let data = vals.value.map((str) => {
  264. // 处理每个值,如果是数组类型(JSON 字符串),则转换为数组
  265. try {
  266. return JSON.parse(str);
  267. } catch (e) {
  268. return Number(str); // 如果不是数组,直接转换为数字
  269. }
  270. });
  271. convergeDate.value.push(data);
  272. xdata.value.push(rows[i].step);
  273. }
  274. // 遍历每一个列名
  275. for (let j = 0; j < vars.value.length; j++) {
  276. if (vars.value[j] === 'No' || vars.value[j] === 'Time/s') {
  277. continue;
  278. }
  279. let firstColumn = convergeDate.value.map((row) => row[j]);
  280. // 如果该列是数组类型的数据(例如 design_var/upperB),需要为每个值创建一条曲线
  281. if (Array.isArray(firstColumn[0])) {
  282. firstColumn[0].forEach((_, idx) => {
  283. let curveData = convergeDate.value.map((row) => row[j][idx]);
  284. let item = {
  285. name: `${vars.value[j]}-${idx + 1}`, // 为每条曲线命名,使用列名 + 索引
  286. type: "line",
  287. data: curveData
  288. };
  289. series.value.push(item);
  290. });
  291. } else {
  292. // 如果该列不是数组类型(普通值),直接绘制一条曲线
  293. let item = {
  294. name: vars.value[j],
  295. type: "line",
  296. data: firstColumn
  297. };
  298. series.value.push(item);
  299. }
  300. }
  301. // 提取 legend 的名称
  302. const legendData = series.value.map(item => item.name);
  303. // 更新图表配置
  304. myChart.setOption({
  305. legend: {
  306. data: legendData
  307. },
  308. xAxis: {
  309. data: xdata.value
  310. },
  311. series: series.value
  312. });
  313. };
  314. const linechart = () => {
  315. // let chartDom = document.getElementById('line');
  316. // let myChart= echarts.init(chartDom);
  317. option.value = {
  318. tooltip: {
  319. trigger: "axis", //item
  320. backgroundColor: "rgba(0,0,0,.6)",
  321. borderColor: "rgba(147, 235, 248, .8)",
  322. textStyle: {
  323. color: "#FFF"
  324. }
  325. },
  326. legend: {
  327. data: vars.value,
  328. orient: "vertical", // 图例方向 (horizontal水平, vertical垂直)
  329. right: '0%',
  330. top: '3%',
  331. itemWidth: 30, // 设置每个图例项的宽度
  332. itemHeight: 0, // 设置每个图例项的高度
  333. // icon: "line",
  334. width: 'auto',
  335. height: 'auto',
  336. pageButtonItemGap: 10, // 上下滚动按钮之间的间隔
  337. pageButtonPosition: 'end', // 滚动按钮位置,'start'、'end'
  338. type: 'scroll',
  339. formatter: function (name) {
  340. // 使用 ECharts 内部 API 获取文本宽度
  341. var textWidth = echarts.format.getTextRect(name).width;
  342. // 设置一个最大宽度(如 150px),如果文本宽度超出最大值则截断
  343. if (textWidth > 150) {
  344. return name.substring(0, 15) + '...'; // 超出最大宽度的部分加省略号
  345. }
  346. return name; // 否则,直接返回原始文本
  347. },
  348. },
  349. grid: {
  350. show: false,
  351. left: "6%",
  352. right: "14%",
  353. bottom: "10%",
  354. containLabel: true
  355. },
  356. // toolbox: {
  357. // feature: {
  358. // saveAsImage: {}
  359. // }
  360. // },
  361. xAxis: {
  362. type: "category",
  363. boundaryGap: false,
  364. name: "迭代次数",
  365. nameGap:40,
  366. nameTextStyle:{
  367. fontSize: 16,
  368. color:'#333333',
  369. fontFamily:'Microsoft YaHei'
  370. },
  371. nameLocation: 'middle',
  372. data: xdata.value,
  373. axisLine: {
  374. //X轴线
  375. show: true,
  376. lineStyle: {
  377. color: "#333333", // 线的颜色
  378. width: 1, // 线宽
  379. type: "solid" // 线的类型,默认为实线,可选:'solid', 'dashed', 'dotted'
  380. }
  381. },
  382. splitLine: {
  383. show: true // 如果不需要网格线,可以设置为 false
  384. },
  385. },
  386. yAxis: {
  387. type: "value",
  388. name: "优化变量",
  389. nameGap:40,
  390. nameTextStyle:{
  391. fontSize: 16,
  392. color:'#333333',
  393. fontFamily:'Microsoft YaHei'
  394. },
  395. nameLocation: 'middle',
  396. axisLine: {
  397. //Y轴线
  398. show: true,
  399. lineStyle: {
  400. color: "#333333", // 线的颜色
  401. width: 1, // 线宽
  402. type: "solid" // 线的类型,默认为实线,可选:'solid', 'dashed', 'dotted'
  403. }
  404. },
  405. axisTick: {
  406. // Y轴刻度线
  407. show:true,
  408. },
  409. splitLine: {
  410. show: true // 如果不需要网格线,可以设置为 false
  411. },
  412. },
  413. dataZoom: [
  414. {
  415. type: "inside", // 鼠标滚轮缩放
  416. xAxisIndex: [0], // 针对 X 轴
  417. },
  418. {
  419. type: "slider", // 滑动条缩放
  420. xAxisIndex: [0],
  421. show: false,
  422. }
  423. ],
  424. series: series.value
  425. }
  426. option.value && myChart.setOption(option.value)
  427. window.onresize = function () {
  428. // 让图表自适应大小
  429. myChart.resize()
  430. }
  431. }
  432. // 监听数据变化,重绘图表
  433. // watch( myChart.value, () => {
  434. // console.log(11111)
  435. // window.onresize = function() {
  436. // // 让图表自适应大小
  437. // myChart.value.resize();
  438. // };
  439. // });
  440. //window.addEventListener('resize', handleResize);
  441. // watch(series, () => {
  442. // linechart();
  443. // }, { deep: true });
  444. // watch(() =>props.echartdata, (newValue, oldValue) => {
  445. // // 这里处理 echartData 变化的逻辑
  446. // console.log(11111)
  447. // console.log('echartData changed:', newValue);
  448. // // console.log(optmonitor1.value);
  449. // }, {deep: true ,immediate: true });
  450. defineExpose({ linechart, getshuju, getsockechart, echatinit })
  451. </script>
  452. <style lang="scss" scoped>
  453. .selcal {
  454. position: absolute;
  455. top: 37%;
  456. width: 26px;
  457. color: #000;
  458. font-size: 14px;
  459. font-weight: bold;
  460. left: 5px;
  461. }
  462. .diedai {
  463. color: #000;
  464. font-size: 14px;
  465. padding-bottom: 20px;
  466. font-weight: bold;
  467. }
  468. </style>