conditionAssistance.vue 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941
  1. <template>
  2. <BasicModal
  3. @register="register"
  4. title="局部通风机运行工况智能决策"
  5. :maskStyle="{ backgroundColor: '#000000aa', backdropFilter: 'blur(3px)' }"
  6. :width="isComputeGas ? '1350px' : '950px'"
  7. v-bind="$attrs"
  8. @ok="onSubmit"
  9. :closeFunc="onCancel"
  10. :canFullscreen="false"
  11. :destroyOnClose="true"
  12. :footer="null"
  13. :maskClosable="false"
  14. >
  15. <div class="modal-box">
  16. <div v-if="isComputeGas" class="left-box" style="width: 550px; height: 400px">
  17. <BarAndLine
  18. class="echarts-line"
  19. xAxisPropType="time"
  20. :dataSource="monitorData"
  21. height="400px"
  22. :chartsColumns="chartsColumnList"
  23. :option="echatsOption"
  24. />
  25. </div>
  26. <div class="center-box">
  27. <a-spin :spinning="loadding" tip="正在计算,请稍等。。。">
  28. <div ref="ChartRef" class="info-echarts" :style="{ width: isComputeGas ? '450px' : '520px', height: '350px' }"></div>
  29. </a-spin>
  30. </div>
  31. <div class="right-box">
  32. <!-- <div class="box-title">曲线方程</div> -->
  33. <dv-decoration7 style="height: 20px">
  34. <div class="box-title">曲线方程</div>
  35. </dv-decoration7>
  36. <div class="info-lines">
  37. <div v-for="(item, index) in lineEquation" class="info-item" :key="index">
  38. <div class="title">{{ item }}</div>
  39. </div>
  40. </div>
  41. </div>
  42. <div class="tip-box">
  43. <div class="title">最佳工况点 <SendOutlined class="ml-5px" /></div>
  44. <div class="tip-container" :style="{ width: isComputeGas ? '898px' : '1000px' }">
  45. <template v-if="resultObj && isHaCross">
  46. <div class="ml-10px">
  47. <span>频率:</span>
  48. <span style="color: #d066ff; padding: 0 10px; font-weight: 600">{{ formatNum(resultObj.Hz) }}Hz</span>
  49. </div>
  50. <div class="ml-10px">
  51. <span>风量:</span>
  52. <span style="color: #3adeff; padding: 0 10px; font-weight: 600">{{ formatNum(resultObj.x) }} m³/min</span>
  53. </div>
  54. <div class="ml-10px">
  55. <span>负压</span>
  56. <span style="color: #ffbe34; padding: 0 10px; font-weight: 600">{{ formatNum(resultObj.y) }} Pa</span>
  57. </div>
  58. </template>
  59. <div v-else-if="isHaCross" class="ml-10px">暂无</div>
  60. <div v-else style="color: #ffbe34; padding: 0 10px; font-weight: 600" class="ml-10px">无有效工况点</div>
  61. </div>
  62. </div>
  63. </div>
  64. <div class="setting-box">
  65. <div class="right-inputs">
  66. <div class="vent-flex-row">
  67. <div class="input-title">风量(m³/min):</div>
  68. <InputNumber :disabled="isComputeGas" class="input-box" size="large" v-model:value="uQ1" />
  69. <div class="input-title">风压(Pa):</div>
  70. <InputNumber :disabled="isComputeGas" class="input-box" size="large" v-model:value="uH" />
  71. <div v-if="!isComputeGas" class="btn btn1" @click="makeLine">决策工况</div>
  72. <template v-else>
  73. <div class="btn btn1" @click="startCompute">一键调控</div>
  74. <div class="btn btn1" @click="resetCompute">一键复位</div>
  75. </template>
  76. </div>
  77. </div>
  78. </div>
  79. </BasicModal>
  80. </template>
  81. <script lang="ts" setup>
  82. //ts语法
  83. import { ref, onMounted, reactive, nextTick, computed } from 'vue';
  84. import echarts from '/@/utils/lib/echarts';
  85. import { option, initData, fanInfoData, chartsColumnList, echatsOption } from '../fanLocal.data';
  86. import { BasicModal, useModalInner } from '/@/components/Modal';
  87. import { useForm } from '/@/components/Form/index';
  88. import { Input, InputNumber } from 'ant-design-vue';
  89. import { Decoration7 as DvDecoration7 } from '@kjgl77/datav-vue3';
  90. import { message } from 'ant-design-vue';
  91. import { formatNum } from '/@/utils/ventutil';
  92. import BarAndLine from '/@/components/chart/BarAndLine.vue';
  93. import { cloneDeep } from 'lodash-es';
  94. import dayjs from 'dayjs';
  95. import { SendOutlined } from '@ant-design/icons-vue';
  96. const emit = defineEmits(['close', 'register', 'openModal']);
  97. const props = defineProps({
  98. dataSource: {
  99. type: Array,
  100. default: () => [],
  101. },
  102. frequency: {
  103. type: Number,
  104. default: 30,
  105. },
  106. m3: {
  107. type: Number,
  108. default: 670.8,
  109. },
  110. // gasWarningMax: { type: Number, default: 0.5 },
  111. // gasWarningVal: { type: Number, default: 0.6 },
  112. // windQuantity: { type: Number, default: 635.84 },
  113. });
  114. type AssistanceItemType = {
  115. angle: number;
  116. Hz: number;
  117. a: number;
  118. b: number;
  119. c: number;
  120. min: number;
  121. max: number;
  122. };
  123. // 注册 modal
  124. const [register, { closeModal }] = useModalInner((data) => {
  125. nextTick(() => {
  126. computeAssistance();
  127. if (option['xAxis']) option['xAxis']['data'] = xData;
  128. option['series'] = yDataList;
  129. if (JSON.stringify(data) !== '{}') {
  130. uQ1.value = Number(data['m3']);
  131. uHz.value = Math.ceil(data['frequency']);
  132. gasWarningVal.value = data['gasWarningVal'];
  133. isComputeGas.value = true;
  134. nextTick(() => {
  135. computeUH(data['frequency'], data['m3']);
  136. initEcharts();
  137. setTimeout(() => {
  138. // 根据频率计算uH
  139. makeLine();
  140. }, 2000);
  141. });
  142. } else {
  143. initEcharts();
  144. isComputeGas.value = false;
  145. }
  146. });
  147. });
  148. const loadding = ref<boolean>(false);
  149. const formShow = ref(false);
  150. const formType = ref('');
  151. const ChartRef = ref();
  152. const myChart = ref();
  153. const refresh = ref(true);
  154. const xDataMax = 1000;
  155. let xDataMin = 0;
  156. const xData: any[] = [];
  157. const yDataList: [] = [];
  158. let lineNum = 0;
  159. const lineEquation = ref<string[]>([]);
  160. const assistanceData = ref([]);
  161. const monitorData = ref([]);
  162. const gasWarningVal = ref(0);
  163. const gasWarningMax = ref(0.5);
  164. const isComputeGas = ref(false);
  165. const isStartCompute = ref(0);
  166. const uHz = ref(0);
  167. const uQ1 = ref(0);
  168. const uQ = computed(() => {
  169. if (uQ1.value) {
  170. if (gasWarningVal.value) {
  171. return ((uQ1.value * gasWarningVal.value) / gasWarningMax.value) * 1.08;
  172. }
  173. return uQ1.value;
  174. } else {
  175. return 0;
  176. }
  177. });
  178. const uH = ref<number | undefined>(undefined); // - 1000
  179. const isHaCross = ref(true);
  180. const resultObj = ref<{ x: number; y: number; Hz: number } | null>(null);
  181. const [registerForm, {}] = useForm({
  182. labelWidth: 120,
  183. actionColOptions: {
  184. span: 24,
  185. },
  186. compact: true,
  187. showSubmitButton: true,
  188. submitButtonOptions: {
  189. text: '提交',
  190. preIcon: '',
  191. },
  192. showResetButton: true,
  193. resetButtonOptions: {
  194. text: '关闭',
  195. preIcon: '',
  196. },
  197. resetFunc: async () => {
  198. formShow.value = false;
  199. },
  200. });
  201. function computeAssistance() {
  202. assistanceData.value = initData();
  203. lineNum = 0;
  204. const assistanceDataList = [];
  205. const lineEquationList: string[] = [];
  206. for (const key in assistanceData.value) {
  207. const item = assistanceData.value[key];
  208. assistanceDataList.push(item);
  209. lineEquationList.push(
  210. `H${parseInt(item['Hz'])} = ${item['a']}Q² ${Number(item['b']) > 0 ? '+' : '-'} ${Math.abs(Number(item['b'])).toFixed(4)}Q ${
  211. Number(item['c']) > 0 ? '+' : '-'
  212. } ${Math.abs(Number(item['c'])).toFixed(4)}`
  213. );
  214. }
  215. lineEquation.value = lineEquationList;
  216. lineNum = assistanceDataList.length;
  217. xDataMin =
  218. Math.min.apply(
  219. Math,
  220. assistanceDataList.map((item) => {
  221. return item.min;
  222. })
  223. ) - 100;
  224. // const xDataMax = Math.max.apply(Math, assistanceDataList.map(item => { return item.max }))
  225. fanInfoData.flfw = `${xDataMin}~${xDataMax}`;
  226. const computeItem = (item: AssistanceItemType) => {
  227. const min = item.min;
  228. const max = item.max;
  229. const HList: number[] = [];
  230. for (let i = xDataMin; i <= xDataMax; i++) {
  231. if (i < min) {
  232. HList.push(null);
  233. } else if (i > max) {
  234. HList.push(null);
  235. } else {
  236. HList.push(item.a * i * i + item.b * i + item.c);
  237. }
  238. }
  239. return HList;
  240. };
  241. for (const key in assistanceData.value) {
  242. const element: AssistanceItemType = assistanceData.value[key];
  243. const yData: number[] = computeItem(element);
  244. const series = {
  245. type: 'line',
  246. name: `${element['Hz']}Hz`,
  247. smooth: true,
  248. showSymbol: false,
  249. symbol: 'none',
  250. emphasis: {
  251. focus: 'series',
  252. },
  253. itemStyle: { normal: { label: { show: true } } },
  254. lineStyle: {
  255. width: 1,
  256. color: '#ffffff88',
  257. },
  258. zlevel: 0,
  259. z: 1,
  260. endLabel: {
  261. show: true,
  262. formatter: '{a}',
  263. distance: 0,
  264. color: '#39E9FE99',
  265. backgroundColor: 'transparent',
  266. padding: [3, 3, 2, 3],
  267. },
  268. data: yData,
  269. };
  270. yDataList.push(series);
  271. }
  272. for (let i = xDataMin; i <= xDataMax; i++) {
  273. xData.push(i);
  274. }
  275. }
  276. function computeUH(Hz: number, uQ: number) {
  277. debugger;
  278. const equation = assistanceData.value.find((item) => {
  279. return Math.ceil(Hz) == item['Hz'];
  280. });
  281. if (equation) {
  282. const uHMax = Math.round((equation['a'] * equation['min'] * equation['min'] + equation['b'] * equation['min'] + equation['c']) * 100) / 100;
  283. const uHMin = Math.round((equation['a'] * equation['max'] * equation['max'] + equation['b'] * equation['max'] + equation['c']) * 100) / 100;
  284. const uH1 = Math.round((equation['a'] * uQ * uQ + equation['b'] * uQ + equation['c']) * 100) / 100;
  285. if (uH1 >= uHMin && uH1 <= uHMax) {
  286. uH.value = uH1;
  287. isHaCross.value = true;
  288. } else {
  289. isHaCross.value = false;
  290. }
  291. }
  292. }
  293. function computeRLine() {
  294. console.log('计算后的风量为------------>', uQ.value);
  295. if (uH.value && uQ.value) {
  296. const R = uH.value / Number(uQ.value) / Number(uQ.value);
  297. const yAxis: number[] = [];
  298. for (let i = 0; i < xData.length; i++) {
  299. const x = xData[i];
  300. const y = R * x * x;
  301. if (x == uQ.value) {
  302. uH.value = y;
  303. }
  304. yAxis.push(y);
  305. }
  306. const series = {
  307. name: 'R',
  308. type: 'line',
  309. smooth: true,
  310. showSymbol: false,
  311. zlevel: 0,
  312. emphasis: {
  313. focus: 'series',
  314. },
  315. itemStyle: { normal: { label: { show: true } } },
  316. lineStyle: {
  317. width: 2,
  318. color: '#D0A343',
  319. },
  320. endLabel: {
  321. show: true,
  322. formatter: '{a}',
  323. distance: 0,
  324. color: '#D0A343',
  325. },
  326. data: yAxis,
  327. };
  328. yDataList[lineNum] = series;
  329. }
  330. }
  331. function reSetLine() {
  332. let minIndex = -1;
  333. for (let i = 0; i < yDataList.length; i++) {
  334. if (i !== lineNum && i != lineNum + 1) {
  335. if (yDataList[i]['lineStyle']) yDataList[i]['lineStyle']['color'] = '#ffffff88';
  336. if (yDataList[i]['lineStyle']) yDataList[i]['lineStyle']['width'] = 1;
  337. if (yDataList[i]['endLabel'] && yDataList[i]['endLabel']['color']) {
  338. yDataList[i]['endLabel']['color'] = '#39E9FE99';
  339. }
  340. if (yDataList[i]['endLabel'] && yDataList[i]['endLabel']['backgroundColor']) yDataList[i]['endLabel']['backgroundColor'] = 'transparent';
  341. if (yDataList[i]['z']) yDataList[i]['z'] = 1;
  342. }
  343. if (resultObj.value && `${resultObj.value.Hz}Hz` == yDataList[i]['name']) {
  344. minIndex = i;
  345. }
  346. }
  347. if (minIndex != -1) {
  348. yDataList[minIndex]['lineStyle']['color'] = '#9A60B4';
  349. yDataList[minIndex]['lineStyle']['width'] = 2;
  350. yDataList[minIndex]['endLabel']['color'] = '#9A60B4';
  351. yDataList[minIndex]['endLabel']['backgroundColor'] = '#111';
  352. yDataList[minIndex]['z'] = 999;
  353. }
  354. }
  355. // 根据风量计算压差
  356. function computePa() {
  357. debugger;
  358. const R = uH.value / Number(uQ.value) / Number(uQ.value);
  359. const pointX = Number(uQ.value);
  360. const pointY = Number(uH.value);
  361. type ItemType = {
  362. x: number;
  363. y: number;
  364. Hz: number;
  365. };
  366. const paList = new Map<number, ItemType>(); // key 是最近距离
  367. const getIntersectionPoint = (a, b, c, R, min, max) => {
  368. const obj: { x: undefined | number; y: undefined | number; min: number; max: number } = { x: undefined, y: undefined, min: min, max: max };
  369. // 计算二次方程的判别式
  370. const discriminant = b * b - 4 * (a - R) * c;
  371. if (discriminant > 0) {
  372. // 有两个实根
  373. const x1 = (-b + Math.sqrt(discriminant)) / (2 * (a - R));
  374. const x2 = (-b - Math.sqrt(discriminant)) / (2 * (a - R));
  375. const y1 = R * x1 * x1;
  376. const y2 = R * x2 * x2;
  377. if (x1 >= min && x1 <= max) {
  378. obj.x = x1;
  379. obj.y = y1;
  380. } else {
  381. obj.x = x2;
  382. obj.y = y2;
  383. }
  384. } else if (discriminant === 0) {
  385. // 有一个实根
  386. const x = -b / (2 * (a - R));
  387. const y = R * x * x;
  388. if (x >= min && x <= max) {
  389. obj.x = x;
  390. obj.y = y;
  391. }
  392. // console.log(`唯一交点: (${x}, ${y})`);
  393. } else {
  394. // 没有实根,交点在虚数域
  395. console.log('没有实数交点');
  396. isHaCross.value = false;
  397. }
  398. return obj;
  399. };
  400. for (let key in assistanceData.value) {
  401. const item: AssistanceItemType = assistanceData.value[key];
  402. paList.set(item.Hz, getIntersectionPoint(item.a, item.b, item.c, R, item.min, item.max));
  403. }
  404. const min = (points: Map<number, ItemType>) => {
  405. const targetX = uQ.value;
  406. const targetY = uH.value;
  407. let minDistance = Number.POSITIVE_INFINITY;
  408. let closestPoint = null;
  409. let keyVal = '';
  410. // 遍历已知点数组,计算距离并更新最小距离和对应的点
  411. for (const [key, point] of points) {
  412. const distance = Math.sqrt((targetX - point.x) ** 2 + (targetY - point.y) ** 2);
  413. if (distance < minDistance) {
  414. minDistance = distance;
  415. closestPoint = point;
  416. keyVal = key;
  417. }
  418. }
  419. if (closestPoint !== null) {
  420. // console.log(`距离最小的点是 (${closestPoint.x}, ${closestPoint.y}), 距离为 ${minDistance}`);
  421. if (closestPoint.x < closestPoint.min || closestPoint.x > closestPoint.max) {
  422. resultObj.value = null;
  423. isHaCross.value = false;
  424. console.log('没有找到最小距离的点');
  425. } else {
  426. resultObj.value = { x: closestPoint.x, y: closestPoint.y, Hz: keyVal };
  427. isHaCross.value = true;
  428. }
  429. } else {
  430. resultObj.value = null;
  431. isHaCross.value = false;
  432. console.log('没有找到最小距离的点');
  433. }
  434. };
  435. min(paList);
  436. }
  437. function computeR() {
  438. if (uQ.value && uH.value) {
  439. computeRLine();
  440. computePa();
  441. const x = resultObj.value && resultObj.value.x ? resultObj.value.x.toFixed(0) : -100;
  442. const y = resultObj.value && resultObj.value.y ? Number(resultObj.value.y.toFixed(0)) : -100;
  443. const series = {
  444. type: 'effectScatter',
  445. symbolSize: 5,
  446. // symbolOffset:[1, 1],
  447. showEffectOn: 'render',
  448. // 涟漪特效相关配置。
  449. rippleEffect: {
  450. // 波纹的绘制方式,可选 'stroke' 和 'fill'。
  451. brushType: 'stroke',
  452. },
  453. zlevel: 1,
  454. z: 999,
  455. itemStyle: {
  456. color: '#C60000',
  457. },
  458. data: [[x, y]],
  459. };
  460. yDataList[lineNum + 1] = series;
  461. }
  462. // // 根据计算后的得到的频率,风量,瓦斯浓度
  463. // getMonitor();
  464. }
  465. function getMonitor() {
  466. clearTimeout(timer);
  467. timer = undefined;
  468. const n = 10;
  469. const windQuantity = uQ1.value;
  470. const obj = {
  471. m3: windQuantity,
  472. gas: gasWarningVal.value,
  473. time: '',
  474. Hz: uHz.value,
  475. };
  476. const monitorList: { m3: number; gas: number; Hz: number; time: string }[] = [];
  477. for (let i = 0; i < n; i++) {
  478. const item = cloneDeep(obj);
  479. const m3Temp = (Math.random() * 2 - 1) * Math.random() * 20;
  480. const gas = m3Temp * 0.0002;
  481. item.time = dayjs(new Date().getTime() - (n + i) * 3000).format('HH:mm:ss');
  482. item.m3 = (obj.m3 + m3Temp).toFixed(2);
  483. item.gas = (obj.gas + gas).toFixed(4);
  484. item.Hz = (obj.Hz + Math.random()).toFixed(2);
  485. monitorList.unshift(item);
  486. }
  487. monitorData.value = cloneDeep(monitorList);
  488. setTimeout(() => {
  489. clearTimeout(timer);
  490. timer = undefined;
  491. timer = 0;
  492. if (uQ1.value && uH.value && uQ.value) {
  493. openTimer(cloneDeep(obj), 0);
  494. } else {
  495. openTimer(cloneDeep(obj), 0);
  496. }
  497. }, 1000);
  498. }
  499. function startCompute() {
  500. setTimeout(() => {
  501. message.success('指令下发成功!');
  502. isStartCompute.value = 1;
  503. }, 800);
  504. }
  505. function resetCompute() {
  506. setTimeout(() => {
  507. message.success('指令下发成功!');
  508. isStartCompute.value = -1;
  509. tempList.length = 0;
  510. n = 0;
  511. }, 800);
  512. }
  513. let timer = undefined;
  514. let n = 0;
  515. let tempList = [];
  516. function openTimer(obj: { m3: number; gas: number; Hz: number; time: string }) {
  517. // 打开定时器
  518. const monitorList = cloneDeep(monitorData.value);
  519. if (timer !== undefined) {
  520. timer = setTimeout(() => {
  521. obj.m3 = Number(obj.m3);
  522. obj.gas = Number(obj.gas);
  523. obj.Hz = Number(obj.Hz);
  524. const item = cloneDeep(obj);
  525. item.time = dayjs(new Date().getTime()).format('HH:mm:ss');
  526. if (resultObj.value && resultObj.value.x && resultObj.value.y && isStartCompute.value != 0) {
  527. if (isStartCompute.value == 1 && Number(obj.m3) > uQ.value && Number(obj.gas) < gasWarningMax.value) {
  528. isStartCompute.value = 0;
  529. n = 0;
  530. } else if (isStartCompute.value == -1 && Number(obj.m3) < uQ1.value) {
  531. isStartCompute.value = 0;
  532. n = 0;
  533. }
  534. }
  535. if (!isStartCompute.value) {
  536. const m3Temp = (Math.random() * 2 - 1) * Math.random() * Math.random() * 10;
  537. const gas = m3Temp * 0.0002;
  538. item.m3 = (obj.m3 + m3Temp).toFixed(2);
  539. item.gas = (obj.gas + gas).toFixed(4);
  540. item.Hz = (obj.Hz + Math.random()).toFixed(2);
  541. n = 0;
  542. } else {
  543. if (n < 2) {
  544. const item1 = cloneDeep(obj);
  545. const m3Temp = Math.random() * Math.random() * 10;
  546. const gas = m3Temp * 0.0002;
  547. item1.m3 = (obj.m3 + m3Temp).toFixed(2);
  548. item1.gas = (obj.gas + gas).toFixed(4);
  549. item1.Hz = (obj.Hz + (Math.random() * 2 - 1) * Math.random()).toFixed(2);
  550. tempList.push(item1);
  551. }
  552. // 计算 uQ1 -> uQ gas -> gasWarningMax.value Hz -> resultObj.value.Hz
  553. if (isStartCompute.value == 1) {
  554. if (resultObj.value.Hz - obj.Hz > 0) {
  555. item.Hz = (uHz.value + (2 * n * (resultObj.value.Hz - uHz.value)) / 20).toFixed(2);
  556. if (resultObj.value.Hz - obj.Hz < 0) {
  557. item.Hz = (resultObj.value.Hz + Math.random() * 0.5).toFixed(2);
  558. }
  559. } else {
  560. // item.Hz = (resultObj.value.Hz + (Math.random() * 2 - 1) * Math.random() * 2).toFixed(2);
  561. item.Hz = (resultObj.value.Hz + Math.random() * 0.5).toFixed(2);
  562. }
  563. item.m3 = (obj.m3 + (0.027 * n * item.Hz * (item.Hz - uHz.value) * (uQ.value - uQ1.value)) / 600).toFixed(2);
  564. if (Number(item.m3) > uQ.value) {
  565. item.m3 = (uQ.value + Math.random() * 10).toFixed(2);
  566. }
  567. item.gas = (
  568. gasWarningVal.value -
  569. (0.015 * item.Hz * n * (item.Hz - uHz.value) * (gasWarningVal.value - gasWarningMax.value)) / 200
  570. ).toFixed(4);
  571. } else {
  572. // 复位
  573. if (obj.Hz - uHz.value > 0) {
  574. item.Hz = (obj.Hz - (2 * n * (resultObj.value.Hz - uHz.value)) / 30).toFixed(2);
  575. if (item.Hz - uHz.value < 0) {
  576. item.Hz = uHz.value - 0.3;
  577. }
  578. } else {
  579. item.Hz = (uHz.value + (Math.random() * 2 - 1) * Math.random() * 2).toFixed(2);
  580. }
  581. item.m3 = (obj.m3 - (0.02 * n * n * item.Hz * (resultObj.value.Hz - uHz.value) * (uQ.value - uQ1.value)) / 400).toFixed(2);
  582. if (item.m3 < uQ1.value) {
  583. item.m3 = uQ1.value - Math.random() * 10;
  584. }
  585. item.gas = (obj.gas + (0.015 * item.Hz * n * (uHz.value - item.Hz) * (gasWarningVal.value - gasWarningMax.value)) / 800).toFixed(4);
  586. }
  587. }
  588. if (monitorList.length >= 10) {
  589. monitorList.shift();
  590. const monitor = cloneDeep(item);
  591. const data = tempList.shift();
  592. if (data) {
  593. item['m3'] = data['m3'];
  594. item['gas'] = data['gas'];
  595. }
  596. tempList.push(monitor);
  597. monitorList.push(item);
  598. } else {
  599. monitorList.push(item);
  600. }
  601. monitorData.value = monitorList;
  602. // console.log('瓦斯监测数据-------------->', monitorData.value);
  603. if (timer) {
  604. if (!isStartCompute.value) {
  605. // n++;
  606. openTimer(cloneDeep(obj));
  607. } else {
  608. n++;
  609. openTimer(cloneDeep(item));
  610. }
  611. }
  612. }, 3000);
  613. }
  614. }
  615. function edit(flag) {
  616. if (flag == 'info') {
  617. formType.value = '编辑风机信息';
  618. }
  619. if (flag == 'line') {
  620. formType.value = '编辑特性曲线';
  621. }
  622. if (formShow.value == true) {
  623. formShow.value = false;
  624. nextTick(() => {
  625. formShow.value = true;
  626. });
  627. } else {
  628. formShow.value = true;
  629. }
  630. }
  631. function onSubmit() {
  632. emit('close');
  633. closeModal();
  634. ChartRef.value = null;
  635. uQ.value = undefined;
  636. uH.value = undefined;
  637. formType.value = '';
  638. refresh.value = true;
  639. xData.length = 0;
  640. yDataList.length = 0;
  641. lineNum = 0;
  642. lineEquation.value = [];
  643. resultObj.value = null;
  644. monitorData.value = [];
  645. clearTimeout(timer);
  646. timer = undefined;
  647. }
  648. async function onCancel() {
  649. return new Promise((resolve) => {
  650. if (isStartCompute.value == 0) {
  651. onSubmit();
  652. resolve(true);
  653. } else {
  654. message.warning('为保障矿井安全生产,请确保已复位!!!');
  655. resolve(false);
  656. }
  657. });
  658. }
  659. function initEcharts() {
  660. if (ChartRef.value) {
  661. reSetLine();
  662. myChart.value = echarts.init(ChartRef.value);
  663. option && myChart.value.setOption(option);
  664. refresh.value = false;
  665. getMonitor();
  666. nextTick(() => {
  667. setTimeout(() => {
  668. refresh.value = true;
  669. }, 0);
  670. });
  671. }
  672. }
  673. function makeLine() {
  674. if (uQ.value && uH.value) {
  675. loadding.value = true;
  676. setTimeout(() => {
  677. computeR();
  678. reSetLine();
  679. option && myChart.value.setOption(option);
  680. loadding.value = false;
  681. }, 1200);
  682. }
  683. }
  684. function handleSubmit() {
  685. message.success('提交成功');
  686. setTimeout(() => {
  687. formShow.value = false;
  688. }, 800);
  689. }
  690. onMounted(() => {
  691. timer = undefined;
  692. });
  693. </script>
  694. <style scoped lang="less">
  695. .modal-box {
  696. display: flex;
  697. flex-direction: row;
  698. background-color: #ffffff05;
  699. padding: 20px 8px 0 8px;
  700. border: 1px solid #00d8ff22;
  701. position: relative;
  702. // min-height: 600px;
  703. .box-title {
  704. width: calc(100% - 40px);
  705. text-align: center;
  706. background-color: #1dc1f522;
  707. }
  708. .info-item {
  709. display: flex;
  710. justify-content: space-between;
  711. align-items: center;
  712. padding: 2px 0px;
  713. margin: 10px 0;
  714. line-height: 30px;
  715. background-image: linear-gradient(to right, #39deff15, #3977e500);
  716. &:first-child {
  717. margin-top: 0;
  718. }
  719. .title {
  720. width: 200px;
  721. text-align: left;
  722. padding-left: 20px;
  723. color: #f1f1f1cc;
  724. }
  725. .value {
  726. width: 150px;
  727. color: #00d8ff;
  728. padding-right: 20px;
  729. text-align: right;
  730. }
  731. }
  732. .right-box {
  733. width: 320px;
  734. .info-lines {
  735. width: calc(100% - 2px);
  736. height: 450px;
  737. box-shadow: 0px 0px 50px #86baff08 inset;
  738. overflow-y: auto;
  739. margin-top: 5px;
  740. .title {
  741. width: 100%;
  742. color: #f1f1f1cc;
  743. }
  744. }
  745. }
  746. .center-box {
  747. flex: 1;
  748. margin: 0 10px;
  749. display: flex;
  750. .info-echarts {
  751. // background-color: #ffffff11;
  752. }
  753. .result-tip {
  754. text-align: center;
  755. background-color: #00000011;
  756. line-height: 28px;
  757. margin: 10px 50px 0 50px;
  758. border: 1px solid #00d8ff22;
  759. border-radius: 2px;
  760. }
  761. }
  762. .tip-box {
  763. width: 1040px;
  764. height: 44px;
  765. position: absolute;
  766. top: 417px;
  767. display: flex;
  768. padding: 0 20px;
  769. .title {
  770. width: 142px;
  771. height: 43px;
  772. display: flex;
  773. align-items: center;
  774. padding-left: 30px;
  775. background-image: url('@/assets/images/fanlocal-tip/tip-title.png');
  776. position: relative;
  777. &::before {
  778. content: '';
  779. display: inline-block;
  780. position: absolute;
  781. width: 31px;
  782. height: 31px;
  783. top: 5px;
  784. left: -8px;
  785. background-image: url('@/assets/images/fanlocal-tip/tip-icon.png');
  786. }
  787. }
  788. .tip-container {
  789. width: 898px;
  790. height: 44px;
  791. line-height: 44px;
  792. display: flex;
  793. background-image: url('@/assets/images/fanlocal-tip/tip-bg.png');
  794. background-size: cover;
  795. }
  796. }
  797. }
  798. .setting-box {
  799. width: 1170px;
  800. height: 70px;
  801. margin: 10px 0;
  802. background-color: #ffffff05;
  803. border: 1px solid #00d8ff22;
  804. display: flex;
  805. align-items: center;
  806. justify-content: space-between;
  807. .right-inputs {
  808. width: 100%;
  809. display: flex;
  810. height: 40px;
  811. margin: 0 10px;
  812. justify-content: space-between;
  813. }
  814. .left-buttons {
  815. display: flex;
  816. height: 40px;
  817. .btn {
  818. margin: 0 10px;
  819. }
  820. }
  821. .border-clip {
  822. width: 1px;
  823. height: 25px;
  824. border-right: 1px solid #8b8b8b77;
  825. }
  826. .input-title {
  827. max-width: 150px;
  828. }
  829. .input-box {
  830. width: 220px !important;
  831. background: transparent !important;
  832. border-color: #00d8ff44 !important;
  833. margin-right: 20px;
  834. color: #fff !important;
  835. }
  836. .btn {
  837. padding: 8px 20px;
  838. position: relative;
  839. border-radius: 2px;
  840. color: #fff;
  841. width: fit-content;
  842. cursor: pointer;
  843. &::before {
  844. position: absolute;
  845. display: block;
  846. content: '';
  847. width: calc(100% - 4px);
  848. height: calc(100% - 4px);
  849. top: 2px;
  850. left: 2px;
  851. border-radius: 2px;
  852. z-index: -1;
  853. }
  854. }
  855. .btn1 {
  856. border: 1px solid #5cfaff;
  857. &::before {
  858. background-image: linear-gradient(#2effee92, #0cb1d592);
  859. }
  860. &:hover {
  861. border: 1px solid #5cfaffaa;
  862. &::before {
  863. background-image: linear-gradient(#2effee72, #0cb1d572);
  864. }
  865. }
  866. }
  867. }
  868. .is-open {
  869. animation: open 0.5s;
  870. animation-iteration-count: 1;
  871. animation-fill-mode: forwards;
  872. animation-timing-function: ease-in;
  873. }
  874. .is-close {
  875. height: 0px;
  876. }
  877. @keyframes open {
  878. 0% {
  879. height: 0px;
  880. }
  881. 100% {
  882. height: fit-content;
  883. }
  884. }
  885. @keyframes close {
  886. 0% {
  887. height: fit-content;
  888. }
  889. 100% {
  890. height: 0px;
  891. }
  892. }
  893. :deep(.zxm-divider-inner-text) {
  894. color: #cacaca88 !important;
  895. }
  896. :deep(.zxm-form-item) {
  897. margin-bottom: 10px;
  898. }
  899. </style>