管灌系统农户端微信小程序(嘉峪关应用)
更新项目配置,启用URL检查功能;修改监测页面状态管理逻辑,优化在线状态的判断方式,提升用户体验和代码可读性。
5个文件已修改
1347 ■■■■ 已修改文件
pages/stationMonitor/stationMonitor.js 355 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/stationMonitor/stationMonitor.wxml 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/stationMonitor/stationMonitor.wxss 899 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
project.private.config.json 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
utils/projectConfig.js 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/stationMonitor/stationMonitor.js
@@ -387,7 +387,7 @@
            return {
              id: item.id,
              name: item.name,
              online: true, // 默认在线,实际项目中可能需要额外的状态检查
              onLine: true, // 默认在线,实际项目中可能需要额外的状态检查
              lastUpdate: new Date().toLocaleString(), // 当前时间作为最后更新时间
              isPlaying: false, // 视频播放状态
              hslUrl: rtmpUrl, // 使用生成的RTMP URL
@@ -432,356 +432,12 @@
 
  /**
   * 批量获取所有摄像头的HLS播放地址
   */
  batchGetHlsUrls(cameraList) {
    if (!cameraList || cameraList.length === 0) {
      console.log('摄像头列表为空,无需获取播放地址');
      return;
    }
    console.log('开始批量获取播放地址,摄像头数量:', cameraList.length);
    // 为每个摄像头获取播放地址
    cameraList.forEach((camera, index) => {
      // 延迟获取,避免同时发起太多请求
      setTimeout(() => {
        this.getHlsUrlForCamera(camera);
      }, index * 500); // 每个请求间隔500ms
    });
  },
  /**
   * 播放视频
   */
  playVideo(e) {
    const camera = e.currentTarget.dataset.camera;
    console.log('=== 播放视频开始 ===');
    console.log('摄像头信息:', camera);
    console.log('设备信息:', this.data.deviceInfo);
    console.log('设备特定配置:', this.data.deviceSpecificConfig);
    if (!camera.online) {
      console.log('摄像头离线,无法播放');
      wx.showToast({
        title: '设备离线,无法播放',
        icon: 'error'
      });
      return;
    }
    if (!camera.hslUrl) {
      console.log('无播放地址,无法播放');
      wx.showToast({
        title: '暂无播放地址,请稍后重试',
        icon: 'error'
      });
      return;
    }
    if (camera.isLoadingUrl) {
      console.log('正在加载URL,无法播放');
      wx.showToast({
        title: '正在获取播放地址,请稍候',
        icon: 'none'
      });
      return;
    }
    console.log('开始播放视频,播放地址:', camera.hslUrl);
    console.log('当前页面数据状态:', {
      cameraList: this.data.cameraList,
      activeTab: this.data.activeTab,
      isLoading: this.data.isLoading
    });
    // 检查URL格式
    if (camera.hslUrl.startsWith('rtmp://')) {
      console.log('检测到RTMP URL格式,开始播放');
      // 更新播放状态
    const cameraList = this.data.cameraList.map(item => {
      if (item.id === camera.id) {
        return {
          ...item,
          isPlaying: true
        };
      }
      return item;
    });
    this.setData({
      cameraList: cameraList
    });
      // 显示播放成功提示
      wx.showToast({
        title: `开始播放 ${camera.name}`,
        icon: 'success'
      });
      console.log(`播放状态已更新,摄像头 ${camera.name} 开始播放RTMP流`);
    } else {
      console.log('URL格式不是RTMP,无法播放');
      wx.showToast({
        title: '播放地址格式不正确',
        icon: 'error'
      });
    }
    console.log('=== 播放视频结束 ===');
  },
  /**
   * 暂停视频
   */
  pauseVideo(e) {
    const camera = e.currentTarget.dataset.camera;
    console.log('暂停摄像头:', camera.name);
    // 更新视频播放状态
    const cameraList = this.data.cameraList.map(item => {
      if (item.id === camera.id) {
        return {
          ...item,
          isPlaying: false
        };
      }
      return item;
    });
    this.setData({
      cameraList: cameraList
    });
  },
  /**
   * 停止视频
   */
  stopVideo(e) {
    const camera = e.currentTarget.dataset.camera;
    console.log('停止摄像头:', camera.name);
    // 更新视频播放状态
    const cameraList = this.data.cameraList.map(item => {
      if (item.id === camera.id) {
        return {
          ...item,
          isPlaying: false
        };
      }
      return item;
    });
    this.setData({
      cameraList: cameraList
    });
  },
  /**
   * 直播播放器状态变化
   */
  onLivePlayerStateChange(e) {
    const camera = e.currentTarget.dataset.camera;
    console.log('直播播放器状态变化:', camera.name, e.detail);
    const {
      code
    } = e.detail;
    // 显示状态信息给用户
    let statusText = '';
    let isPlaying = false;
    switch (code) {
      case 2001:
        statusText = '已经连接服务器';
        break;
      case 2002:
        statusText = '已经连接 RTMP 服务器,开始拉流';
        isPlaying = true;
        break;
      case 2003:
        statusText = '网络接收到首个视频数据包(IDR)';
        isPlaying = true;
        break;
      case 2004:
        statusText = '视频播放开始';
        isPlaying = true;
        break;
      case 2005:
        statusText = '视频播放进度';
        isPlaying = true;
        break;
      case 2006:
        statusText = '视频播放结束';
        isPlaying = false;
        break;
      case 2007:
        statusText = '视频播放Loading';
        isPlaying = true;
        break;
      case 2008:
        statusText = '解码器启动';
        isPlaying = true;
        break;
      case 2009:
        statusText = '视频分辨率改变';
        isPlaying = true;
        break;
      case 2101:
        statusText = '网络断连,且经多次重连抢救无效';
        isPlaying = false;
        break;
      case 2102:
        statusText = '获取加速拉流地址失败';
        isPlaying = false;
        break;
      case 2103:
        statusText = '当前视频帧解码失败';
        isPlaying = false;
        break;
      case 2104:
        statusText = '网络断连, 已启动自动重连';
        isPlaying = false;
        break;
      case 2105:
        statusText = '网络来断连, 且经多次重连抢救无效';
        isPlaying = false;
        break;
      case 2106:
        statusText = '网络来断连, 且经多次重连抢救无效';
        isPlaying = false;
        break;
      default:
        statusText = `未知状态码: ${code}`;
        break;
    }
    console.log(`摄像头 ${camera.name} 状态: ${statusText}`);
    // 更新播放状态
    const cameraList = this.data.cameraList.map(item => {
      if (item.id === camera.id) {
        return {
          ...item,
          isPlaying: isPlaying
        };
      }
      return item;
    });
    this.setData({
      cameraList: cameraList
    });
  },
  /**
   * 直播播放器网络状态
   */
  onLivePlayerNetStatus(e) {
    const camera = e.currentTarget.dataset.camera;
    console.log('直播播放器网络状态:', camera.name, e.detail);
  },
  /**
   * 直播播放器错误
   */
  onLivePlayerError(e) {
    const camera = e.currentTarget.dataset.camera;
    console.error('直播播放器错误:', camera.name, e.detail);
    wx.showToast({
      title: '直播播放失败',
      icon: 'error'
    });
    // 更新播放状态
    const cameraList = this.data.cameraList.map(item => {
      if (item.id === camera.id) {
        return {
          ...item,
          isPlaying: false
        };
      }
      return item;
    });
    this.setData({
      cameraList: cameraList
    });
  },
  /**
   * 全屏播放视频
   */
  fullscreenVideo(e) {
    const camera = e.currentTarget.dataset.camera;
    console.log('全屏播放:', camera.name);
    if (!camera.online) {
      wx.showToast({
        title: '摄像头离线',
        icon: 'error'
      });
      return;
    }
    // 使用RTMP URL进行全屏播放
    if (camera.hslUrl) {
      console.log('全屏视频URL:', camera.hslUrl);
      wx.showModal({
        title: '全屏播放',
        content: `即将全屏播放 ${camera.name} 的视频流`,
        confirmText: '开始播放',
        success: (res) => {
          if (res.confirm) {
            // 这里可以跳转到全屏视频播放页面
            wx.showToast({
              title: '正在加载全屏视频...',
              icon: 'loading'
            });
            // 模拟全屏视频加载
            setTimeout(() => {
              wx.showToast({
                title: '全屏播放中',
                icon: 'success'
              });
            }, 1500);
          }
        }
      });
    } else {
      wx.showToast({
        title: '全屏视频地址无效',
        icon: 'error'
      });
    }
  },
  /**
   * 摄像头设置
   */
  cameraSettings(e) {
    const camera = e.currentTarget.dataset.camera;
    console.log('摄像头设置:', camera.name);
    wx.showActionSheet({
      itemList: ['云台控制', '录像设置', '画质调节', '报警设置'],
      success: (res) => {
        const actions = ['云台控制', '录像设置', '画质调节', '报警设置'];
        wx.showToast({
          title: `${actions[res.tapIndex]}功能开发中`,
          icon: 'none'
        });
      }
    });
  },
  /**
   * 获取气象站列表(兼容性方法,现在调用统一接口)
@@ -849,8 +505,6 @@
            windDirectionAngle: content.windDirection, // 风向角度
            // 在线状态
            onLine: content.onLine,
            // 计算在线状态
            online: content.onLine === 1,
            // 格式化显示数据
            lastUpdate: content.dt || new Date().toLocaleString()
          };
@@ -903,7 +557,7 @@
      windSpeed: 0.00,
      windDirection: '北',
      windDirectionAngle: 0,
      onLine: 1,
      onLine: false,
      online: true,
      lastUpdate: new Date().toLocaleString()
    };
@@ -1071,8 +725,7 @@
      soilTemperature4: 0.00,
      soilTemperature5: 0.00,
      // 在线状态
      onLine: 1,
      online: true,
      onLine: false,
      lastUpdate: new Date().toLocaleString()
    };
@@ -1240,7 +893,7 @@
      stirTime: 0,
      stirDuration: 300,
      injectDuration: 300,
      onLine: 1,
      onLine: false,
      mixingEnabled: false,
      fertilizingEnabled: false,
      lastUpdate: new Date().toLocaleString()
pages/stationMonitor/stationMonitor.wxml
@@ -47,8 +47,8 @@
        <!-- 状态栏 -->
        <view class="status-bar">
          <view class="status-item">
            <view class="status-indicator {{currentWeatherStation.online ? 'online' : 'offline'}}"></view>
            <text class="status-text">{{currentWeatherStation.online ? '在线' : '离线'}}</text>
            <view class="status-indicator {{currentWeatherStation.onLine === true ? 'online' : 'offline'}}"></view>
            <text class="status-text">{{currentWeatherStation.onLine === true ? '在线' : '离线'}}</text>
          </view>
          <view class="refresh-btn" bind:tap="refreshWeatherData">
            <image class="refresh-icon" src="/images/refresh.svg" />
@@ -65,7 +65,7 @@
            </view>
            <view class="data-content">
              <text class="data-label">空气湿度(%)</text>
              <text class="data-value">{{currentWeatherStation.humidity || '--'}}%</text>
              <text class="data-value">{{currentWeatherStation.humidity !== null && currentWeatherStation.humidity !== undefined ? currentWeatherStation.humidity : '--'}}%</text>
            </view>
          </view>
@@ -76,7 +76,7 @@
            </view>
            <view class="data-content">
              <text class="data-label">空气温度(℃)</text>
              <text class="data-value">{{currentWeatherStation.temperature || '--'}}°C</text>
              <text class="data-value">{{currentWeatherStation.temperature !== null && currentWeatherStation.temperature !== undefined ? currentWeatherStation.temperature : '--'}}°C</text>
            </view>
          </view>
@@ -87,7 +87,7 @@
            </view>
            <view class="data-content">
              <text class="data-label">紫外线(mW/m²)</text>
              <text class="data-value">{{currentWeatherStation.uv || '--'}}</text>
              <text class="data-value">{{currentWeatherStation.uv !== null && currentWeatherStation.uv !== undefined ? currentWeatherStation.uv : '--'}}</text>
            </view>
          </view>
@@ -98,7 +98,7 @@
            </view>
            <view class="data-content">
              <text class="data-label">光照强度(lm/㎡)</text>
              <text class="data-value">{{currentWeatherStation.light || '--'}} lux</text>
              <text class="data-value">{{currentWeatherStation.light !== null && currentWeatherStation.light !== undefined ? currentWeatherStation.light : '--'}} lux</text>
            </view>
          </view>
@@ -109,7 +109,7 @@
            </view>
            <view class="data-content">
              <text class="data-label">雨量(mm)</text>
              <text class="data-value">{{currentWeatherStation.rainfall || '--'}} mm</text>
              <text class="data-value">{{currentWeatherStation.rainfall !== null && currentWeatherStation.rainfall !== undefined ? currentWeatherStation.rainfall : '--'}} mm</text>
            </view>
          </view>
@@ -120,7 +120,7 @@
            </view>
            <view class="data-content">
              <text class="data-label">风速(m/s)</text>
              <text class="data-value">{{currentWeatherStation.windSpeed || '--'}} m/s</text>
              <text class="data-value">{{currentWeatherStation.windSpeed !== null && currentWeatherStation.windSpeed !== undefined ? currentWeatherStation.windSpeed : '--'}} m/s</text>
            </view>
          </view>
@@ -133,7 +133,7 @@
              <text class="data-label">风向</text>
              <view class="wind-direction-display">
                <!-- <image class="wind-arrow" src="/images/wind-arrow.svg" style="transform: rotate({{currentWeatherStation.windDirectionAngle || 0}}deg)" /> -->
                <text class="data-value">{{currentWeatherStation.windDirection || '--'}}</text>
                <text class="data-value">{{currentWeatherStation.windDirection !== null && currentWeatherStation.windDirection !== undefined ? currentWeatherStation.windDirection : '--'}}</text>
              </view>
            </view>
          </view>
@@ -172,8 +172,8 @@
        <!-- 状态栏 -->
        <view class="status-bar">
          <view class="status-item">
            <view class="status-indicator {{currentSoilStation.online ? 'online' : 'offline'}}"></view>
            <text class="status-text">{{currentSoilStation.online ? '在线' : '离线'}}</text>
            <view class="status-indicator {{currentSoilStation.onLine === true ? 'online' : 'offline'}}"></view>
            <text class="status-text">{{currentSoilStation.onLine === true ? '在线' : '离线'}}</text>
          </view>
          <view class="refresh-btn" bind:tap="refreshSoilData">
            <image class="refresh-icon" src="/images/refresh.svg" />
@@ -190,7 +190,7 @@
            </view>
            <view class="data-content">
              <text class="data-label">土壤湿度1(%)</text>
              <text class="data-value">{{currentSoilStation.soilHumidity1 || '--'}}%</text>
              <text class="data-value">{{currentSoilStation.soilHumidity1 !== null && currentSoilStation.soilHumidity1 !== undefined ? currentSoilStation.soilHumidity1 : '--'}}%</text>
            </view>
          </view>
@@ -200,7 +200,7 @@
            </view>
            <view class="data-content">
              <text class="data-label">土壤温度1(℃)</text>
              <text class="data-value">{{currentSoilStation.soilTemperature1 || '--'}}°C</text>
              <text class="data-value">{{currentSoilStation.soilTemperature1 !== null && currentSoilStation.soilTemperature1 !== undefined ? currentSoilStation.soilTemperature1 : '--'}}°C</text>
            </view>
          </view>
@@ -211,7 +211,7 @@
            </view>
            <view class="data-content">
              <text class="data-label">土壤湿度2(%)</text>
              <text class="data-value">{{currentSoilStation.soilHumidity2 || '--'}}%</text>
              <text class="data-value">{{currentSoilStation.soilHumidity2 !== null && currentSoilStation.soilHumidity2 !== undefined ? currentSoilStation.soilHumidity2 : '--'}}%</text>
            </view>
          </view>
@@ -221,7 +221,7 @@
            </view>
            <view class="data-content">
              <text class="data-label">土壤温度2(℃)</text>
              <text class="data-value">{{currentSoilStation.soilTemperature2 || '--'}}°C</text>
              <text class="data-value">{{currentSoilStation.soilTemperature2 !== null && currentSoilStation.soilTemperature2 !== undefined ? currentSoilStation.soilTemperature2 : '--'}}°C</text>
            </view>
          </view>
@@ -232,7 +232,7 @@
            </view>
            <view class="data-content">
              <text class="data-label">土壤湿度3(%)</text>
              <text class="data-value">{{currentSoilStation.soilHumidity3 || '--'}}%</text>
              <text class="data-value">{{currentSoilStation.soilHumidity3 !== null && currentSoilStation.soilHumidity3 !== undefined ? currentSoilStation.soilHumidity3 : '--'}}%</text>
            </view>
          </view>
@@ -242,7 +242,7 @@
            </view>
            <view class="data-content">
              <text class="data-label">土壤温度3(℃)</text>
              <text class="data-value">{{currentSoilStation.soilTemperature3 || '--'}}°C</text>
              <text class="data-value">{{currentSoilStation.soilTemperature3 !== null && currentSoilStation.soilTemperature3 !== undefined ? currentSoilStation.soilTemperature3 : '--'}}°C</text>
            </view>
          </view>
@@ -253,7 +253,7 @@
            </view>
            <view class="data-content">
              <text class="data-label">土壤湿度4(%)</text>
              <text class="data-value">{{currentSoilStation.soilHumidity4 || '--'}}%</text>
              <text class="data-value">{{currentSoilStation.soilHumidity4 !== null && currentSoilStation.soilHumidity4 !== undefined ? currentSoilStation.soilHumidity4 : '--'}}%</text>
            </view>
          </view>
@@ -263,7 +263,7 @@
            </view>
            <view class="data-content">
              <text class="data-label">土壤温度4(℃)</text>
              <text class="data-value">{{currentSoilStation.soilTemperature4 || '--'}}°C</text>
              <text class="data-value">{{currentSoilStation.soilTemperature4 !== null && currentSoilStation.soilTemperature4 !== undefined ? currentSoilStation.soilTemperature4 : '--'}}°C</text>
            </view>
          </view>
@@ -274,7 +274,7 @@
            </view>
            <view class="data-content">
              <text class="data-label">土壤湿度5(%)</text>
              <text class="data-value">{{currentSoilStation.soilHumidity5 || '--'}}%</text>
              <text class="data-value">{{currentSoilStation.soilHumidity5 !== null && currentSoilStation.soilHumidity5 !== undefined ? currentSoilStation.soilHumidity5 : '--'}}%</text>
            </view>
          </view>
@@ -284,7 +284,7 @@
            </view>
            <view class="data-content">
              <text class="data-label">土壤温度5(℃)</text>
              <text class="data-value">{{currentSoilStation.soilTemperature5 || '--'}}°C</text>
              <text class="data-value">{{currentSoilStation.soilTemperature5 !== null && currentSoilStation.soilTemperature5 !== undefined ? currentSoilStation.soilTemperature5 : '--'}}°C</text>
            </view>
          </view>
        </view>
@@ -324,8 +324,8 @@
        <!-- 状态栏 -->
        <view class="status-bar">
          <view class="status-item">
            <view class="status-indicator {{currentFertilizerStation.onLine === 1 ? 'online' : 'offline'}}"></view>
            <text class="status-text">{{currentFertilizerStation.onLine === 1 ? '在线' : '离线'}}</text>
            <view class="status-indicator {{currentFertilizerStation.onLine === true ? 'online' : 'offline'}}"></view>
            <text class="status-text">{{currentFertilizerStation.onLine === true ? '在线' : '离线'}}</text>
          </view>
          <view class="refresh-btn" bind:tap="refreshFertilizerData">
            <image class="refresh-icon" src="/images/refresh.svg" />
@@ -340,13 +340,13 @@
            <!-- 搅拌开关 -->
            <view class="switch-item">
              <text class="switch-label">搅拌</text>
              <switch class="custom-switch" checked="{{currentFertilizerStation.mixingEnabled}}" bindchange="toggleMixing" disabled="{{currentFertilizerStation.onLine !== 1}}" color="#07c160" />
              <switch class="custom-switch" checked="{{currentFertilizerStation.mixingEnabled}}" bindchange="toggleMixing" disabled="{{currentFertilizerStation.onLine !== true}}" color="#07c160" />
            </view>
            <!-- 注肥开关 -->
            <view class="switch-item">
              <text class="switch-label">注肥</text>
              <switch class="custom-switch" checked="{{currentFertilizerStation.fertilizingEnabled}}" bindchange="toggleFertilizing" disabled="{{currentFertilizerStation.onLine !== 1}}" color="#07c160" />
              <switch class="custom-switch" checked="{{currentFertilizerStation.fertilizingEnabled}}" bindchange="toggleFertilizing" disabled="{{currentFertilizerStation.onLine !== true}}" color="#07c160" />
            </view>
          </view>
        </view>
@@ -362,7 +362,7 @@
              </view>
              <view class="data-content">
                <text class="data-label">肥料流量(升)</text>
                <text class="data-value">{{currentFertilizerStation.manureFlow || '--'}} L</text>
                <text class="data-value">{{currentFertilizerStation.manureFlow !== null && currentFertilizerStation.manureFlow !== undefined ? currentFertilizerStation.manureFlow : '--'}} L</text>
              </view>
            </view>
@@ -373,7 +373,7 @@
              </view>
              <view class="data-content">
                <text class="data-label">注肥时长(秒)</text>
                <text class="data-value">{{currentFertilizerStation.manureTime || '--'}} s</text>
                <text class="data-value">{{currentFertilizerStation.manureTime !== null && currentFertilizerStation.manureTime !== undefined ? currentFertilizerStation.manureTime : '--'}} s</text>
              </view>
            </view>
@@ -384,7 +384,7 @@
              </view>
              <view class="data-content">
                <text class="data-label">搅拌时长(秒)</text>
                <text class="data-value">{{currentFertilizerStation.stirTime || '--'}} s</text>
                <text class="data-value">{{currentFertilizerStation.stirTime !== null && currentFertilizerStation.stirTime !== undefined ? currentFertilizerStation.stirTime : '--'}} s</text>
              </view>
            </view>
@@ -395,7 +395,7 @@
              </view>
              <view class="data-content">
                <text class="data-label">搅拌设定时间(秒)</text>
                <text class="data-value">{{currentFertilizerStation.stirDuration || '--'}} s</text>
                <text class="data-value">{{currentFertilizerStation.stirDuration !== null && currentFertilizerStation.stirDuration !== undefined ? currentFertilizerStation.stirDuration : '--'}} s</text>
              </view>
            </view>
@@ -406,7 +406,7 @@
              </view>
              <view class="data-content">
                <text class="data-label">注肥设定时间(秒)</text>
                <text class="data-value">{{currentFertilizerStation.injectDuration || '--'}} s</text>
                <text class="data-value">{{currentFertilizerStation.injectDuration !== null && currentFertilizerStation.injectDuration !== undefined ? currentFertilizerStation.injectDuration : '--'}} s</text>
              </view>
            </view>
          </view>
@@ -435,13 +435,13 @@
          <!-- 摄像头名称 -->
          <view class="camera-header">
            <text class="camera-name">{{item.name}}</text>
            <view class="camera-status {{item.online ? 'online' : 'offline'}}">
              <text>{{item.online ? '在线' : '离线'}}</text>
            <view class="camera-status {{item.onLine === true ? 'online' : 'offline'}}">
              <text>{{item.onLine === true ? '在线' : '离线'}}</text>
            </view>
          </view>
          <!-- 摄像头视频 -->
          <view class="camera-video-container" style="height: {{deviceSpecificConfig.videoHeight}}rpx;">
          <view class="camera-video-container" >
            <!-- 加载状态 -->
            <view wx:if="{{item.isLoadingUrl}}" class="video-loading">
              <view class="loading-spinner"></view>
@@ -459,28 +459,13 @@
            </view>
            <!-- 正常播放状态 -->
            <view wx:elif="{{item.online && item.hslUrl}}" class="video-wrapper">
            <view wx:elif="{{item.onLine && item.hslUrl}}" class="video-wrapper">
              <!-- 直播播放器组件 -->
              <ezplayer
                id="ezplayer-{{item.id}}"
                accessToken="{{item.accessToken}}"
                url="{{item.hslUrl}}"
                deviceSerial="{{item.deviceSerial}}"
                channelNo="1"
                width="300rpx"
                height="300rpx"
                plugins="talk,voice,capture,ptz,privacy,mirror"
                watermark="大禹"
                autoPlay="{{true}}"
                theme="{{ { showFullScreenBtn: true, showHdBtn: true, showTimeLine: true } }}"
                bind:handleError="handleError"
                bind:onControlEvent="onControlEvent"
                style="width: 100vw; height: 100%; max-width: 100vw; min-width: 100vw; position: absolute; left: 0; right: 0; top: 0; bottom: 0; overflow: hidden; margin: 0; padding: 0; transform: none; border: none; border-radius: 0; box-shadow: none; background: transparent;"
              />
              <ezplayer class="video-wrapper-ezplayer" id="ezplayer-{{item.id}}" accessToken="{{item.accessToken}}" url="{{item.hslUrl}}" deviceSerial="{{item.deviceSerial}}" channelNo="1" plugins="capture,ptz,mirror" watermark="大禹" autoPlay="{{true}}" theme="{{ { showFullScreenBtn: true, showHdBtn: true, showTimeLine: true } }}" bind:handleError="handleError" bind:onControlEvent="onControlEvent" />
            </view>
            <!-- 离线状态显示 -->
            <view wx:elif="{{!item.online}}" class="video-offline">
            <view wx:elif="{{!item.onLine}}" class="video-offline">
              <image class="offline-icon" src="/images/camera.svg" />
              <text class="offline-text">设备离线</text>
            </view>
pages/stationMonitor/stationMonitor.wxss
@@ -18,7 +18,8 @@
  padding: 0;
  margin: 0;
  background-color: #f5f5f5;
  height: 100vh; /* 固定高度为视口高度 */
  height: 100vh;
  /* 固定高度为视口高度 */
  width: 100%;
  box-sizing: border-box;
  /* 防止任何滚动 */
@@ -40,13 +41,16 @@
  background-color: #fff;
  padding: 4rpx 0;
  width: 100%;
  flex-shrink: 0; /* 防止被压缩 */
  flex-shrink: 0;
  /* 防止被压缩 */
  box-shadow: 0 4rpx 8rpx rgba(0, 0, 0, 0.05);
  border-bottom: 1rpx solid #eaeaea;
  position: sticky; /* 使用sticky定位 */
  position: sticky;
  /* 使用sticky定位 */
  top: 0;
  z-index: 9999;
  background-color: #fff; /* 确保背景色 */
  background-color: #fff;
  /* 确保背景色 */
  /* 减小tabs高度 */
  height: 100rpx;
  box-sizing: border-box;
@@ -152,12 +156,17 @@
  box-sizing: border-box;
  /* 使用flex: 1填充剩余空间 */
  flex: 1;
  min-height: 0; /* 允许flex项目收缩 */
  overflow-y: auto; /* 垂直滚动 */
  overflow-x: hidden; /* 隐藏水平滚动 */
  min-height: 0;
  /* 允许flex项目收缩 */
  overflow-y: auto;
  /* 垂直滚动 */
  overflow-x: hidden;
  /* 隐藏水平滚动 */
  /* 隐藏滚动条 */
  -ms-overflow-style: none;  /* IE and Edge */
  scrollbar-width: none;  /* Firefox */
  -ms-overflow-style: none;
  /* IE and Edge */
  scrollbar-width: none;
  /* Firefox */
  /* 为tabs留出空间 */
  margin-top: 0;
}
@@ -186,6 +195,7 @@
    opacity: 0;
    transform: translateY(20rpx);
  }
  to {
    opacity: 1;
    transform: translateY(0);
@@ -474,7 +484,8 @@
  
  .tab-item {
    padding: 16rpx 2rpx;
    width: 25%; /* 确保小屏幕下也均分 */
    width: 25%;
    /* 确保小屏幕下也均分 */
  }
  
  /* 气象站数据项响应式字体 */
@@ -536,81 +547,44 @@
.camera-list {
  display: flex;
  flex-direction: column;
  /* gap: 20rpx; */
  margin: 0;
  width: 100%;
  box-sizing: border-box;
  /* 确保在不同设备上的一致性 */
  max-width: 100vw;
  overflow-x: hidden;
  /* 新增:移除左右内边距,确保完全填充 */
  /* padding: 0; */
  /* 新增:强制约束,防止ezplayer超出 */
  /* contain: layout style paint; */
  /* 新增:强制左对齐,无任何边距 */
  /* left: 0 !important;
  right: 0 !important; */
  gap: 20rpx;
}
.camera-item {
  width: 100%;
  max-width: 100%;
  min-width: 0;
  background: white;
  border-radius: 16rpx;
  /* 移除左右内边距,确保完全填充 */
  padding: 24rpx 0;
  box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
  box-sizing: border-box;
  margin: 0;
  position: relative;
  overflow: hidden;
  /* 确保在不同设备上的显示一致性 */
  flex-shrink: 0;
  flex-grow: 0;
  /* 新增:强制约束,防止ezplayer超出 */
  contain: layout style paint;
  /* 新增:强制左对齐,无任何边距 */
  left: 0 !important;
  right: 0 !important;
  border-radius: 12rpx;
  margin-bottom: 10rpx;
  box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
}
/* 摄像头头部 */
.camera-header {
  width: 100%;
  max-width: 100%;
  min-width: 0;
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20rpx;
  box-sizing: border-box;
  /* 防止文字溢出 */
  overflow: hidden;
  margin: 20rpx 10rpx;
  margin-bottom: 16rpx;
  margin-top: 15rpx;
  margin-left: 15rpx;
  margin-right: 15rpx;
}
.camera-name {
  font-size: 32rpx;
  font-size: 28rpx;
  font-weight: 600;
  color: #333;
  flex: 1;
  min-width: 0;
  /* 文字溢出处理 */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.camera-status {
  padding: 8rpx 16rpx;
  border-radius: 20rpx;
  font-size: 24rpx;
  padding: 6rpx 12rpx;
  border-radius: 16rpx;
  font-size: 22rpx;
  font-weight: 500;
  white-space: nowrap;
  flex-shrink: 0;
  /* 确保状态标签不被压缩 */
  min-width: fit-content;
}
.camera-status.online {
@@ -629,52 +603,42 @@
.camera-video-container {
  position: relative;
  width: 100%;
  max-width: 100%;
  min-width: 0;
  /* height: 400rpx; */
  /* 移除所有装饰性样式,确保完全填充 */
  border-radius: 0;
  height: 100%;
  border-radius: 8rpx;
  overflow: hidden;
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  background-color: transparent;
  border: none;
  /* 确保在不同设备上的显示一致性 */
  flex-shrink: 0;
  /* 防止ezplayer超出容器 - 强化约束 */
  overflow: hidden !important;
  /* 新增:绝对定位约束 */
  position: relative !important;
  /* 新增:强制宽度约束,防止ezplayer超出 */
  max-width: 100vw !important;
  /* 新增:确保容器不会超出父元素 */
  contain: layout style paint !important;
  /* 新增:强制左对齐,防止右移 */
  left: 0 !important;
  right: 0 !important;
  /* 新增:强制填充整个屏幕 */
  /* width: 100vw !important;
  min-width: 100vw !important; */
  background-color: #f5f5f5;
}
/* 移除调试边框,避免影响ezplayer显示 */
/* 加载状态 */
.video-loading {
  width: 100%;
  height: 100%;
  max-width: 100%;
  min-width: 0;
/* 视频状态样式 */
.video-loading,
.video-error,
.video-offline,
.video-no-url {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background-color: #f8f9fa;
  /* 确保在不同设备上的显示一致性 */
  flex-shrink: 0;
  height: 100%;
  text-align: center;
}
.video-loading {
  background-color: #f8f9fa;
}
.video-error {
  background-color: #fff2f0;
  border: 1rpx solid #ffccc7;
}
.video-offline,
.video-no-url {
  background-color: #f5f5f5;
}
/* 加载动画 */
.loading-spinner {
  width: 60rpx;
  height: 60rpx;
@@ -683,8 +647,6 @@
  border-radius: 50%;
  animation: spin 1s linear infinite;
  margin-bottom: 16rpx;
  /* 确保动画在不同设备上的一致性 */
  flex-shrink: 0;
}
@keyframes spin {
@@ -692,650 +654,75 @@
  100% { transform: rotate(360deg); }
}
.loading-text {
  font-size: 26rpx;
.loading-text,
.error-text,
.offline-text,
.no-url-text {
  font-size: 24rpx;
  color: #666;
  font-weight: 500;
  text-align: center;
  /* 确保文字在不同设备上的一致性 */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
/* 错误状态 */
.video-error {
  width: 100%;
  height: 100%;
  max-width: 100%;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background-color: #fff2f0;
  border: 1rpx solid #ffccc7;
  /* 确保在不同设备上的显示一致性 */
  flex-shrink: 0;
}
.error-icon {
  width: 80rpx;
  height: 80rpx;
  opacity: 0.6;
  margin-bottom: 16rpx;
  filter: grayscale(100%) brightness(0) saturate(100%) invert(27%) sepia(51%) saturate(2878%) hue-rotate(346deg) brightness(104%) contrast(97%);
  /* 确保图标在不同设备上的一致性 */
  flex-shrink: 0;
  margin-top: 8rpx;
}
.error-text {
  font-size: 26rpx;
  color: #ff4d4f;
  font-weight: 500;
  margin-bottom: 20rpx;
  text-align: center;
  /* 确保文字在不同设备上的一致性 */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
/* 图标样式 */
.error-icon,
.offline-icon,
.no-url-icon {
  width: 60rpx;
  height: 60rpx;
  opacity: 0.5;
}
/* 重试按钮 */
.retry-btn {
  display: flex;
  align-items: center;
  gap: 8rpx;
  padding: 12rpx 24rpx;
  gap: 6rpx;
  padding: 8rpx 16rpx;
  background-color: #ff4d4f;
  color: white;
  border: none;
  border-radius: 20rpx;
  font-size: 24rpx;
  transition: all 0.3s ease;
  /* 确保按钮在不同设备上的一致性 */
  flex-shrink: 0;
  min-width: fit-content;
  border-radius: 16rpx;
  font-size: 22rpx;
  margin-top: 12rpx;
}
.retry-btn:active {
  background-color: #cf1322;
  transform: scale(0.98);
}
.retry-icon {
  width: 24rpx;
  height: 24rpx;
  filter: brightness(0) invert(1);
  /* 确保图标在不同设备上的一致性 */
  flex-shrink: 0;
}
/* 无播放地址状态 */
.video-no-url {
  width: 100%;
  height: 100%;
  max-width: 100%;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background-color: #f5f5f5;
  /* 确保在不同设备上的显示一致性 */
  flex-shrink: 0;
}
.no-url-icon {
  width: 80rpx;
  height: 80rpx;
  opacity: 0.4;
  margin-bottom: 16rpx;
  filter: grayscale(100%);
  /* 确保图标在不同设备上的一致性 */
  flex-shrink: 0;
}
.no-url-text {
  font-size: 26rpx;
  color: #999;
  font-weight: 500;
  text-align: center;
  /* 确保文字在不同设备上的一致性 */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
.video-wrapper {
  position: relative;
  width: 100%;
  height: 100%;
  max-width: 100%;
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  /* 确保在不同设备上的显示一致性 */
  flex-shrink: 0;
  /* 防止内容溢出 */
  overflow: hidden !important;
  /* 新增:绝对定位约束 */
  position: relative !important;
  /* 新增:移除所有边距和内边距 */
  margin: 0 !important;
  padding: 0 !important;
  /* 新增:强制左对齐 */
  left: 0 !important;
  right: 0 !important;
}
/* ezplayer组件样式优化 - 修复超出屏幕问题 */
.video-wrapper ezplayer {
  width: 100% !important;
  height: 100% !important;
  max-width: 100% !important;
  min-width: 0 !important;
  border-radius: 12rpx;
  overflow: hidden !important;
  /* 确保在不同设备上的显示一致性 */
  flex-shrink: 0;
  /* 防止超出屏幕的关键设置 */
  position: absolute !important;
  left: 0 !important;
  right: 0 !important;
  top: 0 !important;
  bottom: 0 !important;
  /* 强制约束尺寸 - 修复最小宽度问题 */
  max-width: 100% !important;
  max-height: 100% !important;
  /* 新增:强制约束到父容器 */
  transform: none !important;
  transform-origin: center center !important;
  /* 新增:确保不超出边界 */
  clip-path: inset(0 0 0 0) !important;
  /* 新增:防止任何形式的溢出 */
  contain: layout style paint !important;
  /* 新增:强制宽度约束,覆盖ezplayer的最小宽度限制 */
  min-width: 0 !important;
  min-height: 0 !important;
  /* 新增:确保组件完全约束在容器内 */
  box-sizing: border-box !important;
  /* 新增:移除所有边距和内边距 */
  margin: 0 !important;
  padding: 0 !important;
  /* 新增:强制完全填充容器 */
  inset: 0 !important;
}
/* 针对ezplayer组件的特殊约束 */
.video-wrapper ezplayer {
  /* 确保组件不会超出父容器 */
  box-sizing: border-box !important;
  /* 防止水平滚动 */
  overflow-x: hidden !important;
  overflow-y: hidden !important;
  /* 确保在flex容器中的行为 */
  flex: 0 0 auto !important;
  /* 防止缩放问题 */
  transform-origin: top left !important;
  /* 确保边框圆角生效 */
  border-radius: 12rpx !important;
  /* 新增:强制尺寸约束 */
  min-width: 0 !important;
  min-height: 0 !important;
  /* 新增:防止任何形式的拉伸 */
  flex-basis: auto !important;
  flex-grow: 0 !important;
  flex-shrink: 0 !important;
  /* 新增:确保定位正确 */
  position: absolute !important;
  top: 0 !important;
  left: 0 !important;
  right: 0 !important;
  bottom: 0 !important;
  /* 新增:强制宽度和高度 */
  width: 100% !important;
  height: 100% !important;
}
/* 新增:专门处理ezplayer暂停状态的样式 */
.video-wrapper ezplayer[data-paused="true"],
.video-wrapper ezplayer.paused {
  /* 强制约束宽度,防止超出屏幕 */
  width: 100% !important;
  max-width: 100% !important;
  min-width: 0 !important;
  /* 确保组件完全在容器内 */
  position: absolute !important;
  left: 0 !important;
  right: 0 !important;
  /* 防止任何形式的溢出 */
  overflow: hidden !important;
  /* 强制约束到父容器 */
  contain: layout style paint !important;
}
/* 新增:使用CSS Grid强制约束ezplayer */
.video-wrapper {
  display: grid !important;
  grid-template-columns: 1fr !important;
  grid-template-rows: 1fr !important;
  place-items: stretch !important;
}
/* 新增:只针对摄像头相关元素强制约束 */
.camera-list,
.camera-item,
.camera-video-container,
.video-wrapper,
.camera-header,
.camera-name,
.camera-status,
.camera-video-container > ezplayer,
.video-wrapper > ezplayer {
  max-width: 100% !important;
  min-width: 0 !important;
  box-sizing: border-box !important;
  overflow: hidden !important;
}
/* 新增:强制移除所有可能的边距和装饰 */
.camera-list,
.camera-item,
.camera-video-container,
.video-wrapper {
  margin: 0 !important;
  padding: 0 !important;
  border: none !important;
  border-radius: 0 !important;
  box-shadow: none !important;
  background: transparent !important;
}
/* 新增:特别针对ezplayer的强制约束 */
ezplayer {
  width: 100vw !important;
  height: 100% !important;
  max-width: 100vw !important;
  max-height: 100% !important;
  min-width: 100vw !important;
  min-height: 0 !important;
  position: absolute !important;
  left: 0 !important;
  right: 0 !important;
  top: 0 !important;
  bottom: 0 !important;
  overflow: hidden !important;
  box-sizing: border-box !important;
  contain: layout style paint !important;
  /* 新增:强制填充整个屏幕宽度 */
  margin: 0 !important;
  padding: 0 !important;
  transform: none !important;
  transform-origin: center center !important;
  /* 新增:强制移除所有装饰 */
  border: none !important;
  border-radius: 0 !important;
  box-shadow: none !important;
  background: transparent !important;
  /* 新增:强制约束到屏幕边缘 */
  inset: 0 !important;
}
.video-wrapper ezplayer {
  grid-column: 1 !important;
  grid-row: 1 !important;
  place-self: stretch !important;
  /* 强制完全填充网格单元格 */
  width: 100% !important;
  height: 100% !important;
  max-width: 100% !important;
  max-height: 100% !important;
  min-width: 0 !important;
  min-height: 0 !important;
}
/* 视频包装器的绝对定位约束 */
.video-wrapper {
  position: relative;
  width: 100%;
  height: 100%;
  max-width: 100%;
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  /* 确保在不同设备上的显示一致性 */
  flex-shrink: 0;
  /* 防止内容溢出 */
  overflow: hidden !important;
  /* 新增:绝对定位约束 */
  position: relative !important;
}
.live-player {
  width: 100%;
  height: 100%;
  max-width: 100%;
  min-width: 0;
  background-color: #000;
  border-radius: 12rpx;
  /* 确保在不同设备上的显示一致性 */
  flex-shrink: 0;
}
.video-overlay {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.3);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 10;
}
.play-overlay {
  width: 80rpx;
  height: 80rpx;
  background: rgba(0, 0, 0, 0.6);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.3s ease;
}
.play-overlay:active {
  transform: scale(0.9);
}
.play-icon {
  width: 40rpx;
  height: 40rpx;
  width: 20rpx;
  height: 20rpx;
  filter: brightness(0) invert(1);
}
.video-info {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  background: linear-gradient(transparent, rgba(0, 0, 0, 0.7));
  padding: 20rpx 16rpx 16rpx;
  color: white;
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.video-time {
  font-size: 24rpx;
  opacity: 0.9;
}
.video-status {
  font-size: 22rpx;
  opacity: 0.8;
  color: #52c41a;
}
/* 播放控制按钮 */
.video-controls {
  position: absolute;
  top: 16rpx;
  right: 16rpx;
  display: flex;
  gap: 12rpx;
  z-index: 20;
}
.control-btn {
  width: 60rpx;
  height: 60rpx;
  background: rgba(0, 0, 0, 0.6);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.3s ease;
}
.control-btn:active {
  transform: scale(0.9);
  background: rgba(0, 0, 0, 0.8);
}
.control-icon {
  width: 32rpx;
  height: 32rpx;
  filter: brightness(0) invert(1);
}
/* 调试按钮 */
.debug-controls {
  position: absolute;
  bottom: 16rpx;
  right: 16rpx;
  z-index: 20;
}
.debug-btn {
  padding: 8rpx 16rpx;
  background: rgba(255, 0, 0, 0.7);
  border-radius: 20rpx;
  font-size: 20rpx;
  color: white;
}
/* 离线状态 */
.video-offline {
/* 视频播放器容器 */
.video-wrapper {
  width: 100%;
  height: 100%;
  max-width: 100%;
  min-width: 0;
  background-color: #f5f5f5;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  border-radius: 12rpx;
  /* 确保在不同设备上的显示一致性 */
  flex-shrink: 0;
}
.offline-icon {
  width: 80rpx;
  height: 80rpx;
  opacity: 0.4;
  margin-bottom: 16rpx;
  filter: grayscale(100%);
  /* 确保图标在不同设备上的一致性 */
  flex-shrink: 0;
}
.offline-text {
  font-size: 28rpx;
  color: #999;
  font-weight: 500;
  text-align: center;
  /* 确保文字在不同设备上的一致性 */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
/* 操作按钮 */
.camera-actions {
.video-wrapper-ezplayer {
  width: 100%;
  max-width: 100%;
  min-width: 0;
  display: flex;
  gap: 16rpx;
  box-sizing: border-box;
  /* 确保在不同设备上的显示一致性 */
  flex-shrink: 0;
  height: 100%;
}
.action-btn {
  flex: 1;
  height: 72rpx;
  border-radius: 36rpx;
  font-size: 26rpx;
  border: none;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8rpx;
  transition: all 0.3s ease;
  box-sizing: border-box;
  /* 确保按钮在不同设备上的一致性 */
  min-width: 0;
  overflow: hidden;
}
.action-btn.primary {
  background-color: #1890FF;
  color: white;
}
.action-btn.primary:active {
  background-color: #096dd9;
  transform: scale(0.98);
}
.action-btn.secondary {
  background-color: #f5f5f5;
  color: #666;
  border: 1rpx solid #d9d9d9;
}
.action-btn.secondary:active {
  background-color: #e8e8e8;
  transform: scale(0.98);
}
/* 禁用状态 */
.action-btn[disabled] {
  background-color: #f5f5f5 !important;
  color: #bfbfbf !important;
  border-color: #d9d9d9 !important;
  cursor: not-allowed;
  opacity: 0.6;
  /* 确保禁用状态在不同设备上的一致性 */
  transform: none !important;
}
.action-btn[disabled]:active {
  transform: none !important;
  background-color: #f5f5f5 !important;
}
.action-btn.primary[disabled] {
  background-color: #d9d9d9 !important;
  color: #bfbfbf !important;
}
.action-btn.secondary[disabled] {
  background-color: #f5f5f5 !important;
  color: #bfbfbf !important;
  border-color: #d9d9d9 !important;
}
.action-icon {
  width: 32rpx;
  height: 32rpx;
  /* 确保图标在不同设备上的一致性 */
  flex-shrink: 0;
}
/* 响应式优化 - 确保在不同设备上的一致性 */
@media (max-width: 400px) {
  .camera-item {
    padding: 20rpx;
    margin-bottom: 16rpx;
  }
  
  .camera-header {
    margin-bottom: 16rpx;
  }
  
  .camera-name {
    font-size: 28rpx;
  }
  .camera-status {
    font-size: 22rpx;
    padding: 6rpx 12rpx;
  }
  .camera-video-container {
    height: 320rpx;
    margin-bottom: 16rpx;
  }
  .action-btn {
    height: 64rpx;
    font-size: 24rpx;
  }
  .action-icon {
    width: 28rpx;
    height: 28rpx;
  }
}
/* 确保在不同设备上的一致性 - 额外的兼容性处理 */
.camera-item {
  /* 防止在不同设备上的布局差异 */
  transform: translateZ(0);
  backface-visibility: hidden;
  perspective: 1000px;
}
.camera-video-container {
  /* 防止在不同设备上的显示差异 */
  transform: translateZ(0);
  backface-visibility: hidden;
}
/* 修复可能的溢出问题 */
.camera-list {
  max-width: 100%;
  overflow: hidden;
  /* 确保在不同设备上的一致性 */
  transform: translateZ(0);
}
.camera-item {
  overflow: hidden;
  /* 确保在不同设备上的一致性 */
  transform: translateZ(0);
}
/* 针对真机的特殊优化 */
@media screen and (max-device-width: 750px) {
  .camera-item {
    /* 真机上可能需要稍微调整间距 */
    margin-bottom: 16rpx;
  }
  .camera-video-container {
    /* 真机上可能需要稍微调整高度 */
    height: 380rpx;
  }
  .action-btn {
    /* 真机上可能需要稍微调整高度 */
    height: 68rpx;
  }
}
/* 土壤墒情站专用样式 */
.weather-data-item.soil-item {
@@ -1400,8 +787,10 @@
  display: flex;
  flex-direction: column;
  gap: 8rpx;
  min-width: 0; /* 防止内容溢出 */
  overflow: hidden; /* 隐藏溢出内容 */
  min-width: 0;
  /* 防止内容溢出 */
  overflow: hidden;
  /* 隐藏溢出内容 */
}
.weather-data-item.soil-item .data-label {
@@ -1409,9 +798,12 @@
  color: #333;
  font-weight: 500;
  line-height: 1.4;
  white-space: nowrap; /* 防止标签换行 */
  overflow: hidden; /* 隐藏溢出内容 */
  text-overflow: ellipsis; /* 显示省略号 */
  white-space: nowrap;
  /* 防止标签换行 */
  overflow: hidden;
  /* 隐藏溢出内容 */
  text-overflow: ellipsis;
  /* 显示省略号 */
}
.weather-data-item.soil-item .data-value {
@@ -1419,9 +811,12 @@
  color: #1890ff;
  font-weight: 700;
  line-height: 1.2;
  white-space: nowrap; /* 防止数值换行 */
  overflow: hidden; /* 隐藏溢出内容 */
  text-overflow: ellipsis; /* 显示省略号 */
  white-space: nowrap;
  /* 防止数值换行 */
  overflow: hidden;
  /* 隐藏溢出内容 */
  text-overflow: ellipsis;
  /* 显示省略号 */
}
/* 土壤墒情站图标优化 */
@@ -1755,90 +1150,4 @@
    width: 32rpx;
    height: 32rpx;
  }
}
/* ezplayer组件样式 - 防止变形和超出屏幕 */
.video-wrapper ezplayer {
  /* 基础尺寸约束 */
  width: 100% !important;
  height: 100% !important;
  max-width: 100% !important;
  max-height: 100% !important;
  min-width: 0 !important;
  min-height: 0 !important;
  /* 位置约束 */
  position: relative !important;
  left: 0 !important;
  right: 0 !important;
  top: 0 !important;
  bottom: 0 !important;
  /* 溢出控制 */
  overflow: hidden !important;
  clip-path: inset(0 0 0 0) !important;
  /* 变换约束 */
  transform: none !important;
  transform-origin: center center !important;
  /* 布局约束 */
  contain: layout style paint !important;
  flex-basis: auto !important;
  flex-grow: 0 !important;
  flex-shrink: 0 !important;
  /* 盒模型约束 */
  box-sizing: border-box !important;
  margin: 0 !important;
  padding: 0 !important;
  /* 渲染优化 */
  backface-visibility: hidden !important;
  perspective: 1000px !important;
  will-change: auto !important;
  /* 真机特殊处理 */
  -webkit-transform: none !important;
  -webkit-transform-origin: center center !important;
  -webkit-backface-visibility: hidden !important;
  -webkit-perspective: 1000px !important;
}
/* 真机上的特殊约束 */
@media screen and (max-device-width: 750px) {
  .video-wrapper ezplayer {
    /* 真机上更严格的约束 */
    max-width: 100vw !important;
    max-height: 100vh !important;
    left: 0 !important;
    right: 0 !important;
    top: 0 !important;
    bottom: 0 !important;
    /* 防止真机上的缩放问题 */
    -webkit-transform: scale(1) !important;
    transform: scale(1) !important;
    /* 真机上的溢出控制 */
    overflow: hidden !important;
    clip: rect(0, auto, auto, 0) !important;
  }
}
/* 暂停状态的特殊处理 */
.video-wrapper ezplayer[data-paused="true"] {
  /* 暂停时保持尺寸 */
  width: 100% !important;
  height: 100% !important;
  max-width: 100% !important;
  max-height: 100% !important;
  /* 暂停时防止变形 */
  transform: none !important;
  -webkit-transform: none !important;
  /* 暂停时的溢出控制 */
  overflow: hidden !important;
  clip-path: inset(0 0 0 0) !important;
project.private.config.json
@@ -3,7 +3,7 @@
  "projectname": "irrigate_user",
  "setting": {
    "compileHotReLoad": true,
    "urlCheck": false
    "urlCheck": true
  },
  "libVersion": "3.9.1"
}
utils/projectConfig.js
@@ -4,8 +4,8 @@
  URL_233: 'https://wanzheng.dayuyanjiuyuan.top/',
  URL_55: 'https://irrigate.dayuyanjiuyuan.top/',
  URL_166: 'https://wanzheng.dayuyanjiuyuan.top/frp/',
  // URL_121: 'https://shifanqu1.dayuyanjiuyuan.top/',
  URL_121: 'https://wanzheng.dayuyanjiuyuan.top/frp/',
  URL_121: 'https://shifanqu1.dayuyanjiuyuan.top/',
  // URL_121: 'https://wanzheng.dayuyanjiuyuan.top/frp/',
  URL_87: 'http://192.168.10.87:54321/'
};