收藏
回答

小程序使用“lime-echart echarts图表”插件显示国内省份地图不显示?

在【微信开发者工具】的真机调试没有问题,但是上线后就无法显示了,图片如图:图1是上线后的,图2是真机模拟的。

<template>
	<view style="height: 600rpx">
		<view class="chart-container" :style="{height: '600rpx'}">
			<l-echart 
				v-if="isAppReady && isEchartsReady && !chartInitError" 
				ref="chart" 
				:canvas-id="canvasId"
			></l-echart>
		</view>
	</view>
	
	
	
  <view class="container">
    <view class="main-content">
      <!-- 数据统计 -->
      <view class="stats-section">
        <view class="section-header">
          <view class="section-title">
            <text>全国省份数据分析</text>
          </view>
          <view class="time-filter">
            <view class="filter-tabs">
              <view 
                class="filter-tab" 
                :class="{ active: timeRange === 'day' }"
                @click="changeTimeRange('day')"
              >
                今日
              </view>
              <view 
                class="filter-tab" 
                :class="{ active: timeRange === 'week' }"
                @click="changeTimeRange('week')"
              >
                本周
              </view>
              <view 
                class="filter-tab" 
                :class="{ active: timeRange === 'month' }"
                @click="changeTimeRange('month')"
              >
                本月
              </view>
            </view>
          </view>
        </view>
        
        <!-- 机器总数 -->
        <view class="total-machine-count">
          <text class="total-label">总数据量</text>
          <text class="total-value">{{ animatedTotalMachines }}</text>
        </view>
        
		<!-- 省份类型切换按钮 -->
		<view class="machine-type-filter">
		  <view 
		    class="type-tab" 
		    :class="{ active: selectedType === 'all' }"
		    @click="changeMachineType('all')"
		  >
		    全部
		  </view>
		  <view 
		    class="type-tab" 
		    :class="{ active: selectedType === 'province' }"
		    @click="changeMachineType('province')"
		  >
		    省份
		  </view>
		  <view 
		    class="type-tab" 
		    :class="{ active: selectedType === 'city' }"
		    @click="changeMachineType('city')"
		  >
		    直辖市
		  </view>
		  <view 
		    class="type-tab" 
		    :class="{ active: selectedType === 'special' }"
		    @click="changeMachineType('special')"
		  >
		    特别行政区
		  </view>
		</view>
		
        <!-- 横向条形图展示 -->
        <view class="chart-container">
          <view class="horizontal-chart">
            <view class="horizontal-bars">
              <view 
                class="horizontal-bar-item" 
                v-for="(item, index) in animatedChartData" 
                :key="index"
              >
                <view class="bar-label-horizontal">{{ item.shortLabel }}</view>
                <view class="bar-container-horizontal">
                  <view 
                    class="bar-fill-horizontal" 
                    :style="{ 
                      width: `${item.animatedPercentage}%`, 
                      backgroundColor: item.animatedColor,
                      minWidth: '10rpx',
                      borderRadius: '0 6rpx 6rpx 0',
                      transformOrigin: 'left',
                      boxShadow: '2rpx 0 8rpx rgba(0,0,0,0.1)'
                    }"
                  ></view>
                  <view class="bar-value-horizontal">{{ item.animatedValue }}</view>
                </view>
              </view>
            </view>
          </view>
        </view>
    
      </view>
    </view>


    <!-- 底部安全区域 -->
    <view class="safe-area-bottom"></view>
  </view>
</template>


<script>
// import MAP1 from '/pages/DataDisplay/DataDisplay.vue'
let echartsCache = null;


export default {
	// components: {
	//   // MAP1
	// },
  data() {
    return {
	  // 初始化状态
	  isAppReady: false,
	  isEchartsReady: false,
	  isLoading: true,
	  chartInitError: false,
	  errorMessage: '',
	  
	  // 图表相关
	  canvasId: 'chart_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9),
	  chartInstance: null,
	  
	  // 重试机制
	  retryCount: 0,
	  maxRetries: 3,
	  retryTimer: null,
		
		
		
      timeRange: 'day',
      chartData: [],
      animatedChartData: [],
      totalMachines: 0,
      animatedTotalMachines: 0,
      selectedType: 'all',
      animationDuration: 500, // 增加动画时长以获得更平滑的CSS过渡效果
      isAnimating: false,
      
      // 优化的颜色配置 - 使用柔和的渐变色系
      colorPalettes: {
        'province': ['#4E79A7', '#A0CBE8'], // 蓝色系
        'city': ['#59A14F', '#8CD17D'], // 绿色系
        'special': ['#B07AA1', '#D4A6C8'], // 紫色系
        'default': ['#499894', '#86BCB6'] // 默认青色系
      },
      
      provinces: [
        { name: '北京市', type: 'city', shortName: '北京' },
        { name: '天津市', type: 'city', shortName: '天津' },
        { name: '上海市', type: 'city', shortName: '上海' },
        { name: '重庆市', type: 'city', shortName: '重庆' },
        { name: '河北省', type: 'province', shortName: '河北' },
        { name: '山西省', type: 'province', shortName: '山西' },
        { name: '辽宁省', type: 'province', shortName: '辽宁' },
        { name: '吉林省', type: 'province', shortName: '吉林' },
        { name: '黑龙江省', type: 'province', shortName: '黑龙江' },
        { name: '江苏省', type: 'province', shortName: '江苏' },
        { name: '浙江省', type: 'province', shortName: '浙江' },
        { name: '安徽省', type: 'province', shortName: '安徽' },
        { name: '福建省', type: 'province', shortName: '福建' },
        { name: '江西省', type: 'province', shortName: '江西' },
        { name: '山东省', type: 'province', shortName: '山东' },
        { name: '河南省', type: 'province', shortName: '河南' },
        { name: '湖北省', type: 'province', shortName: '湖北' },
        { name: '湖南省', type: 'province', shortName: '湖南' },
        { name: '广东省', type: 'province', shortName: '广东' },
        { name: '海南省', type: 'province', shortName: '海南' },
        { name: '四川省', type: 'province', shortName: '四川' },
        { name: '贵州省', type: 'province', shortName: '贵州' },
        { name: '云南省', type: 'province', shortName: '云南' },
        { name: '陕西省', type: 'province', shortName: '陕西' },
        { name: '甘肃省', type: 'province', shortName: '甘肃' },
        { name: '青海省', type: 'province', shortName: '青海' },
        { name: '台湾省', type: 'province', shortName: '台湾' },
        { name: '内蒙古自治区', type: 'province', shortName: '内蒙古' },
        { name: '广西壮族自治区', type: 'province', shortName: '广西' },
        { name: '西藏自治区', type: 'province', shortName: '西藏' },
        { name: '宁夏回族自治区', type: 'province', shortName: '宁夏' },
        { name: '新疆维吾尔自治区', type: 'province', shortName: '新疆' },
        { name: '香港特别行政区', type: 'special', shortName: '香港' },
        { name: '澳门特别行政区', type: 'special', shortName: '澳门' }
      ]
    };
  },
  
  onLoad() { 
	  console.log('页面开始加载,检查App状态...');
	  this.checkAppStatus();
    setTimeout(() => {
      this.updateChartData();
    }, 500);
  },
  
  
  // 使用onLoad而不是onReady,更早的生命周期
  // onLoad() {
  // 	console.log('页面开始加载,检查App状态...');
  // 	this.checkAppStatus();
  // },
  
  // 确保清理定时器
  onUnload() {
  	if (this.retryTimer) {
  		clearTimeout(this.retryTimer);
  		this.retryTimer = null;
  	}
  	if (this.chartInstance) {
  		try {
  			this.chartInstance.dispose();
  		} catch (e) {
  			console.warn('清理图表实例失败:', e);
  		}
  		this.chartInstance = null;
  	}
  },
  
  methods: {
	// 安全地检查App状态
	checkAppStatus() {
		try {
			const app = getApp();
			console.log('getApp()返回:', app);
			
			if (app && app.$vm) {
				console.log('App实例已准备好,$vm存在');
				this.isAppReady = true;
				this.loadEcharts();
			} else {
				console.log('App实例未完全准备好,等待...');
				
				// 使用指数退避策略重试
				const delay = Math.min(1000, 100 * Math.pow(2, this.retryCount));
				
				this.retryTimer = setTimeout(() => {
					this.retryCount++;
					if (this.retryCount <= this.maxRetries) {
						console.log(`第${this.retryCount}次重试检查App状态...`);
						this.checkAppStatus();
					} else {
						this.showError('应用初始化超时,请稍后重试');
					}
				}, delay);
			}
		} catch (error) {
			console.error('检查App状态时出错:', error);
			this.showError('应用状态检查失败: ' + error.message);
		}
	},
	
	// 加载echarts库
	async loadEcharts() {
		try {
			console.log('开始加载ECharts...');
			
			// 尝试从缓存获取
			if (echartsCache) {
				console.log('从缓存获取ECharts');
				this.isEchartsReady = true;
				this.initChartWithEcharts(echartsCache);
				return;
			}
			
			// 动态导入echarts
			const echartsModule = await this.loadEchartsModule();
			if (echartsModule && echartsModule.default) {
				echartsCache = echartsModule.default;
				this.isEchartsReady = true;
				this.initChartWithEcharts(echartsCache);
			} else {
				throw new Error('ECharts模块加载失败');
			}
		} catch (error) {
			console.error('加载ECharts失败:', error);
			this.showError('图表库加载失败: ' + error.message);
		}
	},
	
	
	// 加载echarts模块(使用更可靠的加载方式)
	loadEchartsModule() {
		return new Promise((resolve, reject) => {
			// 尝试多种加载方式
			const loadAttempts = [
				// 方式1: 直接require
				() => {
					try {
						// const echarts = require('../../uni_modules/lime-echart/static/app/echarts.min.js');
						// const echarts = require('../../uni_modules/lime-echart/static/app/echarts.min.js');
						const echarts = require('../../../uni_modules/lime-echart/static/app/echarts.min.js');
						resolve({ default: echarts });
					} catch (e) {
						throw new Error('Require加载失败: ' + e.message);
					}
				},
				
				// 方式2: 如果上面失败,尝试使用动态import
				() => {
					// 这里可以根据实际情况调整路径
					// import('../../uni_modules/lime-echart/static/app/echarts.min.js')
					import('../../../uni_modules/lime-echart/static/app/echarts.min.js')
						.then(resolve)
						.catch(e => {
							throw new Error('Import加载失败: ' + e.message);
						});
				}
			];
			
			// 按顺序尝试加载
			const attemptLoad = (index) => {
				if (index >= loadAttempts.length) {
					reject(new Error('所有加载方式都失败了'));
					return;
				}
				
				try {
					loadAttempts[index]();
				} catch (error) {
					console.warn(`加载方式${index + 1}失败:`, error.message);
					// 延迟后尝试下一种方式
					setTimeout(() => attemptLoad(index + 1), 300);
				}
			};
			
			// 开始尝试加载
			attemptLoad(0);
		});
	},
	
	// 使用echarts初始化图表
	initChartWithEcharts(echarts) {
		// 确保DOM已更新
		this.$nextTick(() => {
			setTimeout(() => {
				try {
					if (!this.$refs.chart) {
						throw new Error('图表组件引用不存在');
					}
					
					console.log('开始初始化图表组件...');
					
					// 初始化图表
					this.$refs.chart.init(echarts, async (chart) => {
						this.chartInstance = chart;
						await this.renderChartData(chart, echarts);
					});
				} catch (error) {
					console.error('初始化图表组件失败:', error);
					this.showError('图表初始化失败: ' + error.message);
				}
			}, 100); // 额外延迟确保DOM完全渲染
		});
	},
	
	// 渲染图表数据
	async renderChartData(chart, echarts) {
		try {
			chart.showLoading();
			
			// 先设置一个基础的option,避免空白
			const baseOption = {
				title: {
					text: '加载中国地图数据...',
					left: 'center'
				},
				graphic: {
					type: 'text',
					left: 'center',
					top: 'middle',
					style: {
						text: '数据加载中',
						fill: '#999',
						fontSize: 16
					}
				}
			};
			chart.setOption(baseOption);
			
			// 获取地图数据
			const mapData = await this.fetchMapData();
			
			if (!mapData || typeof mapData !== 'object') {
				throw new Error('获取的地图数据格式不正确');
			}
			
			// 注册地图
			echarts.registerMap('china', mapData);
			
			// 设置完整的option
			const fullOption = this.getChartOption();
			chart.setOption(fullOption, true); // true表示不合并,完全替换
			chart.hideLoading();
			this.isLoading = false;
			
			console.log('图表渲染完成');
		} catch (error) {
			console.error('渲染图表数据失败:', error);
			chart.hideLoading();
			
			// 显示降级内容
			const fallbackOption = {
				title: {
					text: '数据加载失败',
					subtext: error.message || '请检查网络连接',
					left: 'center',
					top: 'center',
					textStyle: {
						color: '#f56c6c',
						fontSize: 16
					}
				}
			};
			chart.setOption(fallbackOption, true);
			
			this.showError('数据加载失败: ' + error.message);
		}
	},
	
	// 获取地图数据
	fetchMapData() {
		return new Promise((resolve, reject) => {
			const timeout = 10000; // 10秒超时
			const timeoutId = setTimeout(() => {
				reject(new Error('请求超时'));
			}, timeout);
			
			uni.request({
				url: 'https://www.isqqw.com/asset/get/areas_v3/country/china.json',
				timeout: 8000,
				success: (res) => {
					clearTimeout(timeoutId);
					if (res.statusCode === 200 && res.data) {
						resolve(res.data);
					} else {
						reject(new Error(`请求失败,状态码: ${res.statusCode}`));
					}
				},
				fail: (err) => {
					clearTimeout(timeoutId);
					reject(new Error(`网络请求失败: ${err.errMsg || '未知错误'}`));
				}
			});
		});
	},
	
	// 获取图表配置
	getChartOption() {
		// 简化配置,避免复杂对象导致的问题
		return {
			title: {
				text: '各省机器分布情况',
				left: 'center',
				textStyle: {
				        fontSize: 14 // 设置您需要的字体大小,单位是像素(px)
				    }
			},
			tooltip: {
				trigger: 'item',
				formatter: '{b} : {c}'
			},
			grid: {
			      left: '0%',   // 绘图区域距离容器左侧的距离,可以调整为 0%, 1%, 3% 等更小的值
			      right: '0%'// 绘图区域距离容器右侧的距离,同样调整
			      top: '10%',   // 绘图区域距离容器顶部的距离,可根据标题调整
			      bottom: '0%', // 绘图区域距离容器底部的距离
			      containLabel: true // 确保坐标轴标签也在 grid 区域内
			    },
				series: [{
				      name: '机器数量',
				      type: 'map',
				      map: 'china',
				      roam: false,
				      
				      // 关键配置:控制地图在容器中的位置和大小
				      layoutCenter: ['50%', '50%'], // 地图中心点位置
				      layoutSize: '130%', // 地图尺寸,可调整为120%、130%等      
				      label: {
				        show: true,
				        fontSize: 10
				      },
				      emphasis: {
				        label: {
				          show: true
				        }
				      },
				}],	  
			visualMap: {
				show:false,
				min: 0,
				max: 1000,
				text: ['数量'],
				realtime: false,
				calculable: true,
				inRange: {
					color: ['lightskyblue', 'yellow', 'orangered']
					// color: ['lightskyblue', 'lightskyblue', 'lightskyblue']
				},
				left: 'left',
				top: 'bottom'
			},
			series: [{
				name: '机器数量',
				type: 'map',
				map: 'china',
				roam: false, // 禁用拖动缩放,减少性能问题
				label: {
					show: true,
					fontSize: 10
				},
				emphasis: {
					label: {
						show: true
					}
				},
				data: [
					{ name: '北京', value: 112 },
					    { name: '天津', value: 316 },
					    { name: '河北', value: 300 },
					    { name: '山西', value: 400 },
					    { name: '内蒙古', value: 100 },
					    { name: '辽宁', value: 200 },
					    { name: '吉林', value: 150 },
					    { name: '黑龙江', value: 344 },
					    { name: '上海', value: 40 },
					    { name: '江苏', value: 900 },
					    { name: '浙江', value: 800 },
					    { name: '安徽', value: 300 },
					    { name: '福建', value: 700 },
					    { name: '江西', value: 930 },
					    { name: '山东', value: 310 },
					    { name: '河南', value: 520 },
					    { name: '湖北', value: 900 },
					    { name: '湖南', value: 1000 },
					    { name: '广东', value: 100 },
					    { name: '广西', value: 10 },
					    { name: '海南', value: 200 },
					    { name: '重庆', value: 450 },
					    { name: '四川', value: 710 },
					    { name: '贵州', value: 299 },
					    { name: '云南', value: 909 },
					    { name: '西藏', value: 303 },
					    { name: '陕西', value: 209 },
					    { name: '甘肃', value: 180 },
					    { name: '青海', value: 500 },
					    { name: '宁夏', value: 180 },
					    { name: '新疆', value: 380 },
					    { name: '台湾', value: 506 },
					    { name: '香港', value: 700 },
					    { name: '澳门', value: 900 },
						{ name: '南海诸岛', value: 900 },
				]
			}]
		};
	},
	
	// 安全的重试方法
	safeRetry() {
		// 清理旧的状态
		if (this.retryTimer) {
			clearTimeout(this.retryTimer);
			this.retryTimer = null;
		}
		if (this.chartInstance) {
			try {
				this.chartInstance.dispose();
			} catch (e) {
				// 忽略清理错误
			}
			this.chartInstance = null;
		}
		
		// 重置状态
		this.retryCount = 0;
		this.chartInitError = false;
		this.isLoading = true;
		this.isAppReady = false;
		this.isEchartsReady = false;
		
		// 重新开始初始化
		setTimeout(() => {
			this.checkAppStatus();
		}, 500);
	},
	
	// 显示错误
	showError(message) {
		this.errorMessage = message;
		this.chartInitError = true;
		this.isLoading = false;
		console.error('图表错误:', message);
	},
	
	
    changeTimeRange(range) {
      if (this.timeRange === range || this.isAnimating) return;
      this.timeRange = range;
      this.updateChartData();
    },
    
    changeMachineType(type) {
      if (this.selectedType === type || this.isAnimating) return;
      this.selectedType = type;
      this.updateChartData();
    },
    
    // 生成优美的渐变色
    generateGradientColor(baseColor, intensity) {
      // 根据强度生成渐变色,数值越大颜色越深
      const colors = {
        '#4E79A7': ['#A0CBE8', '#4E79A7', '#2C5E9E'], // 蓝色渐变
        '#59A14F': ['#8CD17D', '#59A14F', '#2E7D32'], // 绿色渐变
        '#B07AA1': ['#D4A6C8', '#B07AA1', '#8C5A7B'], // 紫色渐变
        '#499894': ['#86BCB6', '#499894', '#2A6D6A'// 青色渐变
      };
      
      const palette = colors[baseColor] || colors['#499894'];
      if (intensity < 0.5) {
        return this.interpolateColor(palette[0], palette[1], intensity * 2);
      } else {
        return this.interpolateColor(palette[1], palette[2], (intensity - 0.5) * 2);
      }
    },
    
    // 颜色插值
    interpolateColor(color1, color2, factor) {
      const hex = color => {
        const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(color);
        return result ? {
          r: parseInt(result[1], 16),
          g: parseInt(result[2], 16),
          b: parseInt(result[3], 16)
        } : { r: 0, g: 0, b: 0 };
      };
      
      const c1 = hex(color1);
      const c2 = hex(color2);
      
      const r = Math.round(c1.r + (c2.r - c1.r) * factor);
      const g = Math.round(c1.g + (c2.g - c1.g) * factor);
      const b = Math.round(c1.b + (c2.b - c1.b) * factor);
      
      return `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`;
    },
    
    // 获取类型基础色
    getTypeBaseColor(type) {
      return this.colorPalettes[type] ? this.colorPalettes[type][0] : this.colorPalettes.default[0];
    },
    
    updateChartData() {
      if (this.isAnimating) return;
      
      let provinceData = [];
      
      // 根据时间范围生成测试数据
      if (this.timeRange === 'day') {
        provinceData = this.provinces.map((province, index) => ({
          name: province.name,
          value: Math.floor(Math.random() * 100) + 10
        }));
      } else if (this.timeRange === 'week') {
        provinceData = this.provinces.map((province, index) => ({
          name: province.name,
          value: Math.floor(Math.random() * 500) + 50
        }));
      } else if (this.timeRange === 'month') {
        provinceData = this.provinces.map((province, index) => ({
          name: province.name,
          value: Math.floor(Math.random() * 1000) + 200
        }));
      }
      
      // 过滤数据
      if (this.selectedType !== 'all') {
        provinceData = provinceData.filter(item => {
          const provinceInfo = this.provinces.find(p => p.name === item.name);
          return provinceInfo && provinceInfo.type === this.selectedType;
        });
      }
      
      const newTotal = provinceData.reduce((sum, item) => sum + item.value, 0);
      const maxValue = Math.max(...provinceData.map(item => item.value), 1); // 避免除零错误
      const minValue = Math.min(...provinceData.map(item => item.value));
      
      // 构建图表数据
      const newChartData = provinceData.map(item => {
        const provinceInfo = this.provinces.find(p => p.name === item.name);
        const baseColor = this.getTypeBaseColor(provinceInfo?.type || 'default');
        const colorIntensity = maxValue > minValue ? 
          (item.value - minValue) / (maxValue - minValue) : 0.5;
        
        return {
          label: item.name,
          shortLabel: provinceInfo?.shortName || item.name,
          value: item.value,
          percentage: maxValue > 0 ? (item.value / maxValue) * 100 : 0,
          baseColor: baseColor,
          colorIntensity: colorIntensity,
          type: provinceInfo?.type || 'default'
        };
      });
      
      this.animateChartData(newChartData, newTotal);
    },
    
    // 优化后的动画方法:使用CSS transition替代部分JS动画
    animateChartData(newChartData, newTotal) {
      this.isAnimating = true;
      
      // 直接设置目标值,让CSS transition处理动画
      this.animatedChartData = newChartData.map(item => ({
        ...item,
        animatedValue: item.value,
        animatedPercentage: item.percentage,
        animatedColor: this.generateGradientColor(item.baseColor, item.colorIntensity)
      }));
      
      this.animatedTotalMachines = newTotal;
      this.chartData = newChartData;
      this.totalMachines = newTotal;
      
      // 设置动画完成状态
      setTimeout(() => {
        this.isAnimating = false;
      }, this.animationDuration);
    }
  }
};
</script>


<style lang="scss" scoped>
.chart-container {
	width: 100%;
	position: relative;
}


.loading-state,
.error-state {
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	bottom: 0;
	display: flex;
	flex-direction: column;
	justify-content: center;
	align-items: center;
	background-color: rgba(255, 255, 255, 0.9);
	z-index: 10;
}


.spinner {
	width: 40px;
	height: 40px;
	border: 3px solid #f3f3f3;
	border-top: 3px solid #007aff;
	border-radius: 50%;
	animation: spin 1s linear infinite;
	margin-bottom: 10px;
}


@keyframes spin {
	0% { transform: rotate(0deg); }
	100% { transform: rotate(360deg); }
}


.loading-text {
	font-size: 14px;
	color: #666;
}


.error-text {
	font-size: 14px;
	color: #f56c6c;
	margin-bottom: 15px;
	text-align: center;
	padding: 0 20px;
}


.retry-btn {
	background-color: #007aff;
	color: white;
	border: none;
	padding: 8px 16px;
	border-radius: 4px;
	font-size: 14px;
}






.chart-container {
	width: 100%;
	position: relative;
}


.loading-state,
.error-state {
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	bottom: 0;
	display: flex;
	flex-direction: column;
	justify-content: center;
	align-items: center;
	background-color: rgba(255, 255, 255, 0.9);
	z-index: 10;
}


.spinner {
	width: 40px;
	height: 40px;
	border: 3px solid #f3f3f3;
	border-top: 3px solid #007aff;
	border-radius: 50%;
	animation: spin 1s linear infinite;
	margin-bottom: 10px;
}


@keyframes spin {
	0% { transform: rotate(0deg); }
	100% { transform: rotate(360deg); }
}


.loading-text {
	font-size: 14px;
	color: #666;
}


.error-text {
	font-size: 14px;
	color: #f56c6c;
	margin-bottom: 15px;
	text-align: center;
	padding: 0 20px;
}


.retry-btn {
	background-color: #007aff;
	color: white;
	border: none;
	padding: 8px 16px;
	border-radius: 4px;
	font-size: 14px;
}	
	
	
	
.container {
  min-height: 100vh;
  background: linear-gradient(135deg, #f5f7fa 0%, #e4e7ed 100%);
  padding-bottom: env(safe-area-inset-bottom);
}


.main-content {
  padding: 20rpx;
}


.stats-section {
  background: #fff;
  border-radius: 16rpx;
  padding: 20rpx;
  box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
  
  .section-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 30rpx;
  }
  
  .section-title {
    font-size: 30rpx;
    font-weight: 500;
    color: #333;
    
    text {
      position: relative;
      padding-left: 16rpx;
      
      &::before {
        content: '';
        position: absolute;
        left: 0;
        top: 50%;
        transform: translateY(-50%);
        width: 6rpx;
        height: 24rpx;
        background: linear-gradient(135deg, #52c41a, #389e0d);
        border-radius: 3rpx;
      }
    }
  }
}


.total-machine-count {
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 10rpx;
  background: linear-gradient(135deg, #f0f9ff 0%, #e6f7ff 100%);
  border-radius: 12rpx;
  margin-bottom: 30rpx;
  border: 1rpx solid #e6f7ff;
  
  .total-label {
    font-size: 26rpx;
    color: #666;
    margin-right: 10rpx;
  }
  
  .total-value {
    font-size: 36rpx;
    color: #1890ff;
    font-weight: bold;
    transition: all 1s cubic-bezier(0.25, 0.46, 0.45, 0.94); /* 使用CSS transition */
  }
}


// 竖形图表样式
.chart-container {
  margin-bottom: 30rpx;
  /* 创建新的图层,减少重排影响 */
  transform: translateZ(0);
}


// 横向图表样式 - 优化动画性能
.horizontal-chart {
  .horizontal-bars {
    display: flex;
    flex-direction: column;
    gap: 30rpx;
    padding: 20rpx 0;
	
    
    .horizontal-bar-item {
      display: flex;
      align-items: center;
      height: 60rpx;
      
      .bar-label-horizontal {
        width: 80rpx;
        font-size: 22rpx;
        color: #666;
        text-align: right;
        padding-right: 20rpx;
        transition: all 1s ease; /* 添加过渡效果 */
      }
      
      .bar-container-horizontal {
        flex: 1;
        display: flex;
        align-items: center;
        height: 100%;
        background: #f5f5f5;
        border-radius: 6rpx;
        position: relative;
        overflow: hidden; /* 确保动画内容不溢出 */
        
        .bar-fill-horizontal {
          height: 100%;
          background: linear-gradient(135deg, #4E79A7, #A0CBE8);
          display: flex;
          align-items: center;
          padding-left: 20rpx;
          color: white;
          font-size: 20rpx;
          font-weight: 500;
          border-radius: 0 6rpx 6rpx 0;
          transform-origin: left;
          box-shadow: 2rpx 0 8rpx rgba(0,0,0,0.1);
          
          /* 使用CSS transition替代JS动画 */
          transition: 
            width 1s cubic-bezier(0.25, 0.46, 0.45, 0.94),
            background-color 1s cubic-bezier(0.25, 0.46, 0.45, 0.94),
            transform 0.3s ease;
          
          /* 启用GPU加速 */
          transform: translateZ(0);
          backface-visibility: hidden;
          perspective: 1000px;
          /* 减少重排重绘 */
          will-change: transform, width;
        }
        
        .bar-value-horizontal {
          position: absolute;
          right: 20rpx;
          font-size: 22rpx;
          color: #333;
          font-weight: 500;
          transition: all 1s cubic-bezier(0.25, 0.46, 0.45, 0.94); /* 使用CSS transition */
          
          /* 启用GPU加速 */
          transform: translateZ(0);
          backface-visibility: hidden;
        }
      }
    }
  }
}


.machine-type-filter {
  display: flex;
  justify-content: space-around;
  margin-top: 30rpx;
  padding: 10rpx;
  background: #f5f5f5;
  border-radius: 20rpx;
  
  .type-tab {
    font-size: 24rpx;
    color: #666;
    padding: 12rpx 20rpx;
    border-radius: 16rpx;
    transition: all 0.3s;
    
    &.active {
      background: #fff;
      color: #1890ff;
      box-shadow: 0 2rpx 8rpx rgba(24, 144, 255, 0.2);
      font-weight: 500;
    }
  }
}


.time-filter {
  .filter-tabs {
    display: flex;
    background: #f5f5f5;
    border-radius: 20rpx;
    padding: 6rpx;
  }
  
  .filter-tab {
    font-size: 24rpx;
    color: #666;
    padding: 12rpx 20rpx;
    border-radius: 16rpx;
    transition: all 0.3s;
    
    &.active {
      background: #fff;
      color: #1890ff;
      box-shadow: 0 2rpx 8rpx rgba(24, 144, 255, 0.2);
      font-weight: 500;
    }
  }
}


.safe-area-bottom {
  height: env(safe-area-inset-bottom);
}


/* 优化动画关键帧 - 使用transform和opacity实现高性能动画 */
@keyframes barGrowth {
  from {
    opacity: 0.1;
    transform: scaleY(0);
  }
  to {
    opacity: 1;
    transform: scaleY(1);
  }
}


@keyframes barGrowthHorizontal {
  from {
    opacity: 0.1;
    transform: scaleX(0);
  }
  to {
    opacity: 1;
    transform: scaleX(1);
  }
}


/* 高性能动画类 */
.bar-fill {
  animation: barGrowth 0.5s ease-out;
  /* 启用GPU加速 */
  transform: translateZ(0);
  backface-visibility: hidden;
  perspective: 1000px;
  /* 减少重排重绘 */
  will-change: transform, height;
}


.bar-fill-horizontal {
  animation: barGrowthHorizontal 0.5s ease-out;
  /* 启用GPU加速 */
  transform: translateZ(0);
  backface-visibility: hidden;
  perspective: 1000px;
  /* 减少重排重绘 */
  will-change: transform, width;
}


/* 添加高性能过渡类 */
.smooth-transition {
  transition: all 1s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}


/* 优化渲染性能 */
.optimized-render {
  /* 创建独立的合成层 */
  transform: translateZ(0);
  /* 避免重绘 */
  will-change: transform, opacity;
  /* 优化动画性能 */
  backface-visibility: hidden;
  perspective: 1000px;
}
</style>
回答关注问题邀请回答
收藏

1 个回答

登录 后发表内容