|
|
@@ -0,0 +1,454 @@
|
|
|
+<template>
|
|
|
+ <div class="internet-detail-container">
|
|
|
+ <div class="gauge-charts-container">
|
|
|
+ <div class="gauge-charts-wrapper">
|
|
|
+ <div class="gauge-card" v-for="item in realData">
|
|
|
+ <GaugeChart
|
|
|
+ :value="item.value"
|
|
|
+ :min="item.min"
|
|
|
+ :max="item.max"
|
|
|
+ :title="item.name"
|
|
|
+ :unit="item.unit"
|
|
|
+ :colors="['#5470C6', '#91CC75', '#FAC858', '#EE6666']"
|
|
|
+ :options="{ pointer: { itemStyle: { color: '#5470C6' } } }"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="gauge-charts-wrapper">
|
|
|
+ <el-form label-width="150px" style="width: 100%">
|
|
|
+ <el-row v-for="obj in realData">
|
|
|
+ <template>
|
|
|
+ <!-- 过滤掉运行状态 v-if="!['status', 'status_m'].includes(key)" -->
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item :label="obj.name">
|
|
|
+ <span>{{ obj.value }}</span>
|
|
|
+ <span style="margin-left: 5px" v-if="obj.unit">{{
|
|
|
+ obj.unit
|
|
|
+ }}</span>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="最大值">
|
|
|
+ <!-- <span>最大值</span> -->
|
|
|
+ <span style="margin-left: 5px">{{
|
|
|
+ obj.max
|
|
|
+ }}</span>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ <el-col :span="12">
|
|
|
+ <el-form-item label="最小值">
|
|
|
+ <!-- <span>最小值</span> -->
|
|
|
+ <span style="margin-left: 5px">{{
|
|
|
+ obj.min
|
|
|
+ }}</span>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </template>
|
|
|
+ <!-- 运行状态设置 -->
|
|
|
+ <el-col :span="12" v-if="realData.status_m">
|
|
|
+ <el-form-item label="运行状态">
|
|
|
+ <div class="yx-warp">
|
|
|
+ <span>{{ realData.status_m.value }}</span>
|
|
|
+ <span
|
|
|
+ class="sz-span"
|
|
|
+ @click="handlsz"
|
|
|
+
|
|
|
+ >设置</span
|
|
|
+ >
|
|
|
+ </div>
|
|
|
+ </el-form-item>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </el-form>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 折线图区域 -->
|
|
|
+ <div class="line-charts-wrapper">
|
|
|
+
|
|
|
+ <div class="chart-card" v-for="item in historyData">
|
|
|
+ <el-row :gutter="20">
|
|
|
+ <el-col :span="8">{{item.name}}</el-col>
|
|
|
+ <el-col :span="8">最高值{{ item.maxValue }}{{ item.unit}} | 最低值{{ item.minValue }}{{ item.unit}} | 平均值{{ item.avgValue }}{{ item.unit}}</el-col>
|
|
|
+ <el-col :span="8">
|
|
|
+ <div class="tools">
|
|
|
+ <div class="">
|
|
|
+ <el-date-picker
|
|
|
+ v-model="item.chartTime"
|
|
|
+ :type="item.timeType"
|
|
|
+ placeholder="选择日期"
|
|
|
+ >
|
|
|
+ </el-date-picker>
|
|
|
+ </div>
|
|
|
+ <div class="timeType">
|
|
|
+ <span
|
|
|
+ :class="{ active: item.timeType === 'date' }"
|
|
|
+ @click="dateClick(item, 'date')"
|
|
|
+ >日</span
|
|
|
+ >
|
|
|
+ <!-- <span
|
|
|
+ :class="{ active: item.timeType === 'week' }"
|
|
|
+ @click="dateClick(item, 'week')"
|
|
|
+ >周</span
|
|
|
+ > -->
|
|
|
+ <span
|
|
|
+ :class="{ active: item.timeType === 'month' }"
|
|
|
+ @click="dateClick(item, 'month')"
|
|
|
+ >月</span
|
|
|
+ >
|
|
|
+ <span
|
|
|
+ :class="{ active: item.timeType === 'year' }"
|
|
|
+ @click="dateClick(item, 'year')"
|
|
|
+ >年</span
|
|
|
+ >
|
|
|
+ </div>
|
|
|
+ <el-button type="primary" size="small" @click="refreshSingleChart(item)">查询</el-button>
|
|
|
+ </div>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ <LineChart
|
|
|
+ :data="item.trendData"
|
|
|
+ title=""
|
|
|
+ xAxisName="时间"
|
|
|
+ :yAxisName="item.unit"
|
|
|
+ height="300px"
|
|
|
+ :options="{}"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <runningDialog
|
|
|
+ ref="runningDialog"
|
|
|
+ :id="info.id"
|
|
|
+ @succeed="getRealData"
|
|
|
+ ></runningDialog>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import GaugeChart from './GaugeChart.vue';
|
|
|
+import LineChart from './LineChart.vue';
|
|
|
+import { getRealData, getHistoryData } from '@/api/ledgerAssets/equipment.js';
|
|
|
+import { getMonday } from '@/utils/index';
|
|
|
+import runningDialog from './runningDialog.vue';
|
|
|
+
|
|
|
+export default {
|
|
|
+ props: {
|
|
|
+ info: {
|
|
|
+ type: Object,
|
|
|
+ default: () => ({})
|
|
|
+ },
|
|
|
+ id: {
|
|
|
+ type: String,
|
|
|
+ default: ''
|
|
|
+ },
|
|
|
+ },
|
|
|
+ name: 'InternetDetail',
|
|
|
+ components: {
|
|
|
+ GaugeChart,
|
|
|
+ LineChart,
|
|
|
+ runningDialog
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ realData: [],
|
|
|
+ dict: {
|
|
|
+ chartTime: {
|
|
|
+ date: 3,
|
|
|
+ month: 2,
|
|
|
+ year: 1
|
|
|
+ }
|
|
|
+ },
|
|
|
+ historyData: [], // 存储历史数据数组
|
|
|
+ };
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ // this.setMonth();
|
|
|
+ // 初始化数据
|
|
|
+ this.getRealData();
|
|
|
+ },
|
|
|
+ beforeDestroy() {
|
|
|
+ // 清除定时器
|
|
|
+ // if (this.timer) {
|
|
|
+ // clearInterval(this.timer);
|
|
|
+ // }
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ handlsz() {
|
|
|
+ this.$refs.runningDialog.open();
|
|
|
+ },
|
|
|
+ // 刷新单个图表数据
|
|
|
+ async refreshSingleChart(item) {
|
|
|
+ try {
|
|
|
+ const updatedData = await this.getHistoryDatas(item);
|
|
|
+ // 找到对应的图表数据并更新
|
|
|
+ const index = this.historyData.findIndex(d => d.identifier === item.identifier);
|
|
|
+ if (index !== -1) {
|
|
|
+ this.$set(this.historyData, index, updatedData);
|
|
|
+ }
|
|
|
+ console.log(`刷新了图表 ${item.name || item.identifier} 的数据`);
|
|
|
+ } catch (error) {
|
|
|
+ console.error(`刷新图表 ${item.name || item.identifier} 数据失败:`, error);
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 刷新所有历史数据
|
|
|
+ async refreshHistoryData() {
|
|
|
+ try {
|
|
|
+ // 并行请求所有property的历史数据
|
|
|
+ const historyPromises = this.realData.map(item =>
|
|
|
+ this.getHistoryDatas(item)
|
|
|
+ );
|
|
|
+
|
|
|
+ // 等待所有请求完成并存储结果
|
|
|
+ this.historyData = await Promise.all(historyPromises);
|
|
|
+ console.log('刷新后的历史数据数组~~~~~', this.historyData);
|
|
|
+ } catch (error) {
|
|
|
+ console.error('刷新历史数据失败:', error);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 请求实时数据
|
|
|
+ async getRealData() {
|
|
|
+ try {
|
|
|
+ // 获取实时数据
|
|
|
+ const res = await getRealData(this.id);
|
|
|
+ this.realData = res;
|
|
|
+
|
|
|
+ // 处理属性映射
|
|
|
+ const tempData = this.info.properties || [];
|
|
|
+ this.realData.forEach(item => {
|
|
|
+ tempData?.forEach(property => {
|
|
|
+ if (property.identifier == item.identifier) {
|
|
|
+ item.max = property.dataType.specs.max;
|
|
|
+ item.min = property.dataType.specs.min;
|
|
|
+ item.unit = property.dataType.specs.unit;
|
|
|
+ item.unitName = property.dataType.specs.unitName;
|
|
|
+ // item.value = property.dataType.specs.scale ? item.value / property.dataType.specs.scale : item.value;
|
|
|
+ // 为每个图表添加独立的状态
|
|
|
+ item.chartTime = new Date();
|
|
|
+ item.timeType = 'month';
|
|
|
+ }
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ console.log('info~~~~~', this.info);
|
|
|
+ console.log('实时数据~~~~~', this.realData);
|
|
|
+
|
|
|
+ // 并行请求所有property的历史数据
|
|
|
+ const historyPromises = this.realData.map(item =>
|
|
|
+ this.getHistoryDatas(item)
|
|
|
+ );
|
|
|
+
|
|
|
+ // 等待所有请求完成并存储结果
|
|
|
+ this.historyData = await Promise.all(historyPromises);
|
|
|
+ console.log('历史数据数组~~~~~', this.historyData);
|
|
|
+ } catch (error) {
|
|
|
+ console.error('获取数据失败:', error);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 请求历史数据
|
|
|
+ async getHistoryDatas(item) {
|
|
|
+ try {
|
|
|
+ let time = this.getTimeList(item.chartTime, item.timeType);
|
|
|
+ const res = await getHistoryData({
|
|
|
+ startTime: time.startTime,
|
|
|
+ endTime: time.endTime,
|
|
|
+ property: item.identifier,
|
|
|
+ substanceId: this.id,
|
|
|
+ timeType: this.dict.chartTime[item.timeType]
|
|
|
+ });
|
|
|
+ console.log('历史数据~~~~~', res);
|
|
|
+ res.identifier = item.identifier;
|
|
|
+ res.name = item.name;
|
|
|
+ res.unit = item.unit;
|
|
|
+ res.unitName = item.unitName;
|
|
|
+ res.chartTime = item.chartTime;
|
|
|
+ res.timeType = item.timeType;
|
|
|
+ const trendData = {
|
|
|
+ xAxis: [],
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ name: '',
|
|
|
+ data: [],
|
|
|
+ color: '#5470C6'
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ res.timeHistoryList.map(i => {
|
|
|
+ trendData.xAxis.push(i.time);
|
|
|
+ trendData.series[0].data.push(i.value);
|
|
|
+ })
|
|
|
+
|
|
|
+ trendData.series[0].name = item.name;
|
|
|
+ res.trendData = trendData;
|
|
|
+ console.log(`属性 ${item.name || item.identifier} 的历史数据:`, res);
|
|
|
+ return res; // 返回历史数据供Promise.all收集
|
|
|
+ } catch (error) {
|
|
|
+ console.error(`获取属性 ${item.name || item.identifier} 的历史数据失败:`, error);
|
|
|
+ return null; // 出错时返回null
|
|
|
+ }
|
|
|
+ },
|
|
|
+ dateClick(item, dateType) {
|
|
|
+ item.chartTime = '';
|
|
|
+ item.timeType = dateType;
|
|
|
+ },
|
|
|
+ // 日期数据格式化
|
|
|
+ getTimeList(date, timeType) {
|
|
|
+ function fnNum(num) {
|
|
|
+ return num < 10 ? '0' + num : num;
|
|
|
+ }
|
|
|
+
|
|
|
+ let startTime;
|
|
|
+ let endTime;
|
|
|
+
|
|
|
+ let ndate = date ? new Date(date) : new Date();
|
|
|
+ let year = ndate.getFullYear();
|
|
|
+ let month = ndate.getMonth() + 1;
|
|
|
+ let day = ndate.getDate();
|
|
|
+
|
|
|
+ switch (timeType) {
|
|
|
+ case 'date': {
|
|
|
+ let _date = `${year}-${fnNum(month)}-${fnNum(day)}`;
|
|
|
+ startTime = _date + ' 00:00:00';
|
|
|
+ endTime = _date + ' 23:59:59';
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case 'month': {
|
|
|
+ let month = getMonday(date);
|
|
|
+ startTime = month[0] + ' 00:00:00';
|
|
|
+ endTime = month[1] + ' 23:59:59';
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case 'year': {
|
|
|
+ let year = ndate.getFullYear();
|
|
|
+ startTime = year + '-01-01 00:00:00';
|
|
|
+ endTime = year + '-12-31 23:59:59';
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ return {
|
|
|
+ startTime,
|
|
|
+ endTime
|
|
|
+ };
|
|
|
+ },
|
|
|
+ // 默认当月(不再需要,每个图表有独立的时间设置)
|
|
|
+ setMonth() {
|
|
|
+ // 不再需要设置全局温度时间
|
|
|
+ },
|
|
|
+ }
|
|
|
+};
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped lang="scss">
|
|
|
+.internet-detail-container {
|
|
|
+ /* padding: 20px;
|
|
|
+ background-color: #f5f7fa;
|
|
|
+ border-radius: 8px; */
|
|
|
+}
|
|
|
+
|
|
|
+.gauge-charts-container {
|
|
|
+ display: flex;
|
|
|
+ gap: 30px;
|
|
|
+// flex-wrap: wrap;
|
|
|
+}
|
|
|
+
|
|
|
+.section-title {
|
|
|
+ font-size: 20px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #303133;
|
|
|
+ margin-bottom: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.section-subtitle {
|
|
|
+ font-size: 18px;
|
|
|
+ font-weight: 500;
|
|
|
+ color: #303133;
|
|
|
+ margin: 30px 0 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.gauge-charts-wrapper {
|
|
|
+ display: flex;
|
|
|
+ gap: 30px;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ width: 50%;
|
|
|
+}
|
|
|
+
|
|
|
+.line-charts-wrapper {
|
|
|
+ margin-top: 30px;
|
|
|
+}
|
|
|
+
|
|
|
+.gauge-card,
|
|
|
+.chart-card {
|
|
|
+ flex: 1;
|
|
|
+ min-width: 250px;
|
|
|
+ background: white;
|
|
|
+ border-radius: 8px;
|
|
|
+ padding: 20px;
|
|
|
+ box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
|
|
+ margin-bottom: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.gauge-title,
|
|
|
+.chart-title {
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 500;
|
|
|
+ color: #606266;
|
|
|
+ margin-bottom: 15px;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+
|
|
|
+.chart-title {
|
|
|
+ font-size: 15px;
|
|
|
+ margin-bottom: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.gauge-info {
|
|
|
+ margin-top: 15px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-around;
|
|
|
+ font-size: 14px;
|
|
|
+ color: #909399;
|
|
|
+}
|
|
|
+
|
|
|
+.info-item {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+
|
|
|
+@media (max-width: 768px) {
|
|
|
+ .gauge-charts-wrapper {
|
|
|
+ flex-direction: column;
|
|
|
+ }
|
|
|
+
|
|
|
+ .gauge-card,
|
|
|
+ .chart-card {
|
|
|
+ width: 100%;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.tools {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ .el-button {
|
|
|
+ margin: 0 12px;
|
|
|
+ }
|
|
|
+ .timeType {
|
|
|
+ margin: 0 20px;
|
|
|
+ // letter-spacing: 8px;
|
|
|
+ span {
|
|
|
+ cursor: pointer;
|
|
|
+ margin: 0 4px;
|
|
|
+ }
|
|
|
+ span.active,
|
|
|
+ span:hover {
|
|
|
+ border-bottom: 2px solid #1890ff;
|
|
|
+ color: #1890ff;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+</style>
|