conditionAssistance1.vue 27 KB

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