conditionAssistance.vue 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942
  1. <template>
  2. <BasicModal
  3. @register="register"
  4. title="局部通风机运行工况智能决策"
  5. :maskStyle="{ backgroundColor: '#000000aa', backdropFilter: 'blur(3px)' }"
  6. :width="isComputeGas ? '1400px' : '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: '400px' }"></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' : '400px' }">
  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 = 1200;
  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. const equation = assistanceData.value.find((item) => {
  278. return Math.ceil(Hz) == item['Hz'];
  279. });
  280. if (equation) {
  281. const uHMax = Math.round((equation['a'] * equation['min'] * equation['min'] + equation['b'] * equation['min'] + equation['c']) * 100) / 100;
  282. const uHMin = Math.round((equation['a'] * equation['max'] * equation['max'] + equation['b'] * equation['max'] + equation['c']) * 100) / 100;
  283. const uH1 = Math.round((equation['a'] * uQ * uQ + equation['b'] * uQ + equation['c']) * 100) / 100;
  284. if (uH1 >= uHMin && uH1 <= uHMax) {
  285. uH.value = uH1;
  286. isHaCross.value = true;
  287. } else {
  288. isHaCross.value = false;
  289. }
  290. }
  291. }
  292. function computeRLine() {
  293. console.log('计算后的风量为------------>', uQ.value);
  294. if (uH.value && uQ.value) {
  295. const R = uH.value / Number(uQ.value) / Number(uQ.value);
  296. const yAxis: number[] = [];
  297. for (let i = 0; i < xData.length; i++) {
  298. const x = xData[i];
  299. const y = R * x * x;
  300. if (x == uQ.value) {
  301. uH.value = y;
  302. }
  303. yAxis.push(y);
  304. }
  305. const series = {
  306. name: 'R',
  307. type: 'line',
  308. smooth: true,
  309. showSymbol: false,
  310. zlevel: 0,
  311. emphasis: {
  312. focus: 'series',
  313. },
  314. itemStyle: { normal: { label: { show: true } } },
  315. lineStyle: {
  316. width: 2,
  317. color: '#D0A343',
  318. },
  319. endLabel: {
  320. show: true,
  321. formatter: '{a}',
  322. distance: 0,
  323. color: '#D0A343',
  324. },
  325. data: yAxis,
  326. };
  327. yDataList[lineNum] = series;
  328. }
  329. }
  330. function reSetLine() {
  331. let minIndex = -1;
  332. for (let i = 0; i < yDataList.length; i++) {
  333. if (i !== lineNum && i != lineNum + 1) {
  334. if (yDataList[i]['lineStyle']) yDataList[i]['lineStyle']['color'] = '#ffffff88';
  335. if (yDataList[i]['lineStyle']) yDataList[i]['lineStyle']['width'] = 1;
  336. if (yDataList[i]['endLabel'] && yDataList[i]['endLabel']['color']) {
  337. if (i % 5 == 0) {
  338. yDataList[i]['endLabel']['color'] = '#39E9FE99';
  339. } else {
  340. yDataList[i]['endLabel']['color'] = '#39E9FE00';
  341. }
  342. }
  343. if (yDataList[i]['endLabel'] && yDataList[i]['endLabel']['backgroundColor']) yDataList[i]['endLabel']['backgroundColor'] = 'transparent';
  344. if (yDataList[i]['z']) yDataList[i]['z'] = 1;
  345. }
  346. if (resultObj.value && `${resultObj.value.Hz}Hz` == yDataList[i]['name']) {
  347. minIndex = i;
  348. }
  349. }
  350. if (minIndex != -1) {
  351. yDataList[minIndex]['lineStyle']['color'] = '#9A60B4';
  352. yDataList[minIndex]['lineStyle']['width'] = 2;
  353. yDataList[minIndex]['endLabel']['color'] = '#9A60B4';
  354. yDataList[minIndex]['endLabel']['backgroundColor'] = '#111';
  355. yDataList[minIndex]['z'] = 999;
  356. }
  357. }
  358. // 根据风量计算压差
  359. function computePa() {
  360. const R = uH.value / Number(uQ.value) / Number(uQ.value);
  361. const pointX = Number(uQ.value);
  362. const pointY = Number(uH.value);
  363. type ItemType = {
  364. x: number;
  365. y: number;
  366. Hz: number;
  367. };
  368. const paList = new Map<number, ItemType>(); // key 是最近距离
  369. const getIntersectionPoint = (a, b, c, R, min, max) => {
  370. const obj: { x: undefined | number; y: undefined | number; min: number; max: number } = { x: undefined, y: undefined, min: min, max: max };
  371. // 计算二次方程的判别式
  372. const discriminant = b * b - 4 * (a - R) * c;
  373. if (discriminant > 0) {
  374. // 有两个实根
  375. const x1 = (-b + Math.sqrt(discriminant)) / (2 * (a - R));
  376. const x2 = (-b - Math.sqrt(discriminant)) / (2 * (a - R));
  377. const y1 = R * x1 * x1;
  378. const y2 = R * x2 * x2;
  379. if (x1 >= min && x1 <= max) {
  380. obj.x = x1;
  381. obj.y = y1;
  382. } else {
  383. obj.x = x2;
  384. obj.y = y2;
  385. }
  386. } else if (discriminant === 0) {
  387. // 有一个实根
  388. const x = -b / (2 * (a - R));
  389. const y = R * x * x;
  390. if (x >= min && x <= max) {
  391. obj.x = x;
  392. obj.y = y;
  393. }
  394. // console.log(`唯一交点: (${x}, ${y})`);
  395. } else {
  396. // 没有实根,交点在虚数域
  397. console.log('没有实数交点');
  398. isHaCross.value = false;
  399. }
  400. return obj;
  401. };
  402. for (let key in assistanceData.value) {
  403. const item: AssistanceItemType = assistanceData.value[key];
  404. paList.set(item.Hz, getIntersectionPoint(item.a, item.b, item.c, R, item.min, item.max));
  405. }
  406. const min = (points: Map<number, ItemType>) => {
  407. const targetX = uQ.value;
  408. const targetY = uH.value;
  409. let minDistance = Number.POSITIVE_INFINITY;
  410. let closestPoint = null;
  411. let keyVal = '';
  412. // 遍历已知点数组,计算距离并更新最小距离和对应的点
  413. for (const [key, point] of points) {
  414. const distance = Math.sqrt((targetX - point.x) ** 2 + (targetY - point.y) ** 2);
  415. if (distance < minDistance) {
  416. minDistance = distance;
  417. closestPoint = point;
  418. keyVal = key;
  419. }
  420. }
  421. if (closestPoint !== null) {
  422. // console.log(`距离最小的点是 (${closestPoint.x}, ${closestPoint.y}), 距离为 ${minDistance}`);
  423. if (closestPoint.x < closestPoint.min || closestPoint.x > closestPoint.max) {
  424. resultObj.value = null;
  425. isHaCross.value = false;
  426. console.log('没有找到最小距离的点');
  427. } else {
  428. resultObj.value = { x: closestPoint.x, y: closestPoint.y, Hz: keyVal };
  429. isHaCross.value = true;
  430. }
  431. } else {
  432. resultObj.value = null;
  433. isHaCross.value = false;
  434. console.log('没有找到最小距离的点');
  435. }
  436. };
  437. min(paList);
  438. }
  439. function computeR() {
  440. if (uQ.value && uH.value) {
  441. computeRLine();
  442. computePa();
  443. const x = resultObj.value && resultObj.value.x ? resultObj.value.x.toFixed(0) : -100;
  444. const y = resultObj.value && resultObj.value.y ? Number(resultObj.value.y.toFixed(0)) : -100;
  445. const series = {
  446. type: 'effectScatter',
  447. symbolSize: 5,
  448. // symbolOffset:[1, 1],
  449. showEffectOn: 'render',
  450. // 涟漪特效相关配置。
  451. rippleEffect: {
  452. // 波纹的绘制方式,可选 'stroke' 和 'fill'。
  453. brushType: 'stroke',
  454. },
  455. zlevel: 1,
  456. z: 999,
  457. itemStyle: {
  458. color: '#C60000',
  459. },
  460. data: [[x, y]],
  461. };
  462. yDataList[lineNum + 1] = series;
  463. }
  464. // // 根据计算后的得到的频率,风量,瓦斯浓度
  465. // getMonitor();
  466. }
  467. function getMonitor() {
  468. clearTimeout(timer);
  469. timer = undefined;
  470. const n = 10;
  471. const windQuantity = uQ1.value;
  472. const obj = {
  473. m3: windQuantity,
  474. gas: gasWarningVal.value,
  475. time: '',
  476. Hz: uHz.value,
  477. };
  478. const monitorList: { m3: number; gas: number; Hz: number; time: string }[] = [];
  479. for (let i = 0; i < n; i++) {
  480. const item = cloneDeep(obj);
  481. const m3Temp = (Math.random() * 2 - 1) * Math.random() * 20;
  482. const gas = m3Temp * 0.0002;
  483. item.time = dayjs(new Date().getTime() - (n + i) * 3000).format('HH:mm:ss');
  484. item.m3 = (obj.m3 + m3Temp).toFixed(2);
  485. item.gas = (obj.gas + gas).toFixed(4);
  486. item.Hz = (obj.Hz + Math.random()).toFixed(2);
  487. monitorList.unshift(item);
  488. }
  489. monitorData.value = cloneDeep(monitorList);
  490. setTimeout(() => {
  491. clearTimeout(timer);
  492. timer = undefined;
  493. timer = 0;
  494. if (uQ1.value && uH.value && uQ.value) {
  495. openTimer(cloneDeep(obj), 0);
  496. } else {
  497. openTimer(cloneDeep(obj), 0);
  498. }
  499. }, 1000);
  500. }
  501. function startCompute() {
  502. setTimeout(() => {
  503. message.success('指令下发成功!');
  504. isStartCompute.value = 1;
  505. }, 800);
  506. }
  507. function resetCompute() {
  508. setTimeout(() => {
  509. message.success('指令下发成功!');
  510. isStartCompute.value = -1;
  511. tempList.length = 0;
  512. n = 0;
  513. }, 800);
  514. }
  515. let timer = undefined;
  516. let n = 0;
  517. let tempList = [];
  518. function openTimer(obj: { m3: number; gas: number; Hz: number; time: string }) {
  519. // 打开定时器
  520. const monitorList = cloneDeep(monitorData.value);
  521. if (timer !== undefined) {
  522. timer = setTimeout(() => {
  523. obj.m3 = Number(obj.m3);
  524. obj.gas = Number(obj.gas);
  525. obj.Hz = Number(obj.Hz);
  526. const item = cloneDeep(obj);
  527. item.time = dayjs(new Date().getTime()).format('HH:mm:ss');
  528. if (resultObj.value && resultObj.value.x && resultObj.value.y && isStartCompute.value != 0) {
  529. if (isStartCompute.value == 1 && Number(obj.m3) > uQ.value && Number(obj.gas) < gasWarningMax.value) {
  530. isStartCompute.value = 0;
  531. n = 0;
  532. } else if (isStartCompute.value == -1 && Number(obj.m3) < uQ1.value) {
  533. isStartCompute.value = 0;
  534. n = 0;
  535. }
  536. }
  537. if (!isStartCompute.value) {
  538. const m3Temp = (Math.random() * 2 - 1) * Math.random() * Math.random() * 10;
  539. const gas = m3Temp * 0.0002;
  540. item.m3 = (obj.m3 + m3Temp).toFixed(2);
  541. item.gas = (obj.gas + gas).toFixed(4);
  542. item.Hz = (obj.Hz + Math.random()).toFixed(2);
  543. n = 0;
  544. } else {
  545. if (n < 2) {
  546. const item1 = cloneDeep(obj);
  547. const m3Temp = Math.random() * Math.random() * 10;
  548. const gas = m3Temp * 0.0002;
  549. item1.m3 = (obj.m3 + m3Temp).toFixed(2);
  550. item1.gas = (obj.gas + gas).toFixed(4);
  551. item1.Hz = (obj.Hz + (Math.random() * 2 - 1) * Math.random()).toFixed(2);
  552. tempList.push(item1);
  553. }
  554. // 计算 uQ1 -> uQ gas -> gasWarningMax.value Hz -> resultObj.value.Hz
  555. if (isStartCompute.value == 1) {
  556. if (resultObj.value.Hz - obj.Hz > 0) {
  557. item.Hz = (uHz.value + (2 * n * (resultObj.value.Hz - uHz.value)) / 20).toFixed(2);
  558. if (resultObj.value.Hz - obj.Hz < 0) {
  559. item.Hz = (resultObj.value.Hz + Math.random() * 0.5).toFixed(2);
  560. }
  561. } else {
  562. // item.Hz = (resultObj.value.Hz + (Math.random() * 2 - 1) * Math.random() * 2).toFixed(2);
  563. item.Hz = (resultObj.value.Hz + Math.random() * 0.5).toFixed(2);
  564. }
  565. item.m3 = (obj.m3 + (0.017 * n * item.Hz * (item.Hz - uHz.value) * (uQ.value - uQ1.value)) / 600).toFixed(2);
  566. if (Number(item.m3) > uQ.value) {
  567. item.m3 = (uQ.value + Math.random() * 10).toFixed(2);
  568. }
  569. item.gas = (
  570. gasWarningVal.value -
  571. (0.015 * item.Hz * n * (item.Hz - uHz.value) * (gasWarningVal.value - gasWarningMax.value)) / 200
  572. ).toFixed(4);
  573. } else {
  574. // 复位
  575. if (obj.Hz - uHz.value > 0) {
  576. item.Hz = (obj.Hz - (2 * n * (resultObj.value.Hz - uHz.value)) / 30).toFixed(2);
  577. if (item.Hz - uHz.value < 0) {
  578. item.Hz = uHz.value - 0.3;
  579. }
  580. } else {
  581. item.Hz = (uHz.value + (Math.random() * 2 - 1) * Math.random() * 2).toFixed(2);
  582. }
  583. item.m3 = (obj.m3 - (0.02 * n * n * item.Hz * (resultObj.value.Hz - uHz.value) * (uQ.value - uQ1.value)) / 400).toFixed(2);
  584. if (item.m3 < uQ1.value) {
  585. item.m3 = uQ1.value - Math.random() * 10;
  586. }
  587. item.gas = (obj.gas + (0.015 * item.Hz * n * (uHz.value - item.Hz) * (gasWarningVal.value - gasWarningMax.value)) / 800).toFixed(4);
  588. }
  589. }
  590. if (monitorList.length >= 10) {
  591. monitorList.shift();
  592. const monitor = cloneDeep(item);
  593. const data = tempList.shift();
  594. if (data) {
  595. item['m3'] = data['m3'];
  596. item['gas'] = data['gas'];
  597. }
  598. tempList.push(monitor);
  599. monitorList.push(item);
  600. } else {
  601. monitorList.push(item);
  602. }
  603. monitorData.value = monitorList;
  604. // console.log('瓦斯监测数据-------------->', monitorData.value);
  605. if (timer) {
  606. if (!isStartCompute.value) {
  607. // n++;
  608. openTimer(cloneDeep(obj));
  609. } else {
  610. n++;
  611. openTimer(cloneDeep(item));
  612. }
  613. }
  614. }, 3000);
  615. }
  616. }
  617. function edit(flag) {
  618. if (flag == 'info') {
  619. formType.value = '编辑风机信息';
  620. }
  621. if (flag == 'line') {
  622. formType.value = '编辑特性曲线';
  623. }
  624. if (formShow.value == true) {
  625. formShow.value = false;
  626. nextTick(() => {
  627. formShow.value = true;
  628. });
  629. } else {
  630. formShow.value = true;
  631. }
  632. }
  633. function onSubmit() {
  634. emit('close');
  635. closeModal();
  636. ChartRef.value = null;
  637. uQ.value = undefined;
  638. uH.value = undefined;
  639. formType.value = '';
  640. refresh.value = true;
  641. xData.length = 0;
  642. yDataList.length = 0;
  643. lineNum = 0;
  644. lineEquation.value = [];
  645. resultObj.value = null;
  646. monitorData.value = [];
  647. clearTimeout(timer);
  648. timer = undefined;
  649. }
  650. async function onCancel() {
  651. return new Promise((resolve) => {
  652. if (isStartCompute.value == 0) {
  653. onSubmit();
  654. resolve(true);
  655. } else {
  656. message.warning('为保障矿井安全生产,请确保已复位!!!');
  657. resolve(false);
  658. }
  659. });
  660. }
  661. function initEcharts() {
  662. if (ChartRef.value) {
  663. reSetLine();
  664. myChart.value = echarts.init(ChartRef.value);
  665. option && myChart.value.setOption(option);
  666. refresh.value = false;
  667. getMonitor();
  668. nextTick(() => {
  669. setTimeout(() => {
  670. refresh.value = true;
  671. }, 0);
  672. });
  673. }
  674. }
  675. function makeLine() {
  676. if (uQ.value && uH.value) {
  677. loadding.value = true;
  678. setTimeout(() => {
  679. computeR();
  680. reSetLine();
  681. option && myChart.value.setOption(option);
  682. loadding.value = false;
  683. }, 1200);
  684. }
  685. }
  686. function handleSubmit() {
  687. message.success('提交成功');
  688. setTimeout(() => {
  689. formShow.value = false;
  690. }, 800);
  691. }
  692. onMounted(() => {
  693. timer = undefined;
  694. });
  695. </script>
  696. <style scoped lang="less">
  697. .modal-box {
  698. display: flex;
  699. flex-direction: row;
  700. background-color: #ffffff05;
  701. padding: 20px 8px;
  702. border: 1px solid #00d8ff22;
  703. position: relative;
  704. // min-height: 600px;
  705. .box-title {
  706. width: calc(100% - 40px);
  707. text-align: center;
  708. background-color: #1dc1f522;
  709. }
  710. .info-item {
  711. display: flex;
  712. justify-content: space-between;
  713. align-items: center;
  714. padding: 2px 0px;
  715. margin: 4px 0;
  716. background-image: linear-gradient(to right, #39deff15, #3977e500);
  717. &:first-child {
  718. margin-top: 0;
  719. }
  720. .title {
  721. width: 200px;
  722. text-align: left;
  723. padding-left: 20px;
  724. color: #f1f1f1cc;
  725. }
  726. .value {
  727. width: 150px;
  728. color: #00d8ff;
  729. padding-right: 20px;
  730. text-align: right;
  731. }
  732. }
  733. .right-box {
  734. width: 320px;
  735. .info-lines {
  736. width: calc(100% - 2px);
  737. height: 450px;
  738. box-shadow: 0px 0px 50px #86baff08 inset;
  739. overflow-y: auto;
  740. margin-top: 5px;
  741. .title {
  742. width: 100%;
  743. color: #f1f1f1cc;
  744. }
  745. }
  746. }
  747. .center-box {
  748. flex: 1;
  749. margin: 0 10px;
  750. display: flex;
  751. .info-echarts {
  752. // background-color: #ffffff11;
  753. }
  754. .result-tip {
  755. text-align: center;
  756. background-color: #00000011;
  757. line-height: 28px;
  758. margin: 10px 50px 0 50px;
  759. border: 1px solid #00d8ff22;
  760. border-radius: 2px;
  761. }
  762. }
  763. .tip-box {
  764. width: 1040px;
  765. height: 44px;
  766. position: absolute;
  767. top: 447px;
  768. display: flex;
  769. padding: 0 20px;
  770. .title {
  771. width: 142px;
  772. height: 43px;
  773. display: flex;
  774. align-items: center;
  775. padding-left: 30px;
  776. background-image: url('@/assets/images/fanlocal-tip/tip-title.png');
  777. position: relative;
  778. &::before {
  779. content: '';
  780. display: inline-block;
  781. position: absolute;
  782. width: 31px;
  783. height: 31px;
  784. top: 5px;
  785. left: -8px;
  786. background-image: url('@/assets/images/fanlocal-tip/tip-icon.png');
  787. }
  788. }
  789. .tip-container {
  790. width: 898px;
  791. height: 44px;
  792. line-height: 44px;
  793. display: flex;
  794. background-image: url('@/assets/images/fanlocal-tip/tip-bg.png');
  795. background-size: cover;
  796. }
  797. }
  798. }
  799. .setting-box {
  800. width: 1170px;
  801. height: 70px;
  802. margin: 10px 0;
  803. background-color: #ffffff05;
  804. border: 1px solid #00d8ff22;
  805. display: flex;
  806. align-items: center;
  807. justify-content: space-between;
  808. .right-inputs {
  809. width: 100%;
  810. display: flex;
  811. height: 40px;
  812. margin: 0 10px;
  813. justify-content: space-between;
  814. }
  815. .left-buttons {
  816. display: flex;
  817. height: 40px;
  818. .btn {
  819. margin: 0 10px;
  820. }
  821. }
  822. .border-clip {
  823. width: 1px;
  824. height: 25px;
  825. border-right: 1px solid #8b8b8b77;
  826. }
  827. .input-title {
  828. max-width: 150px;
  829. }
  830. .input-box {
  831. width: 220px !important;
  832. background: transparent !important;
  833. border-color: #00d8ff44 !important;
  834. margin-right: 20px;
  835. color: #fff !important;
  836. }
  837. .btn {
  838. padding: 8px 20px;
  839. position: relative;
  840. border-radius: 2px;
  841. color: #fff;
  842. width: fit-content;
  843. cursor: pointer;
  844. &::before {
  845. position: absolute;
  846. display: block;
  847. content: '';
  848. width: calc(100% - 4px);
  849. height: calc(100% - 4px);
  850. top: 2px;
  851. left: 2px;
  852. border-radius: 2px;
  853. z-index: -1;
  854. }
  855. }
  856. .btn1 {
  857. border: 1px solid #5cfaff;
  858. &::before {
  859. background-image: linear-gradient(#2effee92, #0cb1d592);
  860. }
  861. &:hover {
  862. border: 1px solid #5cfaffaa;
  863. &::before {
  864. background-image: linear-gradient(#2effee72, #0cb1d572);
  865. }
  866. }
  867. }
  868. }
  869. .is-open {
  870. animation: open 0.5s;
  871. animation-iteration-count: 1;
  872. animation-fill-mode: forwards;
  873. animation-timing-function: ease-in;
  874. }
  875. .is-close {
  876. height: 0px;
  877. }
  878. @keyframes open {
  879. 0% {
  880. height: 0px;
  881. }
  882. 100% {
  883. height: fit-content;
  884. }
  885. }
  886. @keyframes close {
  887. 0% {
  888. height: fit-content;
  889. }
  890. 100% {
  891. height: 0px;
  892. }
  893. }
  894. :deep(.zxm-divider-inner-text) {
  895. color: #cacaca88 !important;
  896. }
  897. :deep(.zxm-form-item) {
  898. margin-bottom: 10px;
  899. }
  900. </style>