管灌系统农户端微信小程序(嘉峪关应用)
添加clientId字段到全局状态,优化请求参数处理,更新页面路由,调整取水口和灌溉相关界面,增强用户体验。
17个文件已修改
5个文件已添加
2780 ■■■■ 已修改文件
api/request.js 27 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app.json 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
images/irrigation.svg 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/createIrrigation/createIrrigation.wxml 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/createIrrigation/createIrrigation.wxss 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/groupDetail/groupDetail.js 168 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/groupDetail/groupDetail.wxml 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/groupDetail/groupDetail.wxss 199 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/home/home.js 1169 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/home/home.wxml 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/irrigation/irrigation.js 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/irrigation/irrigation.wxml 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/irrigationDetail/irrigationDetail.js 308 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/irrigationDetail/irrigationDetail.json 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/irrigationDetail/irrigationDetail.wxml 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/irrigationDetail/irrigationDetail.wxss 234 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/login/login.js 351 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/login/login.wxml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/login/login.wxss 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/waterIntake/waterIntake.js 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
utils/storage.js 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
api/request.js
@@ -31,8 +31,16 @@
    form,
    isShowLoding,
    timeout,
    header
    header,
    useParams
  } = _options
  // 检查url是否为undefined
  if (!url) {
    console.error('请求URL不能为空');
    return Promise.reject(new Error('请求URL不能为空'));
  }
  const app = getApp()
  // 设置请求头
  if (form) {
@@ -58,7 +66,7 @@
  return new Promise((resolve, reject) => {
    // 获取最新的 BASEURL
    let currentBaseUrl = app.globalData.baseUrl || config.BASEURL;
    console.log("url:" + currentBaseUrl + url);
    if (isShowLoding) {
      wx.showLoading({
@@ -71,6 +79,12 @@
      myUrl = url;
    } else {
      myUrl = currentBaseUrl + url;
    }
    // 如果 useParams 为 true,拼接查询参数
    if (useParams && data) {
      const queryString = objToQueryString(data); // 使用上面定义的函数
      myUrl += `?${queryString}`; // 拼接查询字符串
      data = {}; // 请求体数据设为空
    }
    wx.request({
      url: myUrl,
@@ -116,7 +130,14 @@
    })
  })
}
function objToQueryString(obj) {
  return Object.keys(obj)
      .map(key => {
          // 对键和值进行 URL 编码
          return `${encodeURIComponent(key)}=${encodeURIComponent(obj[key])}`;
      })
      .join('&'); // 将所有键值对用 '&' 连接起来
}
// 封装toast函数
function showToast(title, icon = 'none', duration = 2500, mask = false) {
  wx.showToast({
app.js
@@ -23,6 +23,7 @@
    token:"",
    isLoggedIn:false,
    operator:"2025030416200600006",
    clientId:"",
    AppID:"wxbc2b6a00dd904ead"
  }
})
app.json
@@ -1,8 +1,6 @@
{
  "pages": [
    "pages/irrigation/irrigation",
    "pages/createIrrigation/createIrrigation",
    "pages/groupDetail/groupDetail",
    "pages/home/home",
    "pages/valveList/valveList",
    "pages/feedback/feedback",
@@ -17,7 +15,11 @@
    "pages/personCharge/personcharge",
    "pages/openCard/openCard",
    "pages/rechargeMoney/rechargMoney",
    "pages/rechargeCard/rechargeCard"
    "pages/rechargeCard/rechargeCard",
    "pages/irrigation/irrigation",
    "pages/createIrrigation/createIrrigation",
    "pages/irrigationDetail/irrigationDetail",
    "pages/groupDetail/groupDetail"
  ],
  "window": {
    "navigationBarTextStyle": "white",
images/irrigation.svg
New file
@@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg width="24" height="24" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M14 6.67578C8.02198 10.1339 4 16.5973 4 24.0001M14 6.67578V14.0001M14 6.67578H6.67564" stroke="#4090FF" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/><path d="M6.67564 34C10.1337 39.978 16.5972 44 24 44M6.67564 34H14M6.67564 34V41.3244" stroke="#4090FF" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/><path d="M34 41.3244C39.978 37.8663 44 31.4028 44 24M34 41.3244V34M34 41.3244H41.3244" stroke="#4090FF" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/><path d="M41.3242 14C37.8661 8.02199 31.4027 4 23.9999 4M41.3242 14H33.9999M41.3242 14V6.67564" stroke="#4090FF" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/></svg>
pages/createIrrigation/createIrrigation.wxml
@@ -34,8 +34,8 @@
          <!-- 轮灌组列表 -->
          <view class="group-list {{item.expanded ? 'expanded' : ''}}">
            <block wx:for="{{item.groups}}" wx:for-item="group" wx:for-index="groupIndex" wx:key="id">
              <view class="group-item {{group.selected ? 'selected' : ''}}">
                <view class="group-info" bindtap="navigateToGroupDetail" data-project-index="{{index}}" data-group-index="{{groupIndex}}">
              <view class="group-item {{group.selected ? 'selected' : ''}}" bindtap="navigateToGroupDetail" data-project-index="{{index}}" data-group-index="{{groupIndex}}">
                <view class="group-info"  >
                  <view class="group-name">{{group.name}}</view>
                </view>
                <view class="group-duration">
pages/createIrrigation/createIrrigation.wxss
@@ -162,6 +162,25 @@
  align-items: center;
  padding: 25rpx 30rpx;
  border-top: 1rpx solid #eee;
  position: relative;
  transition: all 0.3s ease;
}
.group-item::after {
  content: '';
  position: absolute;
  right: 15rpx;
  top: 50%;
  transform: translateY(-50%);
  width: 16rpx;
  height: 16rpx;
  border-top: 2rpx solid #999;
  border-right: 2rpx solid #999;
  transform: translateY(-50%) rotate(45deg);
}
.group-item:active {
  background-color: #e6f7ff;
}
.group-item.selected {
@@ -172,16 +191,44 @@
  flex: 1;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
}
.group-name {
  font-size: 26rpx;
  color: #666;
  position: relative;
  padding-left: 10rpx;
  background-color: rgba(24, 144, 255, 0.1);
  padding: 4rpx 20rpx;
  border-radius: 10rpx;
}
.group-hint {
  font-size: 22rpx;
  color: #1890FF;
  margin-left: 10rpx;
  background-color: rgba(24, 144, 255, 0.1);
  padding: 4rpx 10rpx;
  border-radius: 10rpx;
}
/* .group-name::before {
  content: '';
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  width: 6rpx;
  height: 6rpx;
  background-color: #1890FF;
  border-radius: 50%;
} */
.group-duration {
  display: flex;
  align-items: center;
  margin-right: 20rpx; /* 为右侧箭头留出空间 */
}
.duration-input {
pages/groupDetail/groupDetail.js
@@ -5,79 +5,179 @@
   * 页面的初始数据
   */
  data: {
    projectId: '',
    projectName: '',
    groupId: '',
    groupName: '',
    valveList: [
      // 模拟数据,实际应从API获取
      { id: '1', name: '阀控器1', status: 'online', location: '位置A' },
      { id: '2', name: '阀控器2', status: 'offline', location: '位置B' },
      { id: '3', name: '阀控器3', status: 'online', location: '位置C' },
      { id: '4', name: '阀控器4', status: 'online', location: '位置D' },
      { id: '5', name: '阀控器5', status: 'offline', location: '位置E' }
    ],
    loading: false
    groupId: '',
    waterOutletList: [],
    refreshing: false,
    isIrrigating: false // 是否正在灌溉中
  },
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    console.log('接收到的参数:', options);
    if (options) {
      // 直接使用传递的isIrrigating参数,而不是根据status判断
      const isIrrigating = options.isIrrigating === 'true';
      console.log('灌溉状态判断:', options.status, '是否正在灌溉:', isIrrigating);
      // 处理接收到的参数
      this.setData({
        projectId: options.projectId || '',
        projectName: options.projectName || '',
        groupName: options.groupName || '',
        groupId: options.groupId || '',
        groupName: options.groupName || ''
        isIrrigating: isIrrigating
      });
      
      console.log('设置后的数据:', this.data);
      // 设置导航栏标题
      wx.setNavigationBarTitle({
        title: this.data.groupName || '轮灌组详情'
      });
      
      // 获取阀控器列表
      this.fetchValveList();
      this.loadWaterOutletData();
    }
  },
  /**
   * 获取阀控器列表
   * 加载取水口数据
   */
  fetchValveList: function () {
    this.setData({ loading: true });
  loadWaterOutletData: function() {
    this.setData({
      refreshing: true
    });
    
    // 这里应该是实际的API请求
    // 模拟API请求延迟
    console.log('加载取水口数据,灌溉状态:', this.data.isIrrigating);
    // 模拟数据
    let mockData = {
      waterOutlets: []
    };
    // 生成取水口数据,所有取水口都有命令状态
    mockData.waterOutlets = [
      {
        id: 1,
        name: '取水口 A-1',
        status: 'online',
        commandStatus: 'sent' // 命令已下发
      },
      {
        id: 2,
        name: '取水口 A-2',
        status: 'online',
        commandStatus: 'unsent' // 命令未下发
      },
      {
        id: 3,
        name: '取水口 A-3',
        status: 'offline',
        commandStatus: 'unsent' // 命令未下发
      }
    ];
    // 模拟网络请求延迟
    setTimeout(() => {
      this.setData({ loading: false });
      // 实际数据已在data中初始化,这里只是模拟请求完成
      this.setData({
        waterOutletList: mockData.waterOutlets,
        refreshing: false
      });
      console.log('设置取水口数据完成:', this.data.waterOutletList);
    }, 1000);
    
    // 实际API请求示例
    // 实际项目中应该使用wx.request获取数据
    // wx.request({
    //   url: 'your-api-url',
    //   data: {
    //     projectId: this.data.projectId,
    //     groupId: this.data.groupId
    //   },
    //   url: `https://your-api-url/groups/${this.data.groupId}/waterOutlets`,
    //   method: 'GET',
    //   success: (res) => {
    //     this.setData({
    //       valveList: res.data,
    //       loading: false
    //     });
    //     if (res.data && res.data.code === 0) {
    //       this.setData({
    //         waterOutletList: res.data.data.waterOutlets,
    //         refreshing: false
    //       });
    //     } else {
    //       wx.showToast({
    //         title: '获取数据失败',
    //         icon: 'none'
    //       });
    //       this.setData({
    //         refreshing: false
    //       });
    //     }
    //   },
    //   fail: () => {
    //     this.setData({ loading: false });
    //     wx.showToast({
    //       title: '获取数据失败',
    //       title: '网络错误',
    //       icon: 'none'
    //     });
    //     this.setData({
    //       refreshing: false
    //     });
    //   }
    // });
  },
  /**
   * 下拉刷新处理函数
   */
  onRefresh: function() {
    this.loadWaterOutletData();
  },
  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {
  },
  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {
  },
  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {
  },
  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {
  },
  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh: function () {
  },
  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {
  },
  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {
  },
  /**
   * 返回上一页
   */
  goBack: function () {
pages/groupDetail/groupDetail.wxml
@@ -9,40 +9,49 @@
    </view>
  </view>
  <!-- 阀控器列表 -->
  <!-- 取水口列表 -->
  <view class="valve-list-container">
    <view class="section-title">取水口阀控器列表</view>
    <!-- 加载中 -->
    <!-- 加载中
    <view class="loading-container" wx:if="{{loading}}">
      <view class="loading-icon"></view>
      <view class="loading-text">加载中...</view>
    </view>
    </view> -->
    
    <!-- 阀控器列表 -->
    <view class="valve-list" wx:else>
      <block wx:for="{{valveList}}" wx:key="id">
    <!-- 取水口列表 - 可下拉刷新的scroll-view -->
    <scroll-view
      class="valve-list"
      scroll-y="true"
      refresher-enabled="{{true}}"
      refresher-threshold="50"
      refresher-default-style="black"
      refresher-background="#f2f2f2"
      refresher-triggered="{{refreshing}}"
      bindrefresherrefresh="onRefresh"
     >
      <block wx:for="{{waterOutletList}}" wx:key="id">
        <view class="valve-item">
          <view class="valve-info">
            <view class="valve-name">{{item.name}}</view>
            <view class="valve-location">{{item.location}}</view>
            <view class="valve-name">
              <text>{{item.name}}</text>
              <view class="valve-status-inline {{item.status === 'online' ? 'online' : 'offline'}}">
                {{item.status === 'online' ? '在线' : '离线'}}
              </view>
            </view>
          </view>
          <view class="valve-status {{item.status === 'online' ? 'online' : 'offline'}}">
            {{item.status === 'online' ? '在线' : '离线'}}
          <view class="command-status {{item.commandStatus}}">
            {{item.commandStatus === 'sent' ? '命令已下发' : '命令未下发'}}
          </view>
        </view>
      </block>
    </view>
    <!-- 空状态 -->
    <view class="empty-state" wx:if="{{!loading && valveList.length === 0}}">
      <image class="empty-icon" src="/images/empty.svg" mode="aspectFit"></image>
      <view class="empty-text">暂无阀控器数据</view>
    </view>
      <!-- 空状态 -->
      <view class="empty-state" wx:if="{{waterOutletList.length === 0}}">
        <image class="empty-icon" src="/images/empty.svg" mode="aspectFit"></image>
        <view class="empty-text">暂无取水口数据</view>
      </view>
    </scroll-view>
  </view>
  <!-- 底部按钮 -->
  <view class="bottom-button">
    <button class="back-button" hover-class="back-button-hover" bindtap="goBack">返回</button>
  </view>
</view> 
pages/groupDetail/groupDetail.wxss
@@ -1,15 +1,16 @@
.group-detail-container {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  background-color: #f5f5f5;
  height: 100vh;
  background-color: #F5F5F5;
}
/* 页面标题样式 */
.page-header {
  background-color: #1890FF;
  background-color: #FFFFFF;
  padding: 30rpx;
  color: #fff;
  box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
  margin-bottom: 20rpx;
}
.header-content {
@@ -23,43 +24,141 @@
}
.project-name {
  font-size: 24rpx;
  opacity: 0.8;
  font-size: 28rpx;
  color: #666666;
  margin-bottom: 10rpx;
}
.group-name {
  font-size: 32rpx;
  font-weight: 500;
  font-size: 36rpx;
  font-weight: bold;
  color: #333333;
}
/* 阀控器列表容器 */
/* 取水口列表容器 */
.valve-list-container {
  flex: 1;
  padding: 30rpx;
  padding: 0 30rpx;
  overflow: hidden;
}
.section-title {
  font-size: 28rpx;
  color: #333;
  font-weight: 500;
/* 取水口列表 */
.valve-list {
  height: 100%;
}
/* 取水口项目 */
.valve-item {
  background-color: #FFFFFF;
  border-radius: 12rpx;
  padding: 30rpx;
  margin-bottom: 20rpx;
  display: flex;
  justify-content: space-between;
  align-items: center;
  box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
}
.valve-info {
  flex: 1;
}
.valve-name {
  font-size: 32rpx;
  font-weight: 500;
  color: #333333;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
}
.valve-status-container {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
}
.valve-status {
  padding: 8rpx 20rpx;
  border-radius: 30rpx;
  font-size: 24rpx;
  font-weight: 500;
  margin-bottom: 10rpx;
}
.valve-status.online {
  background-color: rgba(82, 196, 26, 0.1);
  color: #52C41A;
}
.valve-status.offline {
  background-color: rgba(245, 34, 45, 0.1);
  color: #F5222D;
}
/* 内联状态样式 */
.valve-status-inline {
  font-size: 24rpx;
  font-weight: 500;
  padding: 4rpx 12rpx;
  border-radius: 20rpx;
  margin-left: 12rpx;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 32rpx;
  line-height: 1;
}
.valve-status-inline.online {
  background-color: rgba(82, 196, 26, 0.1);
  color: #52C41A;
}
.valve-status-inline.offline {
  background-color: rgba(245, 34, 45, 0.1);
  color: #F5222D;
}
/* 命令状态样式 */
.command-status {
  padding: 8rpx 20rpx;
  border-radius: 30rpx;
  font-size: 24rpx;
  font-weight: 500;
  text-align: center;
  min-width: 160rpx;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 40rpx;
  line-height: 1;
}
.command-status.sent {
  background-color: rgba(82, 196, 26, 0.1);
  color: #52C41A;
}
.command-status.unsent {
  background-color: rgba(250, 173, 20, 0.1);
  color: #FAAD14;
}
/* 加载中样式 */
.loading-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 60rpx 0;
  align-items: center;
  height: 300rpx;
}
.loading-icon {
  width: 60rpx;
  height: 60rpx;
  border: 4rpx solid #f3f3f3;
  border-top: 4rpx solid #1890FF;
  width: 80rpx;
  height: 80rpx;
  border: 6rpx solid #f3f3f3;
  border-top: 6rpx solid #3498db;
  border-radius: 50%;
  animation: spin 1s linear infinite;
  margin-bottom: 20rpx;
@@ -71,67 +170,17 @@
}
.loading-text {
  font-size: 26rpx;
  color: #999;
}
/* 阀控器列表样式 */
.valve-list {
  display: flex;
  flex-direction: column;
}
.valve-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 30rpx;
  background-color: #fff;
  margin-bottom: 20rpx;
  border-radius: 8rpx;
  box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
}
.valve-info {
  display: flex;
  flex-direction: column;
}
.valve-name {
  font-size: 28rpx;
  color: #333;
  margin-bottom: 10rpx;
  font-weight: 500;
}
.valve-location {
  font-size: 24rpx;
  color: #999;
}
.valve-status {
  padding: 8rpx 20rpx;
  border-radius: 30rpx;
  font-size: 24rpx;
}
.valve-status.online {
  background-color: #e6f7ff;
  color: #1890FF;
}
.valve-status.offline {
  background-color: #fff1f0;
  color: #f5222d;
  color: #666666;
}
/* 空状态样式 */
.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 100rpx 0;
  align-items: center;
  height: 400rpx;
}
.empty-icon {
@@ -141,8 +190,8 @@
}
.empty-text {
  font-size: 26rpx;
  color: #999;
  font-size: 28rpx;
  color: #999999;
}
/* 底部按钮样式 */
pages/home/home.js
@@ -4,7 +4,9 @@
  get,
  post
} = require('../../api/request.js');
const { PROJECT_URLS } = require('../../api/config.js');
const {
  PROJECT_URLS
} = require('../../api/config.js');
Page({
  /**
@@ -17,7 +19,7 @@
    waterIntakeName: "",
    image: "/images/ic_head_bg.jpg",
    userPhone: "",
    userName: "请登录",
    userName: "请点击登录",
    scrollViewHeight: 0,
    listData: [],
    isRefreshing: false,
@@ -32,13 +34,22 @@
    lastIntakeName: "",
    showProjectDialog: false,
    selectedProject: '',
    avatarTapCount: 0
    avatarTapCount: 0,
    isFromLogin: false
  },
  openValve: function (e) {
    wx.navigateTo({
      url: '/pages/waterIntake/waterIntake',
    })
    const app = getApp();
    if (app.globalData.isLoggedIn) {
      wx.navigateTo({
        url: '/pages/waterIntake/waterIntake',
      })
    } else {
      wx.showToast({
        title: '请先登录',
        icon: 'error'
      })
    }
  },
  calculateScrollViewHeight: function () {
    wx.createSelectorQuery().selectAll('.list-item').boundingClientRect((rects) => {
@@ -79,67 +90,171 @@
   * 生命周期函数--监听页面加载
   */
  onLoad(options) {
    // 检查是否已选择项目
    const { PROJECT_URLS } = require('../../api/config.js');
    storage.getItem('selectedProject').then((project) => {
      if (project) {
        this.setData({
          selectedProject: project
        });
        // 确保全局变量存在
        getApp().globalData = getApp().globalData || {};
        // 设置 baseUrl
        const baseUrl = PROJECT_URLS[project];
        getApp().globalData.baseUrl = baseUrl;
        getApp().globalData.selectedProject = project;
        // 根据项目设置对应的tag
        if (project === 'JYG') {
          getApp().globalData.tag = 'ym'; // 嘉峪关项目对应tag为ym
        } else if (project === 'MQ') {
          getApp().globalData.tag = 'mq'; // 民勤项目对应tag为mq
        }
        console.log('加载已保存的项目:', project, '域名:', baseUrl, 'tag:', getApp().globalData.tag);
        // 检查登录状态
        if (!getApp().globalData.isLoggedIn) {
          this.checkLoginStatus();
          return; // 如果未登录,等待跳转到登录页面
        }
      } else {
        // 首次进入,显示项目选择弹窗
        this.setData({
          showProjectDialog: true
        });
        return; // 等待用户选择项目
    console.log('home页面onLoad开始,参数:', options);
    // 检查是否从登录页面返回
    let fromLogin = false;
    // 检查URL参数
    if (options && options.fromLogin === 'true') {
      console.log('检测到URL参数fromLogin=true');
      fromLogin = true;
    }
    // 检查是否有临时标记
    try {
      const tempFromLogin = wx.getStorageSync('_temp_from_login');
      console.log('读取到的临时标记值:', tempFromLogin);
      if (tempFromLogin === 'true') {
        console.log('检测到临时fromLogin标记');
        fromLogin = true;
        // 延迟清除临时标记,确保其他地方有足够时间读取
        setTimeout(() => {
          try {
            wx.removeStorageSync('_temp_from_login');
            console.log('自动清除临时fromLogin标记');
          } catch (e) {
            console.error('清除临时标记失败:', e);
          }
        }, 10000); // 延长到10秒
      }
      //判断本地是否保存sessionId
      // 使用 wx.nextTick 等待页面渲染完成
      wx.nextTick(() => {
        this.calculateScrollViewHeight();
      });
      //当开阀成功后调用刷新
      console.log("onLoad:" + options.param);
      if (options.param) {
        wx.showToast({
          title: '开阀成功',
          icon: 'success',
          duration: 3000
        })
        this.getOpenList();
      }
      this.initData();
    }).catch(err => {
      console.error('Failed to get selectedProject:', err);
      // 出错时也显示项目选择弹窗
    } catch (e) {
      console.error('读取临时标记失败:', e);
    }
    console.log('home页面加载,fromLogin:', fromLogin, '参数:', options);
    // 设置fromLogin标志
    if (fromLogin) {
      console.log('设置isFromLogin=true');
      this.setData({
        showProjectDialog: true
        isFromLogin: true
      });
    });
    }
    // 延迟执行剩余的初始化过程,以确保临时标记和URL参数能被正确处理
    setTimeout(() => {
      this.initializePage(options, fromLogin);
    }, 100);
  },
  // 新增的初始化页面辅助函数,分离出onLoad中的逻辑以便延迟执行
  initializePage(options, fromLogin) {
    // 检查是否已选择项目
    const {
      PROJECT_URLS
    } = require('../../api/config.js');
    // 确保全局变量存在
    getApp().globalData = getApp().globalData || {};
    storage.getItemSafe('selectedProject')
      .then((project) => {
        if (project) {
          this.setData({
            selectedProject: project
          });
          // 设置 baseUrl
          const baseUrl = PROJECT_URLS[project];
          getApp().globalData.baseUrl = baseUrl;
          getApp().globalData.selectedProject = project;
          // 根据项目设置对应的tag
          if (project === 'JYG') {
            getApp().globalData.tag = 'ym'; // 嘉峪关项目对应tag为ym
          } else if (project === 'MQ') {
            getApp().globalData.tag = 'mq'; // 民勤项目对应tag为mq
          }
          console.log('加载已保存的项目:', project, '域名:', baseUrl, 'tag:', getApp().globalData.tag);
          // 检查sessionId是否存在
          return storage.getItemSafe('sessionId');
        } else {
          // 首次进入,显示项目选择弹窗
          this.setData({
            showProjectDialog: true
          });
          return Promise.reject({
            type: 'project_not_selected',
            message: '未选择项目'
          }); // 终止后续处理
        }
      })
      .then(sessionId => {
        if (sessionId) {
          // 如果sessionId存在,设置全局登录状态
          getApp().globalData.sessionId = sessionId;
          getApp().globalData.isLoggedIn = true;
          // 尝试获取clientId
          return storage.getItemSafe('clientId');
        } else {
          return Promise.reject({
            type: 'session_not_found',
            message: '未找到sessionId'
          });
        }
      })
      .then(clientId => {
        if (clientId) {
          getApp().globalData.clientId = clientId;
        }
        // 继续初始化页面
        this.continueInitPage(options);
      })
      .catch(err => {
        // 将错误对象规范化
        const error = typeof err === 'object' ? err : {
          type: 'unknown',
          message: String(err)
        };
        console.log('获取存储数据中断:', error.message);
        // 如果是从登录页返回或已登录,不再跳转
        if (fromLogin || getApp().globalData.isLoggedIn) {
          console.log('从登录页返回或已登录,继续初始化页面');
          this.continueInitPage(options);
          return;
        }
        // 处理未选择项目的情况
        if (error.type === 'project_not_selected') {
          console.log('未选择项目,显示项目选择弹窗');
          this.setData({
            showProjectDialog: true
          });
          return;
        }
        // 处理未找到sessionId的情况
        if (error.type === 'session_not_found' && this.data.selectedProject) {
          // 检查是否已从登录页返回
          const isReturning = this.getFromLogin();
          console.log('未找到sessionId,是否从登录页返回:', isReturning);
          // 如果已经是从登录页返回的,不要再跳回去
          if (isReturning) {
            console.log('已经从登录页返回,不再跳转回去');
            this.continueInitPage(options);
            return;
          }
          console.log('未找到sessionId,跳转到登录页');
          wx.redirectTo({
            url: `/pages/login/login?project=${this.data.selectedProject}`
          });
          return;
        }
        // 其他未知错误,尝试继续初始化页面
        console.warn('未知错误,尝试继续初始化页面:', error);
        this.continueInitPage(options);
      });
  },
  /**
@@ -153,21 +268,83 @@
   * 生命周期函数--监听页面显示
   */
  onShow() {
    console.log('home页面onShow开始');
    // 获取当前页面的参数
    const pages = getCurrentPages();
    const currentPage = pages[pages.length - 1];
    let fromLogin = false;
    // 检查是否有fromLogin参数
    if (currentPage && currentPage.options && currentPage.options.fromLogin === 'true') {
      console.log('onShow: 检测到fromLogin参数,设置isFromLogin标记');
      fromLogin = true;
      this.setData({
        isFromLogin: true
      });
    }
    // 检查是否有临时标记
    try {
      const tempFromLogin = wx.getStorageSync('_temp_from_login');
      console.log('onShow: 读取到的临时标记值:', tempFromLogin);
      if (tempFromLogin === 'true') {
        console.log('onShow: 检测到临时fromLogin标记');
        fromLogin = true;
        this.setData({
          isFromLogin: true
        });
      }
    } catch (e) {
      console.error('onShow: 读取临时标记失败:', e);
    }
    // 初始化处理
    if (fromLogin || this.data.isFromLogin) {
      console.log('onShow: 从登录页返回,不进行登录检查');
    } else {
      console.log('onShow: 正常显示页面');
      // 延迟检查登录状态,确保能正确识别临时标记
      setTimeout(() => {
        this.checkLoginStatusIfNeeded();
      }, 300);
    }
  },
  // 检查登录状态(仅在需要时)
  checkLoginStatusIfNeeded() {
    // 再次确认是否从登录页返回
    if (this.getFromLogin()) {
      console.log('检测到从登录页返回的标记,不进行登录检查');
      return;
    }
    // 再次检查全局登录状态
    if (getApp().globalData.isLoggedIn) {
      console.log('检测到全局登录状态,不进行登录检查');
      return;
    }
    console.log('执行登录状态检查');
    this.checkLoginStatus();
  },
  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide() {
    // 页面隐藏时考虑清理临时标记
    this.cleanupTempMarkers();
  },
  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload() {
    // 页面卸载时清理临时标记
    this.cleanupTempMarkers();
  },
  /**
@@ -222,6 +399,24 @@
      icon: 'none'
    })
  },
  //解绑用户
  unbind() {
    wx.showModal({
      title: '解绑确认',
      content: '确定要解绑当前账号吗?',
      success: (res) => {
        if (res.confirm) {
          this.unBindPost()
        }
      }
    });
  },
  //轮灌
  irrigation() {
    wx.navigateTo({
      url: '/pages/irrigation/irrigation',
    })
  },
  handleChange(e) {
    const item = e.currentTarget.dataset.item;
    console.log(item);
@@ -261,7 +456,7 @@
      rtuAddr: rtuAddr,
      vcNum: vcNum, //虚拟卡ID
      orderNo: orderNo,
      operator: app.globalData.operator //操作员
      operator: app.globalData.clientId //操作员
    };
    console.log("postCloseValaue" + data);
    post({
@@ -298,29 +493,83 @@
   */
  getOpenList() {
    const app = getApp();
    // 检查是否从登录页返回
    const fromLogin = this.getFromLogin();
    // 检查clientId是否存在
    if (!app.globalData.clientId) {
      console.log('getOpenList: clientId不存在,不执行API请求');
      // 如果是从登录页返回,就显示空列表而不是错误提示
      this.setData({
        listData: [],
        isRefreshing: false,
        isWXRefreshing: false
      });
      // 如果不是从登录页返回且不处于刷新状态,考虑检查登录状态
      if (!fromLogin && !this.data.isRefreshing && !this.data.isWXRefreshing) {
        console.log('getOpenList: 非刷新状态下检测到无clientId,尝试自动登录');
        // 延迟调用微信登录,尝试自动恢复会话
        setTimeout(() => {
          if (!getApp().globalData.clientId && !this.getFromLogin()) {
            this.wxLogin();
          }
        }, 1000);
      }
      return;
    }
    console.log('getOpenList: 开始获取列表数据, clientId:', app.globalData.clientId);
    const params = {
      url: 'wx/valve/get',
      data: {
        operator: app.globalData.operator
        operator: app.globalData.clientId
      }
    };
    get(params).then(data => {
      console.log('获取列表数据成功:', data);
      this.setData({
        listData: data.content,
        isRefreshing: false, // 将triggered属性设置为false,表示下拉刷新已完成
        isWXRefreshing: false, // 将triggered属性设置为false,表示下拉刷新已完成
      })
      });
      // 成功获取数据后刷新UI高度
      setTimeout(() => {
        this.calculateScrollViewHeight();
      }, 200);
    }).catch(err => {
      console.error('获取列表数据失败:', err);
      // 错误回调
      this.setData({
        isRefreshing: false, // 将triggered属性设置为false,表示下拉刷新已完成
        isWXRefreshing: false, // 将triggered属性设置为false,表示下拉刷新已完成
      })
      wx.showToast({
        title: err.msg,
        icon: 'error',
        duration: 3000
      })
      });
      // 检查错误类型
      if (err && err.code === '0003') {
        console.log('会话无效或过期,但不进行跳转');
        // 如果不是从登录页返回,显示错误提示
        if (!fromLogin) {
          wx.showToast({
            title: '登录已过期,请刷新重试',
            icon: 'none',
            duration: 3000
          });
        }
      } else {
        // 一般错误,显示错误信息
        wx.showToast({
          title: err.msg || '获取列表数据失败',
          icon: 'none',
          duration: 3000
        });
      }
    });
  },
  /**
@@ -335,26 +584,65 @@
  },
  //根据session获取农户信息
  getUserDataBySession() {
    // 先检查是否从登录页返回
    if (this.getFromLogin()) {
      console.log('getUserDataBySession: 检测到从登录页返回的标记,不执行API请求');
      return;
    }
    const app = getApp();
    // 检查是否有sessionId
    if (!app.globalData.sessionId) {
      console.log('getUserDataBySession: sessionId不存在,不执行API请求');
      return;
    }
    console.log('getUserDataBySession: 开始获取用户数据, sessionId:', app.globalData.sessionId);
    const params = {
      url: 'wx/client/simple_info',
      data: {
        sessionId: app.globalData.sessionId
      }
    };
    get(params).then(data => {
      console.log('获取用户数据成功:', data);
      this.setData({
        userName: data.content.clientName,
        userPhone: this.maskPhoneNumber(data.content.phone)
      })
      });
    }).catch(err => {
      // 错误回调
      wx.showToast({
        title: err.msg,
        icon: 'error',
        duration: 3000
      })
    })
      console.error('获取用户数据失败:', err);
      // 错误回调,但不进行页面跳转
      // 检查错误类型
      if (err && err.code === '0003') {
        console.log('会话无效或过期,但不进行跳转');
        // 不再直接跳转到登录页
        // 清除会话信息
        app.globalData.sessionId = '';
        app.globalData.isLoggedIn = false;
        // 如果不是从登录页返回,显示错误提示
        if (!this.getFromLogin()) {
          wx.showToast({
            title: '登录已过期,请重新登录',
            icon: 'none',
            duration: 3000
          });
        }
      } else {
        // 其他错误,显示错误信息
        wx.showToast({
          title: err.msg || '获取用户信息失败',
          icon: 'none',
          duration: 3000
        });
      }
    });
  },
  maskPhoneNumber(phoneNumber) {
    if (phoneNumber.length !== 11) {
@@ -421,7 +709,7 @@
    const data = {
      intakeName: intakeName, //取水口ID
      // vcId: vcId, //虚拟卡ID
      operator: app.globalData.operator, //操作员
      operator: app.globalData.clientId, //操作员
      forceOpen: !!isforce // 使用逻辑非操作符 !! 来确保 isForce 是布尔值  
    };
    post({
@@ -468,32 +756,118 @@
  //进入界面获取界面数据
  initData() {
    const app = getApp();
    console.log("tag>>>>:" +app.globalData.tag)
    if (storage.isHasKeySync("userData")) {
      storage.getItem('userData').then((data) => {
        let jsonObj = JSON.parse(data);
        app.globalData.sessionId = jsonObj.sessionId;
        app.globalData.tag = jsonObj.tag;
    console.log("initData开始,tag:", app.globalData.tag);
    // 首先检查是否从登录页返回
    if (this.getFromLogin()) {
      console.log('initData: 检测到从登录页返回的标记,仅获取基本数据');
      // 即使从登录页返回,也尝试获取开阀列表以显示基本UI
      // 但先检查是否有客户端ID可用
      if (!app.globalData.clientId) {
        console.log('initData: 从登录页返回且无clientId,尝试从存储恢复');
        // 尝试从存储恢复clientId
        storage.getItemSafe('clientId')
          .then(clientId => {
            if (clientId) {
              console.log('initData: 从存储恢复clientId成功:', clientId);
              app.globalData.clientId = clientId;
              this.getOpenList();
            } else {
              console.log('initData: 无法恢复clientId,显示空列表');
              this.setData({
                listData: []
              });
            }
          })
          .catch(err => {
            console.error('initData: 恢复clientId失败:', err);
            this.setData({
              listData: []
            });
          });
      } else {
        this.getOpenList();
      }
      return;
    }
    // 尝试获取用户数据和已开阀记录
    try {
      // 优先检查全局变量中是否有sessionId
      if (app.globalData.sessionId) {
        console.log('initData: 使用全局sessionId获取数据');
        this.getUserDataBySession();
        this.getOpenList();
        console.log("userData>>>>>>>" + data)
      }).catch((err) => {
        console.error('Failed to load parameter:', err);
      });
    } else {
      this.getUserDataBySession();
      this.getOpenList();
      console.log('Failed to load parameter:false');
        return;
      }
      // 检查是否有存储的userData
      const hasUserData = storage.isHasKeySync("userData");
      console.log('initData: 是否存在userData:', hasUserData);
      if (hasUserData) {
        storage.getItemSafe('userData')
          .then((data) => {
            console.log('initData: 成功读取userData');
            if (data) {
              try {
                let jsonObj = JSON.parse(data);
                app.globalData.sessionId = jsonObj.sessionId;
                app.globalData.tag = jsonObj.tag;
                console.log("userData已加载:", data);
              } catch (e) {
                console.error('userData解析失败:', e);
              }
            }
            // 无论如何都尝试获取用户信息和开阀列表
            this.getUserDataBySession();
            this.getOpenList();
          })
          .catch((err) => {
            console.error('加载userData失败:', err);
            // 再次检查是否从登录页返回
            if (this.getFromLogin()) {
              console.log('initData:catch: 检测到从登录页返回的标记,只获取开阀列表');
              this.getOpenList();
            } else {
              this.getUserDataBySession();
              this.getOpenList();
            }
          });
      } else {
        console.log('未找到userData,直接获取数据');
        // 再次检查是否从登录页返回
        if (this.getFromLogin()) {
          console.log('initData:else: 检测到从登录页返回的标记,只获取开阀列表');
          this.getOpenList();
        } else {
          this.getUserDataBySession();
          this.getOpenList();
        }
      }
    } catch (e) {
      console.error('initData执行出错:', e);
      // 再次检查是否从登录页返回
      if (this.getFromLogin()) {
        console.log('initData:error: 检测到从登录页返回的标记,只获取开阀列表');
        this.getOpenList();
      } else {
        // 出错时仍尝试获取数据
        this.getUserDataBySession();
        this.getOpenList();
      }
    }
  },
  // 处理头像点击
  handleAvatarTap() {
    this.setData({
      avatarTapCount: this.data.avatarTapCount + 1
    });
    if (this.data.avatarTapCount >= 5) {
      this.setData({
        showProjectDialog: true,
@@ -508,7 +882,9 @@
    if (!e.detail.visible && !this.data.selectedProject) {
      return;
    }
    this.setData({ showProjectDialog: e.detail.visible });
    this.setData({
      showProjectDialog: e.detail.visible
    });
  },
  // 处理项目选择变化
@@ -528,164 +904,575 @@
      });
      return;
    }
    const projectName = this.data.selectedProject === 'JYG' ? '嘉峪关项目' : '民勤项目';
    // 获取当前已选项目和新选择的项目
    const currentProject = getApp().globalData.selectedProject;
    const newProject = this.data.selectedProject;
    const projectName = newProject === 'JYG' ? '嘉峪关项目' : '民勤项目';
    // 检查是否切换了项目(如果当前项目不同于新选择的项目)
    const isProjectChanged = currentProject && currentProject !== newProject;
    // 如果切换了项目,先清除登录状态
    if (isProjectChanged) {
      console.log(`正在从项目 ${currentProject} 切换到 ${newProject},将清除登录状态`);
      // 清除全局登录状态
      getApp().globalData.sessionId = '';
      getApp().globalData.clientId = '';
      getApp().globalData.isLoggedIn = false;
      getApp().globalData.userInfo = null;
      // 清除存储中的登录状态
      try {
        wx.removeStorageSync('sessionId');
        wx.removeStorageSync('clientId');
        wx.removeStorageSync('userData');
        wx.removeStorageSync('isLoggedIn');
        console.log('已清除登录相关的存储数据');
      } catch (e) {
        console.error('清除存储数据失败:', e);
      }
      // 重置UI显示状态
      this.setData({
        userName: "请登录",
        userPhone: "",
        listData: []
      });
    }
    // 保存项目选择到本地存储
    storage.setItem('selectedProject', this.data.selectedProject).then(() => {
    storage.setItem('selectedProject', newProject).then(() => {
      // 更新 BASEURL
      const { PROJECT_URLS } = require('../../api/config.js');
      const baseUrl = PROJECT_URLS[this.data.selectedProject];
      // 直接修改全局变量
      const {
        PROJECT_URLS
      } = require('../../api/config.js');
      const baseUrl = PROJECT_URLS[newProject];
      // 更新全局变量
      getApp().globalData = getApp().globalData || {};
      getApp().globalData.baseUrl = baseUrl;
      getApp().globalData.selectedProject = this.data.selectedProject;
      getApp().globalData.selectedProject = newProject;
      // 根据项目设置对应的tag
      if (this.data.selectedProject === 'JYG') {
      if (newProject === 'JYG') {
        getApp().globalData.tag = 'ym'; // 嘉峪关项目对应tag为ym
      } else if (this.data.selectedProject === 'MQ') {
      } else if (newProject === 'MQ') {
        getApp().globalData.tag = 'mq'; // 民勤项目对应tag为mq
      }
      console.log('已切换到项目:', projectName, '域名:', baseUrl, 'tag:', getApp().globalData.tag);
      this.setData({
        showProjectDialog: false
      });
      // 显示切换成功提示
      wx.showToast({
        title: `已选择${projectName}`,
        title: isProjectChanged ? `已切换至${projectName},请重新登录` : `已选择${projectName}`,
        icon: 'success',
        duration: 2000
      });
      // 检查登录状态
      // setTimeout(() => {
      //   this.checkLoginStatus();
      // }, 500);
      // 如果切换了项目,延迟跳转到登录页面
      if (isProjectChanged) {
        setTimeout(() => {
          console.log('项目已切换,正在跳转到登录页面');
          wx.redirectTo({
            url: `/pages/login/login?project=${newProject}`,
            success: () => console.log('成功跳转到登录页'),
            fail: (err) => console.error('跳转到登录页失败:', err)
          });
        }, 2000);
      }
    }).catch(err => {
      console.error('保存项目选择失败:', err);
      wx.showToast({
        title: '保存失败,请重试',
        icon: 'success',
        icon: 'none',
        duration: 2000
      });
    });
  },
  // 检查登录状态
  checkLoginStatus() {
    const app = getApp();
    // 首先,强制再次检查是否从登录页返回
    try {
      const tempFromLogin = wx.getStorageSync('_temp_from_login');
      if (tempFromLogin === 'true') {
        console.log('checkLoginStatus: 检测到临时存储_temp_from_login=true,不执行跳转');
        this.setData({
          isFromLogin: true
        });
        return;
      }
    } catch (e) {
      console.error('checkLoginStatus: 读取临时标记失败:', e);
    }
    // 检查是否已登录
    if (app.globalData.isLoggedIn && app.globalData.sessionId) {
      // 已登录,重新加载页面
      wx.reLaunch({
        url: '/pages/home/home'
      console.log('已从全局变量检测到登录状态');
      return;
    }
    // 检查本页面是否正在处理返回逻辑
    const fromLogin = this.getFromLogin();
    if (fromLogin) {
      console.log('从登录页返回,不再重定向');
      return;
    }
    // 获取当前页面路由和参数
    const pages = getCurrentPages();
    const currentPage = pages[pages.length - 1];
    const currentRoute = currentPage ? currentPage.route : '';
    const currentOptions = currentPage ? currentPage.options || {} : {};
    console.log('当前页面路由:', currentRoute, '参数:', currentOptions);
    // 检查URL参数中是否有fromLogin
    if (currentOptions.fromLogin === 'true') {
      console.log('URL参数中检测到fromLogin=true,不执行跳转');
      this.setData({
        isFromLogin: true
      });
    } else {
      // 尝试从本地存储获取用户信息
      storage.getItem('userInfo').then(userInfoStr => {
        if (userInfoStr) {
      return;
    }
    // 如果当前已在登录页,不再跳转
    if (currentRoute === 'pages/login/login') {
      console.log('当前已在登录页,不再跳转');
      return;
    }
    // Promise链处理存储检查
    Promise.all([
        storage.getItemSafe('sessionId'),
        storage.getItemSafe('clientId'),
        storage.getItemSafe('isLoggedIn')
      ])
      .then(([sessionId, clientId, isLoggedIn]) => {
        // 最后一次检查临时标记
        try {
          const tempFromLogin = wx.getStorageSync('_temp_from_login');
          if (tempFromLogin === 'true') {
            console.log('Promise内部: 检测到临时存储_temp_from_login=true,不执行跳转');
            this.setData({
              isFromLogin: true
            });
            return;
          }
        } catch (e) {}
        if (sessionId) {
          // 从存储中恢复登录状态
          app.globalData.sessionId = sessionId;
          app.globalData.isLoggedIn = true;
          if (clientId) {
            app.globalData.clientId = clientId;
          }
          console.log('已从存储恢复登录状态');
          // 已登录,刷新页面
          wx.reLaunch({
            url: '/pages/home/home'
          });
        } else {
          // 标记当前页面正在处理返回逻辑
          this.setData({
            isFromLogin: true
          });
          // 未登录,可能需要跳转到登录页面
          console.log('未检测到登录状态,可能需要跳转到登录页');
          // 最后再检查一次是否已从登录页返回
          const finalCheck = this.getFromLogin();
          if (finalCheck) {
            console.log('最终检查: 已从登录页返回,不再跳转');
            return;
          }
          console.log('确认需要跳转到登录页');
          // 跳转前再次检查登录页面临时标记
          try {
            const userInfo = JSON.parse(userInfoStr);
            // 验证用户信息是否有效
            if (userInfo && userInfo.sessionId) {
              // 恢复登录状态
              app.globalData.sessionId = userInfo.sessionId;
              app.globalData.token = userInfo.token;
              app.globalData.userInfo = userInfo;
              app.globalData.isLoggedIn = true;
              // 已登录,重新加载页面
              wx.reLaunch({
                url: '/pages/home/home'
              });
              return;
            }
          } catch (e) {
            console.error('解析用户信息失败:', e);
          }
            wx.setStorageSync('_attempted_login_redirect', 'true');
          } catch (e) {}
          wx.redirectTo({
            url: `/pages/login/login?project=${this.data.selectedProject}`,
            success: () => console.log('成功跳转到登录页'),
            fail: (err) => console.error('跳转到登录页失败:', err)
          });
        }
        // 未登录,跳转到登录页面
        wx.redirectTo({
          url: `/pages/login/login?project=${this.data.selectedProject}`
      })
      .catch(err => {
        console.error('检查登录状态时出错:', err);
        // 标记当前页面正在处理返回逻辑
        this.setData({
          isFromLogin: true
        });
      }).catch(err => {
        console.error('获取用户信息失败:', err);
        // 未登录,跳转到登录页面
        // 再次检查是否已从登录页返回
        if (this.getFromLogin()) {
          console.log('错误处理: 已从登录页返回,不再跳转');
          return;
        }
        // 出错时也跳转到登录页
        wx.redirectTo({
          url: `/pages/login/login?project=${this.data.selectedProject}`
          url: `/pages/login/login?project=${this.data.selectedProject}`,
          success: () => console.log('错误后成功跳转到登录页'),
          fail: (err) => console.error('错误后跳转到登录页失败:', err)
        });
      });
  },
  // 辅助函数:检查是否从登录页返回
  getFromLogin() {
    // 先检查全局变量(作为备用方案)
    if (getApp().globalData && getApp().globalData._tempFromLogin === true) {
      console.log('getFromLogin: 检测到全局变量_tempFromLogin=true');
      // 设置标志,确保下次检查时能识别
      this.setData({
        isFromLogin: true
      });
      // 清除全局标记,防止重复识别
      setTimeout(() => {
        getApp().globalData._tempFromLogin = false;
        console.log('已清除全局变量_tempFromLogin标记');
      }, 100);
      return true;
    }
    // 检查是否有设置fromLogin标志
    if (this.data.isFromLogin) {
      console.log('getFromLogin: 检测到this.data.isFromLogin=true');
      return true;
    }
    // 检查当前页面的options
    const pages = getCurrentPages();
    const currentPage = pages[pages.length - 1];
    if (currentPage && currentPage.options && currentPage.options.fromLogin === 'true') {
      console.log('getFromLogin: 检测到URL参数fromLogin=true');
      // 设置标志,确保下次检查时能识别
      this.setData({
        isFromLogin: true
      });
      return true;
    }
    // 检查临时标记
    try {
      const tempFromLogin = wx.getStorageSync('_temp_from_login');
      console.log('getFromLogin: 读取到的临时标记值:', tempFromLogin);
      if (tempFromLogin === 'true') {
        console.log('getFromLogin: 检测到临时存储_temp_from_login=true');
        // 设置标志,确保下次检查时能识别
        this.setData({
          isFromLogin: true
        });
        return true;
      }
    } catch (e) {
      console.error('getFromLogin: 读取临时标记失败:', e);
    }
    console.log('getFromLogin: 未检测到从登录页返回的标记');
    return false;
  },
  // 继续初始化页面
  continueInitPage(options) {
    console.log('继续初始化页面,options:', options);
    // 检查是否从登录页返回
    let fromLogin = false;
    // 从URL参数中检查
    if (options && options.fromLogin === 'true') {
      console.log('continueInitPage: 从URL参数检测到fromLogin=true');
      fromLogin = true;
      this.setData({
        isFromLogin: true
      });
    }
    // 从临时标记中检查
    try {
      const tempFromLogin = wx.getStorageSync('_temp_from_login');
      if (tempFromLogin === 'true') {
        console.log('continueInitPage: 检测到临时标记_temp_from_login=true');
        fromLogin = true;
        this.setData({
          isFromLogin: true
        });
      }
    } catch (e) {
      console.error('continueInitPage: 读取临时标记失败:', e);
    }
    // 从页面数据中检查
    if (this.data.isFromLogin) {
      console.log('continueInitPage: 从页面数据中检测到isFromLogin=true');
      fromLogin = true;
    }
    // 判断本地是否保存sessionId
    // 使用 wx.nextTick 等待页面渲染完成
    wx.nextTick(() => {
      this.calculateScrollViewHeight();
    });
    // 当开阀成功后调用刷新
    if (options && options.param) {
      console.log("开阀成功参数:", options.param);
      wx.showToast({
        title: '开阀成功',
        icon: 'success',
        duration: 3000
      });
      this.getOpenList();
    }
    // 初始化数据
    this.initData();
    // 如果不是从登录页返回,则设置延迟检查登录状态
    if (!fromLogin) {
      console.log('不是从登录页返回,延迟检查登录状态');
      setTimeout(() => {
        // 再次检查是否已从登录页返回(可能在初始化过程中状态已变)
        if (this.getFromLogin()) {
          console.log('延迟检查:检测到从登录页返回的标记,不再检查登录状态');
          return;
        }
        // 仅在未登录且不是从登录页返回时检查登录状态
        if (!getApp().globalData.isLoggedIn) {
          console.log('延迟检查:未登录且不是从登录页返回,执行登录状态检查');
          this.checkLoginStatus();
        }
      }, 500);
    } else {
      console.log('从登录页返回,不检查登录状态');
    }
  },
  wxLogin(){
    if(!getApp().globalData.isLoggedIn){
      const that = this;
  // 微信登录
  wxLogin() {
    if (!getApp().globalData.isLoggedIn) {
      wx.showLoading({
        title: '正在登录请稍候...',
        mask: true
      });
      wx.login({
        success: function (res) {
        success: (res) => {
          if (res.code) {
            var code = res.code;
            console.log(code);
            // 将code发送到服务器获取openid
            that.codeLogin(code);
            post({
              url: "wx/client/code_login",
              data: {
                code: res.code
              }
            }).then(response => {
              wx.hideLoading();
              if (response.code === "0001") {
                if (response.content.client.clientId === "") {
                  // 未绑定账号,跳转到登录页面
                  wx.redirectTo({
                    url: `/pages/login/login?project=${this.data.selectedProject}`
                  });
                } else {
                  this.setData({
                    userName: response.content.client.clientName,
                    userPhone: response.content.client.userPhone
                  })
                  // 已有账号,保存数据并初始化
                  const sessionId = response.content.client.sessionId;
                  const clientId = response.content.client.clientId;
                  // 设置全局变量
                  getApp().globalData.sessionId = sessionId;
                  getApp().globalData.clientId = clientId;
                  getApp().globalData.isLoggedIn = true;
                  // 设置正确的项目tag
                  const tag = this.data.selectedProject === 'JYG' ? 'ym' : 'mq';
                  getApp().globalData.tag = tag;
                  // 保存到存储
                  storage.setItem("sessionId", sessionId);
                  storage.setItem("clientId", clientId);
                  storage.setItem("isLoggedIn", "true");
                  // 保存userData信息,包含sessionId和tag
                  const userData = JSON.stringify({
                    sessionId: sessionId,
                    tag: tag,
                    project: this.data.selectedProject,
                    userName: response.content.client.clientName,
                    userPhone: response.content.client.userPhone
                  });
                  storage.setItem("userData", userData)
                    .then(() => {
                      console.log('用户数据保存成功,包含项目信息:', this.data.selectedProject, 'tag:', tag);
                      this.initData();
                    })
                    .catch(err => {
                      console.warn('保存userData失败,但继续初始化:', err);
                      this.initData();
                    });
                }
              } else {
                wx.showToast({
                  title: '登录失败',
                  icon: 'error',
                  duration: 2000
                });
                wx.redirectTo({
                  url: `/pages/login/login?project=${this.data.selectedProject}`
                });
              }
            }).catch(error => {
              wx.hideLoading();
              console.error('登录请求失败:', error);
              wx.showToast({
                title: '登录失败,请重试',
                icon: 'none'
              });
              wx.redirectTo({
                url: `/pages/login/login?project=${this.data.selectedProject}`
              });
            });
          } else {
            wx.hideLoading();
            console.log('登录失败!' + res.errMsg);
            wx.showToast({
              title: '微信登录失败',
              icon: 'none'
            });
          }
        },
        fail: (err) => {
          wx.hideLoading();
          console.error('微信登录API调用失败:', err);
          wx.showToast({
            title: '登录失败,请重试',
            icon: 'none'
          });
        }
      });
    }
  },
  //微信code登录
  codeLogin(codeData) {
  // 辅助函数:清理临时标记
  cleanupTempMarkers() {
    // 只有在isFromLogin为true时才进行清理
    if (this.data.isFromLogin) {
      console.log('清理临时标记');
      // 清理存储标记
      try {
        wx.removeStorageSync('_temp_from_login');
      } catch (e) {
        console.error('清理存储标记失败:', e);
      }
      // 清理全局变量标记
      if (getApp().globalData) {
        getApp().globalData._tempFromLogin = false;
      }
      // 重设isFromLogin为false,但添加延迟,避免影响当前页面的返回逻辑
      setTimeout(() => {
        this.setData({
          isFromLogin: false
        });
        console.log('重置isFromLogin=false');
      }, 5000);
    }
  }, //确认解绑
  unBindPost() {
    this.setData({
      showUnBind: false
    })
    wx.showLoading({
      title: '正在登录请稍候...', // 加载提示文字
      title: '正在解绑请稍候...', // 加载提示文字
      mask: true // 是否显示透明蒙层,防止触摸穿透,默认为 false
    });
    const data = {
      code: codeData, //临时登录凭证
      sessionId: getApp().globalData.sessionId //取水口ID
    };
    post({
      url: "wx/client/code_login",
      url: 'wx/client/unbind',
      data: data,
      useParams: true
    }).then(response => {
      // 处理成功响应
      console.log('请求成功:', response);
      // 加载完成后隐藏加载动画
      wx.hideLoading();
      if (response.code === "0001") {
        //假如为空则跳转到绑定界面
        if (response.content.client.clientId === "") {
          wx.navigateTo({
            url: '/pages/login/login'
          })
        } else {
          //缓存在本地
      const app = getApp();
      // 清除全局登录状态
      app.globalData.sessionId = '';
      app.globalData.clientId = '';
      app.globalData.isLoggedIn = false;
      app.globalData.userInfo = null;
      // 清除存储中的登录状态
      const storage = require('../../utils/storage.js');
      storage.removeItem('sessionId')
        .then(() => storage.removeItem('clientId'))
        .then(() => storage.removeItem('userData'))
        .then(() => storage.removeItem('isLoggedIn'))
        .then(() => {
          wx.showToast({
            title: '解绑成功',
            icon: 'success',
            duration: 2000
          });
          // 重置UI显示状态
          this.setData({
            isLogin: true
          })
          getApp().globalData.sessionId = response.content.client.sessionId
          storage.setItem("sessionId", response.content.client.sessionId)
          getApp().globalData.clientId = response.content.client.clientId
          storage.setItem("clientId", response.content.client.clientId)
          this.initData();
        }
      } else {
        wx.showToast({
          title: 'title',
          icon: 'error',
          duration: 2000
            userName: "请点击登录",
            userPhone: "",
            listData: []
          });
        })
      }
        .catch(err => {
          console.error('解绑过程中出错:', err);
          wx.showToast({
            title: '解绑失败,请重试',
            icon: 'none',
            duration: 2000
          });
        });
    }).catch(error => {
      // 加载完成后隐藏加载动画
      wx.hideLoading();
      // 处理错误响应
      console.error('请求失败:', error);
      wx.showToast({
        title: '解绑失败',
        icon: 'error',
        duration: 3000
      })
    });
  },
})
pages/home/home.wxml
@@ -9,7 +9,7 @@
        <text class="head-bottom">{{userPhone}}</text>
      </view>
      <view class="head-button-wrapper">
        <text class="unbind" bind:tap="feedBack">解绑</text>
        <text class="unbind" bind:tap="unbind">解绑</text>
        <text class="head-bottom" bind:tap="feedBack">联系客服</text>
      </view>
      <view class="scen-view" bind:tap="scenCode">
@@ -33,8 +33,8 @@
      <image src="/images/record.svg" />
      <text>开关阀记录</text>
    </view>
    <view class="center-view" bind:tap="feedBack">
      <image src="/images/question.svg" />
    <view class="center-view" bind:tap="irrigation">
      <image src="/images/irrigation.svg" />
      <text>轮灌</text>
    </view>
  </view>
pages/irrigation/irrigation.js
@@ -139,6 +139,19 @@
  },
  /**
   * 点击列表项
   */
  onItemTap: function (e) {
    const id = e.currentTarget.dataset.id;
    const status = e.currentTarget.dataset.status;
    // 导航到灌溉详情页面,并传递参数
    wx.navigateTo({
      url: `/pages/irrigationDetail/irrigationDetail?id=${id}&fromList=true`
    });
  },
  /**
   * 点击发布按钮
   */
  onPublish: function (e) {
@@ -214,6 +227,14 @@
  },
  /**
   * 阻止事件冒泡
   */
  stopPropagation: function (e) {
    // 阻止事件冒泡
    return false;
  },
  /**
   * 开始下拉刷新
   */
  startPullDownRefresh: function() {
pages/irrigation/irrigation.wxml
@@ -19,7 +19,7 @@
    <view class="scroll-bg">
      <block wx:if="{{currentList.length > 0}}">
        <!-- 统一显示所有列表项,不再按状态分组 -->
        <view class="list-item" wx:for="{{currentList}}" wx:key="id">
        <view class="list-item" wx:for="{{currentList}}" wx:key="id" bindtap="onItemTap" data-id="{{item.id}}" data-status="{{item.status}}">
          <view class="item-header">
            <view class="info-row title-row">
              <view class="info-label">编号:</view>
@@ -55,7 +55,7 @@
              </view>
            </block>
          </view>
          <view class="item-actions">
          <view class="item-actions" catchtap="stopPropagation">
            <!-- 根据状态显示不同的按钮 -->
            <block wx:if="{{item.status === '未发布'}}">
              <button class="action-button publish-button" hover-class="publish-button-hover" bindtap="onPublish" data-id="{{item.id}}">发布</button>
pages/irrigationDetail/irrigationDetail.js
New file
@@ -0,0 +1,308 @@
Page({
  /**
   * 页面的初始数据
   */
  data: {
    planCode: '',
    startTime: '',
    projects: [],
    isRefreshing: false, // 下拉刷新状态
    planId: '' // 保存计划ID
  },
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    if (options.id) {
      this.setData({
        planId: options.id
      });
      // 从列表页面进入时,所有项目默认收起
      const fromListPage = options.fromList === 'true';
      this.loadIrrigationDetail(options.id, !fromListPage);
    }
  },
  /**
   * 加载灌溉计划详情
   * @param {string} id 灌溉计划ID
   * @param {boolean} isFirstLoad 是否首次加载
   */
  loadIrrigationDetail: function (id, isFirstLoad = false) {
    // 开始加载,设置刷新状态
    this.setData({
      isRefreshing: true
    });
    // 保存当前项目的展开状态
    const currentExpandStates = {};
    if (!isFirstLoad && this.data.projects.length > 0) {
      this.data.projects.forEach((project, index) => {
        currentExpandStates[project.id] = project.expanded;
      });
    }
    // 这里应该是从API获取数据
    // 以下是模拟数据
    const mockData = {
      planCode: 'IRG20240317001',
      startTime: '2024-03-17 08:00',
      projects: [
        {
          id: 1,
          name: '项目A',
          expanded: isFirstLoad ? true : false, // 仅在非列表页进入且首次加载时展开第一个项目
          groups: [
            {
              id: 1,
              name: '轮灌组A-1',
              status: 'irrigated', // 已灌溉
              statusText: '已灌溉',
              startTime: '2024-03-17 08:00',
              endTime: '2024-03-17 09:30',
              duration: 90
            },
            {
              id: 2,
              name: '轮灌组A-2',
              status: 'irrigating', // 正在灌溉
              statusText: '正在灌溉',
              startTime: '2024-03-17 09:30',
              endTime: '2024-03-17 11:00',
              duration: 90
            }
          ]
        },
        {
          id: 2,
          name: '项目B',
          expanded: false,
          groups: [
            {
              id: 3,
              name: '轮灌组B-1',
              status: 'waiting', // 未灌溉
              statusText: '未灌溉',
              startTime: '2024-03-17 11:00',
              endTime: '2024-03-17 12:30',
              duration: 90
            },
            {
              id: 4,
              name: '轮灌组B-2',
              status: 'waiting', // 未灌溉
              statusText: '未灌溉',
              startTime: '2024-03-17 12:30',
              endTime: '2024-03-17 14:00',
              duration: 90
            }
          ]
        },
        {
          id: 3,
          name: '项目C',
          expanded: false,
          groups: [
            {
              id: 5,
              name: '轮灌组C-1',
              status: 'waiting', // 未灌溉
              statusText: '未灌溉',
              startTime: '2024-03-17 14:00',
              endTime: '2024-03-17 15:30',
              duration: 90
            }
          ]
        }
      ]
    };
    // 计算每个项目的总灌溉时长
    mockData.projects = this.calculateProjectTotalDuration(mockData.projects);
    // 如果不是首次加载,恢复项目的展开状态
    if (!isFirstLoad) {
      mockData.projects.forEach(project => {
        if (currentExpandStates[project.id] !== undefined) {
          project.expanded = currentExpandStates[project.id];
        }
      });
    }
    // 模拟网络请求延迟
    setTimeout(() => {
      // 设置页面数据
      this.setData({
        planCode: mockData.planCode,
        startTime: mockData.startTime,
        projects: mockData.projects,
        isRefreshing: false // 结束刷新状态
      });
    }, 1000);
    // 实际项目中应该使用wx.request获取数据
    // wx.request({
    //   url: 'https://your-api-url/irrigation/' + id,
    //   method: 'GET',
    //   success: (res) => {
    //     if (res.data && res.data.code === 0) {
    //       // 获取新数据
    //       let projects = res.data.data.projects;
    //
    //       // 如果是首次加载,设置默认展开状态
    //       if (isFirstLoad) {
    //         projects = projects.map((project, index) => {
    //           return {
    //             ...project,
    //             expanded: index === 0 // 默认只展开第一个项目
    //           };
    //         });
    //       } else {
    //         // 如果不是首次加载,恢复项目的展开状态
    //         projects = projects.map(project => {
    //           return {
    //             ...project,
    //             expanded: currentExpandStates[project.id] !== undefined
    //               ? currentExpandStates[project.id]
    //               : false
    //           };
    //         });
    //       }
    //
    //       // 计算每个项目的总灌溉时长
    //       projects = this.calculateProjectTotalDuration(projects);
    //
    //       this.setData({
    //         planCode: res.data.data.planCode,
    //         startTime: res.data.data.startTime,
    //         projects: projects,
    //         isRefreshing: false // 结束刷新状态
    //       });
    //     } else {
    //       wx.showToast({
    //         title: '获取数据失败',
    //         icon: 'none'
    //       });
    //       this.setData({
    //         isRefreshing: false // 结束刷新状态
    //       });
    //     }
    //   },
    //   fail: () => {
    //     wx.showToast({
    //       title: '网络错误',
    //       icon: 'none'
    //     });
    //     this.setData({
    //       isRefreshing: false // 结束刷新状态
    //     });
    //   }
    // });
  },
  /**
   * 计算每个项目的总灌溉时长
   */
  calculateProjectTotalDuration: function(projects) {
    return projects.map(project => {
      // 计算项目下所有轮灌组的总时长
      const totalDuration = project.groups.reduce((total, group) => {
        return total + (group.duration || 0);
      }, 0);
      return {
        ...project,
        totalDuration: totalDuration
      };
    });
  },
  /**
   * 切换项目展开/收起状态
   */
  toggleProject: function (e) {
    const index = e.currentTarget.dataset.index;
    const expanded = this.data.projects[index].expanded;
    // 更新项目的展开状态
    const key = `projects[${index}].expanded`;
    this.setData({
      [key]: !expanded
    });
  },
  /**
   * 导航到轮灌组详情页面
   */
  navigateToGroupDetail: function (e) {
    const projectName = e.currentTarget.dataset.projectName;
    const groupName = e.currentTarget.dataset.groupName;
    const groupId = e.currentTarget.dataset.groupId;
    const status = e.currentTarget.dataset.status;
    console.log('跳转到组详情页面,原始状态:', status);
    // 导航到组详情页面,并传递参数
    // 注意:需要将status转换为isIrrigating参数,以便在组详情页面正确显示命令状态
    wx.navigateTo({
      url: `/pages/groupDetail/groupDetail?projectName=${projectName}&groupName=${groupName}&groupId=${groupId}&status=${status}&isIrrigating=${status === 'irrigating' ? 'true' : 'false'}`
    });
  },
  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {
  },
  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {
  },
  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {
  },
  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {
  },
  /**
   * 下拉刷新处理函数
   */
  onPullDownRefresh: function () {
    // 重新加载数据,但保持展开状态
    if (this.data.planId) {
      this.loadIrrigationDetail(this.data.planId, false);
    } else {
      this.setData({
        isRefreshing: false
      });
    }
  },
  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {
  },
  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {
  }
})
pages/irrigationDetail/irrigationDetail.json
New file
@@ -0,0 +1,4 @@
{
  "usingComponents": {},
  "navigationBarTitleText": "轮灌详情"
}
pages/irrigationDetail/irrigationDetail.wxml
New file
@@ -0,0 +1,74 @@
<view class="irrigation-detail-container">
  <!-- 顶部信息区域 -->
  <view class="header-section">
    <view class="plan-info">
      <view class="plan-code">
        <text class="label">计划编号:</text>
        <text class="value">{{planCode}}</text>
      </view>
      <image class="status-icon" src="/images/progress.svg" mode="aspectFit"></image>
    </view>
    <!-- 灌溉时间信息 -->
    <view class="time-info">
      <text class="label">灌溉开始时间:</text>
      <text class="value">{{startTime}}</text>
    </view>
  </view>
  <!-- 项目和轮灌组列表 -->
  <scroll-view
    scroll-y="true"
    class="project-list"
    refresher-enabled="{{true}}"
    refresher-threshold="50"
    refresher-triggered="{{isRefreshing}}"
    bindrefresherrefresh="onPullDownRefresh">
    <view class="scroll-content">
      <block wx:for="{{projects}}" wx:key="id" wx:for-item="project" wx:for-index="projectIndex">
        <!-- 项目信息 -->
        <view class="project-item {{project.expanded ? 'expanded' : 'collapsed'}}">
          <view class="project-header" bindtap="toggleProject" data-index="{{projectIndex}}">
            <image class="toggle-icon {{project.expanded ? 'expanded' : ''}}" src="/images/arrow-down.svg" mode="aspectFit"></image>
            <view class="project-info">
              <view class="project-name">{{project.name}}</view>
              <view class="project-duration">总灌溉时长: {{project.totalDuration || 0}}分钟</view>
            </view>
          </view>
          <!-- 轮灌组列表 -->
          <view class="group-list {{project.expanded ? 'expanded' : 'collapsed'}}">
            <block wx:for="{{project.groups}}" wx:key="id" wx:for-item="group">
              <view class="group-item {{group.status}}" bindtap="navigateToGroupDetail" data-project-name="{{project.name}}" data-group-name="{{group.name}}" data-group-id="{{group.id}}" data-status="{{group.status}}">
                <!-- 轮灌组状态标识 -->
                <view class="group-status-indicator">
                  <view class="status-dot"></view>
                  <text class="status-text">{{group.statusText}}</text>
                </view>
                <!-- 轮灌组信息 -->
                <view class="group-info">
                  <view class="group-name">{{group.name}}</view>
                  <view class="group-time-info">
                    <view class="time-row">
                      <text class="time-label">开始时间:</text>
                      <text class="time-value">{{group.startTime}}</text>
                    </view>
                    <view class="time-row">
                      <text class="time-label">结束时间:</text>
                      <text class="time-value">{{group.endTime}}</text>
                    </view>
                    <view class="time-row">
                      <text class="time-label">灌溉时长:</text>
                      <text class="time-value">{{group.duration}}分钟</text>
                    </view>
                  </view>
                </view>
              </view>
            </block>
          </view>
        </view>
      </block>
    </view>
  </scroll-view>
</view>
pages/irrigationDetail/irrigationDetail.wxss
New file
@@ -0,0 +1,234 @@
.irrigation-detail-container {
  display: flex;
  flex-direction: column;
  height: 100vh;
  background-color: #F5F5F5;
}
/* 顶部信息区域样式 */
.header-section {
  background-color: #FFFFFF;
  padding: 20rpx 30rpx;
  margin-bottom: 20rpx;
  box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
}
.plan-info {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20rpx;
}
.plan-code {
  display: flex;
  align-items: center;
}
.status-icon {
  width: 68rpx;
  height: 68rpx;
}
.time-info {
  display: flex;
  align-items: center;
  padding: 10rpx 0;
}
.label {
  color: #666666;
  font-size: 28rpx;
  margin-right: 10rpx;
}
.value {
  color: #333333;
  font-size: 28rpx;
  font-weight: 500;
}
/* 项目列表样式 */
.project-list {
  flex: 1;
  overflow: hidden;
}
.scroll-content {
  padding: 0 30rpx 30rpx 30rpx;
}
.project-item {
  margin-bottom: 30rpx;
  border-radius: 12rpx;
  overflow: hidden;
  box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
  width: 100%;
  box-sizing: border-box;
}
.project-header {
  background-color: #FFFFFF;
  padding: 20rpx 30rpx;
  margin-bottom: 0;
  display: flex;
  align-items: flex-start;
  width: 100%;
  box-sizing: border-box;
}
/* 所有项目标题都有圆角 */
.project-item .project-header {
  border-radius: 12rpx;
}
/* 展开状态的项目标题只有顶部圆角 */
.project-item.expanded .project-header {
  border-radius: 12rpx 12rpx 0 0;
}
.toggle-icon {
  width: 32rpx;
  height: 32rpx;
  margin-right: 16rpx;
  transition: transform 0.3s ease;
  flex-shrink: 0;
  margin-top: 6rpx;
}
.toggle-icon.expanded {
  transform: rotate(180deg);
}
.project-info {
  flex: 1;
  width: calc(100% - 48rpx);
}
.project-name {
  font-size: 32rpx;
  font-weight: bold;
  color: #333333;
  word-break: break-all;
}
.project-duration {
  font-size: 26rpx;
  color: #666666;
  margin-top: 10rpx;
}
/* 轮灌组列表样式 */
.group-list {
  background-color: #FFFFFF;
  border-radius: 0 0 12rpx 12rpx;
  padding: 0 20rpx;
  overflow: hidden;
  max-height: 0;
  transition: all 0.3s ease-in-out;
  width: 100%;
  box-sizing: border-box;
}
.group-list.expanded {
  max-height: 2000rpx; /* 足够大的高度以容纳内容 */
  padding: 0 20rpx 20rpx 20rpx;
}
.group-list.collapsed {
  max-height: 0;
  padding-top: 0;
  padding-bottom: 0;
}
.group-item {
  border-radius: 8rpx;
  margin-top: 20rpx;
  padding: 20rpx;
  background-color: #F9F9F9;
  position: relative;
}
/* 轮灌组状态样式 */
.group-status-indicator {
  display: flex;
  align-items: center;
  margin-bottom: 20rpx;
}
.status-dot {
  width: 16rpx;
  height: 16rpx;
  border-radius: 50%;
  margin-right: 10rpx;
}
.status-text {
  font-size: 26rpx;
  font-weight: 500;
}
/* 已灌溉状态 */
.irrigated .status-dot {
  background-color: #52C41A;
}
.irrigated .status-text {
  color: #52C41A;
}
/* 正在灌溉状态 */
.irrigating .status-dot {
  background-color: #D43030;
}
.irrigating .status-text {
  color: #D43030;
}
/* 未灌溉状态 */
.waiting .status-dot {
  background-color: #FAAD14;
}
.waiting .status-text {
  color: #FAAD14;
}
/* 轮灌组信息样式 */
.group-info {
  padding-left: 26rpx;
}
.group-name {
  font-size: 30rpx;
  font-weight: bold;
  color: #333333;
  margin-bottom: 20rpx;
}
.group-time-info {
  background-color: #FFFFFF;
  border-radius: 8rpx;
  padding: 20rpx;
}
.time-row {
  display: flex;
  margin-bottom: 10rpx;
}
.time-row:last-child {
  margin-bottom: 0;
}
.time-label {
  color: #666666;
  font-size: 26rpx;
  width: 150rpx;
}
.time-value {
  color: #333333;
  font-size: 26rpx;
}
pages/login/login.js
@@ -17,7 +17,9 @@
    countDown: 60,
    projectName: '嘉峪关项目', // 默认项目名称
    selectedProject: 'JYG', // 默认项目代码
    showErrorDialog: false
    showErrorDialog: false,
    fromBack: false,  // 标记是否是从返回按钮返回的
    manualNavigate: false // 标记是否是通过编程方式导航的
  },
  /**
@@ -61,8 +63,7 @@
      return;
    }
    // 开始倒计时
    this.startCountDown();
    // 发送验证码请求
    this.postCode();
@@ -140,40 +141,14 @@
      title: '登录中...',
      mask: true
    });
    this.wsLogin();
    // 发送登录请求
    post('/api/loginByCode', {
      phone: phone,
      code: verificationCode,
      projectCode: this.data.selectedProject
    }).then(res => {
      wx.hideLoading();
      if (res.code === 0 && res.data) {
        // 保存用户信息和token
        storage.setUserInfo(res.data);
        storage.setToken(res.data.token);
        // 跳转到首页
        wx.switchTab({
          url: '/pages/index/index'
        });
      } else {
        wx.showToast({
          title: res.msg || '登录失败,请重试',
          icon: 'none'
        });
      }
    }).catch(err => {
      wx.hideLoading();
      console.error('登录失败', err);
      wx.showToast({
        title: '网络异常,请重试',
        icon: 'none'
      });
    // 标记为手动导航,确保不会触发返回逻辑
    console.log('登录按钮点击,设置manualNavigate=true');
    this.setData({
      manualNavigate: true
    });
    this.wsLogin();
  },
  /**
@@ -202,20 +177,63 @@
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    // 获取选择的项目
    if (options.project) {
    console.log('login页面加载,options:', options);
    // 设置页面数据
    this.setData({
      fromBack: false,  // 标记是否是从返回按钮返回的
      manualNavigate: false // 标记是否是通过编程方式导航的
    });
    // 获取选择的项目 - 优先使用URL参数
    if (options && options.project) {
      const project = options.project;
      const projectName = project === 'JYG' ? '嘉峪关项目' : '民勤项目';
      console.log(`从URL参数获取项目信息: ${project} (${projectName})`);
      this.setData({
        selectedProject: options.project,
        projectName: options.project === 'JYG' ? '嘉峪关项目' : '民勤项目'
        selectedProject: project,
        projectName: projectName
      });
      // 同步更新全局项目设置
      if (getApp().globalData) {
        getApp().globalData.selectedProject = project;
        // 设置对应的tag
        if (project === 'JYG') {
          getApp().globalData.tag = 'ym';
        } else if (project === 'MQ') {
          getApp().globalData.tag = 'mq';
        }
        // 更新 BASEURL
        try {
          const { PROJECT_URLS } = require('../../api/config.js');
          getApp().globalData.baseUrl = PROJECT_URLS[project];
        } catch (e) {
          console.error('设置baseUrl失败:', e);
        }
      }
      // 保存项目选择到本地存储,确保项目信息一致
      storage.setItem('selectedProject', project)
        .then(() => console.log('成功保存项目选择到存储'))
        .catch(err => console.error('保存项目选择到存储失败:', err));
    } else {
      // 尝试从本地存储获取已选择的项目
      storage.getItem('selectedProject').then(project => {
      // 从本地存储获取已选择的项目
      storage.getItemSafe('selectedProject').then(project => {
        if (project) {
          const projectName = project === 'JYG' ? '嘉峪关项目' : '民勤项目';
          console.log(`从存储获取项目信息: ${project} (${projectName})`);
          this.setData({
            selectedProject: project,
            projectName: project === 'JYG' ? '嘉峪关项目' : '民勤项目'
            projectName: projectName
          });
        } else {
          console.log('未找到已选择的项目,使用默认项目');
        }
      }).catch(err => {
        console.error('获取已选择项目失败:', err);
@@ -241,7 +259,21 @@
   * 生命周期函数--监听页面隐藏
   */
  onHide() {
    // 如果不是通过编程方式导航,则可能是点击了返回按钮
    // 注意:在某些情况下,微信可能会直接调用onUnload而跳过onHide
    if (!this.data.manualNavigate) {
      console.log('页面隐藏,可能是点击了返回按钮');
      this.setData({
        fromBack: true
      });
      // 如果页面隐藏但未登录,记录一个时间戳,帮助识别是否是返回操作
      if (!getApp().globalData.isLoggedIn) {
        this.hideTimestamp = Date.now();
      }
    } else {
      console.log('页面隐藏,是通过代码导航的');
    }
  },
  /**
@@ -253,6 +285,103 @@
      clearInterval(this.countDownTimer);
      this.countDownTimer = null;
    }
    // 记录退出登录页面的情况
    console.log('登录页面卸载,fromBack:', this.data.fromBack, 'manualNavigate:', this.data.manualNavigate, '登录状态:', !!getApp().globalData.isLoggedIn);
    // 如果是登录成功,不执行返回逻辑
    if (getApp().globalData.isLoggedIn) {
      console.log('用户已登录,无需执行返回逻辑');
      return;
    }
    // 检查是否是通过编程方式明确设置了导航
    // 如果没有明确设置,就假定是返回操作
    if (!this.data.manualNavigate) {
      console.log('页面卸载时未设置manualNavigate,假定是返回按钮操作');
      // 立即写入临时标记,以便首页检测到
      try {
        // 多种方式确保写入成功
        wx.setStorageSync('_temp_from_login', 'true');
        console.log('立即写入_temp_from_login标记为true');
        // 创建一个全局对象,作为备用方案
        if (!getApp().globalData) {
          getApp().globalData = {};
        }
        getApp().globalData._tempFromLogin = true;
        console.log('同时设置全局变量_tempFromLogin=true');
        // 检查写入是否成功
        const check = wx.getStorageSync('_temp_from_login');
        console.log('检查临时标记是否写入成功:', check);
      } catch (e) {
        console.error('写入标记失败:', e);
        // 备用方式写入
        wx.setStorage({
          key: '_temp_from_login',
          data: 'true'
        });
      }
      // 尝试使用wx.navigateBack返回上一页(如果可行)
      const pages = getCurrentPages();
      if (pages.length > 1) {
        console.log('检测到有上一页,使用navigateBack返回');
        wx.navigateBack({
          delta: 1,
          success: () => console.log('navigateBack成功'),
          fail: (err) => {
            console.error('navigateBack失败:', err);
            // 如果navigateBack失败,尝试reLaunch
            this.backupReturnToHome();
          }
        });
      } else {
        console.log('无上一页,使用备用返回方式');
        // 没有上一页,使用备用方法
        this.backupReturnToHome();
      }
    } else {
      console.log('通过编程方式离开登录页面');
    }
  },
  // 备用的返回首页方法
  backupReturnToHome() {
    console.log('使用备用方法返回首页');
    // 尝试使用switchTab(如果首页在tabBar中)
    const useReLaunch = () => {
      console.log('使用reLaunch返回首页');
      wx.reLaunch({
        url: '/pages/home/home?fromLogin=true',
        success: () => console.log('reLaunch成功返回首页'),
        fail: (err) => {
          console.error('reLaunch返回首页失败:', err);
          // 最后的备用方案:使用redirectTo
          setTimeout(() => {
            console.log('延迟使用redirectTo尝试返回首页');
            wx.redirectTo({
              url: '/pages/home/home?fromLogin=true',
              success: () => console.log('redirectTo成功返回首页'),
              fail: (err) => console.error('所有返回方法都失败:', err)
            });
          }, 100);
        }
      });
    };
    // 先尝试使用switchTab(某些版本可能将首页设置为tabBar)
    wx.switchTab({
      url: '/pages/home/home',
      success: () => console.log('switchTab成功返回首页'),
      fail: (err) => {
        console.log('switchTab失败(可能首页不在tabBar中):', err);
        useReLaunch();
      }
    });
  },
  /**
@@ -290,8 +419,8 @@
        this.setData({
          codeSent: true,
        });
        // 启动倒计时
        this.startCountdown();
    // 开始倒计时
    this.startCountDown();
      })
      .catch((error) => {
        wx.showToast({
@@ -302,20 +431,39 @@
      });
  },
  wsLogin() {
    // 标记为手动导航
    console.log('wsLogin调用,设置manualNavigate=true');
    this.setData({
      manualNavigate: true
    });
    wx.login({
      success: res => {
        if (res.code) {
          console.log('登录成功,获取到的code:', res.code);
          console.log('微信登录成功,获取到的code:', res.code);
          // 发送 res.code 到后台服务器换取 openId, sessionKey, unionId
          this.verify(res.code)
        } else {
          console.log('登录失败!' + res.errMsg);
          console.log('微信登录失败!' + res.errMsg);
          // 登录失败时重置状态
          this.setData({
            manualNavigate: false
          });
        }
      },
      fail: err => {
        console.error('微信登录API调用失败:', err);
        // 登录失败,重置导航标记
        this.setData({
          manualNavigate: false
        });
      }
    });
  },
  //用户绑定
  verify(wxCode) {
    console.log('verify调用,确认manualNavigate=', this.data.manualNavigate);
    const params = {
      url: 'wx/client/verify',
      data: {
@@ -324,34 +472,115 @@
        code: wxCode
      }
    };
    post(params)
      .then((data) => {
        wx.hideLoading();
        getApp().globalData.sessionId = String(data.content.sessionId)
        storage.setItem("sessionId", String(data.content.sessionId))
        getApp().globalData.clientId = String(data.content.clientId)
        storage.setItem("clientId", String(data.content.clientId))
        this.bindSuccess();
        console.log('验证成功,准备保存用户数据');
        // 确保全局对象已初始化
        if (!getApp().globalData) {
          getApp().globalData = {};
        }
        // 保存会话ID和客户端ID
        getApp().globalData.sessionId = String(data.content.sessionId);
        storage.setItem("sessionId", String(data.content.sessionId));
        getApp().globalData.clientId = String(data.content.clientId);
        storage.setItem("clientId", String(data.content.clientId));
        // 设置当前项目的tag
        const tag = this.data.selectedProject === 'JYG' ? 'ym' : 'mq';
        getApp().globalData.tag = tag;
        // 保存用户信息
        const userInfo = {
          sessionId: String(data.content.sessionId),
          clientId: String(data.content.clientId),
          phone: this.data.phone,
          token: data.content.token || '',
          project: this.data.selectedProject,
          tag: tag
        };
        // 保存到全局变量
        getApp().globalData.userInfo = userInfo;
        getApp().globalData.isLoggedIn = true;
        // 保存到本地存储
        storage.setItem("userInfo", JSON.stringify(userInfo))
          .then(() => {
            console.log('用户信息保存成功');
            return storage.setItem("isLoggedIn", "true");
          })
          .then(() => {
            // 保存userData信息,包含sessionId和tag
            const userData = JSON.stringify({
              sessionId: String(data.content.sessionId),
              tag: tag
            });
            return storage.setItem("userData", userData);
          })
          .then(() => {
            console.log('登录状态和项目信息保存成功');
            this.bindSuccess();
          })
          .catch(err => {
            console.warn('保存用户信息过程中出错,但不影响继续操作:', err);
            this.bindSuccess();
          });
      })
      .catch((error) => {
        wx.hideLoading();
        console.error('验证请求失败:', error);
        // 验证失败,需要重置导航标记
        console.log('验证失败,重置manualNavigate=false');
        this.setData({
          manualNavigate: false
        });
        wx.showToast({
          title: error.msg,
          title: error.msg || '验证失败',
          icon: 'error',
          duration: 3000,
        });
        console.error('Failed to add item:', error);
      });
  },
  bindSuccess: function () {
    if (!this.data.isButtonEnabled) return;
    // 设置标记,表示通过编程方式导航
    console.log('绑定成功,最终确认manualNavigate=true');
    this.setData({
      manualNavigate: true,
      fromBack: false // 确保不会被识别为返回操作
    });
    // 设置全局登录状态
    getApp().globalData.isLoggedIn = true;
    // 确保清除临时标记
    try {
      wx.removeStorageSync('_temp_from_login');
    } catch(e) {
      console.warn('清除临时标记失败', e);
    }
    wx.showToast({
      title: '绑定成功',
      icon: 'success'
    });
    // 跳转到 TabBar 页面
    wx.redirectTo({
      url: '/pages/home/home' // 这里填写你想要跳转的 TabBar 页面路径
      icon: 'success',
      duration: 1500,
      mask: true,
      success: () => {
        // 延迟跳转,确保Toast显示完成
        setTimeout(() => {
          console.log('登录成功,准备跳转到首页');
          // 跳转到首页,使用reLaunch而不是redirectTo
          wx.reLaunch({
            url: '/pages/home/home'
          });
        }, 1500);
      }
    });
  },
})
pages/login/login.wxml
@@ -25,7 +25,7 @@
    </view>
  </view>
  
  <view class="project-info">
  <view class="project-info {{selectedProject === 'MQ' ? 'mq' : 'jyg'}}">
    <text>当前项目: {{projectName}}</text>
  </view>
pages/login/login.wxss
@@ -123,8 +123,25 @@
  bottom: 40rpx;
  width: 100%;
  text-align: center;
  font-size: 28rpx;
  color: #999;
  font-size: 32rpx;
  padding: 16rpx 0;
  background-color: rgba(255, 255, 255, 0.8);
  backdrop-filter: blur(5px);
  box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.1);
}
.project-info text {
  display: inline-block;
  padding: 8rpx 24rpx;
  color: #fff;
  border-radius: 30rpx;
  font-weight: 500;
  box-shadow: 0 4rpx 8rpx rgba(0, 0, 0, 0.2);
  background: linear-gradient(45deg, #1890FF, #36a9fc);
}
.project-info.mq text {
  background: linear-gradient(45deg, #18c063, #36d486);
}
image {
pages/waterIntake/waterIntake.js
@@ -102,7 +102,7 @@
    const data = {
      intakeId: intakeId, //取水口ID
      // vcId: vcId, //虚拟卡ID
      operator: app.globalData.operator, //操作员
      operator: app.globalData.clientId, //操作员
      forceOpen: !!isforce // 使用逻辑非操作符 !! 来确保 isForce 是布尔值  
    };
    post({
@@ -243,7 +243,7 @@
    get({
        url: 'wx/intake/used_intakes',
        data: {
          operatorId: getApp().globalData.operator
          operatorId: getApp().globalData.clientId
        }
      })
      .then((data) => {
utils/storage.js
@@ -1,30 +1,79 @@
const setItem = (key, data) => {
  return new Promise((resolve, reject) => {
    if (!key) {
      reject(new Error('存储键不能为空'));
      return;
    }
    wx.setStorage({
      key: key,
      data: data,
      success: resolve,
      fail: reject
      fail: (err) => {
        console.error(`设置存储项 ${key} 失败:`, err);
        reject(err);
      }
    });
  });
};
const getItem = (key) => {
  return new Promise((resolve, reject) => {
    if (!key) {
      reject(new Error('存储键不能为空'));
      return;
    }
    wx.getStorage({
      key: key,
      success: (res) => resolve(res.data),
      fail: reject
      fail: (err) => {
        console.error(`获取存储项 ${key} 失败:`, err);
        reject(err);
      }
    });
  });
};
// 安全获取存储项,失败时返回默认值而不是拒绝Promise
const getItemSafe = (key, defaultValue = null) => {
  return new Promise((resolve) => {
    if (!key) {
      resolve(defaultValue);
      return;
    }
    wx.getStorage({
      key: key,
      success: (res) => resolve(res.data),
      fail: (err) => {
        // 在开发环境下记录警告,但不作为错误处理
        // 数据不存在是正常情况,不需要作为警告输出
        if (err.errMsg !== "getStorage:fail data not found") {
          console.warn(`安全获取存储项 ${key} 失败:`, err);
        } else {
          console.log(`存储项 ${key} 不存在,返回默认值`);
        }
        resolve(defaultValue);
      }
    });
  });
};
const removeItem = (key) => {
  return new Promise((resolve, reject) => {
    if (!key) {
      reject(new Error('存储键不能为空'));
      return;
    }
    wx.removeStorage({
      key: key,
      success: resolve,
      fail: reject
      fail: (err) => {
        console.error(`删除存储项 ${key} 失败:`, err);
        reject(err);
      }
    });
  });
};
@@ -33,21 +82,27 @@
  return new Promise((resolve, reject) => {
    wx.clearStorage({
      success: resolve,
      fail: reject
      fail: (err) => {
        console.error('清除存储失败:', err);
        reject(err);
      }
    });
  });
};
/**
 * 判断本地是否保存了某个key
 * @param {} key
 * @param {String} key 存储键
 * @returns {Boolean} 是否存在该键
 */
const isHasKeySync= (key) => {
const isHasKeySync = (key) => {
  if (!key) return false;
  try {
    const res = wx.getStorageInfoSync();
    return res.keys.includes(key);
  } catch (e) {
    console.error('Failed to get storage info:', e);
    console.error('获取存储信息失败:', e);
    return false;
  }
};
@@ -55,6 +110,7 @@
module.exports = {
  setItem,
  getItem,
  getItemSafe,
  removeItem,
  clear,
  isHasKeySync