|
@@ -0,0 +1,943 @@
|
|
|
+<template>
|
|
|
+ <BasicModal
|
|
|
+ @register="register"
|
|
|
+ title="局部通风机运行工况智能决策"
|
|
|
+ :maskStyle="{ backgroundColor: '#000000aa', backdropFilter: 'blur(3px)' }"
|
|
|
+ :width="isComputeGas ? '1400px' : '950px'"
|
|
|
+ v-bind="$attrs"
|
|
|
+ @ok="onSubmit"
|
|
|
+ :closeFunc="onCancel"
|
|
|
+ :canFullscreen="false"
|
|
|
+ :destroyOnClose="true"
|
|
|
+ :footer="null"
|
|
|
+ :maskClosable="false"
|
|
|
+ >
|
|
|
+ <div class="modal-box">
|
|
|
+ <div v-if="isComputeGas" class="left-box" style="width: 550px; height: 400px">
|
|
|
+ <BarAndLine
|
|
|
+ class="echarts-line"
|
|
|
+ xAxisPropType="time"
|
|
|
+ :dataSource="monitorData"
|
|
|
+ height="400px"
|
|
|
+ :chartsColumns="chartsColumnList"
|
|
|
+ :option="echatsOption"
|
|
|
+ chartsType="listMonitor"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div class="center-box">
|
|
|
+ <a-spin :spinning="loadding" tip="正在计算,请稍等。。。">
|
|
|
+ <div ref="ChartRef" class="info-echarts" :style="{ width: isComputeGas ? '450px' : '520px', height: '400px' }"></div>
|
|
|
+ </a-spin>
|
|
|
+ </div>
|
|
|
+ <div class="right-box">
|
|
|
+ <!-- <div class="box-title">曲线方程</div> -->
|
|
|
+ <dv-decoration7 style="height: 20px">
|
|
|
+ <div class="box-title">曲线方程</div>
|
|
|
+ </dv-decoration7>
|
|
|
+ <div class="info-lines">
|
|
|
+ <div v-for="(item, index) in lineEquation" class="info-item" :key="index">
|
|
|
+ <div class="title">{{ item }}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="tip-box">
|
|
|
+ <div class="title">最佳工况点 <SendOutlined class="ml-5px" /></div>
|
|
|
+ <div class="tip-container" :style="{ width: isComputeGas ? '898px' : '400px' }">
|
|
|
+ <template v-if="resultObj && isHaCross">
|
|
|
+ <div class="ml-10px">
|
|
|
+ <span>频率:</span>
|
|
|
+ <span style="color: #d066ff; padding: 0 10px; font-weight: 600">{{ formatNum(resultObj.Hz) }}Hz</span>
|
|
|
+ </div>
|
|
|
+ <div class="ml-10px">
|
|
|
+ <span>风量:</span>
|
|
|
+ <span style="color: #3adeff; padding: 0 10px; font-weight: 600">{{ formatNum(resultObj.x) }} m³/min</span>
|
|
|
+ </div>
|
|
|
+ <div class="ml-10px">
|
|
|
+ <span>负压</span>
|
|
|
+ <span style="color: #ffbe34; padding: 0 10px; font-weight: 600">{{ formatNum(resultObj.y) }} Pa</span>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <div v-else-if="isHaCross" class="ml-10px">暂无</div>
|
|
|
+ <div v-else style="color: #ffbe34; padding: 0 10px; font-weight: 600" class="ml-10px">无有效工况点</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="setting-box">
|
|
|
+ <div class="right-inputs">
|
|
|
+ <div class="vent-flex-row">
|
|
|
+ <div class="input-title">风量(m³/min):</div>
|
|
|
+ <InputNumber :disabled="isComputeGas" class="input-box" size="large" v-model:value="uQ1" />
|
|
|
+ <div class="input-title">风压(Pa):</div>
|
|
|
+ <InputNumber :disabled="isComputeGas" class="input-box" size="large" v-model:value="uH" />
|
|
|
+ <div v-if="!isComputeGas" class="btn btn1" @click="makeLine">决策工况</div>
|
|
|
+ <template v-else>
|
|
|
+ <div class="btn btn1" @click="startCompute">一键调控</div>
|
|
|
+ <div class="btn btn1" @click="resetCompute">一键复位</div>
|
|
|
+ </template>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </BasicModal>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script lang="ts" setup>
|
|
|
+ //ts语法
|
|
|
+ import { ref, onMounted, reactive, nextTick, computed } from 'vue';
|
|
|
+ import echarts from '/@/utils/lib/echarts';
|
|
|
+ import { option, initData, fanInfoData, chartsColumnList, echatsOption } from '../fanLocal.data';
|
|
|
+ import { BasicModal, useModalInner } from '/@/components/Modal';
|
|
|
+ import { useForm } from '/@/components/Form/index';
|
|
|
+ import { Input, InputNumber } from 'ant-design-vue';
|
|
|
+ import { Decoration7 as DvDecoration7 } from '@kjgl77/datav-vue3';
|
|
|
+ import { message } from 'ant-design-vue';
|
|
|
+ import { formatNum } from '/@/utils/ventutil';
|
|
|
+ import BarAndLine from '/@/components/chart/BarAndLine.vue';
|
|
|
+ import { cloneDeep } from 'lodash-es';
|
|
|
+ import dayjs from 'dayjs';
|
|
|
+ import { SendOutlined } from '@ant-design/icons-vue';
|
|
|
+
|
|
|
+ const emit = defineEmits(['close', 'register', 'openModal']);
|
|
|
+ const props = defineProps({
|
|
|
+ dataSource: {
|
|
|
+ type: Array,
|
|
|
+ default: () => [],
|
|
|
+ },
|
|
|
+ frequency: {
|
|
|
+ type: Number,
|
|
|
+ default: 30,
|
|
|
+ },
|
|
|
+ m3: {
|
|
|
+ type: Number,
|
|
|
+ default: 670.8,
|
|
|
+ },
|
|
|
+ // gasWarningMax: { type: Number, default: 0.5 },
|
|
|
+ // gasWarningVal: { type: Number, default: 0.6 },
|
|
|
+ // windQuantity: { type: Number, default: 635.84 },
|
|
|
+ });
|
|
|
+ type AssistanceItemType = {
|
|
|
+ angle: number;
|
|
|
+ Hz: number;
|
|
|
+ a: number;
|
|
|
+ b: number;
|
|
|
+ c: number;
|
|
|
+ min: number;
|
|
|
+ max: number;
|
|
|
+ };
|
|
|
+
|
|
|
+ // 注册 modal
|
|
|
+ const [register, { closeModal }] = useModalInner((data) => {
|
|
|
+ nextTick(() => {
|
|
|
+ computeAssistance();
|
|
|
+ if (option['xAxis']) option['xAxis']['data'] = xData;
|
|
|
+ option['series'] = yDataList;
|
|
|
+ if (JSON.stringify(data) !== '{}') {
|
|
|
+ uQ1.value = Number(data['m3']);
|
|
|
+ uHz.value = Math.ceil(data['frequency']);
|
|
|
+ gasWarningVal.value = data['gasWarningVal'];
|
|
|
+ isComputeGas.value = true;
|
|
|
+ nextTick(() => {
|
|
|
+ computeUH(data['frequency'], data['m3']);
|
|
|
+ initEcharts();
|
|
|
+ setTimeout(() => {
|
|
|
+ // 根据频率计算uH
|
|
|
+ makeLine();
|
|
|
+ }, 2000);
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ initEcharts();
|
|
|
+ isComputeGas.value = false;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ const loadding = ref<boolean>(false);
|
|
|
+ const formShow = ref(false);
|
|
|
+ const formType = ref('');
|
|
|
+ const ChartRef = ref();
|
|
|
+ const myChart = ref();
|
|
|
+ const refresh = ref(true);
|
|
|
+ const xDataMax = 1200;
|
|
|
+ let xDataMin = 0;
|
|
|
+ const xData: any[] = [];
|
|
|
+ const yDataList: [] = [];
|
|
|
+ let lineNum = 0;
|
|
|
+ const lineEquation = ref<string[]>([]);
|
|
|
+ const assistanceData = ref([]);
|
|
|
+ const monitorData = ref([]);
|
|
|
+ const gasWarningVal = ref(0);
|
|
|
+ const gasWarningMax = ref(0.5);
|
|
|
+ const isComputeGas = ref(false);
|
|
|
+ const isStartCompute = ref(0);
|
|
|
+ const uHz = ref(0);
|
|
|
+ const uQ1 = ref(0);
|
|
|
+ const uQ = computed(() => {
|
|
|
+ if (uQ1.value) {
|
|
|
+ if (gasWarningVal.value) {
|
|
|
+ return ((uQ1.value * gasWarningVal.value) / gasWarningMax.value) * 1.08;
|
|
|
+ }
|
|
|
+ return uQ1.value;
|
|
|
+ } else {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ const uH = ref<number | undefined>(undefined); // - 1000
|
|
|
+ const isHaCross = ref(true);
|
|
|
+ const resultObj = ref<{ x: number; y: number; Hz: number } | null>(null);
|
|
|
+
|
|
|
+ const [registerForm, {}] = useForm({
|
|
|
+ labelWidth: 120,
|
|
|
+ actionColOptions: {
|
|
|
+ span: 24,
|
|
|
+ },
|
|
|
+ compact: true,
|
|
|
+ showSubmitButton: true,
|
|
|
+ submitButtonOptions: {
|
|
|
+ text: '提交',
|
|
|
+ preIcon: '',
|
|
|
+ },
|
|
|
+ showResetButton: true,
|
|
|
+ resetButtonOptions: {
|
|
|
+ text: '关闭',
|
|
|
+ preIcon: '',
|
|
|
+ },
|
|
|
+ resetFunc: async () => {
|
|
|
+ formShow.value = false;
|
|
|
+ },
|
|
|
+ });
|
|
|
+
|
|
|
+ function computeAssistance() {
|
|
|
+ assistanceData.value = initData();
|
|
|
+ lineNum = 0;
|
|
|
+ const assistanceDataList = [];
|
|
|
+ const lineEquationList: string[] = [];
|
|
|
+ for (const key in assistanceData.value) {
|
|
|
+ const item = assistanceData.value[key];
|
|
|
+ assistanceDataList.push(item);
|
|
|
+ lineEquationList.push(
|
|
|
+ `H${parseInt(item['Hz'])} = ${item['a']}Q² ${Number(item['b']) > 0 ? '+' : '-'} ${Math.abs(Number(item['b'])).toFixed(4)}Q ${
|
|
|
+ Number(item['c']) > 0 ? '+' : '-'
|
|
|
+ } ${Math.abs(Number(item['c'])).toFixed(4)}`
|
|
|
+ );
|
|
|
+ }
|
|
|
+ lineEquation.value = lineEquationList;
|
|
|
+ lineNum = assistanceDataList.length;
|
|
|
+ xDataMin =
|
|
|
+ Math.min.apply(
|
|
|
+ Math,
|
|
|
+ assistanceDataList.map((item) => {
|
|
|
+ return item.min;
|
|
|
+ })
|
|
|
+ ) - 100;
|
|
|
+ // const xDataMax = Math.max.apply(Math, assistanceDataList.map(item => { return item.max }))
|
|
|
+ fanInfoData.flfw = `${xDataMin}~${xDataMax}`;
|
|
|
+ const computeItem = (item: AssistanceItemType) => {
|
|
|
+ const min = item.min;
|
|
|
+ const max = item.max;
|
|
|
+ const HList: number[] = [];
|
|
|
+ for (let i = xDataMin; i <= xDataMax; i++) {
|
|
|
+ if (i < min) {
|
|
|
+ HList.push(null);
|
|
|
+ } else if (i > max) {
|
|
|
+ HList.push(null);
|
|
|
+ } else {
|
|
|
+ HList.push(item.a * i * i + item.b * i + item.c);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return HList;
|
|
|
+ };
|
|
|
+
|
|
|
+ for (const key in assistanceData.value) {
|
|
|
+ const element: AssistanceItemType = assistanceData.value[key];
|
|
|
+ const yData: number[] = computeItem(element);
|
|
|
+ const series = {
|
|
|
+ type: 'line',
|
|
|
+ name: `${element['Hz']}Hz`,
|
|
|
+ smooth: true,
|
|
|
+ showSymbol: false,
|
|
|
+ symbol: 'none',
|
|
|
+ emphasis: {
|
|
|
+ focus: 'series',
|
|
|
+ },
|
|
|
+ itemStyle: { normal: { label: { show: true } } },
|
|
|
+ lineStyle: {
|
|
|
+ width: 1,
|
|
|
+ color: '#ffffff88',
|
|
|
+ },
|
|
|
+ zlevel: 0,
|
|
|
+ z: 1,
|
|
|
+ endLabel: {
|
|
|
+ show: true,
|
|
|
+ formatter: '{a}',
|
|
|
+ distance: 0,
|
|
|
+ color: '#39E9FE99',
|
|
|
+ backgroundColor: 'transparent',
|
|
|
+ padding: [3, 3, 2, 3],
|
|
|
+ },
|
|
|
+ data: yData,
|
|
|
+ };
|
|
|
+
|
|
|
+ yDataList.push(series);
|
|
|
+ }
|
|
|
+
|
|
|
+ for (let i = xDataMin; i <= xDataMax; i++) {
|
|
|
+ xData.push(i);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ function computeUH(Hz: number, uQ: number) {
|
|
|
+ const equation = assistanceData.value.find((item) => {
|
|
|
+ return Math.ceil(Hz) == item['Hz'];
|
|
|
+ });
|
|
|
+ if (equation) {
|
|
|
+ const uHMax = Math.round((equation['a'] * equation['min'] * equation['min'] + equation['b'] * equation['min'] + equation['c']) * 100) / 100;
|
|
|
+ const uHMin = Math.round((equation['a'] * equation['max'] * equation['max'] + equation['b'] * equation['max'] + equation['c']) * 100) / 100;
|
|
|
+ const uH1 = Math.round((equation['a'] * uQ * uQ + equation['b'] * uQ + equation['c']) * 100) / 100;
|
|
|
+ if (uH1 >= uHMin && uH1 <= uHMax) {
|
|
|
+ uH.value = uH1;
|
|
|
+ isHaCross.value = true;
|
|
|
+ } else {
|
|
|
+ isHaCross.value = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ function computeRLine() {
|
|
|
+ console.log('计算后的风量为------------>', uQ.value);
|
|
|
+ if (uH.value && uQ.value) {
|
|
|
+ const R = uH.value / Number(uQ.value) / Number(uQ.value);
|
|
|
+ const yAxis: number[] = [];
|
|
|
+ for (let i = 0; i < xData.length; i++) {
|
|
|
+ const x = xData[i];
|
|
|
+ const y = R * x * x;
|
|
|
+ if (x == uQ.value) {
|
|
|
+ uH.value = y;
|
|
|
+ }
|
|
|
+ yAxis.push(y);
|
|
|
+ }
|
|
|
+ const series = {
|
|
|
+ name: 'R',
|
|
|
+ type: 'line',
|
|
|
+ smooth: true,
|
|
|
+ showSymbol: false,
|
|
|
+ zlevel: 0,
|
|
|
+ emphasis: {
|
|
|
+ focus: 'series',
|
|
|
+ },
|
|
|
+ itemStyle: { normal: { label: { show: true } } },
|
|
|
+ lineStyle: {
|
|
|
+ width: 2,
|
|
|
+ color: '#D0A343',
|
|
|
+ },
|
|
|
+ endLabel: {
|
|
|
+ show: true,
|
|
|
+ formatter: '{a}',
|
|
|
+ distance: 0,
|
|
|
+ color: '#D0A343',
|
|
|
+ },
|
|
|
+ data: yAxis,
|
|
|
+ };
|
|
|
+ yDataList[lineNum] = series;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ function reSetLine() {
|
|
|
+ let minIndex = -1;
|
|
|
+ for (let i = 0; i < yDataList.length; i++) {
|
|
|
+ if (i !== lineNum && i != lineNum + 1) {
|
|
|
+ if (yDataList[i]['lineStyle']) yDataList[i]['lineStyle']['color'] = '#ffffff88';
|
|
|
+ if (yDataList[i]['lineStyle']) yDataList[i]['lineStyle']['width'] = 1;
|
|
|
+ if (yDataList[i]['endLabel'] && yDataList[i]['endLabel']['color']) {
|
|
|
+ if (i % 5 == 0) {
|
|
|
+ yDataList[i]['endLabel']['color'] = '#39E9FE99';
|
|
|
+ } else {
|
|
|
+ yDataList[i]['endLabel']['color'] = '#39E9FE00';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (yDataList[i]['endLabel'] && yDataList[i]['endLabel']['backgroundColor']) yDataList[i]['endLabel']['backgroundColor'] = 'transparent';
|
|
|
+ if (yDataList[i]['z']) yDataList[i]['z'] = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (resultObj.value && `${resultObj.value.Hz}Hz` == yDataList[i]['name']) {
|
|
|
+ minIndex = i;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (minIndex != -1) {
|
|
|
+ yDataList[minIndex]['lineStyle']['color'] = '#9A60B4';
|
|
|
+ yDataList[minIndex]['lineStyle']['width'] = 2;
|
|
|
+ yDataList[minIndex]['endLabel']['color'] = '#9A60B4';
|
|
|
+ yDataList[minIndex]['endLabel']['backgroundColor'] = '#111';
|
|
|
+ yDataList[minIndex]['z'] = 999;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 根据风量计算压差
|
|
|
+ function computePa() {
|
|
|
+ const R = uH.value / Number(uQ.value) / Number(uQ.value);
|
|
|
+ const pointX = Number(uQ.value);
|
|
|
+ const pointY = Number(uH.value);
|
|
|
+ type ItemType = {
|
|
|
+ x: number;
|
|
|
+ y: number;
|
|
|
+ Hz: number;
|
|
|
+ };
|
|
|
+ const paList = new Map<number, ItemType>(); // key 是最近距离
|
|
|
+ const getIntersectionPoint = (a, b, c, R, min, max) => {
|
|
|
+ const obj: { x: undefined | number; y: undefined | number; min: number; max: number } = { x: undefined, y: undefined, min: min, max: max };
|
|
|
+ // 计算二次方程的判别式
|
|
|
+ const discriminant = b * b - 4 * (a - R) * c;
|
|
|
+
|
|
|
+ if (discriminant > 0) {
|
|
|
+ // 有两个实根
|
|
|
+ const x1 = (-b + Math.sqrt(discriminant)) / (2 * (a - R));
|
|
|
+ const x2 = (-b - Math.sqrt(discriminant)) / (2 * (a - R));
|
|
|
+
|
|
|
+ const y1 = R * x1 * x1;
|
|
|
+ const y2 = R * x2 * x2;
|
|
|
+ if (x1 >= min && x1 <= max) {
|
|
|
+ obj.x = x1;
|
|
|
+ obj.y = y1;
|
|
|
+ } else {
|
|
|
+ obj.x = x2;
|
|
|
+ obj.y = y2;
|
|
|
+ }
|
|
|
+ } else if (discriminant === 0) {
|
|
|
+ // 有一个实根
|
|
|
+ const x = -b / (2 * (a - R));
|
|
|
+ const y = R * x * x;
|
|
|
+ if (x >= min && x <= max) {
|
|
|
+ obj.x = x;
|
|
|
+ obj.y = y;
|
|
|
+ }
|
|
|
+ // console.log(`唯一交点: (${x}, ${y})`);
|
|
|
+ } else {
|
|
|
+ // 没有实根,交点在虚数域
|
|
|
+ console.log('没有实数交点');
|
|
|
+ isHaCross.value = false;
|
|
|
+ }
|
|
|
+ return obj;
|
|
|
+ };
|
|
|
+
|
|
|
+ for (let key in assistanceData.value) {
|
|
|
+ const item: AssistanceItemType = assistanceData.value[key];
|
|
|
+ paList.set(item.Hz, getIntersectionPoint(item.a, item.b, item.c, R, item.min, item.max));
|
|
|
+ }
|
|
|
+
|
|
|
+ const min = (points: Map<number, ItemType>) => {
|
|
|
+ const targetX = uQ.value;
|
|
|
+ const targetY = uH.value;
|
|
|
+ let minDistance = Number.POSITIVE_INFINITY;
|
|
|
+ let closestPoint = null;
|
|
|
+ let keyVal = '';
|
|
|
+ // 遍历已知点数组,计算距离并更新最小距离和对应的点
|
|
|
+ for (const [key, point] of points) {
|
|
|
+ const distance = Math.sqrt((targetX - point.x) ** 2 + (targetY - point.y) ** 2);
|
|
|
+ if (distance < minDistance) {
|
|
|
+ minDistance = distance;
|
|
|
+ closestPoint = point;
|
|
|
+ keyVal = key;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (closestPoint !== null) {
|
|
|
+ // console.log(`距离最小的点是 (${closestPoint.x}, ${closestPoint.y}), 距离为 ${minDistance}`);
|
|
|
+ if (closestPoint.x < closestPoint.min || closestPoint.x > closestPoint.max) {
|
|
|
+ resultObj.value = null;
|
|
|
+ isHaCross.value = false;
|
|
|
+ console.log('没有找到最小距离的点');
|
|
|
+ } else {
|
|
|
+ resultObj.value = { x: closestPoint.x, y: closestPoint.y, Hz: keyVal };
|
|
|
+ isHaCross.value = true;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ resultObj.value = null;
|
|
|
+ isHaCross.value = false;
|
|
|
+ console.log('没有找到最小距离的点');
|
|
|
+ }
|
|
|
+ };
|
|
|
+ min(paList);
|
|
|
+ }
|
|
|
+
|
|
|
+ function computeR() {
|
|
|
+ if (uQ.value && uH.value) {
|
|
|
+ computeRLine();
|
|
|
+ computePa();
|
|
|
+ const x = resultObj.value && resultObj.value.x ? resultObj.value.x.toFixed(0) : -100;
|
|
|
+ const y = resultObj.value && resultObj.value.y ? Number(resultObj.value.y.toFixed(0)) : -100;
|
|
|
+ const series = {
|
|
|
+ type: 'effectScatter',
|
|
|
+ symbolSize: 5,
|
|
|
+ // symbolOffset:[1, 1],
|
|
|
+ showEffectOn: 'render',
|
|
|
+ // 涟漪特效相关配置。
|
|
|
+ rippleEffect: {
|
|
|
+ // 波纹的绘制方式,可选 'stroke' 和 'fill'。
|
|
|
+ brushType: 'stroke',
|
|
|
+ },
|
|
|
+ zlevel: 1,
|
|
|
+ z: 999,
|
|
|
+ itemStyle: {
|
|
|
+ color: '#C60000',
|
|
|
+ },
|
|
|
+ data: [[x, y]],
|
|
|
+ };
|
|
|
+ yDataList[lineNum + 1] = series;
|
|
|
+ }
|
|
|
+ // // 根据计算后的得到的频率,风量,瓦斯浓度
|
|
|
+ // getMonitor();
|
|
|
+ }
|
|
|
+
|
|
|
+ function getMonitor() {
|
|
|
+ clearTimeout(timer);
|
|
|
+ timer = undefined;
|
|
|
+ const n = 10;
|
|
|
+ const windQuantity = uQ1.value;
|
|
|
+ const obj = {
|
|
|
+ m3: windQuantity,
|
|
|
+ gas: gasWarningVal.value,
|
|
|
+ time: '',
|
|
|
+ Hz: uHz.value,
|
|
|
+ };
|
|
|
+ const monitorList: { m3: number; gas: number; Hz: number; time: string }[] = [];
|
|
|
+ for (let i = 0; i < n; i++) {
|
|
|
+ const item = cloneDeep(obj);
|
|
|
+ const m3Temp = (Math.random() * 2 - 1) * Math.random() * 20;
|
|
|
+ const gas = m3Temp * 0.0002;
|
|
|
+ item.time = dayjs(new Date().getTime() - (n + i) * 3000).format('HH:mm:ss');
|
|
|
+ item.m3 = (obj.m3 + m3Temp).toFixed(2);
|
|
|
+ item.gas = (obj.gas + gas).toFixed(4);
|
|
|
+ item.Hz = (obj.Hz + Math.random()).toFixed(2);
|
|
|
+ monitorList.unshift(item);
|
|
|
+ }
|
|
|
+ monitorData.value = cloneDeep(monitorList);
|
|
|
+
|
|
|
+ setTimeout(() => {
|
|
|
+ clearTimeout(timer);
|
|
|
+ timer = undefined;
|
|
|
+
|
|
|
+ timer = 0;
|
|
|
+ if (uQ1.value && uH.value && uQ.value) {
|
|
|
+ openTimer(cloneDeep(obj), 0);
|
|
|
+ } else {
|
|
|
+ openTimer(cloneDeep(obj), 0);
|
|
|
+ }
|
|
|
+ }, 1000);
|
|
|
+ }
|
|
|
+
|
|
|
+ function startCompute() {
|
|
|
+ setTimeout(() => {
|
|
|
+ message.success('指令下发成功!');
|
|
|
+ isStartCompute.value = 1;
|
|
|
+ }, 800);
|
|
|
+ }
|
|
|
+
|
|
|
+ function resetCompute() {
|
|
|
+ setTimeout(() => {
|
|
|
+ message.success('指令下发成功!');
|
|
|
+ isStartCompute.value = -1;
|
|
|
+ tempList.length = 0;
|
|
|
+ n = 0;
|
|
|
+ }, 800);
|
|
|
+ }
|
|
|
+
|
|
|
+ let timer = undefined;
|
|
|
+ let n = 0;
|
|
|
+ let tempList = [];
|
|
|
+ function openTimer(obj: { m3: number; gas: number; Hz: number; time: string }) {
|
|
|
+ // 打开定时器
|
|
|
+ const monitorList = cloneDeep(monitorData.value);
|
|
|
+ if (timer !== undefined) {
|
|
|
+ timer = setTimeout(() => {
|
|
|
+ obj.m3 = Number(obj.m3);
|
|
|
+ obj.gas = Number(obj.gas);
|
|
|
+ obj.Hz = Number(obj.Hz);
|
|
|
+ const item = cloneDeep(obj);
|
|
|
+ item.time = dayjs(new Date().getTime()).format('HH:mm:ss');
|
|
|
+ if (resultObj.value && resultObj.value.x && resultObj.value.y && isStartCompute.value != 0) {
|
|
|
+ if (isStartCompute.value == 1 && Number(obj.m3) > uQ.value && Number(obj.gas) < gasWarningMax.value) {
|
|
|
+ isStartCompute.value = 0;
|
|
|
+ n = 0;
|
|
|
+ } else if (isStartCompute.value == -1 && Number(obj.m3) < uQ1.value) {
|
|
|
+ isStartCompute.value = 0;
|
|
|
+ n = 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!isStartCompute.value) {
|
|
|
+ const m3Temp = (Math.random() * 2 - 1) * Math.random() * Math.random() * 10;
|
|
|
+ const gas = m3Temp * 0.0002;
|
|
|
+ item.m3 = (obj.m3 + m3Temp).toFixed(2);
|
|
|
+ item.gas = (obj.gas + gas).toFixed(4);
|
|
|
+ item.Hz = (obj.Hz + Math.random()).toFixed(2);
|
|
|
+ n = 0;
|
|
|
+ } else {
|
|
|
+ if (n < 2) {
|
|
|
+ const item1 = cloneDeep(obj);
|
|
|
+ const m3Temp = Math.random() * Math.random() * 10;
|
|
|
+ const gas = m3Temp * 0.0002;
|
|
|
+ item1.m3 = (obj.m3 + m3Temp).toFixed(2);
|
|
|
+ item1.gas = (obj.gas + gas).toFixed(4);
|
|
|
+ item1.Hz = (obj.Hz + (Math.random() * 2 - 1) * Math.random()).toFixed(2);
|
|
|
+ tempList.push(item1);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算 uQ1 -> uQ gas -> gasWarningMax.value Hz -> resultObj.value.Hz
|
|
|
+ if (isStartCompute.value == 1) {
|
|
|
+ if (resultObj.value.Hz - obj.Hz > 0) {
|
|
|
+ item.Hz = (uHz.value + (2 * n * (resultObj.value.Hz - uHz.value)) / 20).toFixed(2);
|
|
|
+ if (resultObj.value.Hz - obj.Hz < 0) {
|
|
|
+ item.Hz = (resultObj.value.Hz + Math.random() * 0.5).toFixed(2);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // item.Hz = (resultObj.value.Hz + (Math.random() * 2 - 1) * Math.random() * 2).toFixed(2);
|
|
|
+ item.Hz = (resultObj.value.Hz + Math.random() * 0.5).toFixed(2);
|
|
|
+ }
|
|
|
+ item.m3 = (obj.m3 + (0.017 * n * item.Hz * (item.Hz - uHz.value) * (uQ.value - uQ1.value)) / 600).toFixed(2);
|
|
|
+ if (Number(item.m3) > uQ.value) {
|
|
|
+ item.m3 = (uQ.value + Math.random() * 10).toFixed(2);
|
|
|
+ }
|
|
|
+ item.gas = (
|
|
|
+ gasWarningVal.value -
|
|
|
+ (0.015 * item.Hz * n * (item.Hz - uHz.value) * (gasWarningVal.value - gasWarningMax.value)) / 200
|
|
|
+ ).toFixed(4);
|
|
|
+ } else {
|
|
|
+ // 复位
|
|
|
+ if (obj.Hz - uHz.value > 0) {
|
|
|
+ item.Hz = (obj.Hz - (2 * n * (resultObj.value.Hz - uHz.value)) / 30).toFixed(2);
|
|
|
+ if (item.Hz - uHz.value < 0) {
|
|
|
+ item.Hz = uHz.value - 0.3;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ item.Hz = (uHz.value + (Math.random() * 2 - 1) * Math.random() * 2).toFixed(2);
|
|
|
+ }
|
|
|
+ item.m3 = (obj.m3 - (0.02 * n * n * item.Hz * (resultObj.value.Hz - uHz.value) * (uQ.value - uQ1.value)) / 400).toFixed(2);
|
|
|
+ if (item.m3 < uQ1.value) {
|
|
|
+ item.m3 = uQ1.value - Math.random() * 10;
|
|
|
+ }
|
|
|
+ item.gas = (obj.gas + (0.015 * item.Hz * n * (uHz.value - item.Hz) * (gasWarningVal.value - gasWarningMax.value)) / 800).toFixed(4);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (monitorList.length >= 10) {
|
|
|
+ monitorList.shift();
|
|
|
+ const monitor = cloneDeep(item);
|
|
|
+ const data = tempList.shift();
|
|
|
+ if (data) {
|
|
|
+ item['m3'] = data['m3'];
|
|
|
+ item['gas'] = data['gas'];
|
|
|
+ }
|
|
|
+ tempList.push(monitor);
|
|
|
+ monitorList.push(item);
|
|
|
+ } else {
|
|
|
+ monitorList.push(item);
|
|
|
+ }
|
|
|
+ monitorData.value = monitorList;
|
|
|
+ // console.log('瓦斯监测数据-------------->', monitorData.value);
|
|
|
+ if (timer) {
|
|
|
+ if (!isStartCompute.value) {
|
|
|
+ // n++;
|
|
|
+ openTimer(cloneDeep(obj));
|
|
|
+ } else {
|
|
|
+ n++;
|
|
|
+ openTimer(cloneDeep(item));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }, 3000);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ function edit(flag) {
|
|
|
+ if (flag == 'info') {
|
|
|
+ formType.value = '编辑风机信息';
|
|
|
+ }
|
|
|
+ if (flag == 'line') {
|
|
|
+ formType.value = '编辑特性曲线';
|
|
|
+ }
|
|
|
+ if (formShow.value == true) {
|
|
|
+ formShow.value = false;
|
|
|
+ nextTick(() => {
|
|
|
+ formShow.value = true;
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ formShow.value = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ function onSubmit() {
|
|
|
+ emit('close');
|
|
|
+ closeModal();
|
|
|
+ ChartRef.value = null;
|
|
|
+ uQ.value = undefined;
|
|
|
+ uH.value = undefined;
|
|
|
+ formType.value = '';
|
|
|
+ refresh.value = true;
|
|
|
+ xData.length = 0;
|
|
|
+ yDataList.length = 0;
|
|
|
+ lineNum = 0;
|
|
|
+ lineEquation.value = [];
|
|
|
+ resultObj.value = null;
|
|
|
+ monitorData.value = [];
|
|
|
+ clearTimeout(timer);
|
|
|
+ timer = undefined;
|
|
|
+ }
|
|
|
+
|
|
|
+ async function onCancel() {
|
|
|
+ return new Promise((resolve) => {
|
|
|
+ if (isStartCompute.value == 0) {
|
|
|
+ onSubmit();
|
|
|
+ resolve(true);
|
|
|
+ } else {
|
|
|
+ message.warning('为保障矿井安全生产,请确保已复位!!!');
|
|
|
+ resolve(false);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ function initEcharts() {
|
|
|
+ if (ChartRef.value) {
|
|
|
+ reSetLine();
|
|
|
+ myChart.value = echarts.init(ChartRef.value);
|
|
|
+ option && myChart.value.setOption(option);
|
|
|
+ refresh.value = false;
|
|
|
+ getMonitor();
|
|
|
+ nextTick(() => {
|
|
|
+ setTimeout(() => {
|
|
|
+ refresh.value = true;
|
|
|
+ }, 0);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ function makeLine() {
|
|
|
+ if (uQ.value && uH.value) {
|
|
|
+ loadding.value = true;
|
|
|
+ setTimeout(() => {
|
|
|
+ computeR();
|
|
|
+ reSetLine();
|
|
|
+ option && myChart.value.setOption(option);
|
|
|
+ loadding.value = false;
|
|
|
+ }, 1200);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ function handleSubmit() {
|
|
|
+ message.success('提交成功');
|
|
|
+ setTimeout(() => {
|
|
|
+ formShow.value = false;
|
|
|
+ }, 800);
|
|
|
+ }
|
|
|
+ onMounted(() => {
|
|
|
+ timer = undefined;
|
|
|
+ });
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped lang="less">
|
|
|
+ .modal-box {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: row;
|
|
|
+ background-color: #ffffff05;
|
|
|
+ padding: 20px 8px;
|
|
|
+ border: 1px solid #00d8ff22;
|
|
|
+ position: relative;
|
|
|
+ // min-height: 600px;
|
|
|
+ .box-title {
|
|
|
+ width: calc(100% - 40px);
|
|
|
+ text-align: center;
|
|
|
+ background-color: #1dc1f522;
|
|
|
+ }
|
|
|
+ .info-item {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ padding: 2px 0px;
|
|
|
+ margin: 4px 0;
|
|
|
+ background-image: linear-gradient(to right, #39deff15, #3977e500);
|
|
|
+ &:first-child {
|
|
|
+ margin-top: 0;
|
|
|
+ }
|
|
|
+ .title {
|
|
|
+ width: 200px;
|
|
|
+ text-align: left;
|
|
|
+ padding-left: 20px;
|
|
|
+ color: #f1f1f1cc;
|
|
|
+ }
|
|
|
+ .value {
|
|
|
+ width: 150px;
|
|
|
+ color: #00d8ff;
|
|
|
+ padding-right: 20px;
|
|
|
+ text-align: right;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .right-box {
|
|
|
+ width: 320px;
|
|
|
+ .info-lines {
|
|
|
+ width: calc(100% - 2px);
|
|
|
+ height: 450px;
|
|
|
+ box-shadow: 0px 0px 50px #86baff08 inset;
|
|
|
+ overflow-y: auto;
|
|
|
+ margin-top: 5px;
|
|
|
+ .title {
|
|
|
+ width: 100%;
|
|
|
+ color: #f1f1f1cc;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .center-box {
|
|
|
+ flex: 1;
|
|
|
+ margin: 0 10px;
|
|
|
+ display: flex;
|
|
|
+ .info-echarts {
|
|
|
+ // background-color: #ffffff11;
|
|
|
+ }
|
|
|
+ .result-tip {
|
|
|
+ text-align: center;
|
|
|
+ background-color: #00000011;
|
|
|
+ line-height: 28px;
|
|
|
+ margin: 10px 50px 0 50px;
|
|
|
+ border: 1px solid #00d8ff22;
|
|
|
+ border-radius: 2px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .tip-box {
|
|
|
+ width: 1040px;
|
|
|
+ height: 44px;
|
|
|
+ position: absolute;
|
|
|
+ top: 447px;
|
|
|
+ display: flex;
|
|
|
+ padding: 0 20px;
|
|
|
+ .title {
|
|
|
+ width: 142px;
|
|
|
+ height: 43px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ padding-left: 30px;
|
|
|
+ background-image: url('@/assets/images/fanlocal-tip/tip-title.png');
|
|
|
+ position: relative;
|
|
|
+ &::before {
|
|
|
+ content: '';
|
|
|
+ display: inline-block;
|
|
|
+ position: absolute;
|
|
|
+ width: 31px;
|
|
|
+ height: 31px;
|
|
|
+ top: 5px;
|
|
|
+ left: -8px;
|
|
|
+ background-image: url('@/assets/images/fanlocal-tip/tip-icon.png');
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .tip-container {
|
|
|
+ width: 898px;
|
|
|
+ height: 44px;
|
|
|
+ line-height: 44px;
|
|
|
+ display: flex;
|
|
|
+ background-image: url('@/assets/images/fanlocal-tip/tip-bg.png');
|
|
|
+ background-size: cover;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .setting-box {
|
|
|
+ width: 1170px;
|
|
|
+ height: 70px;
|
|
|
+ margin: 10px 0;
|
|
|
+ background-color: #ffffff05;
|
|
|
+ border: 1px solid #00d8ff22;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+
|
|
|
+ .right-inputs {
|
|
|
+ width: 100%;
|
|
|
+ display: flex;
|
|
|
+ height: 40px;
|
|
|
+ margin: 0 10px;
|
|
|
+ justify-content: space-between;
|
|
|
+ }
|
|
|
+ .left-buttons {
|
|
|
+ display: flex;
|
|
|
+ height: 40px;
|
|
|
+
|
|
|
+ .btn {
|
|
|
+ margin: 0 10px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .border-clip {
|
|
|
+ width: 1px;
|
|
|
+ height: 25px;
|
|
|
+ border-right: 1px solid #8b8b8b77;
|
|
|
+ }
|
|
|
+ .input-title {
|
|
|
+ max-width: 150px;
|
|
|
+ }
|
|
|
+ .input-box {
|
|
|
+ width: 220px !important;
|
|
|
+ background: transparent !important;
|
|
|
+ border-color: #00d8ff44 !important;
|
|
|
+ margin-right: 20px;
|
|
|
+ color: #fff !important;
|
|
|
+ }
|
|
|
+ .btn {
|
|
|
+ padding: 8px 20px;
|
|
|
+ position: relative;
|
|
|
+ border-radius: 2px;
|
|
|
+ color: #fff;
|
|
|
+ width: fit-content;
|
|
|
+ cursor: pointer;
|
|
|
+
|
|
|
+ &::before {
|
|
|
+ position: absolute;
|
|
|
+ display: block;
|
|
|
+ content: '';
|
|
|
+ width: calc(100% - 4px);
|
|
|
+ height: calc(100% - 4px);
|
|
|
+ top: 2px;
|
|
|
+ left: 2px;
|
|
|
+ border-radius: 2px;
|
|
|
+ z-index: -1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .btn1 {
|
|
|
+ border: 1px solid #5cfaff;
|
|
|
+
|
|
|
+ &::before {
|
|
|
+ background-image: linear-gradient(#2effee92, #0cb1d592);
|
|
|
+ }
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ border: 1px solid #5cfaffaa;
|
|
|
+
|
|
|
+ &::before {
|
|
|
+ background-image: linear-gradient(#2effee72, #0cb1d572);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .is-open {
|
|
|
+ animation: open 0.5s;
|
|
|
+ animation-iteration-count: 1;
|
|
|
+ animation-fill-mode: forwards;
|
|
|
+ animation-timing-function: ease-in;
|
|
|
+ }
|
|
|
+ .is-close {
|
|
|
+ height: 0px;
|
|
|
+ }
|
|
|
+
|
|
|
+ @keyframes open {
|
|
|
+ 0% {
|
|
|
+ height: 0px;
|
|
|
+ }
|
|
|
+ 100% {
|
|
|
+ height: fit-content;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @keyframes close {
|
|
|
+ 0% {
|
|
|
+ height: fit-content;
|
|
|
+ }
|
|
|
+ 100% {
|
|
|
+ height: 0px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ :deep(.zxm-divider-inner-text) {
|
|
|
+ color: #cacaca88 !important;
|
|
|
+ }
|
|
|
+ :deep(.zxm-form-item) {
|
|
|
+ margin-bottom: 10px;
|
|
|
+ }
|
|
|
+</style>
|