conditionAssistance.vue 27 KB

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