zhaowei
2 天以前 8bfb4724eb500c685546f5c020f6fd8983d7c75b
src/views/dashboard/mdcIndex/MdcManagerSignage.vue
@@ -1,37 +1,37 @@
<template>
  <div class="home-container">
    <div class="tab-nav">
      <div
        v-for="(tab, index) in tabList"
        :key="index"
        :class="['tab-item', activeTab === index ? 'tab-active' : '']"
        @click="handleTabChange(index)"
      >
    <a-card class="tab-nav">
      <div v-for="(tab, index) in tabList" :key="index"
           :class="['tab-item', activeTab === index ? 'tab-item-active' : '']"
           @click="handleTabChange(index)">
        {{ tab.label }}
      </div>
    </div>
    </a-card>
    <div class="chart-container">
      <div class="left-cards">
        <div class="card left-cards-card">
          <div id="running_state_chart" style="width:100%;height: 45%;max-height: 45vh"></div>
          <div id="efficiency_chart" style="width: 100%;height: 55%;max-height: 55vh"></div>
        </div>
      <div class="left-container">
        <a-card title="设备状态">
          <div id="running_state_chart" style="width:100%;height: 100%"></div>
        </a-card>
        <a-card :title="getLeftBottomChartTitle">
          <div id="efficiency_chart" style="width: 100%;height: 100%"></div>
        </a-card>
      </div>
      <div class="right-cards">
        <div class="card right-top-card">
          <div id="first15DaysEfficiency_chart" style="width:100%;height: 100%;max-height: 50vh"></div>
        </div>
      <div class="right-container">
        <a-card title="前15天利用率" class="right-top-container">
          <div id="first15DaysEfficiency_chart" style="width:100%;height: 100%;"></div>
        </a-card>
        <div class="right-bottom-card">
          <div class="card right-bottom-left-card">
            <div id="bar_chart" style="width:100%;height: 100%;max-height: 50vh"></div>
          </div>
          <div class="card right-bottom-right-card">
            <div id="double_bar_chart" style="width:100%;height: 100%;max-height: 50vh"></div>
          </div>
        <div class="right-bottom-container">
          <a-card :title="getRightBottomChartTitle">
            <div id="bar_chart" style="width:100%;height: 100%;"></div>
          </a-card>
          <a-card title="月利用率OEE统计">
            <div id="double_bar_chart" style="width:100%;height: 100%;"></div>
          </a-card>
        </div>
      </div>
    </div>
@@ -39,301 +39,255 @@
</template>
<script>
  import signageApi from '@/api/signage'
  import moment from 'moment'
import signageApi from '@/api/signage'
import moment from 'moment'
export default {
  name: 'DncManagerSignage',
  components: {},
  data() {
    return {
      tabList: [],
      activeTab: -1, // 初始无选中页签(-1表示未选择状态)
      firstEnterClientWidth: null,
      pieChartRadius: ['45%', '55%'],
      normalPieChartRadius: ['45%', '55%'],
      currentPageProductionId: null,
      runningStateChart: '',
      efficiencyChart: '',
      efficiencyData: [],
      barChart: '',
      barChartData: [],
      doubleBarChart: '',
      doubleBarChartData: {},
      runningStateChartDataRequireFinished: false,
      first15DaysEfficiencyChart: '',
      first15DaysEfficiencyData: {
        dataList: [],
        dateList: []
  export default {
    name: 'DncManagerSignage',
    components: {},
    data() {
      return {
        tabList: [],
        activeTab: -1, // 初始无选中页签(-1表示未选择状态)
        runningStateChart: '',
        efficiencyChart: '',
        efficiencyData: [],
        barChart: '',
        barChartData: [],
        doubleBarChart: '',
        doubleBarChartData: {},
        first15DaysEfficiencyChart: '',
        first15DaysEfficiencyData: {
          dataList: [],
          dateList: []
        },
        runningStateData: [
          { value: '0', name: '关机' },
          { value: '0', name: '报警' },
          { value: '0', name: '待机' },
          { value: '0', name: '运行' }
        ]
      }
    },
    mounted() {
      window.addEventListener('resize', this.handleWindowResize)
      this.getAllWorkShop()
      this.getChartDataByApi()
    },
    beforeDestroy() {
      // 组件销毁前移除监听
      window.removeEventListener('resize', this.handleWindowResize)
    },
    computed: {
      getLeftBottomChartTitle() {
        return `${moment().subtract(1, 'days').format('M月D日')}各车间利用率排行`
      },
      runningStateData: [
        { value: '0', name: '关机' },
        { value: '0', name: '报警' },
        { value: '0', name: '待机' },
        { value: '0', name: '运行' }
      ]
    }
  },
  mounted() {
    window.addEventListener('resize', this.handleWindowResize)
    // this.re_drawPieChart()
    this.getAllWorkShop()
    this.getChartDataByApi()
  },
  beforeDestroy() {
    // 组件销毁前移除监听
    window.removeEventListener('resize', this.handleWindowResize)
    this.destroyEchartsInstances()
  },
  methods: {
    getAllWorkShop() {
      this.tabList = []
      signageApi.getAllWorkShop()
        .then(res => {
          if (res.success) {
            this.tabList = res.result.map(workshop => ({
              label: workshop.productionName,
              factoryId: workshop.id
            }))
            if (this.tabList.length > 0) {
              this.activeTab = -1
              this.destroyEchartsInstances()
              this.getChartDataByApi()
      getRightBottomChartTitle() {
        return moment().subtract(1, 'month').format('M月') + `OEE`
      }
    },
    methods: {
      // 获取车间列表
      getAllWorkShop() {
        this.tabList = []
        signageApi.getAllWorkShop()
          .then(res => {
            if (res.success) {
              this.tabList = res.result.map(workshop => ({
                label: workshop.productionName,
                factoryId: workshop.id
              }))
            }
          } else {
            this.tabList = []
            this.activeTab = -1
          }
        })
        .catch(err => {
          this.tabList = []
          this.activeTab = -1
          this.destroyEchartsInstances()
          })
      },
      handleTabChange(index) {
        // 1. 如果点击的是“已选中的页签”,执行“取消选中”逻辑
        if (this.activeTab === index) {
          this.activeTab = -1 // 重置为未选中状态
          this.getChartDataByApi()
        })
    },
    destroyEchartsInstances() {
      const charts = [
        this.runningStateChart,
        this.efficiencyChart,
        this.first15DaysEfficiencyChart,
        this.barChart,
        this.doubleBarChart
      ]
      charts.forEach(chart => {
        if (chart && chart.dispose) chart.dispose()
      })
    },
    handleTabChange(index) {
      // 1. 如果点击的是“已选中的页签”,执行“取消选中”逻辑
      if (this.activeTab === index) {
        this.activeTab = -1; // 重置为未选中状态
        this.destroyEchartsInstances(); // 销毁所有图表实例
        this.getChartDataByApi();
        return;
      }
      // 2. 常规切换页签逻辑(原有逻辑保留)
      this.activeTab = index;
      this.destroyEchartsInstances();
      this.getChartDataByApi();
    },
    /* 调用接口获取图表数据汇总方法 */
    getChartDataByApi() {
      let currentFactoryId = ''
      if (this.tabList[this.activeTab] != null && this.tabList[this.activeTab] !== undefined) {
        currentFactoryId = this.tabList[this.activeTab].factoryId
      }
      console.log('currentFactoryId', currentFactoryId)
      this.getRunningStateDataByApi(currentFactoryId)
      this.getEfficiencyDataByApi(currentFactoryId)
      this.getFirst15DaysEfficiencyDataByApi(currentFactoryId)
      this.getBarChartDataByApi(currentFactoryId)
      this.getDoubleBarChartDataByApi(currentFactoryId)
    },
    /* 调用接口获取设备运行状态 */
    getRunningStateDataByApi(productionCode) {
      this.runningStateChart = this.$echarts.init(document.getElementById('running_state_chart'))
      this.runningStateChart.showLoading({
        text: '数据加载中 ...',
        color: '#0696e1', // 加载动画颜色
        textColor: '#fff',
        maskColor: 'transparent' // 遮罩层
      })
      signageApi.getEquipmentStatusStatisticsApi(productionCode)
        .then(res => {
          if (res.success) {
            this.runningStateData = res.result.list
            this.currentPageProductionId = res.result.productionId
            this.runningStateChartDataRequireFinished = true
            this.drawRunningStateChart(res.result.productionId)
          }
        })
    },
    /* 调用接口获取设备利用率 */
    getEfficiencyDataByApi(productionCode) {
      this.efficiencyChart = this.$echarts.init(document.getElementById('efficiency_chart'))
      this.efficiencyChart.showLoading({
        text: '数据加载中 ...',
        color: '#0696e1', // 加载动画颜色
        textColor: '#fff'
      })
      signageApi.getEquipmentUtilizationStatisticsApi(productionCode)
        .then(res => {
          if (res.success) {
            this.efficiencyData = res.result
            this.drawEfficiencyChart()
          }
        })
    },
    /* 调用接口获取前15天利用率 */
    getFirst15DaysEfficiencyDataByApi(productionCode) {
      this.first15DaysEfficiencyChart = this.$echarts.init(document.getElementById('first15DaysEfficiency_chart'))
      this.first15DaysEfficiencyChart.showLoading({
        text: '数据加载中 ...',
        color: '#0696e1', // 加载动画颜色
        textColor: '#000000',
        maskColor: 'transparent' // 遮罩层
      })
      signageApi.getEquipmentDayUtilizationStatisticsApi(productionCode)
        .then(res => {
          if (res.success) {
            this.first15DaysEfficiencyData = res.result
            this.drawFirst15DaysEfficiencyDataChart()
          }
        })
    },
    /* 绘制前7天利用率柱图 */
    drawFirst15DaysEfficiencyDataChart() {
      this.first15DaysEfficiencyData.dateList.forEach(item => {
        if (!this.first15DaysEfficiencyData.dataList.map(item => item.date).includes(item)) {
          const dateObj = {
            date: item.date,
            openRate: 0,
            startRate: 0,
            utilizationRate: 0
          }
          this.first15DaysEfficiencyData.dataList.push(dateObj)
          return
        }
      })
      const dateList = this.first15DaysEfficiencyData.dataList.map(item => item.date)
      const newData = {
        xAxis: dateList,
        yAxis: [
          {
            name: '利用率',
            value: this.first15DaysEfficiencyData.dataList.map(item => item.utilizationRate)
          },
          {
            name: '开动率',
            value: this.first15DaysEfficiencyData.dataList.map(item => item.startRate)
          },
          {
            name: '开机率',
            value: this.first15DaysEfficiencyData.dataList.map(item => item.openRate)
        // 2. 常规切换页签逻辑(原有逻辑保留)
        this.activeTab = index
        this.getChartDataByApi()
      },
      /* 调用接口获取图表数据汇总方法 */
      getChartDataByApi() {
        this.destroyChartsInstances()
        let currentFactoryId = ''
        if (this.activeTab !== -1) currentFactoryId = this.tabList[this.activeTab].factoryId
        this.getRunningStateDataByApi(currentFactoryId)
        this.getEfficiencyDataByApi(currentFactoryId)
        this.getFirst15DaysEfficiencyDataByApi(currentFactoryId)
        this.getBarChartDataByApi(currentFactoryId)
        this.getDoubleBarChartDataByApi(currentFactoryId)
      },
      destroyChartsInstances() {
        const charts = [
          this.runningStateChart,
          this.efficiencyChart,
          this.first15DaysEfficiencyChart,
          this.barChart,
          this.doubleBarChart
        ]
        charts.forEach(chart => {
          if (chart && chart.dispose) chart.dispose()
        })
      },
      /* 调用接口获取设备运行状态 */
      getRunningStateDataByApi(productionCode) {
        this.runningStateChart = this.$echarts.init(document.getElementById('running_state_chart'))
        this.runningStateChart.showLoading({
          text: '数据加载中 ...',
          color: '#0696e1', // 加载动画颜色
          textColor: '#000'
        })
        signageApi.getEquipmentStatusStatisticsApi(productionCode)
          .then(res => {
            if (res.success) {
              this.runningStateData = res.result.list
              this.drawRunningStateChart(res.result.productionId)
            }
          })
      },
      /* 调用接口获取设备利用率 */
      getEfficiencyDataByApi(productionCode) {
        this.efficiencyChart = this.$echarts.init(document.getElementById('efficiency_chart'))
        this.efficiencyChart.showLoading({
          text: '数据加载中 ...',
          color: '#0696e1', // 加载动画颜色
          textColor: '#000'
        })
        signageApi.getEquipmentUtilizationStatisticsApi(productionCode)
          .then(res => {
            if (res.success) {
              this.efficiencyData = res.result
              this.drawEfficiencyChart()
            }
          })
      },
      /* 调用接口获取前15天利用率 */
      getFirst15DaysEfficiencyDataByApi(productionCode) {
        this.first15DaysEfficiencyChart = this.$echarts.init(document.getElementById('first15DaysEfficiency_chart'))
        this.first15DaysEfficiencyChart.showLoading({
          text: '数据加载中 ...',
          color: '#0696e1', // 加载动画颜色
          textColor: '#000000'
        })
        signageApi.getEquipmentDayUtilizationStatisticsApi(productionCode)
          .then(res => {
            if (res.success) {
              this.first15DaysEfficiencyData = res.result
              this.drawFirst15DaysEfficiencyDataChart()
            }
          })
      },
      /* 绘制前15天利用率柱图 */
      drawFirst15DaysEfficiencyDataChart() {
        this.first15DaysEfficiencyData.dateList.forEach(item => {
          if (!this.first15DaysEfficiencyData.dataList.map(item => item.date).includes(item)) {
            const dateObj = {
              date: item.date,
              openRate: 0,
              startRate: 0,
              utilizationRate: 0
            }
            this.first15DaysEfficiencyData.dataList.push(dateObj)
          }
        ],
        yAxisName: '前15天利用率(%)'
      }
      let legendData = []
      let seriesData = []
      let colorArr = ['#A7F0C1', '#FAE893', '#66DFE2']
      legendData = newData.yAxis.map((item) => item.name)
      seriesData = newData.yAxis.map((item1, index1) => {
        return {
          name: item1.name,
          type: 'bar',
          symbol: 'circle',
          symbolSize: 8,
          itemStyle: {
            color: colorArr[index1],
            barBorderRadius: 100
          },
          lineStyle: {
            width: 2
          },
          markPoint: {
            show: true
          },
          yAxisIndex: 1,
          data: item1.value // 折线图的数据
        })
        const dateList = this.first15DaysEfficiencyData.dataList.map(item => item.date)
        const newData = {
          xAxis: dateList,
          yAxis: [
            {
              name: '利用率',
              value: this.first15DaysEfficiencyData.dataList.map(item => item.utilizationRate)
            },
            {
              name: '开动率',
              value: this.first15DaysEfficiencyData.dataList.map(item => item.startRate)
            },
            {
              name: '开机率',
              value: this.first15DaysEfficiencyData.dataList.map(item => item.openRate)
            }
          ]
        }
      })
      const option = {
        grid: {
          containLabel: true,
          bottom: '1%',
          top: '20%',
          left: '2%',
          right: '1%'
        },
        tooltip: {
          trigger: 'axis',
          axisPointer: {
            type: 'shadow'
          },
          formatter: function(params) {
            let result = ''
            params.forEach((item, index) => {
              let dom = `<span style="display:inline-block;width:10px;height:10px;border-radius:100px;margin-right:5px;background:${item.color}"></span>${item.seriesName}:${item.value}%`
              if (index === 0) {
                result = `<span style="font-weight:bolder;">${item.name}</span>`
              }
              result += '<br />' + dom
            })
            return result
          }
        },
        legend: {
          top: 20,
          right: 'center',
          data: legendData,
          itemGap: 10,
          textStyle: {
            fontSize: 14,
            color: '#000000'
          }
        },
        xAxis: {
          data: newData.xAxis || [],
          axisLabel: {
            interval: 0,
            show: true,
            fontSize: 14,
            color: '#000000'
            // rotate: -30,
          },
          axisLine: {
            show: true,
        let legendData = []
        let seriesData = []
        let colorArr = ['#A7F0C1', '#FAE893', '#66DFE2']
        legendData = newData.yAxis.map((item) => item.name)
        seriesData = newData.yAxis.map((item1, index1) => {
          return {
            name: item1.name,
            type: 'bar',
            symbol: 'circle',
            symbolSize: 8,
            itemStyle: {
              color: colorArr[index1],
              borderRadius: 100
            },
            lineStyle: {
              width: 2
            },
            markPoint: {
              show: true
            },
            yAxisIndex: 1,
            data: item1.value // 折线图的数据
          }
        })
        const option = {
          grid: {
            containLabel: true,
            bottom: '1%',
            top: '10%',
            left: '1%',
            right: '1%'
          },
          tooltip: {
            trigger: 'axis',
            axisPointer: {
              type: 'shadow'
            },
            formatter: function(params) {
              let result = ''
              params.forEach((item, index) => {
                let dom = `<span style="display:inline-block;width:10px;height:10px;border-radius:100px;margin-right:5px;background:${item.color}"></span>${item.seriesName}:${item.value}%`
                if (index === 0) {
                  result = `<span style="font-weight:bolder;">${item.name}</span>`
                }
                result += '<br />' + dom
              })
              return result
            }
          },
          legend: {
            right: 'center',
            data: legendData,
            itemGap: 10,
            textStyle: {
              fontSize: 14,
              color: '#000000'
            }
          },
          axisTick: {
            show: true,
            alignWithLabel: true
          }
        },
        yAxis: [
          {
            name: newData.yAxisName,
            nameTextStyle: {
              color: '#1AD8DE',
              fontSize: 18,
              padding: [0, 0, 0, 110]
          xAxis: {
            data: newData.xAxis || [],
            axisLabel: {
              interval: 0,
              show: true,
              fontSize: 14,
              color: '#000000'
              // rotate: -30,
            },
            nameGap: 30,
            type: 'value',
            position: 'left',
            axisLine: {
              show: true,
              lineStyle: {
@@ -341,543 +295,425 @@
              }
            },
            axisTick: {
              show: false
            },
            splitLine: {
              show: false,
              lineStyle: {
                color: '#000000'
              }
              show: true,
              alignWithLabel: true
            }
          },
          {
          yAxis: [
            {
              name: newData.yAxisName,
              nameTextStyle: {
                color: '#1AD8DE',
                fontSize: 18,
                padding: [0, 0, 0, 110]
              },
              nameGap: 30,
              type: 'value',
              position: 'left',
              axisLine: {
                show: true,
                lineStyle: {
                  color: '#000000'
                }
              },
              axisTick: {
                show: false
              },
              splitLine: {
                show: false,
                lineStyle: {
                  color: '#000000'
                }
              }
            },
            {
              type: 'value',
              position: 'right',
              splitNumber: 5,
              max: 100,
              axisLabel: {
                show: true,
                color: '#000000',
                fontSize: 14
              },
              axisLine: {
                show: true,
                lineStyle: {
                  color: '#000000'
                }
              },
              axisTick: {
                show: true
              },
              splitLine: {
                show: false,
                lineStyle: {
                  color: '#000000'
                }
              }
            }
          ],
          series: seriesData,
          dataZoom: {
            show: false,
            startValue: 0, // 从头开始。
            endValue: 14 // 一次性展示几个
          }
        }
        this.first15DaysEfficiencyChart.setOption(option, true)
        this.first15DaysEfficiencyChart.hideLoading()
      },
      /* 调用接口获取设备OEE统计 */
      getBarChartDataByApi(productionCode) {
        this.barChart = this.$echarts.init(document.getElementById('bar_chart'))
        this.barChart.showLoading({
          text: '数据加载中 ...',
          color: '#0696e1', // 加载动画颜色
          textColor: '#000'
        })
        signageApi.getEquipmentOEEStatistics(productionCode)
          .then(res => {
            if (res.success && res.result) {
              this.barChartData = res.result
              this.drawBarChart()
            }
          })
      },
      /* 调用接口获取设备OEE和利用率对比 */
      getDoubleBarChartDataByApi(productionCode) {
        this.doubleBarChart = this.$echarts.init(document.getElementById('double_bar_chart'))
        this.doubleBarChart.showLoading({
          text: '数据加载中 ...',
          color: '#0696e1', // 加载动画颜色
          textColor: '#000000',
          maskColor: 'transparent' // 遮罩层
        })
        signageApi.getEquipmentMonthStatisticsApi(productionCode)
          .then(res => {
            if (res.success) {
              this.doubleBarChartData = res.result
              this.drawDoubleBarChart()
            }
          })
      },
      /* 绘制设备运行状态玫瑰饼图 */
      drawRunningStateChart() {
        const option = {
          tooltip: {
            trigger: 'item',
            formatter: function(params) {
              return '<span style="font-weight:bolder;">' + params.name + '</span><br/>' +
                '<span style="display:inline-block; width:10%; height:10%; border-radius:100px; margin-right:5px; background:' + params.color + '"></span>' + `${params.value}(${params.percent}%)`
            }
          },
          legend: {
            left: 'center',
            bottom: 0, // 底部距离
            orient: 'horizontal', // 水平排列
            itemWidth: 14,
            itemHeight: 14,
            icon: 'roundRect',
            itemGap: 15,
            textStyle: {
              color: '#000',
              fontSize: 14
            },
            data: ['关机', '报警', '待机', '运行']
          },
          series: [
            {
              type: 'pie',
              roseType: 'angle', // 玫瑰图
              radius: ['40%', '55%'],
              center: ['50%', '40%'],
              color: [
                '#8B8B8B',
                '#F56436',
                '#FFFF40',
                '#0FC61A'
              ],
              label: {
                position: 'outside',
                show: true,
                color: '#000',
                fontSize: 16,
                formatter: function(params) {
                  if (params.name !== '') {
                    return `${params.name}:${params.value}`
                  }
                }
              },
              labelLine: {
                show: true,
                length2: 10,
                length: 10,
                lineStyle: {
                  color: '#000'
                }
              },
              data: this.runningStateData
            }
          ]
        }
        this.runningStateChart.setOption(option, true)
        this.runningStateChart.hideLoading()
      },
      /* 绘制设备利用率胶囊图 */
      drawEfficiencyChart() {
        const data = this.efficiencyData || []
        const colorArray = ['#79CEAA', '#F589A2', '#6FBF9D', '#66DFE2', '#A7F0C1', '#FAE893', '#F7B7A0']
        const dataMax = data.length > 0 ? +data.sort((x, y) => +y.value - +x.value)[0].value : 0
        let yAxisMax = dataMax === 0 ? 1 : Math.ceil(dataMax / 5) * 5
        const yAxisInterval = yAxisMax / 5
        const option = {
          grid: {
            left: '1%',
            right: '1%',
            bottom: '1%',
            top: '1%',
            containLabel: true
          },
          tooltip: {
            trigger: 'axis',
            axisPointer: { type: 'none' },
            formatter: function(params) {
              console.log('params', params)
              return `<span style="font-weight:bolder;">${params[0].name}</span><br/>
                <span style="display:inline-block; width:10px; height:10px; border-radius:100px; margin-right:5px; background:${params[0].color}"></span>
                ${params[0].seriesName} : ${params[0].value}%`
            }
          },
          xAxis: {
            name: '',
            nameTextStyle: { color: '#000000' },
            axisLabel: {
              margin: 20,
              color: '#000000'
            },
            show: true,
            min: 0,
            max: dataMax,
            interval: yAxisInterval,
            type: 'value',
            position: 'right',
            splitNumber: 5,
            max: 100,
            axisTick: { show: false },
            splitLine: { show: false }
          },
          yAxis: [{
            type: 'category',
            inverse: true,
            triggerEvent: true,
            axisLabel: {
              show: true,
              color: '#000000',
              fontSize: 14
              fontSize: '14',
              fontWeight: 'bolder',
              formatter: function(value) {
                return `${data.find(item => item.productionCode === value).name}`
              }
            },
            splitLine: { show: false },
            axisTick: { show: false },
            axisLine: { show: false },
            data: data.map(item => item.productionCode)
          }, {
            type: 'category',
            inverse: true,
            axisTick: 'none',
            axisLine: 'none',
            show: true,
            axisLabel: {
              color: '#000000',
              fontSize: '14',
              formatter: '{value}%'
            },
            data: data
          }],
          series: {
            name: '利用率',
            type: 'bar',
            zlevel: 1,
            itemStyle: {
              borderRadius: 100,
              color: function(params) {
                return colorArray[params.dataIndex % colorArray.length]
              }
            },
            barWidth: 12,
            data: data
          }
        }
        this.efficiencyChart.setOption(option, true)
        this.efficiencyChart.hideLoading()
      },
      /* 绘制单柱图 */
      drawBarChart() {
        const defaultData = []
        const colorArray = ['#79CEAA', '#F589A2', '#6FBF9D', '#66DFE2', '#A7F0C1', '#FAE893', '#F7B7A0']
        const dataMax = this.barChartData.length > 0 ? +this.barChartData.sort((x, y) => +y.value - +x.value)[0].value : 0
        let yAxisMax
        if (dataMax === 0) yAxisMax = 1 // 若数据中最大值为0,则将背景默认值设置为1
        else yAxisMax = Math.ceil(dataMax / 5) * 5 // 设置柱图背景阴影默认值,思路为数据最大值最接近的能被5整除的数字
        const yAxisInterval = yAxisMax / 5 // 同时将刻度值分成5份
        this.barChartData.forEach(item => defaultData.push(yAxisMax))
        const option = {
          grid: {
            left: '1%',
            right: '1%',
            bottom: '3%',
            top: '5%',
            containLabel: true
          },
          tooltip: {
            trigger: 'axis',
            axisPointer: {
              type: 'shadow'
            },
            formatter: function(params) {
              return '<span style="font-weight:bolder;">' + params[0].name + '</span><br/>' +
                '<span style="display:inline-block; width:10px; height:10px; border-radius:100px; margin-right:5px; background:' + params[0].color + '"></span>' + ' OEE: ' + params[0].value + '%'
            },
            // backgroundColor: 'rgba(9, 24, 48, 0.5)',
            borderColor: 'rgba(75, 253, 238, 0.4)',
            borderWidth: 1
          },
          xAxis: {
            name: '',
            nameLocation: 'middle',
            nameGap: 40, // x轴name与横坐标轴线的间距
            type: 'category',
            data: this.barChartData.map(item => item.productionId),
            axisLine: {
              show: true,
              lineStyle: {
                color: '#000000'
              }
            },
            axisLabel: {
              show: true, // 是否显示刻度标签,默认显示
              interval: 0, // 坐标轴刻度标签的显示间隔,在类目轴中有效;默认会采用标签不重叠的策略间隔显示标签;可以设置成0强制显示所有标签;如果设置为1,表示『隔一个标签显示一个标签』,如果值为2,表示隔两个标签显示一个标签,以此类推。
              rotate: this.barChartData.length >= 6 ? -30 : 0, // 刻度标签旋转的角度,在类目轴的类目标签显示不下的时候可以通过旋转防止标签之间重叠;旋转的角度从-90度到90度
              inside: false, // 刻度标签是否朝内,默认朝外
              margin: 10, // 刻度标签与轴线之间的距离
              formatter: value => {
                return `${this.barChartData.find(item => item.productionId === value).name}`
              },
              fontSize: 14
            },
            axisTick: {
              show: true,
              alignWithLabel: true
            }
          },
          yAxis: {
            name: '%',
            min: 0,
            max: yAxisMax,
            interval: yAxisInterval,
            axisLabel: {
              formatter: '{value}',
              color: '#000000',
              fontSize: 14
            },
            axisTick: {
              show: true
            },
            axisLine: {
              show: true
            },
            splitLine: {
              show: false
            }
          },
          series: {
            type: 'bar',
            data: this.barChartData,
            barWidth: this.barChartData.length > 5 ? '40%' : 30,
            itemStyle: {
              color: function(params) {
                let num = colorArray.length
                return colorArray[params.dataIndex % num]
              },
              borderRadius: 100
            },
            zlevel: 1,
            label: {
              show: false,
              lineStyle: {
                color: '#000000'
              }
            }
          }
        ],
        series: seriesData,
        dataZoom: {
          show: false,
          startValue: 0, // 从头开始。
          endValue: 14 // 一次性展示几个
        }
        // toolbox: {
        //   show: true,
        //   feature: {
        //     mark: { show: true },
        //     magicType: { show: true, type: ['line', 'bar'] },
        //     restore: { show: true },
        //     saveAsImage: { show: true, name: '前7天利用率统计图', pixelRatio: 1 }
        //   }
        // }
      }
      this.first15DaysEfficiencyChart.setOption(option, true)
      this.first15DaysEfficiencyChart.hideLoading()
      this.first15DaysEfficiencyChart.on('click', params => {
        this.$router.push({
          name: 'mdc-base-StatisticsChart',
          params: {
            isEquipment: true,
            productionId: params.name,
            tierName: this.first15DaysEfficiencyData.dataList.find(item => item.date === params.name).date
          }
        })
      })
    },
    /* 调用接口获取设备OEE统计 */
    getBarChartDataByApi(productionCode) {
      this.barChart = this.$echarts.init(document.getElementById('bar_chart'))
      this.barChart.showLoading({
        text: '数据加载中 ...',
        color: '#0696e1', // 加载动画颜色
        textColor: '#fff'
      })
      signageApi.getEquipmentOEEStatistics(productionCode)
        .then(res => {
          if (res.success && res.result) {
            this.barChartData = res.result
            this.drawBarChart()
          }
        })
        .finally(() => {
          this.barChart.hideLoading()
        })
    },
    /* 绘制单柱图 */
    drawBarChart() {
      const defaultData = []
      const colorArray = ['#79CEAA', '#F589A2', '#6FBF9D', '#66DFE2', '#A7F0C1', '#FAE893', '#F7B7A0']
      const dataMax = this.barChartData.length > 0 ? +this.barChartData.sort((x, y) => +y.value - +x.value)[0].value : 0
      let yAxisMax
      if (dataMax === 0) yAxisMax = 1 // 若数据中最大值为0,则将背景默认值设置为1
      else yAxisMax = Math.ceil(dataMax / 5) * 5 // 设置柱图背景阴影默认值,思路为数据最大值最接近的能被5整除的数字
      const yAxisInterval = yAxisMax / 5 // 同时将刻度值分成5份
      this.barChartData.forEach(item => defaultData.push(yAxisMax))
      const option = {
        title: {
          show: true, // 是否显示标题,默认为true
          text: '', // 主标题文本
          x: 'left', // 标题水平安放位置,可选值为'left'、'center'、'right'或具体的水平坐标值
          y: 'top', // 标题垂直安放位置,可选值为'top'、'bottom'、'center'或具体的垂直坐标值
          textStyle: {
            // 主标题文本样式
            fontSize: 18,
            fontWeight: 'normal',
            color: '#1AD8DE'
          }
        },
        tooltip: {
          trigger: 'axis',
          axisPointer: {
            type: 'shadow'
          },
          formatter: function(params) {
            return '<span style="font-weight:bolder;">' + params[0].name + '</span><br/>' +
              '<span style="display:inline-block; width:10px; height:10px; border-radius:100px; margin-right:5px; background:' + params[0].color + '"></span>' + ' OEE: ' + params[0].value + '%'
          },
          // backgroundColor: 'rgba(9, 24, 48, 0.5)',
          borderColor: 'rgba(75, 253, 238, 0.4)',
          textStyle: {
            // color: '#CFE3FC'
          },
          borderWidth: 1
        },
        grid: {
          top: '20%',
          left: '10%'
        },
        xAxis: [{
          name: '',
          nameLocation: 'middle',
          nameGap: 40, // x轴name与横坐标轴线的间距
          type: 'category',
          data: this.barChartData.map(item => item.productionId),
          axisLine: {
            lineStyle: {
              color: '#000000'
            }
          },
          axisLabel: {
            show: true, // 是否显示刻度标签,默认显示
            interval: 0, // 坐标轴刻度标签的显示间隔,在类目轴中有效;默认会采用标签不重叠的策略间隔显示标签;可以设置成0强制显示所有标签;如果设置为1,表示『隔一个标签显示一个标签』,如果值为2,表示隔两个标签显示一个标签,以此类推。
            rotate: this.barChartData.length >= 6 ? -30 : 0, // 刻度标签旋转的角度,在类目轴的类目标签显示不下的时候可以通过旋转防止标签之间重叠;旋转的角度从-90度到90度
            inside: false, // 刻度标签是否朝内,默认朝外
            margin: 10, // 刻度标签与轴线之间的距离
            formatter: value => {
              return `${this.barChartData.find(item => item.productionId === value).name}`
            },
            fontSize: 14
          },
          axisTick: {
            show: true,
            alignWithLabel: true
          }
        }],
        yAxis: [{
          name: '%',
          min: 0,
          max: yAxisMax,
          interval: yAxisInterval,
          axisLabel: {
            formatter: '{value}',
            color: '#000000',
            fontSize: 14
          },
          axisTick: {
            show: false
          },
          axisLine: {
            show: false,
            lineStyle: {
              color: '#000000'
            }
          },
          splitLine: {
            show: false,
            lineStyle: {
              color: 'rgba(255,255,255,0.12)'
            }
          }
        }],
        series: [{
          type: 'bar',
          data: this.barChartData,
          barWidth: this.barChartData.length > 5 ? '40%' : 30,
          itemStyle: {
            color: function(params) {
              let num = colorArray.length
              return colorArray[params.dataIndex % num]
            },
            barBorderRadius: 100
          },
          zlevel: 1,
          label: {
            show: false,
            lineHeight: 10,
            formatter: params => {
              if (+params.value === 0) return ''
              else return params.value
            },
            position: 'top',
            textStyle: {
              lineHeight: 10,
              formatter: params => {
                if (+params.value === 0) return ''
                else return params.value
              },
              position: 'top',
              color: '#000000',
              fontSize: 16
            }
          }
        }]
      }
      option.title.text = moment().subtract(1, 'month').format('M月') + `OEE`
      this.barChart.setOption(option, true)
    },
    /* 绘制设备运行状态玫瑰饼图 */
    drawRunningStateChart() {
      const option = {
        height: 300,
        title: {
          show: true, // 是否显示标题,默认为true
          text: '设备状态', // 主标题文本
          x: 'left', // 标题水平安放位置,可选值为'left'、'center'、'right'或具体的水平坐标值
          y: 'top', // 标题垂直安放位置,可选值为'top'、'bottom'、'center'或具体的垂直坐标值
          textStyle: {
            // 主标题文本样式
            fontSize: 18,
            fontWeight: 'normal',
            color: '#1AD8DE'
          }
        },
        tooltip: {
          trigger: 'item',
          formatter: function(params) {
            return '<span style="font-weight:bolder;">' + params.name + '</span><br/>' +
              '<span style="display:inline-block; width:10%; height:10%; border-radius:100px; margin-right:5px; background:' + params.color + '"></span>' + `${params.value}(${params.percent}%)`
          }
        },
        legend: {
          top: 'auto',
          left: 'center',
          bottom: '10%', // 底部距离
          orient: 'horizontal', // 水平排列
          right: '10%',
          // bottom: "0",
          itemWidth: 14,
          itemHeight: 14,
          icon: 'roundRect',
          itemGap: 15,
          textStyle: {
            color: '#000',
            fontSize: 14,
            padding: [0, 0, 0, 0]
          },
          data: ['关机', '报警', '待机', '运行']
        },
        grid: {
          containLabel: true
        },
        series: [
          {
            type: 'pie',
            roseType: 'angle', // 玫瑰图
            // selectedMode: "single",
            radius: this.pieChartRadius,
            center: ['45%', '55%'],
            color: [
              '#8B8B8B',
              '#F56436',
              '#FFFF40',
              '#0FC61A'
            ],
            label: {
              position: 'outside',
              show: true,
              color: '#000',
              // textBorderColor: 'inherit',
              // textBorderWidth: 1,
              fontSize: 16,
              formatter: function(params) {
                if (params.name !== '') {
                  return `${params.name}:${params.value}`
                }
              }
            },
            labelLine: {
              show: true,
              length2: 10,
              length: 10
            },
            data: this.runningStateData
          }
        ]
      }
      this.runningStateChart.setOption(option, true)
      this.runningStateChart.hideLoading()
    },
    /* 绘制设备利用率胶囊图 */
    drawEfficiencyChart() {
      const data = this.efficiencyData || []
      // 无论数据是否为空,先取消loading状态
      this.efficiencyChart.hideLoading()
      // 标题文本统一处理
      const titleText = `${moment().subtract(1, 'days').format('M月D日')}各车间利用率排行`
      if (data.length === 0) {
        // 数据为空时只展示标题
        const option = {
          title: {
            show: true,
            text: titleText,
            x: 'left',
            y: 'top',
            textStyle: {
              fontSize: 18,
              fontWeight: 'normal',
              color: '#1AD8DE'
            }
          },
          // 隐藏所有轴和网格
          xAxis: { show: false },
          yAxis: [{ show: false }, { show: false }],
          grid: { show: false },
          series: []
        }
        this.efficiencyChart.setOption(option, true)
        return
      }
        this.barChart.setOption(option, true)
        this.barChart.hideLoading()
      },
      // 数据不为空时的正常处理逻辑(保持不变)
      const colorArray = [
        { top: '#79CEAA', bottom: '#79CEAA' },
        { top: '#F589A2', bottom: '#F589A2' },
        { top: '#6FBF9D', bottom: '#6FBF9D' },
        { top: '#66DFE2', bottom: '#66DFE2' },
        { top: '#A7F0C1', bottom: '#A7F0C1' },
        { top: '#FAE893', bottom: '#FAE893' },
        { top: '#F7B7A0', bottom: '#F7B7A0' }
      ]
      const dataMax = +data.sort((x, y) => +y.value - +x.value)[0].value
      let yAxisMax = dataMax === 0 ? 1 : Math.ceil(dataMax / 5) * 5
      const yAxisInterval = yAxisMax / 5
      const option = {
        title: {
          show: true,
          text: titleText,
          x: 'left',
          y: 'top',
          textStyle: {
            fontSize: 18,
            fontWeight: 'normal',
            color: '#1AD8DE'
          }
        },
        grid: {
          left: '3%',
          right: '5%',
          bottom: '0%',
          top: '6%',
          containLabel: true
        },
        tooltip: {
          trigger: 'axis',
          axisPointer: { type: 'none' },
          formatter: function(params) {
            return `<span style="font-weight:bolder;">${params[0].name}</span><br/>
                <span style="display:inline-block; width:10px; height:10px; border-radius:100px; margin-right:5px; background:${params[0].color.colorStops[params[0].dataIndex].color}"></span>
                ${params[0].seriesName} : ${params[0].value}%`
          }
        },
        xAxis: {
          name: '',
          nameTextStyle: { color: '#000000' },
          axisLabel: {
            margin: 20,
            textStyle: { color: '#000000' }
          },
          show: true,
          min: 0,
          max: 'dataMax',
          interval: yAxisInterval,
          type: 'value',
          axisTick: { show: false },
          splitLine: { show: false }
        },
        yAxis: [{
          type: 'category',
          inverse: true,
          triggerEvent: true,
          axisLabel: {
            show: true,
            textStyle: { color: '#000000', fontSize: '14', fontWeight: 'bolder' },
            formatter: function(value) {
              return `${data.find(item => item.productionCode === value).name}`
      /* 绘制双柱图 */
      drawDoubleBarChart() {
        const option = {
          color: ['#66DFE2', '#79CEAA'],
          tooltip: {
            trigger: 'axis',
            axisPointer: {
              type: 'shadow'
            },
            formatter: function(params) {
              let result = ''
              params.forEach((item, index) => {
                let dom = `<span style="display:inline-block;width:10px;height:10px;border-radius:100px;margin-right:5px;background:${item.color}"></span>${item.seriesName}:${item.value}%`
                if (index === 0) {
                  result = `<span style="font-weight:bolder;">${item.name}</span>`
                }
                result += '<br />' + dom
              })
              return result
            }
          },
          splitLine: { show: false },
          axisTick: { show: false },
          axisLine: { show: false },
          data: data.map(item => item.productionCode)
        }, {
          type: 'category',
          inverse: true,
          axisTick: 'none',
          axisLine: 'none',
          show: true,
          axisLabel: {
            textStyle: { color: '#000000', fontSize: '14' },
            formatter: '{value}%'
          grid: {
            left: '1%',
            right: '1%',
            bottom: '5%',
            top: '10%',
            containLabel: true
          },
          data: data
        }],
        series: [{
          name: '利用率',
          type: 'bar',
          zlevel: 1,
          itemStyle: {
            barBorderRadius: 100,
            color: function(params) {
              const num = colorArray.length
              return {
                type: 'linear',
                colorStops: [{
                  offset: 0,
                  color: colorArray[params.dataIndex % num].bottom
                }, {
                  offset: 1,
                  color: colorArray[params.dataIndex % num].top
                }]
          legend: {
            icon: 'roundRect',
            left: 'center',
            itemWidth: 14,
            itemHeight: 14,
            textStyle: {
              fontSize: 14,
              color: '#000'
            },
            data: ['OEE', 'TEEP']
          },
          xAxis: {
            type: 'category',
            data: this.doubleBarChartData.dateList,
            axisLine: {
              lineStyle: {
                color: 'rgba(0,0,0)'
              }
            },
            axisLabel: {
              fontSize: 14,
              color: '#000000'
            },
            axisTick: {
              show: true
            }
          },
          barWidth: 12,
          data: data
        }]
      }
      this.efficiencyChart.setOption(option, true)
    },
    re_drawPieChart() {
      const clientWidth = document.body.clientWidth || document.documentElement.clientWidth
      if (this.firstEnterClientWidth != 1920) {
        this.pieChartRadius = this.normalPieChartRadius.map(item => item = (+item.slice(0, -1) * (clientWidth / 1920)) + '%')
      } else {
        this.pieChartRadius = this.normalPieChartRadius.map(item => item = (+item.slice(0, -1) * (clientWidth / this.firstEnterClientWidth)) + '%')
      }
      console.log('pieChartRadius', this.pieChartRadius)
    },
    /* 调用接口获取设备OEE和利用率对比 */
    getDoubleBarChartDataByApi(productionCode) {
      this.doubleBarChart = this.$echarts.init(document.getElementById('double_bar_chart'))
      this.doubleBarChart.showLoading({
        text: '数据加载中 ...',
        color: '#0696e1', // 加载动画颜色
        textColor: '#000000',
        maskColor: 'transparent' // 遮罩层
      })
      signageApi.getEquipmentMonthStatisticsApi(productionCode)
        .then(res => {
          if (res.success) {
            this.doubleBarChartData = res.result
            this.drawDoubleBarChart()
          }
        })
    },
    /* 绘制双柱图 */
    drawDoubleBarChart() {
      const option = {
        title: {
          text: '月利用率OEE统计',
          left: 'left',
          top: 'top',
          textStyle: {
            fontSize: 18,
            fontWeight: 'normal',
            color: '#1AD8DE'
          }
        },
        color: ['#66DFE2', '#79CEAA'],
        tooltip: {
          confine: true,
          formatter: function(params) {
            return '<span style="font-weight:bolder;">' + params.name + '</span><br/>' +
              '<span style="display:inline-block; width:10px; height:10px; border-radius:100px; margin-right:5px; background:' + params.color + '"></span>' + params.seriesName + ' : ' + params.value + '%'
          }
        },
        grid: {
          left: '5%',
          right: '4%',
          bottom: '10%',
          top: '20%',
          containLabel: true
        },
        legend: {
          icon: 'roundRect',
          orient: 'horizontal',
          left: 'center',
          itemWidth: 14,
          itemHeight: 14,
          formatter: ['{a|{name}}'].join('\n'),
          textStyle: {
            fontSize: 14,
            color: '#000000',
            height: 8,
            rich: {
              a: {
                verticalAlign: 'bottom'
              }
            }
          },
          data: ['OEE', 'TEEP']
        },
        xAxis: {
          type: 'category',
          data: this.doubleBarChartData.dateList,
          axisLine: {
            lineStyle: {
              color: 'rgba(0,0,0)'
            }
          },
          axisLabel: {
            fontSize: 14,
            color: '#000000'
          },
          axisTick: {
            show: true
          }
        },
        yAxis: [
          {
          yAxis: {
            name: '%',
            nameTextStyle: {
              color: '#000000'
@@ -904,241 +740,140 @@
              fontFamily: 'Bebas'
            }
          },
          {
            type: 'value',
            axisLine: {
              show: true
          series: [
            {
              type: 'bar',
              barWidth: 15,
              itemStyle: { borderRadius: 100 },
              name: 'OEE',
              data: this.doubleBarChartData.oeeList,
              label: {
                show: false
              }
            },
            axisTick: {
              show: false
            },
            splitLine: {
              show: false
            },
            axisLabel: {
              fontSize: 14,
              formatter: '{value}%', // 右侧Y轴文字显示
              fontFamily: 'Bebas',
              color: '#6A93B9'
            },
            splitArea: {
              show: false
            {
              type: 'bar',
              barWidth: 15,
              itemStyle: { borderRadius: 100 },
              name: 'TEEP',
              data: this.doubleBarChartData.utilizationList,
              label: {
                show: false
              }
            }
          }],
        series: [{
          type: 'bar',
          barWidth: 15,
          itemStyle: { barBorderRadius: 100 },
          name: 'OEE',
          data: this.doubleBarChartData.oeeList,
          label: {
            show: false,
            lineHeight: 10,
            formatter: params => {
              if (+params.value === 0) return ''
              else return params.value
            },
            position: 'inside',
            textStyle: {
              color: '#000000',
              fontSize: 12
            }
          ]
        }
        this.doubleBarChart.setOption(option, true)
        this.doubleBarChart.hideLoading()
      },
      /**
       * 窗口尺寸变化时触发
       * 调整图表尺寸以适应分辨率
       */
      handleWindowResize() {
        if (this.runningStateChart) this.runningStateChart.resize()
        if (this.efficiencyChart) this.efficiencyChart.resize()
        if (this.first15DaysEfficiencyChart) this.first15DaysEfficiencyChart.resize()
        if (this.barChart) this.barChart.resize()
        if (this.doubleBarChart) this.doubleBarChart.resize()
      }
    }
  }
</script>
<style scoped lang="less">
  @container-margin: 10px;
  /* 主容器样式 */
  .home-container {
    display: flex;
    flex-direction: column;
    height: 100vh;
    gap: @container-margin;
    /* 车间导航列表 */
    .tab-nav {
      height: 60px;
      border-radius: 20px;
      /deep/ .ant-card-body {
        height: 100%;
        padding: 0 12px;
        display: flex;
        align-items: center;
      }
      .tab-item {
        padding: 8px 16px;
        font-size: 14px;
        color: #666666;
        border-radius: 20px;
        cursor: pointer;
        white-space: nowrap;
        transition: all 0.3s ease;
        margin-right: @container-margin;
        &:hover {
          background-color: #f0f5ff;
          color: #0696e1;
        }
      }
      .tab-item-active {
        background-color: #0696e1;
        color: #fff;
        font-weight: 500;
      }
    }
    /* 图表容器样式 */
    .chart-container {
      display: flex;
      gap: @container-margin;
      height: calc(100% - 60px - @container-margin);
      /deep/ .ant-card {
        display: flex;
        flex-direction: column;
        .ant-card-body {
          flex: 1;
        }
      }
      .left-container {
        width: 30%;
        /deep/ .ant-card {
          &:first-child {
            height: calc(45% - @container-margin / 2);
            margin-bottom: @container-margin;
          }
        }, {
          type: 'bar',
          barWidth: 15,
          itemStyle: { barBorderRadius: 100 },
          name: 'TEEP',
          data: this.doubleBarChartData.utilizationList,
          label: {
            show: false,
            lineHeight: 10,
            formatter: params => {
              if (+params.value === 0) return ''
              else return params.value
            },
            position: 'inside',
            textStyle: {
              color: '#000000',
              fontSize: 12
          &:last-child {
            height: calc(55% - @container-margin / 2);
          }
        }
      }
      .right-container {
        width: 70%;
        .right-top-container {
          margin-bottom: @container-margin;
          height: calc(50% - @container-margin / 2);
        }
        .right-bottom-container {
          height: calc(50% - @container-margin / 2);
          display: flex;
          > div {
            width: 50%;
            &:first-child {
              margin-right: @container-margin;
            }
          }
        }
        ]
      }
      this.doubleBarChart.setOption(option, true)
      this.doubleBarChart.hideLoading()
    },
    /**
     * 窗口尺寸变化时触发
     * 调整图表尺寸以适应分辨率
     */
    handleWindowResize() {
      // this.re_drawPieChart()
      if (this.runningStateChart) this.runningStateChart.resize()
      if (this.efficiencyChart) this.efficiencyChart.resize()
      if (this.first15DaysEfficiencyChart) this.first15DaysEfficiencyChart.resize()
      if (this.barChart) this.barChart.resize()
      if (this.doubleBarChart) this.doubleBarChart.resize()
    }
  }
}
</script>
<style scoped>
/* 页签导航样式 */
.tab-nav {
  display: flex;
  gap: 8px;
  padding: 10px 16px;
  background-color: #ffffff;
  border-radius: 8px;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
  overflow-x: auto;
  scrollbar-width: none;
}
.tab-nav::-webkit-scrollbar {
  display: none;
}
.tab-item {
  padding: 8px 16px;
  font-size: 14px;
  color: #666666;
  border-radius: 20px;
  cursor: pointer;
  white-space: nowrap;
  transition: all 0.3s ease;
}
.tab-active {
  background-color: #0696e1;
  color: #ffffff;
  font-weight: 500;
}
.tab-item:hover {
  background-color: #f0f5ff;
  color: #0696e1;
}
/* 主容器样式 */
.home-container {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  padding: 1px;
  box-sizing: border-box;
  gap: 16px;
  background-color: #f0f2f7;
}
/* 图表容器样式 */
.chart-container {
  display: flex;
  gap: 16px;
  flex: 1;
  min-width: 0;
}
/* 左侧卡片区域 */
.left-cards {
  flex: 1;
  min-width: 0;
}
/* 右侧卡片区域 */
.right-cards {
  flex: 2;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 16px;
}
/* 通用卡片样式 */
.card {
  background: #ffffff;
  border-radius: 8px;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
  padding: 16px;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  justify-content: flex-start;
}
/* 左侧卡片 */
.left-cards-card {
  height: 100%;
  min-height: 100vh;
}
/* 右侧顶部卡片 */
.right-top-card {
  flex: 1;
  min-height: 50vh;
}
/* 右侧底部容器 */
.right-bottom-card {
  flex: 1;
  min-width: 0;
  min-height: 50vh;
  display: flex;
  gap: 16px;
}
/* 右侧底部左右卡片 */
.right-bottom-left-card,
.right-bottom-right-card {
  flex: 1;
}
/* 响应式调整 */
@media (max-width: 1200px) {
  .chart-container {
    gap: 12px;
  }
  .card {
    padding: 12px;
  }
}
@media (max-width: 992px) {
  .chart-container {
    flex-direction: column;
  }
  .left-cards, .right-cards {
    width: 100%;
  }
  .left-cards {
    margin-bottom: 16px;
  }
  .right-bottom-card {
    flex-direction: column;
  }
  .tab-item {
    padding: 6px 12px;
    font-size: 13px;
  }
}
@media (max-width: 768px) {
  .home-container {
    padding: 8px;
  }
  .tab-nav {
    padding: 8px;
    margin-bottom: 8px;
  }
}
</style>