Переглянути джерело

feat(设备详情): 物联数据增加图表

liujt 8 місяців тому
батько
коміт
0426efcb36

+ 39 - 0
src/api/ledgerAssets/equipment.js

@@ -0,0 +1,39 @@
+import request from '@/utils/request';
+
+// 查询实例详情
+export async function getDetail(id) {
+  const res = await request.get(`main/asset/getPhysicalModel/${id}`);
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+
+
+
+// 查询实例详情
+export async function getRealData(id) {
+  const res = await request.get(`main/asset/getRealData/${id}`);
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+
+// 查询实例详情
+export async function getHistoryData(data) {
+  const res = await request.post(`main/asset/getHistoryData`, data);
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}
+
+// 查询实例详情
+export async function getPhysicalModel(id) {
+  const res = await request.get(`main/asset/getPhysicalModel/${id}`);
+  if (res.data.code == 0) {
+    return res.data.data;
+  }
+  return Promise.reject(new Error(res.data.message));
+}

+ 367 - 0
src/views/ledgerAssets/components/details/components/GaugeChart.vue

@@ -0,0 +1,367 @@
+<!--
+ * @description: ECharts仪表盘组件
+ * @features:
+ * 1. 可复用:支持在同一页面多次引用
+ * 2. 响应式:页面缩放时自动调整大小
+ * 3. 可配置:支持自定义各种属性和样式
+ * 4. 数据驱动:支持通过props更新数据
+ *
+ * @example:
+ * ```vue
+ * <template>
+ *   <div class="gauge-container">
+ *     基本用法
+ *     <GaugeChart :value="65" title="速度" unit="km/h" />
+ *     
+ *     自定义配置
+ *     <GaugeChart
+ *       :value="80"
+ *       :min="0"
+ *       :max="100"
+ *       title="温度"
+ *       unit="°C"
+ *       :colors="['#36CFC9', '#FF7D00', '#F5222D']"
+ *       width="300px"
+ *       height="300px"
+ *     />
+ *   </div>
+ * </template>
+ *
+ * <script>
+ * import GaugeChart from '@/views/ledgerAssets/components/details/components/GaugeChart.vue';
+ *
+ * export default {
+ *   components: {
+ *     GaugeChart
+ *   },
+ *   data() {
+ *     return {
+ *       // 可以通过data属性动态更新图表数据
+ *     };
+ *   }
+ * };
+ * </script>
+ * ```
+ -->
+<template>
+  <div ref="chartRef" :style="{ width: width, height: height }"></div>
+</template>
+
+<script>
+import * as echarts from 'echarts';
+
+export default {
+  name: 'GaugeChart',
+  props: {
+    /**
+     * 图表宽度
+     * @default '100%'
+     * @type {string}
+     */
+    width: {
+      type: String,
+      default: '100%'
+    },
+    /**
+     * 图表高度
+     * @default '300px'
+     * @type {string}
+     */
+    height: {
+      type: String,
+      default: '300px'
+    },
+    /**
+     * 当前值 - 仪表盘显示的数值
+     * @required true
+     * @type {number}
+     */
+    value: {
+      type: Number,
+      required: true
+    },
+    /**
+     * 最小值 - 仪表盘的最小值范围
+     * @default 0
+     * @type {number}
+     */
+    min: {
+      type: Number,
+      default: 0
+    },
+    /**
+     * 最大值 - 仪表盘的最大值范围
+     * @default 100
+     * @type {number}
+     */
+    max: {
+      type: Number,
+      default: 100
+    },
+    /**
+     * 标题 - 仪表盘的标题文本
+     * @default ''
+     * @type {string}
+     */
+    title: {
+      type: String,
+      default: ''
+    },
+    /**
+     * 单位 - 数值的单位
+     * @default ''
+     * @type {string}
+     */
+    unit: {
+      type: String,
+      default: ''
+    },
+    /**
+     * 颜色配置 - 仪表盘颜色渐变区间
+     * 数组长度决定了颜色分段数量
+     * @default ['#5470C6', '#91CC75', '#FAC858', '#EE6666']
+     * @type {Array<string>}
+     */
+    colors: {
+      type: Array,
+      default: () => ['#5470C6', '#5470C6', '#5470C6', '#5470C6']
+    },
+    /**
+     * 分割线数量 - 仪表盘刻度线数量
+     * @default 10
+     * @type {number}
+     */
+    splitNumber: {
+      type: Number,
+      default: 10
+    },
+    /**
+     * 自定义配置 - 直接覆盖ECharts配置项
+     * 可以用于高级自定义
+     * @default {}
+     * @type {Object}
+     */
+    options: {
+      type: Object,
+      default: () => ({})
+    }
+  },
+  data() {
+    return {
+      chartInstance: null
+    };
+  },
+  mounted() {
+    this.initChart();
+    this.handleResize();
+    window.addEventListener('resize', this.handleResize);
+  },
+  beforeDestroy() {
+    window.removeEventListener('resize', this.handleResize);
+    if (this.chartInstance) {
+      this.chartInstance.dispose();
+    }
+  },
+  watch: {
+    value: {
+      handler() {
+        this.updateChart();
+      },
+      immediate: false
+    },
+    min: 'updateChart',
+    max: 'updateChart',
+    title: 'updateChart',
+    unit: 'updateChart',
+    colors: {
+      handler() {
+        this.updateChart();
+      },
+      deep: true
+    },
+    splitNumber: 'updateChart',
+    options: {
+      handler() {
+        this.updateChart();
+      },
+      deep: true
+    }
+  },
+  methods: {
+    /**
+     * 初始化图表实例
+     * 创建ECharts实例并设置初始配置
+     * @private
+     */
+    initChart() {
+      if (!this.$refs.chartRef) return;
+      
+      // 创建唯一的实例以支持在同一页面多次引用
+      this.chartInstance = echarts.init(this.$refs.chartRef);
+      this.updateChart();
+    },
+    
+    /**
+     * 更新图表数据和配置
+     * 根据props中的最新数据重新渲染图表
+     * @private
+     */
+    updateChart() {
+      if (!this.chartInstance) return;
+      
+      const option = {
+        // 移除顶部标题,改为在底部显示
+        backgroundColor: 'transparent',
+        series: [
+          {
+            name: this.title || '仪表盘',
+            type: 'gauge',
+            // startAngle: 180,
+            // endAngle: 0,
+            min: this.min,
+            max: this.max,
+            splitNumber: this.splitNumber,
+            radius: '90%',
+            center: ['50%', '50%'],
+            progress: {
+              show: true,
+              width: 15,
+              roundCap: true,
+            },
+            // 优化仪表盘轴线样式 - 采用单一蓝色调
+            axisLine: {
+              lineStyle: {
+                width: 15,
+                roundCap: true,
+                // color: this.calculateColorRanges(),
+                // shadowBlur: 10,
+                // shadowColor: 'rgba(84, 112, 198, 0.3)'
+              }
+            },
+            // 优化指针样式 - 更细,蓝色
+            pointer: {
+              show: true,
+              width: 5,
+              length: '65%',
+              itemStyle: {
+                color: '#5470C6',
+                // borderWidth: 1,
+                // borderType: 'solid',
+                // borderColor: '#333'
+              }
+            },
+            // 优化刻度线 - 更细、更短,分布在弧上
+            axisTick: {
+              show: false,
+              distance: 0,
+              length: 6,
+              lineStyle: {
+                color: '#666',
+                width: 1
+              }
+            },
+            // 优化分割线 - 与示例图保持一致
+            splitLine: {
+              distance: 0,
+              length: 10,
+              lineStyle: {
+                color: '#5470C6',
+                width: 2
+              }
+            },
+            // 优化标签位置和样式
+            axisLabel: {
+              color: '#333',
+              distance: 25,
+              fontSize: 14,
+              fontWeight: 'normal'
+            },
+            // 优化中心显示内容 - 居中显示数值
+            detail: {
+              valueAnimation: true,
+              formatter: `{value}${this.unit}`,
+              color: '#333',
+              fontSize: 20,
+              fontWeight: 'bold',
+              offsetCenter: [0, '40%'],
+              borderColor: 'transparent'
+            },
+            // 添加单位显示
+            title: {
+              offsetCenter: [0, '65%'],
+              fontSize: 14,
+              color: '#333',
+              fontWeight: 'normal'
+            },
+            data: [
+              {
+                value: this.value,
+                name: this.title
+              }
+            ]
+          }
+        ],
+        // 合并自定义配置,允许用户覆盖默认设置
+        ...this.options
+      };
+      
+      // 使用true参数强制更新所有配置项
+      this.chartInstance.setOption(option, true);
+    },
+    
+    /**
+     * 计算仪表盘颜色渐变范围
+     * 根据最小值、最大值和颜色数组计算分段颜色区间
+     * @private
+     * @returns {Array<Array<number|string>>} 颜色范围数组
+     */
+    calculateColorRanges() {
+      // 对于压力计等场景,使用单一蓝色调更合适
+      // 但保持配置灵活性,允许用户自定义颜色
+      const ranges = [];
+      const step = (this.max - this.min) / this.colors.length;
+      
+      for (let i = 0; i < this.colors.length; i++) {
+        ranges.push([
+          this.min + step * i,
+          this.min + step * (i + 1),
+          this.colors[i]
+        ]);
+      }
+      
+      return ranges;
+    },
+    
+    /**
+     * 处理窗口大小变化
+     * 当页面缩放时自动调整图表大小以保持显示正常
+     * @private
+     */
+    handleResize() {
+      if (this.chartInstance) {
+        this.chartInstance.resize();
+      }
+    },
+    
+    /**
+     * 手动触发重绘
+     * 提供给父组件调用的公共方法,用于强制刷新图表
+     * @public
+     */
+    redraw() {
+      if (!this.chartInstance) {
+        this.initChart();
+      } else {
+        this.updateChart();
+      }
+    }
+  }
+};
+</script>
+
+<style scoped>
+:deep(.echarts) {
+  width: 100%;
+  height: 100%;
+}
+</style>

+ 337 - 0
src/views/ledgerAssets/components/details/components/LineChart.vue

@@ -0,0 +1,337 @@
+<template>
+  <div class="line-chart-container">
+    <div ref="chartContainer" class="chart-wrapper" :style="{ width: width, height: height }"></div>
+  </div>
+</template>
+
+<script>
+import * as echarts from 'echarts';
+
+export default {
+  name: 'LineChart',
+  props: {
+    /**
+     * 图表宽度
+     * @default '100%'
+     */
+    width: {
+      type: String,
+      default: '100%'
+    },
+    
+    /**
+     * 图表高度
+     * @default '400px'
+     */
+    height: {
+      type: String,
+      default: '400px'
+    },
+    
+    /**
+     * 图表数据
+     * @example
+     * {
+     *   xAxis: ['周一', '周二', '周三', '周四', '周五'],
+     *   series: [
+     *     {
+     *       name: '数据1',
+     *       data: [120, 200, 150, 80, 70],
+     *       color: '#5470C6'
+     *     },
+     *     {
+     *       name: '数据2',
+     *       data: [90, 150, 220, 160, 130],
+     *       color: '#91CC75'
+     *     }
+     *   ]
+     * }
+     */
+    data: {
+      type: Object,
+      required: true,
+      validator: (value) => {
+        return value && Array.isArray(value.xAxis) && Array.isArray(value.series);
+      }
+    },
+    
+    /**
+     * 图表标题
+     */
+    title: {
+      type: String,
+      default: ''
+    },
+    
+    /**
+     * X轴名称
+     */
+    xAxisName: {
+      type: String,
+      default: ''
+    },
+    
+    /**
+     * Y轴名称
+     */
+    yAxisName: {
+      type: String,
+      default: ''
+    },
+    
+    /**
+     * 是否显示图例
+     * @default true
+     */
+    showLegend: {
+      type: Boolean,
+      default: true
+    },
+    
+    /**
+     * 高级配置项,会与默认配置合并
+     */
+    options: {
+      type: Object,
+      default: () => ({})
+    }
+  },
+  
+  data() {
+    return {
+      chart: null,
+      resizeObserver: null
+    };
+  },
+  
+  watch: {
+    /**
+     * 监听数据变化,更新图表
+     */
+    data: {
+      deep: true,
+      handler(newData) {
+        this.updateChart(newData);
+      }
+    }
+  },
+  
+  mounted() {
+    this.initChart();
+    this.addResizeListener();
+  },
+  
+  beforeDestroy() {
+    this.removeResizeListener();
+    if (this.chart) {
+      this.chart.dispose();
+      this.chart = null;
+    }
+  },
+  
+  methods: {
+    /**
+     * 初始化图表
+     * @private
+     */
+    initChart() {
+      if (!this.$refs.chartContainer) return;
+      
+      this.chart = echarts.init(this.$refs.chartContainer);
+      this.updateChart(this.data);
+    },
+    
+    /**
+     * 更新图表数据
+     * @param {Object} chartData - 图表数据
+     * @public
+     */
+    updateChart(chartData) {
+      if (!this.chart || !chartData) return;
+      
+      // 获取当前图表的yAxisName作为单位
+      const unit = this.yAxisName || '';
+      
+      const series = chartData.series.map(item => ({
+        name: item.name,
+        type: 'line',
+        // 使用简单的数据结构
+        data: item.data,
+        smooth: true,
+        lineStyle: {
+          width: 3,
+          color: item.color
+        },
+        itemStyle: {
+          color: item.color
+        },
+        areaStyle: {
+          opacity: 0.1,
+          color: item.color
+        },
+        emphasis: {
+          focus: 'series'
+        },
+        // 将单位信息作为额外的属性传递
+        seriesUnit: unit
+      }));
+      
+      const legend = this.showLegend ? {
+        data: chartData.series.map(item => item.name),
+        top: '5%'
+      } : {
+        show: false
+      };
+      
+      const option = {
+        title: {
+          text: this.title,
+          left: 'center',
+          top: '5%',
+          textStyle: {
+            fontSize: 16,
+            fontWeight: 'normal'
+          }
+        },
+        tooltip: {
+          trigger: 'axis',
+          backgroundColor: 'rgba(255, 255, 255, 0.95)',
+          borderColor: '#ddd',
+          borderWidth: 1,
+          textStyle: {
+            color: '#333'
+          },
+          formatter: function(params) {
+            let result = params[0].name + '<br/>';
+            params.forEach(item => {
+              // 获取series的unit信息
+              const unit = item.seriesUnit || '';
+              result += `<div style="display: flex; align-items: center; margin: 5px 0;">
+                          <span style="display: inline-block; width: 10px; height: 10px; background: ${item.color}; border-radius: 50%; margin-right: 8px;"></span>
+                          <span style="color: ${item.color};">${item.seriesName}: ${item.value}${unit}</span>
+                        </div>`;
+            });
+            return result;
+          }
+        },
+        legend,
+        grid: {
+          left: '3%',
+          right: '4%',
+          bottom: '3%',
+          top: this.title ? '20%' : '15%',
+          containLabel: true
+        },
+        xAxis: {
+          type: 'category',
+          boundaryGap: false,
+          data: chartData.xAxis,
+          name: this.xAxisName,
+          nameTextStyle: {
+            padding: [0, 0, 0, 40]
+          },
+          axisLine: {
+            lineStyle: {
+              color: '#ddd'
+            }
+          },
+          axisLabel: {
+            color: '#666',
+            fontSize: 12
+          }
+        },
+        yAxis: {
+          type: 'value',
+          name: this.yAxisName,
+          nameTextStyle: {
+            padding: [0, 40, 0, 0]
+          },
+          axisLine: {
+            show: false
+          },
+          axisTick: {
+            show: false
+          },
+          axisLabel: {
+            color: '#666',
+            fontSize: 12
+          },
+          splitLine: {
+            lineStyle: {
+              color: '#f0f0f0',
+              type: 'dashed'
+            }
+          }
+        },
+        series,
+        ...this.options
+      };
+      
+      this.chart.setOption(option, true);
+    },
+    
+    /**
+     * 添加响应式监听
+     * @private
+     */
+    addResizeListener() {
+      if (window.ResizeObserver) {
+        this.resizeObserver = new ResizeObserver(() => {
+          if (this.chart) {
+            this.chart.resize();
+          }
+        });
+        this.resizeObserver.observe(this.$refs.chartContainer);
+      } else {
+        // 兼容旧浏览器
+        window.addEventListener('resize', this.handleResize);
+      }
+    },
+    
+    /**
+     * 移除响应式监听
+     * @private
+     */
+    removeResizeListener() {
+      if (this.resizeObserver) {
+        this.resizeObserver.disconnect();
+        this.resizeObserver = null;
+      } else {
+        window.removeEventListener('resize', this.handleResize);
+      }
+    },
+    
+    /**
+     * 处理窗口大小变化
+     * @private
+     */
+    handleResize() {
+      if (this.chart) {
+        this.chart.resize();
+      }
+    },
+    
+    /**
+     * 手动调整图表大小
+     * @public
+     */
+    resize() {
+      if (this.chart) {
+        this.chart.resize();
+      }
+    }
+  }
+};
+</script>
+
+<style scoped>
+.line-chart-container {
+  width: 100%;
+  height: 100%;
+}
+
+.chart-wrapper {
+  width: 100%;
+  height: 100%;
+}
+</style>

+ 454 - 0
src/views/ledgerAssets/components/details/components/internetDetail.vue

@@ -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>

+ 17 - 14
src/views/ledgerAssets/components/details/internet.vue

@@ -7,11 +7,12 @@
       </div>
     </div>
     <!-- 挤压机 65 -->
-    <InternetExtruder :info="info" v-if="parentClassId == '65'" />
+    <!-- <InternetExtruder :info="info" v-if="parentClassId == '65'" /> -->
     <!-- 干燥箱 57 -->
-    <InternetDryingBox :info="info" v-else-if="parentClassId == '57'" />
+    <!-- <InternetDryingBox :info="info" v-else-if="parentClassId == '57'" /> -->
     <!-- 其他设备 -->
-    <InternetOther v-else :id="id"></InternetOther>
+    <!-- <InternetOther v-else :id="id"></InternetOther> -->
+     <internetDetail :info="info" :id="id"></internetDetail>
   </div>
 </template>
 
@@ -19,10 +20,11 @@
   import InternetExtruder from './InternetExtruder/InternetExtruder';
   import InternetDryingBox from './InternetDryingBox/InternetDryingBox';
   import InternetOther from './InternetOther';
-  // import { getDetail } from '@/api/ledgerAssets/equipment';
+  import internetDetail from './components/internetDetail.vue';
+  import { getDetail } from '@/api/ledgerAssets/equipment';
   export default {
     props: ['id'],
-    components: { InternetExtruder, InternetDryingBox, InternetOther },
+    components: { InternetExtruder, InternetDryingBox, InternetOther, internetDetail },
 
     data() {
       return {
@@ -30,7 +32,7 @@
         // 设备信息
         info: '',
         // 父类id
-        parentClassId: ''
+        parentClassId: '65'
       };
     },
     created() {
@@ -38,14 +40,15 @@
     },
     methods: {
       getInfo() {
-        // getDetail({
-        //   id: this.id
-        // }).then((res) => {
-        //   this.info = res.data;
-        //   this.parentClassId = this.setParentClassId(
-        //     this.info.information.classificationUrlId
-        //   );
-        // });
+        getDetail(
+          this.id
+        ).then((res) => {
+          this.info = res;
+          console.log(this.info);
+          // this.parentClassId = this.setParentClassId(
+          //   this.info.information.classificationUrlId
+          // );
+        });
       },
       // 获取父类id
       setParentClassId(val) {