管灌系统农户端微信小程序(嘉峪关应用)
更新灌溉计划页面,添加灌溉计划列表刷新标记,优化项目选择器和时间选择器的逻辑;更新样式以提升用户体验,确保在切换标签时只加载必要的数据。
20个文件已修改
1个文件已添加
2122 ■■■■■ 已修改文件
api/config.js 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
app.js 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
images/time.svg 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/createIrrigation/createIrrigation.js 906 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/createIrrigation/createIrrigation.wxml 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/createIrrigation/createIrrigation.wxss 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/groupDetail/groupDetail.js 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/home/home.js 149 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/home/home.json 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/home/home.wxml 44 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/home/home.wxss 274 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/irrigation/irrigation.js 136 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/irrigation/irrigation.wxml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/irrigationDetail/irrigationDetail.js 131 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/irrigationDetail/irrigationDetail.wxml 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/irrigationDetail/irrigationDetail.wxss 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/valveList/valveList.js 210 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/valveList/valveList.wxml 73 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/valveList/valveList.wxss 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pages/waterIntake/waterIntake.json 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
utils/projectConfig.js 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
api/config.js
@@ -7,7 +7,9 @@
  JYG: 'https://irrigate.dayuyanjiuyuan.top/', // 嘉峪关项目
  MQ: 'https://shifanqu1.dayuyanjiuyuan.top/', // 民勤项目
  TEST: 'https://no253541tf71.vicp.fun/', // test项目
  SCHOOL: 'https://school.dayuyanjiuyuan.top/' // 学校项目
  SCHOOL: 'https://school.dayuyanjiuyuan.top/', // 学校项目
  JC:'https://shifanqu1.dayuyanjiuyuan.top/',
  GSCLT:'https://irrigate.dayuyanjiuyuan.top/'//甘肃农科院崔龙天
  // TEST:'http://192.168.40.182:8087/'// test项目
  // MQ: 'https://no253541tf71.vicp.fun/'    // 民勤项目
  // TEST: 'http://192.168.40.166:54321/'
app.js
@@ -25,6 +25,7 @@
    operator:"2025030416200600006",
    clientId:"",
    AppID:"wxbc2b6a00dd904ead",
    vcId:""
    vcId:"",
    needRefreshIrrigationList: false // 用于标记是否需要刷新灌溉计划列表
  }
})
images/time.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="M24 44C35.0457 44 44 35.0457 44 24C44 12.9543 35.0457 4 24 4C12.9543 4 4 12.9543 4 24C4 35.0457 12.9543 44 24 44Z" fill="none" stroke="#1890FF" stroke-width="4" stroke-linejoin="round"/><path d="M24.0084 12.0001L24.0072 24.0089L32.4866 32.4883" stroke="#1890FF" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/></svg>
pages/createIrrigation/createIrrigation.js
@@ -1,450 +1,488 @@
const app = getApp();
const { get, post } = require('../../api/request');
const {
  get,
  post
} = require('../../api/request');
const dayjs = require('dayjs');
Page({
    /**
     * 页面的初始数据
     */
    data: {
        // 表单数据
        planCode: '', // 计划编号
        startTime: '', // 灌溉开始时间
        pickerValue: '', // 时间选择器的值
        timePickerVisible: false, // 时间选择器是否可见
        timeInfoVisible: false, // 时间提示弹窗是否可见
        // 项目选择器相关
        projectPickerVisible: false,
        projectPickerValue: [],
        selectedProject: null,
        projectOptions: [],
        totalDuration: 0, // 添加总灌溉时间
        // 项目列表
        projectList: [],
        // 时间选择器选项
        timeOptions: [],
        // 轮灌组列表刷新状态
        isRefreshing: false
    },
  /**
   * 页面的初始数据
   */
  data: {
    // 表单数据
    planCode: '', // 计划编号
    startTime: '', // 灌溉开始时间
    pickerValue: '', // 时间选择器的值
    timePickerVisible: false, // 时间选择器是否可见
    timeInfoVisible: false, // 时间提示弹窗是否可见
    // 项目选择器相关
    projectPickerVisible: false,
    projectPickerValue: [],
    selectedProject: null,
    projectOptions: [],
    totalDuration: 0, // 添加总灌溉时间
    // 项目列表
    projectList: [],
    // 时间选择器选项
    timeOptions: [],
    // 轮灌组列表刷新状态
    isRefreshing: false
  },
    /**
     * 生命周期函数--监听页面加载
     */
    onLoad: function (options) {
        // 生成计划编号
        this.generatePlanCode();
        // 设置时间选择器的初始值
        const now = dayjs();
        this.setData({
            pickerValue: now.add(8.5, 'hour').format('YYYY-MM-DD HH:mm')
        });
        // 获取项目列表
        this.fetchProjects();
    },
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    // 生成计划编号
    this.generatePlanCode();
    // 设置时间选择器的初始值
    const now = dayjs();
    this.setData({
      pickerValue: now.add(8.5, 'hour').format('YYYY-MM-DD HH:mm')
    });
    // 获取项目列表
    this.fetchProjects();
  },
    /**
     * 生成计划编号
     */
    generatePlanCode: function () {
        const now = dayjs();
        const dateStr = now.format('YYYYMMDD');
        const randomNum = Math.floor(Math.random() * 10000).toString().padStart(4, '0');
        const planCode = `${dateStr}${randomNum}`;
        this.setData({ planCode });
    },
  /**
   * 生成计划编号
   */
  generatePlanCode: function () {
    const now = dayjs();
    const dateStr = now.format('YYYY-MM-DD');
    const randomNum = Math.floor(Math.random() * 10000).toString().padStart(4, '0');
    const planCode = `${dateStr}${-randomNum}`;
    this.setData({
      planCode
    });
  },
    /**
     * 获取项目列表
     */
    fetchProjects: function () {
        return get({
            url: '/wx/irrigation/getSimpleProjects',
            isShowLoding: true
        }).then(res => {
            if (res.success) {
                const projectList = res.content.map(project => ({
                    id: project.projectId,
                    name: project.projectName,
                    groupCount: project.groupCount,
                    groups: []
                }));
                const projectOptions = projectList.map(project => ({
                    label: project.name,
                    value: project.id
                }));
                this.setData({
                    projectList,
                    projectOptions
                });
            } else {
                wx.showToast({
                    title: res.msg || '获取项目列表失败',
                    icon: 'none'
                });
                return Promise.reject(new Error(res.msg || '获取项目列表失败'));
            }
        }).catch(err => {
            console.error('获取项目列表失败:', err);
            wx.showToast({
                title: '获取项目列表失败',
                icon: 'none'
            });
            return Promise.reject(err);
        });
    },
    /**
     * 获取轮灌组列表
     */
    fetchGroups: function (projectId) {
        return get({
            url: '/wx/irrigation/getSimpleGroups',
            data: {
                projectId: projectId,
            },
            isShowLoding: true
        }).then(res => {
            if (res.success) {
                console.log('轮灌组数据:', res.content.obj);
                // 更新选中项目的轮灌组信息
                const projectList = this.data.projectList.map(project => {
                    if (project.id === projectId) {
                        return {
                            ...project,
                            groups: res.content.obj.map(group => ({
                                id: group.groupId,
                                name: group.groupCode,
                                duration: group.defaultDuration || 0,
                                selected: false,
                                intakeCount: group.intakeCount
                            }))
                        };
                    }
                    return project;
                });
                // 更新选中的项目
                const selectedProject = projectList.find(project => project.id === projectId);
                console.log('更新后的选中项目:', selectedProject);
                this.setData({
                    projectList,
                    selectedProject
                }, () => {
                    // 计算总时间
                    this.calculateTotalDuration();
                });
            } else {
                wx.showToast({
                    title: res.msg || '获取轮灌组列表失败',
                    icon: 'none'
                });
                return Promise.reject(new Error(res.msg || '获取轮灌组列表失败'));
            }
        }).catch(err => {
            console.error('获取轮灌组列表失败:', err);
            wx.showToast({
                title: '获取轮灌组列表失败',
                icon: 'none'
            });
            return Promise.reject(err);
        });
    },
    /**
     * 显示时间选择器
     */
    showTimePicker: function () {
        // 如果没有选择时间,使用当前时间
        if (!this.data.pickerValue) {
            const now = dayjs();
            this.setData({
                pickerValue: now.format('YYYY-MM-DD HH:mm')
            });
        }
        this.setData({
            timePickerVisible: true
        });
    },
    /**
     * 时间选择器确认回调
     */
    onTimePickerConfirm: function (e) {
        const { value } = e.detail;
        this.setData({
            timePickerVisible: false,
            startTime: value
        });
    },
    /**
     * 时间选择器取消回调
     */
    onTimePickerCancel: function () {
        this.setData({
            timePickerVisible: false
        });
    },
    /**
     * 切换项目展开/折叠状态
     */
    toggleProject: function (e) {
        const index = e.currentTarget.dataset.index;
        const currentValue = this.data.projectList[index].expanded;
        // 创建新的项目列表,先将所有项目设为折叠状态
        const newProjectList = this.data.projectList.map((item, idx) => {
            return {
                ...item,
                expanded: false
            };
        });
        // 如果当前点击的项目已经是展开状态,则保持所有项目折叠
        // 否则,将当前点击的项目设为展开状态
        if (!currentValue) {
            newProjectList[index].expanded = true;
        }
        this.setData({
            projectList: newProjectList
        });
    },
    /**
     * 切换轮灌组选中状态
     */
    toggleGroupSelection: function (e) {
        const projectIndex = e.currentTarget.dataset.projectIndex;
        const groupIndex = e.currentTarget.dataset.groupIndex;
        const key = `projectList[${projectIndex}].groups[${groupIndex}].selected`;
        const currentValue = this.data.projectList[projectIndex].groups[groupIndex].selected;
        this.setData({
            [key]: !currentValue
        });
        // 更新项目总时长
        this.updateProjectTotalDuration(projectIndex);
    },
    /**
     * 处理时长输入
     */
    onDurationInput: function (e) {
        const { groupIndex } = e.currentTarget.dataset;
        const duration = parseInt(e.detail.value) || 0;
        const selectedProject = { ...this.data.selectedProject };
        selectedProject.groups[groupIndex].duration = duration;
        this.setData({
            selectedProject
        }, () => {
            // 输入时长后重新计算总时间
            this.calculateTotalDuration();
        });
    },
    /**
     * 计算并更新项目总时长
     */
    updateProjectTotalDuration: function (projectIndex) {
        const project = this.data.projectList[projectIndex];
        let totalDuration = 0;
        // 计算所有选中的轮灌组的时长总和
        project.groups.forEach(group => {
            if (group.selected) {
                totalDuration += parseInt(group.duration) || 0;
            }
        });
        // 更新项目总时长
        const totalDurationKey = `projectList[${projectIndex}].totalDuration`;
        this.setData({
            [totalDurationKey]: totalDuration
        });
    },
    /**
     * 阻止事件冒泡
     */
    stopPropagation: function (e) {
        if (e && e.stopPropagation) {
            e.stopPropagation();
        }
        return false;
    },
    /**
     * 跳转到轮灌组详情页
     */
    navigateToGroupDetail: function (e) {
        const { groupIndex } = e.currentTarget.dataset;
        // TODO: 实现跳转逻辑
    },
    /**
     * 确认按钮点击事件
     */
    onConfirm: function () {
        const { planCode, startTime, selectedProject } = this.data;
        if (!planCode) {
            wx.showToast({
                title: '请输入计划编号',
                icon: 'none'
            });
            return;
        }
        if (!selectedProject) {
            wx.showToast({
                title: '请选择项目',
                icon: 'none'
            });
            return;
        }
        // 构建上报数据
        const schedules = selectedProject.groups.map(group => ({
            groupId: group.id,
            duration: parseInt(group.duration) || 0
  /**
   * 获取项目列表
   */
  fetchProjects: function (isShowDiaolog) {
    return get({
      url: '/wx/irrigation/getSimpleProjects',
      isShowLoding: true
    }).then(res => {
      if (res.success) {
        const projectList = res.content.map(project => ({
          id: project.projectId,
          name: project.projectName,
          groupCount: project.groupCount,
          groups: []
        }));
        const requestData = {
            projectId: selectedProject.id,
            planName: planCode,
            startupMode: startTime ? 2 : 1,
            operatorId: app.globalData.clientId,
            schedules: schedules
        };
        const projectOptions = projectList.map(project => ({
          label: project.name,
          value: project.id
        }));
        // 如果有开始时间,添加到请求数据中
        if (startTime) {
            requestData.planStartTime = startTime;
        }
        // 发送请求
        post({
            url: '/wx/plan/createPlan',
            data: requestData,
            isShowLoding: true
        }).then(res => {
            if (res.success) {
                wx.showToast({
                    title: '创建成功',
                    icon: 'success'
                });
                // 返回上一页
                setTimeout(() => {
                    wx.navigateBack();
                }, 1500);
            } else {
                wx.showToast({
                    title: res.msg || '创建失败',
                    icon: 'none'
                });
            }
        }).catch(err => {
            console.error('创建计划失败:', err);
            wx.showToast({
                title: '创建失败',
                icon: 'none'
            });
        });
    },
    // 显示项目选择器
    showProjectPicker() {
        this.setData({
          projectList,
          projectOptions
        });
        if (isShowDiaolog) {
          this.setData({
            projectPickerVisible: true
        });
    },
    // 项目选择器确认
    onProjectPickerConfirm(e) {
        const { value } = e.detail;
        console.log('选择的项目ID:', value[0]); // 添加日志查看数据
        const selectedProject = this.data.projectList.find(project => project.id === value[0]);
        console.log('找到的项目:', selectedProject); // 添加日志查看数据
        this.setData({
            projectPickerVisible: false,
            selectedProject: selectedProject,
            projectPickerValue: value
        }, () => {
            // 选择项目后获取轮灌组列表
            if (selectedProject) {
                this.fetchGroups(selectedProject.id);
            }
        });
    },
    // 项目选择器取消
    onProjectPickerCancel() {
        this.setData({
            projectPickerVisible: false
        });
    },
    /**
     * 计算总灌溉时间
     */
    calculateTotalDuration: function () {
        if (!this.data.selectedProject) return;
        const totalDuration = this.data.selectedProject.groups.reduce((sum, group) => {
            return sum + (parseInt(group.duration) || 0);
        }, 0);
        this.setData({
            totalDuration
        });
    },
    /**
     * 轮灌组列表下拉刷新
     */
    onGroupListRefresh: function () {
        if (!this.data.selectedProject) {
            this.setData({ isRefreshing: false });
            return;
          });
        }
        this.setData({ isRefreshing: true });
        this.fetchGroups(this.data.selectedProject.id)
            .then(() => {
                this.setData({ isRefreshing: false });
            })
            .catch(() => {
                this.setData({ isRefreshing: false });
            });
    },
    /**
     * 显示时间提示弹窗
     */
    showTimeInfo: function () {
        this.setData({
            timeInfoVisible: true
      } else {
        wx.showToast({
          title: res.msg || '获取项目列表失败',
          icon: 'none'
        });
    },
        return Promise.reject(new Error(res.msg || '获取项目列表失败'));
      }
    }).catch(err => {
      console.error('获取项目列表失败:', err);
      wx.showToast({
        title: '获取项目列表失败',
        icon: 'none'
      });
      return Promise.reject(err);
    });
  },
    /**
     * 关闭时间提示弹窗
     */
    onTimeInfoConfirm: function () {
        this.setData({
            timeInfoVisible: false
  /**
   * 获取轮灌组列表
   */
  fetchGroups: function (projectId) {
    return get({
      url: '/wx/irrigation/getSimpleGroups',
      data: {
        projectId: projectId,
      },
      isShowLoding: true
    }).then(res => {
      if (res.success) {
        console.log('轮灌组数据:', res.content);
        // 更新选中项目的轮灌组信息
        const projectList = this.data.projectList.map(project => {
          if (project.id === projectId) {
            return {
              ...project,
              groups: res.content.map(group => ({
                id: group.groupId,
                name: group.groupCode,
                duration: group.defaultDuration || 0,
                selected: false,
                intakeCount: group.intakeCount
              }))
            };
          }
          return project;
        });
    },
});
        // 更新选中的项目
        const selectedProject = projectList.find(project => project.id === projectId);
        console.log('更新后的选中项目:', selectedProject);
        this.setData({
          projectList,
          selectedProject
        }, () => {
          // 计算总时间
          this.calculateTotalDuration();
        });
      } else {
        wx.showToast({
          title: res.msg || '获取轮灌组列表失败',
          icon: 'none'
        });
        return Promise.reject(new Error(res.msg || '获取轮灌组列表失败'));
      }
    }).catch(err => {
      console.error('获取轮灌组列表失败:', err);
      wx.showToast({
        title: '获取轮灌组列表失败',
        icon: 'none'
      });
      return Promise.reject(err);
    });
  },
  /**
   * 显示时间选择器
   */
  showTimePicker: function () {
    // 如果没有选择时间,使用当前时间
    if (!this.data.pickerValue) {
      const now = dayjs();
      this.setData({
        pickerValue: now.format('YYYY-MM-DD HH:mm')
      });
    }
    this.setData({
      timePickerVisible: true
    });
  },
  /**
   * 时间选择器确认回调
   */
  onTimePickerConfirm: function (e) {
    const {
      value
    } = e.detail;
    this.setData({
      timePickerVisible: false,
      startTime: value
    });
  },
  /**
   * 时间选择器取消回调
   */
  onTimePickerCancel: function () {
    this.setData({
      timePickerVisible: false
    });
  },
  /**
   * 切换项目展开/折叠状态
   */
  toggleProject: function (e) {
    const index = e.currentTarget.dataset.index;
    const currentValue = this.data.projectList[index].expanded;
    // 创建新的项目列表,先将所有项目设为折叠状态
    const newProjectList = this.data.projectList.map((item, idx) => {
      return {
        ...item,
        expanded: false
      };
    });
    // 如果当前点击的项目已经是展开状态,则保持所有项目折叠
    // 否则,将当前点击的项目设为展开状态
    if (!currentValue) {
      newProjectList[index].expanded = true;
    }
    this.setData({
      projectList: newProjectList
    });
  },
  /**
   * 切换轮灌组选中状态
   */
  toggleGroupSelection: function (e) {
    const projectIndex = e.currentTarget.dataset.projectIndex;
    const groupIndex = e.currentTarget.dataset.groupIndex;
    const key = `projectList[${projectIndex}].groups[${groupIndex}].selected`;
    const currentValue = this.data.projectList[projectIndex].groups[groupIndex].selected;
    this.setData({
      [key]: !currentValue
    });
    // 更新项目总时长
    this.updateProjectTotalDuration(projectIndex);
  },
  /**
   * 处理时长输入
   */
  onDurationInput: function (e) {
    const {
      groupIndex
    } = e.currentTarget.dataset;
    const duration = parseInt(e.detail.value) || 0;
    const selectedProject = {
      ...this.data.selectedProject
    };
    selectedProject.groups[groupIndex].duration = duration;
    this.setData({
      selectedProject
    }, () => {
      // 输入时长后重新计算总时间
      this.calculateTotalDuration();
    });
  },
  /**
   * 计算并更新项目总时长
   */
  updateProjectTotalDuration: function (projectIndex) {
    const project = this.data.projectList[projectIndex];
    let totalDuration = 0;
    // 计算所有选中的轮灌组的时长总和
    project.groups.forEach(group => {
      if (group.selected) {
        totalDuration += parseInt(group.duration) || 0;
      }
    });
    // 更新项目总时长
    const totalDurationKey = `projectList[${projectIndex}].totalDuration`;
    this.setData({
      [totalDurationKey]: totalDuration
    });
  },
  /**
   * 阻止事件冒泡
   */
  stopPropagation: function (e) {
    if (e && e.stopPropagation) {
      e.stopPropagation();
    }
    return false;
  },
  /**
   * 跳转到轮灌组详情页
   */
  navigateToGroupDetail: function (e) {
    const {
      groupIndex
    } = e.currentTarget.dataset;
    // TODO: 实现跳转逻辑
  },
  /**
   * 确认按钮点击事件
   */
  onConfirm: function () {
    const {
      planCode,
      startTime,
      selectedProject
    } = this.data;
    if (!planCode) {
      wx.showToast({
        title: '请输入计划编号',
        icon: 'none'
      });
      return;
    }
    if (!selectedProject) {
      wx.showToast({
        title: '请选择项目',
        icon: 'none'
      });
      return;
    }
    // 构建上报数据
    const schedules = selectedProject.groups.map(group => ({
      groupId: group.id,
      duration: parseInt(group.duration) || 0
    }));
    const requestData = {
      projectId: selectedProject.id,
      planName: planCode,
      startupMode: startTime ? 2 : 1,
      operatorId: app.globalData.clientId,
      schedules: schedules
    };
    // 如果有开始时间,添加到请求数据中
    if (startTime) {
      requestData.planStartTime = startTime;
    }
    // 发送请求
    post({
      url: '/wx/plan/createPlan',
      data: requestData,
      isShowLoding: true
    }).then(res => {
      if (res.success) {
        wx.showToast({
          title: '创建成功',
          icon: 'success'
        });
        // 返回上一页,并传递参数指示需要刷新列表并切换到当前计划列表
        setTimeout(() => {
          // 使用全局变量标记需要刷新
          const app = getApp();
          app.globalData.needRefreshIrrigationList = true;
          // 直接返回上一页
          wx.navigateBack({
            delta: 1
          });
        }, 1500);
      } else {
        wx.showToast({
          title: res.msg || '创建失败',
          icon: 'none'
        });
      }
    }).catch(err => {
      console.error('创建计划失败:', err);
      wx.showToast({
        title: '创建失败',
        icon: 'none'
      });
    });
  },
  // 显示项目选择器
  showProjectPicker() {
    this.fetchProjects(true)
  },
  // 项目选择器确认
  onProjectPickerConfirm(e) {
    const {
      value
    } = e.detail;
    console.log('选择的项目ID:', value[0]); // 添加日志查看数据
    const selectedProject = this.data.projectList.find(project => project.id === value[0]);
    console.log('找到的项目:', selectedProject); // 添加日志查看数据
    this.setData({
      projectPickerVisible: false,
      selectedProject: selectedProject,
      projectPickerValue: value
    }, () => {
      // 选择项目后获取轮灌组列表
      if (selectedProject) {
        this.fetchGroups(selectedProject.id);
      }
    });
  },
  // 项目选择器取消
  onProjectPickerCancel() {
    this.setData({
      projectPickerVisible: false
    });
  },
  /**
   * 计算总灌溉时间
   */
  calculateTotalDuration: function () {
    if (!this.data.selectedProject) return;
    const totalDuration = this.data.selectedProject.groups.reduce((sum, group) => {
      return sum + (parseInt(group.duration) || 0);
    }, 0);
    this.setData({
      totalDuration
    });
  },
  /**
   * 轮灌组列表下拉刷新
   */
  onGroupListRefresh: function () {
    if (!this.data.selectedProject) {
      this.setData({
        isRefreshing: false
      });
      return;
    }
    this.setData({
      isRefreshing: true
    });
    this.fetchGroups(this.data.selectedProject.id)
      .then(() => {
        this.setData({
          isRefreshing: false
        });
      })
      .catch(() => {
        this.setData({
          isRefreshing: false
        });
      });
  },
  /**
   * 显示时间提示弹窗
   */
  showTimeInfo: function () {
    this.setData({
      timeInfoVisible: true
    });
  },
  /**
   * 关闭时间提示弹窗
   */
  onTimeInfoConfirm: function () {
    this.setData({
      timeInfoVisible: false
    });
  },
});
pages/createIrrigation/createIrrigation.wxml
@@ -65,7 +65,11 @@
        <block wx:for="{{selectedProject.groups}}" wx:key="id" wx:for-item="group" wx:for-index="groupIndex">
          <view class="group-item {{group.selected ? 'selected' : ''}}" bindtap="navigateToGroupDetail" data-group-index="{{groupIndex}}">
            <view class="group-info">
              <view class="group-name">{{group.name || '未命名轮灌组'}}  (共{{group.intakeCount}}个取水口)</view>
              <text class="group-index">{{groupIndex + 1}}.</text>
              <view class="group-name">
                <text class="group-name-text">{{group.name || '未命名轮灌组'}}</text>
                <text class="group-intake-count">(共{{group.intakeCount}}个取水口)</text>
              </view>
            </view>
            <view class="group-duration">
              <input 
pages/createIrrigation/createIrrigation.wxss
@@ -257,16 +257,33 @@
  flex-wrap: wrap;
}
.group-index {
  color: #1890FF;
  margin-right: 8rpx;
  font-size: 26rpx;
}
.group-name {
  display: flex;
  align-items: center;
  font-size: 26rpx;
  color: #666;
  position: relative;
  padding-left: 10rpx;
  background-color: rgba(24, 144, 255, 0.1);
  padding: 4rpx 20rpx;
  background-color: rgba(24, 144, 255, 0.1);
  border-radius: 10rpx;
}
.group-name-text {
  color: #333;
  margin-right: 8rpx;
}
.group-intake-count {
  color: #999;
  font-size: 24rpx;
}
.group-hint {
  font-size: 22rpx;
  color: #1890FF;
pages/groupDetail/groupDetail.js
@@ -34,11 +34,6 @@
      
      console.log('设置后的数据:', this.data);
      
      // 设置导航栏标题
      wx.setNavigationBarTitle({
        title: this.data.groupName || '轮灌组详情'
      });
      this.loadWaterOutletData();
    }
  },
pages/home/home.js
@@ -58,14 +58,14 @@
            })
        }
    },
    calculateScrollViewHeight: function () {
        wx.createSelectorQuery().selectAll('.list-item').boundingClientRect((rects) => {
            let totalHeight = rects.reduce((sum, rect) => sum + rect.height, 0);
            this.setData({
                scrollViewHeight: totalHeight,
            });
        }).exec();
    },
    // calculateScrollViewHeight: function () {
    //     wx.createSelectorQuery().selectAll('.list-item').boundingClientRect((rects) => {
    //         let totalHeight = rects.reduce((sum, rect) => sum + rect.height, 0);
    //         this.setData({
    //             scrollViewHeight: totalHeight,
    //         });
    //     }).exec();
    // },
    startPullDownRefresh() {
        if (getApp().globalData.isLoggedIn) {
            if (!this.data.isWXRefreshing) {
@@ -340,13 +340,17 @@
        })
    },
    openValveList() {
        // wx.navigateTo({
        //   url: '/pages/valveList/valveList',
        // })
        wx.showToast({
            title: '暂未开放',
            icon: 'none'
        })
      const app = getApp();
      if (app.globalData.isLoggedIn) {
          wx.navigateTo({
            url: '/pages/valveList/valveList',
          })
      } else {
          wx.showToast({
              title: '请先登录',
              icon: 'error'
          })
      }
    },
    feedBack() {
        wx.showToast({
@@ -538,11 +542,8 @@
                isRefreshing: false, // 将triggered属性设置为false,表示下拉刷新已完成
                isWXRefreshing: false, // 将triggered属性设置为false,表示下拉刷新已完成
            });
            this.updateDisplayText();
            // 成功获取数据后刷新UI高度
            setTimeout(() => {
                this.calculateScrollViewHeight();
            }, 200);
        }).catch(err => {
            console.error('获取列表数据失败:', err);
            // 错误回调
@@ -1235,13 +1236,6 @@
            console.log('continueInitPage: 从页面数据中检测到isFromLogin=true');
            fromLogin = true;
        }
        // 判断本地是否保存sessionId
        // 使用 wx.nextTick 等待页面渲染完成
        wx.nextTick(() => {
            this.calculateScrollViewHeight();
        });
        // 当开阀成功后调用刷新
        if (options && options.param) {
            console.log("开阀成功参数:", options.param);
@@ -1498,4 +1492,107 @@
            showInfoDialog: false
        })
    },
  //强制删除
  onDelete(e) {
    const item = e.currentTarget.dataset.item;
    const that = this;
    if (this.data.useTestData) {
      // 测试数据模式下,模拟删除操作
      wx.showLoading({
        title: '正在强制删除请稍候...',
        mask: true
      });
      // 模拟请求延迟
      setTimeout(() => {
        wx.hideLoading();
        // 从列表中移除被删除的项
        const updatedList = this.data.listData.filter(listItem =>
          listItem.orderNo !== item.orderNo
        );
        this.setData({
          listData: updatedList
        });
        wx.showToast({
          title: '删除成功',
          icon: 'success',
          duration: 2000
        });
      }, 1500);
      return;
    }
    wx.showLoading({
      title: '正在强制删除请稍候...', // 加载提示文字
      mask: true // 是否显示透明蒙层,防止触摸穿透,默认为 false
    });
    const data = {
      vcNum: item.vcNum, //取水口ID
      rtuAddr: item.rtuAddr, //阀控器地址
    };
    post({
      url: "wx/valve/deleteUnclosed",
      data: data,
      timeout: 180000
    }).then(response => {
      // 处理成功响应
      console.log('请求成功:', response);
      // 加载完成后隐藏加载动画
      wx.hideLoading();
      //重新获取列表刷新数据
      this.getOpenList();
    }).catch(error => {
      // 加载完成后隐藏加载动画
      wx.hideLoading();
      // 处理错误响应
      console.error('请求失败:', error);
    });
  },
  //修改按钮文字
  updateDisplayText() {
    const updatedList = this.data.listData.map(item => {
      let displayText = '';
      if (item.planned) {
        displayText = '取消';
      } else {
        displayText = "关阀"
      }
      let deleteText = "删除"
      let time;
      if (!item.dt) {
        time = "暂无"
      } else {
        time = this.extractTime(item.dt)
      }
      if (item.waterInstant===null) {
        item.waterInstant = "暂无"
      }
      return {
        ...item,
        displayText,
        deleteText,
        time
      }; // 保留所有其他字段,并添加 displayText 字段
    });
    // 更新列表数据
    this.setData({
      listData: updatedList
    });
  },
    //处理时间去掉年月日
    extractTime(datetimeString) {
      const formattedDate = datetimeString.replace(" ", "T");
      const date = new Date(formattedDate);
      // 获取小时、分钟和秒
      const hours = date.getHours().toString().padStart(2, '0');
      const minutes = date.getMinutes().toString().padStart(2, '0');
      const seconds = date.getSeconds().toString().padStart(2, '0');
      return `${hours}:${minutes}:${seconds}`;
    },
})
pages/home/home.json
@@ -2,7 +2,7 @@
  "component": true,
  "usingComponents": {
    "t-avatar": "tdesign-miniprogram/avatar/avatar",
    "t-switch": "tdesign-miniprogram/switch/switch",
    "t-swipe-cell": "tdesign-miniprogram/swipe-cell/swipe-cell",
    "t-dialog": "tdesign-miniprogram/dialog/dialog"
  },
  "navigationBarTitleText": "大禹节水",
pages/home/home.wxml
@@ -47,7 +47,6 @@
    </view>
    <text class="refresh-button" bind:tap="startPullDownRefresh">刷新</text>
  </view>
  <view class="divider"></view>
  <!-- refresher-enabled="true" refresher-threshold="50" -->
  <scroll-view class="scroll-view" scroll-x="false" scroll-y="true" refresher-enabled="{{isRefreshing==false?true:false}}" refresher-threshold="50" bindrefresherrefresh="onPullDownRefresh" refresher-triggered="{{isWXRefreshing}}">
    <view wx:if="{{isRefreshing}}" class="refresh-view">
@@ -56,16 +55,29 @@
      <view class="dot"></view>
    </view>
    <view class="scroll-bg">
      <view wx:if="{{listData.length > 0}}" class="list-item" wx:for="{{listData}}" wx:key="index">
        <view class="item-left">
          <!-- <image class="item-img" src="/images/pipeline.svg" /> -->
          <text>{{item.intakeNum}}</text>
          <image class="item-img" src="{{item.isOnLine ? '/images/wifi_no.svg' : '/images/wifi_off.svg'}}" />
        </view>
        <view>
          <!-- <t-switch  class="switch" data-item="{{item}}" bindchange="handleChange" value="{{true}}" label="{{['开', '关']}}" slot="note" /> -->
          <text class="item-button" bind:tap="handleChange" data-item="{{item}}">关阀</text>
        </view>
      <view wx:if="{{listData.length > 0}}" wx:for="{{listData}}" wx:key="index">
        <t-swipe-cell>
          <view class="swipe-cell">
            <view class="list-item">
              <view class="item-left">
                <view class="left-intake-name">
                  <image class="item-img-left" src="/images/valve.svg" />
                  <text class="water-intake-name">{{item.intakeNum}}</text>
                  <image class="item-img" src="{{item.isOnLine ? '/images/wifi_no.svg' : '/images/wifi_off.svg'}}" />
                </view>
                <view class="left-time">
                  <image class="item-img" src="/images/time.svg" />
                  <text class="flow-time">{{item.time}}</text>
                  <text class="flow-rate">瞬时流量:{{item.waterInstant}} m³/h</text>
                </view>
              </view>
              <view class="item-right">
                <text class="item-button" bind:tap="handleChange" data-item="{{item}}">关阀</text>
              </view>
            </view>
          </view>
          <view slot="right" class="delete-btn" bind:tap="onDelete" data-item="{{item}}">{{item.deleteText}}</view>
        </t-swipe-cell>
      </view>
    </view>
    <view wx:if="{{listData.length === 0}}" class="noMore-View-home">
@@ -104,6 +116,14 @@
            <radio value="SCHOOL" checked="{{selectedProject === 'SCHOOL'}}" color="#1890FF" />
            <text>学校项目</text>
          </label>
          <label class="project-radio {{selectedProject === 'JC' ? 'project-radio-selected' : ''}}">
            <radio value="JC" checked="{{selectedProject === 'JC'}}" color="#1890FF" />
            <text>金昌项目</text>
          </label>
          <label class="project-radio {{selectedProject === 'GSCLT' ? 'project-radio-selected' : ''}}">
            <radio value="GSCLT" checked="{{selectedProject === 'GSCLT'}}" color="#1890FF" />
            <text>甘肃农科院-崔</text>
          </label>
        </radio-group>
      </view>
      <view class="project-modal-footer">
@@ -117,7 +137,7 @@
    <scroll-view slot="content" type="list" scroll-y class="long-content">
      <view class="content-container">
        <text class="content-container">
          1.网络等不可抗力因素可能导致设备状态显示延迟或错误。
          1.网络等不可抗力因素可能导致设备状态显示延迟或错误。(当进行了开阀或关阀操作后会有一定延时才可确认是否操作成功)
          2.当提示您操作失败后您可稍后尝试重新操作。
          3.在定时或定量开阀的预约式开阀后,只有阀门到达约定的时间成功开阀后未关阀记录才会显示。
          4.我们诚挚地邀请您通过意见反馈渠道提出宝贵的建议或意见。
pages/home/home.wxss
@@ -143,22 +143,168 @@
    /* 允许垂直滚动 */
    z-index: 0;
    /* 确保 scroll-view 在头部和 center-wrapper 之下 */
    background-color: #f5f5f5;
    margin-top: 0;
    padding-top: 0;
    box-sizing: border-box;
}
.scroll-bg {
    padding: 20rpx 0;
    box-sizing: border-box;
    padding-top: 0;
    width: 100%;
}
/* 确保所有含宽度的元素使用相同的计算方式 */
.bottom-title,
.scroll-bg > view {
    width: calc(100% - 40rpx);
    margin-left: 20rpx;
    margin-right: 20rpx;
    box-sizing: border-box;
}
.scroll-bg > view {
    margin-bottom: 20rpx;
    border-radius: 12rpx;
    overflow: hidden;
    box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
}
t-swipe-cell {
    display: block;
    width: 100%;
    border-radius: 12rpx;
    overflow: hidden;
}
.swipe-cell {
    display: flex;
    justify-content: space-between;
    background-color: #fff;
    width: 100%;
    height: 100%;
    border-radius: 12rpx;
    overflow: hidden;
}
.list-item {
    background-color: #fff;
    margin-bottom: 2rpx;
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding-left: 30rpx;
    padding-right: 30rpx;
    padding-top: 30rpx;
    padding-bottom: 30rpx;
    padding: 30rpx;
    width: 100%;
    box-sizing: border-box;
}
.item-left {
    display: flex;
    flex-direction: column;
    flex: 1;
    width: 100%;
}
.left-intake-name {
    width: 100%;
    display: flex;
    align-items: center;
    margin-bottom: 20rpx;
    padding-left: 4rpx;
}
.item-img-left {
    width: 40rpx;
    height: 40rpx;
    flex-shrink: 0;
}
.item-img {
    width: 40rpx;
    height: 40rpx;
    flex-shrink: 0;
}
.left-intake-name .item-img {
    margin-left: 8rpx;
}
.water-intake-name {
    font-size: 42rpx !important;
    margin-left: 16rpx;
    margin-right: 15rpx;
    white-space: nowrap; /* 防止文本换行 */
    font-weight: 500;
    color: #333;
    flex-shrink: 0;
}
.left-time {
    width: 100%;
    display: flex;
    align-items: center;
    color: #666;
    flex-wrap: nowrap;
    overflow: hidden;
    padding-right: 10rpx;
    padding-left: 4rpx;
}
.flow-time {
    font-size: 28rpx !important;
    margin-left: 16rpx;
    margin-right: 2rpx;
    white-space: nowrap;
    color: #666;
    display: inline-block;
}
.flow-rate {
    font-size: 28rpx !important;
    margin-left: 6rpx;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    flex: 1;
    color: #666;
}
.item-right {
    display: flex;
    align-items: center;
    margin-left: 20rpx;
    margin-right: 20rpx;
}
.item-button {
    display: flex;
    height: 70rpx;
    padding: 0 40rpx;
    background-color: #1890FF;
    color: white;
    border: none;
    border-radius: 35rpx;
    font-size: 30rpx !important;
    align-items: center;
    justify-content: center;
    white-space: nowrap; /* 确保文字不换行 */
    box-shadow: 0 4rpx 8rpx rgba(24, 144, 255, 0.2);
    transition: all 0.3s;
}
.item-button:active {
    background-color: #1378d8;
    transform: scale(0.98);
}
.delete-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 140rpx;
    height: 100%;
    color: white;
    background-color: #e34d59;
    font-size: 30rpx;
}
.list-item text {
@@ -174,34 +320,40 @@
}
.bottom-title {
    border-radius: 5px 5px 0 0;
    border-radius: 12rpx 12rpx 0 0;
    background-color: #fff;
    display: flex;
    align-items: center;
    /* 垂直方向居中 */
    justify-content: space-between;
    /* 子元素在主轴上的对齐方式 */
    padding: 10px;
    padding: 30rpx;
    /* 容器的内边距 */
    width: calc(100% - 40rpx);
    margin-left: 20rpx;
    margin-right: 20rpx;
    margin-top: 20rpx;
    margin-bottom: 0;
    box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.03);
    position: relative;
    box-sizing: border-box;
    border-bottom: 1rpx solid #e7e7e7;
}
.bottom-title-text {
    margin-right: 10rpx;
    /* 给文本和图标之间添加一些间距 */
    font-size: 35rpx;
    font-size: 34rpx;
    /* 字体大小 */
    color: #333;
    /* 字体颜色 */
  }
    font-weight: 500;
}
.refresh-button {
    margin-left: auto;
    /* 将按钮推到容器的最右侧 */
    font-size: 30rpx;
    font-size: 28rpx;
    /* 按钮文字的字体大小 */
    color: #fff;
    /* 按钮文字颜色 */
@@ -209,37 +361,37 @@
    /* 按钮背景颜色 */
    border: none;
    /* 去掉按钮边框 */
    border-radius: 5px;
    border-radius: 30rpx;
    /* 按钮圆角 */
    padding-left: 25rpx;
    padding-right: 25rpx;
    padding-top: 15rpx;
    padding: 15rpx 30rpx;
    display: flex;
    align-items: center;
    justify-content: center;
    padding-bottom: 15rpx;
    box-shadow: 0 4rpx 8rpx rgba(24, 144, 255, 0.2);
    transition: all 0.3s;
}
.refresh-button:active {
    background-color: #7c7c7c;
    /* Change to a darker color when pressed */
    background-color: #1378d8;
    transform: scale(0.98);
}
.refresh-view {
    text-align: center;
    padding: 30rpx;
    padding: 40rpx;
    display: flex;
    justify-content: center;
    align-items: center;
}
.dot {
    width: 20rpx;
    height: 20rpx;
    background-color: #333;
    width: 16rpx;
    height: 16rpx;
    background-color: #1890FF;
    border-radius: 50%;
    margin: 0 5px;
    margin: 0 8rpx;
    animation: blink 1.4s infinite both;
    opacity: 0.7;
}
.dot:nth-child(2) {
@@ -251,15 +403,17 @@
}
@keyframes blink {
    0%,
    80%,
    100% {
        opacity: 0;
    0% {
        opacity: 0.2;
        transform: scale(0.8);
    }
    40% {
    50% {
        opacity: 1;
        transform: scale(1.2);
    }
    100% {
        opacity: 0.2;
        transform: scale(0.8);
    }
}
@@ -267,23 +421,9 @@
    --td-switch-checked-color: #1890FF;
}
.item-left {
    display: flex;
    align-items: center;
}
.item-left text {
    font-size: 40rpx;
/* 修改选择器,使其不会影响flow-time */
.item-left .water-intake-name {
    min-width: 150rpx;
}
.item-img {
    width: 40rpx;
    /* 根据需要调整图标大小 */
    height: 40rpx;
    /* 根据需要调整图标大小 */
    margin-left: 20rpx;
}
.dialog {
@@ -294,39 +434,23 @@
.noMore-View-home {
    display: flex;
    flex-direction: column;
    /* 确保子元素纵向排列 */
    justify-content: center;
    /* 垂直居中 */
    align-items: center;
    /* 水平居中 */
    height: 100%;
    /* 让容器高度占满父元素 */
}
.item-button {
    display: flex;
    height: 80rpx;
    padding: 0 60rpx;
    background-color: #1890FF;
    color: white;
    border: none;
    border-radius: 20rpx;
    font-size: 30rpx;
    align-items: center;
    justify-content: center;
    margin-top: 80rpx;
    padding: 40rpx;
}
.item-button:active {
    background-color: #7c7c7c;
    /* Change to a darker color when pressed */
.noMore-img {
    width: 200rpx;
    height: 200rpx;
    margin-bottom: 20rpx;
    opacity: 0.7;
}
.divider {
    width: 100%;
    margin-top: 2rpx;
    /* background-color: #e0e0e0; */
.noMore-text {
    font-size: 32rpx;
    color: #999;
}
.error-dialog {
    --td-dialog-title-color: red;
@@ -628,7 +752,7 @@
  }
  
  .long-content {
    height: 450rpx;
    height: 500rpx;
    margin-top: 16rpx;
    font-size: 32rpx;
    color: #888;
pages/irrigation/irrigation.js
@@ -51,44 +51,42 @@
  /**
   * 生命周期函数--监听页面显示
   */
  // onShow: function () {
  //   // 设置页面为加载中状态
  //   wx.showLoading({
  //     title: '加载中',
  //     mask: true
  //   });
  onShow: function () {
    // 检查全局变量,判断是否需要刷新列表并切换到当前计划
    const app = getApp();
    
  //   // 先加载当前页面所需的数据
  //   const currentTab = this.data.currentTab;
  //   if (currentTab === 0) {
  //     // 当前标签是"当前灌溉计划",加载这个
  //     this.loadIrrigationData()
  //       .then(() => {
  //         wx.hideLoading();
  //       })
  //       .catch(() => {
  //         wx.hideLoading();
  //       });
  //   } else {
  //     // 当前标签是"历史计划"
  //     // 只加载第一页数据,保留分页状态
  //     if (this.data.completedList.length === 0) {
  //       // 如果历史列表为空,重置分页状态
  //       this.setData({
  //         pageCurr: 1,
  //         hasMoreData: true
  //       });
  //     }
    // 刷新所有数据(当前计划和历史计划),确保数据最新
    wx.showLoading({
      title: '刷新数据中',
      mask: true
    });
    // 同时获取当前计划和历史计划数据
    Promise.all([
      this.loadIrrigationData(),
      this.loadCompletedIrrigationData(true) // 传入true表示是重新加载第一页
    ]).then(() => {
      wx.hideLoading();
      
  //     this.loadCompletedIrrigationData()
  //       .then(() => {
  //         wx.hideLoading();
  //       })
  //       .catch(() => {
  //         wx.hideLoading();
  //       });
  //   }
  // },
      // 如果需要刷新并切换到当前计划
      if (app.globalData.needRefreshIrrigationList) {
        // 重置全局变量
        app.globalData.needRefreshIrrigationList = false;
        console.log('检测到需要刷新灌溉计划列表');
        // 切换到当前灌溉计划标签页
        if (this.data.currentTab !== 0) {
          this.setData({
            currentTab: 0,
            currentList: this.data.activeList
          });
        }
      }
    }).catch(() => {
      wx.hideLoading();
    });
  },
  /**
   * 加载轮灌数据
@@ -148,10 +146,18 @@
  /**
   * 加载已完成的轮灌数据
   */
  loadCompletedIrrigationData: function () {
  loadCompletedIrrigationData: function (isFirstPage) {
    // 如果正在加载或没有更多数据,则不再请求
    if (this.data.loadingMore && !this.data.hasMoreData) {
      return Promise.resolve();
    }
    // 如果是重新加载第一页,重置页码和状态
    if (isFirstPage) {
      this.setData({
        pageCurr: 1,
        hasMoreData: true
      });
    }
    
    // 设置加载状态
@@ -320,7 +326,7 @@
    
    // 导航到灌溉详情页面,并传递参数
    wx.navigateTo({
      url: `/pages/irrigationDetail/irrigationDetail?planId=${id}&fromList=true`
      url: `/pages/irrigationDetail/irrigationDetail?planId=${id}&fromList=true&status=${status}`
    });
  },
@@ -358,10 +364,17 @@
            }
          }).catch(err => {
            console.error('发布失败:', err);
            wx.showToast({
              title: '发布失败',
              icon: 'none'
            });
            if(err.code==='1003'){
              wx.showToast({
                title: err.msg || '发布失败',
                icon: 'none'
              });
            }else{
              wx.showToast({
                title: '发布失败',
                icon: 'none'
              });
            }
          });
        }
      }
@@ -443,8 +456,13 @@
            title: '终止成功',
            icon: 'success'
          });
          // 刷新数据
          this.loadIrrigationData();
          // 同时刷新当前计划列表和历史计划列表
          Promise.all([
            this.loadIrrigationData(),
            this.loadCompletedIrrigationData(true) // 传入true表示重新加载第一页
          ]).catch(err => {
            console.error('刷新数据失败:', err);
          });
        } else {
          wx.showToast({
            title: res.msg || '终止失败',
@@ -578,5 +596,35 @@
          console.error('加载更多历史数据失败:', err);
        });
    }
  },
  /**
   * 从创建灌溉计划页面返回时,切换到当前计划列表并刷新数据
   */
  switchToCurrentPlans: function() {
    console.log('从创建页面返回,切换到当前计划列表并刷新');
    // 如果当前不在 "当前灌溉计划" 标签页,先切换到该标签页
    if (this.data.currentTab !== 0) {
      this.setData({
        currentTab: 0,
        currentList: this.data.activeList
      });
    }
    // 显示加载提示
    wx.showLoading({
      title: '刷新数据中',
      mask: true
    });
    // 刷新当前灌溉计划数据
    this.loadIrrigationData()
      .then(() => {
        wx.hideLoading();
      })
      .catch(() => {
        wx.hideLoading();
      });
  }
}) 
pages/irrigation/irrigation.wxml
@@ -70,7 +70,7 @@
            </view>
            <!-- 操作按钮区域 -->
            <view class="action-section" catchtap="stopPropagation" wx:if="{{item.status !== '4'}}">
            <view class="action-section" catchtap="stopPropagation" wx:if="{{item.status === '1'||item.status === '2'||item.status === '3'}}">
              <block wx:if="{{item.status === '1'}}">
                <view class="action-buttons">
                  <button class="action-button delete-button" hover-class="delete-button-hover" bindtap="onDelete" data-id="{{item.id}}">
pages/irrigationDetail/irrigationDetail.js
@@ -12,7 +12,10 @@
    planId: '',
    planStatusText: '',
    planStatusClass: '',
    failureCount: 0
    failureCount: 0,
    realStopTime: '',
    originalStatus: '',
    currentStatus: null
  },
  /**
@@ -23,7 +26,35 @@
      this.setData({
        planId: options.planId
      });
      this.fetchIrrigationData(options.planId);
      // 获取最新状态
      this.fetchPlanLatestState(options.planId).then(res => {
        if (res.success) {
          const currentStatus = res.content;
          this.setData({
            currentStatus: currentStatus,
            originalStatus: currentStatus
          });
          // 根据最新状态调用相应的接口
          if (currentStatus === 5) {
            this.fetchTerminatedIrrigationData(options.planId);
          } else {
            this.fetchNormalIrrigationData(options.planId);
          }
        } else {
          wx.showToast({
            title: res.msg || '获取状态失败',
            icon: 'none'
          });
        }
      }).catch(err => {
        console.error('获取状态失败:', err);
        wx.showToast({
          title: '获取状态失败',
          icon: 'none'
        });
      });
    } else {
      wx.showToast({
        title: '缺少计划ID',
@@ -36,9 +67,9 @@
  },
  /**
   * 获取灌溉计划数据
   * 获取常规灌溉计划详细数据
   */
  fetchIrrigationData: function(planId) {
  fetchNormalIrrigationData: function(planId) {
    const { get } = require('../../api/request');
    
    const data = {
@@ -69,6 +100,57 @@
  },
  /**
   * 获取已终止灌溉计划详细数据
   */
  fetchTerminatedIrrigationData: function(planId) {
    const { get } = require('../../api/request');
    const data = {
      planId: planId || this.data.planId,
    };
    get({
      url: 'wx/plan/getTerminateResults',
      isShowLoding: true,
      useParams: true,
      data: data
    }).then(res => {
      if (res.success) {
        this.processIrrigationData(res.content);
      } else {
        wx.showToast({
          title: res.msg || '获取数据失败',
          icon: 'none'
        });
      }
    }).catch(err => {
      console.error('请求失败:', err);
      wx.showToast({
        title: '请求失败',
        icon: 'none'
      });
    });
  },
  /**
   * 获取计划最新状态
   */
  fetchPlanLatestState: function(planId) {
    const { get } = require('../../api/request');
    const data = {
      planId: planId || this.data.planId,
    };
    return get({
      url: 'wx/plan/getPlanLatestState',
      isShowLoding: true,
      useParams: true,
      data: data
    });
  },
  /**
   * 处理接口返回的数据
   */
  processIrrigationData: function(data) {
@@ -78,7 +160,9 @@
    const statusMap = {
      2: {status: 'pending', statusText: '未开始'},
      3: {status: 'in_progress', statusText: '灌溉中'},
      4: {status: 'completed', statusText: '已结束'}
      4: {status: 'completed', statusText: '已结束'},
      5: {status: 'terminated', statusText: '中途关阀'},
      6: {status: 'canceled', statusText: '取消开阀'}
    };
    // 处理计划状态
@@ -140,6 +224,7 @@
      projectName: data.projectName,
      startTime: data.planStartTime,
      stopTime: data.planStopTime,
      realStopTime: data.realStopTime || '',
      groupList: groupList,
      planStatusText: planStatusText,
      planStatusClass: planStatusClass,
@@ -182,15 +267,41 @@
    this.setData({
      isRefreshing: true
    });
    this.fetchIrrigationData(this.data.planId);
    
    // 完成刷新
    setTimeout(() => {
    // 获取最新状态并刷新数据
    this.fetchPlanLatestState(this.data.planId).then(res => {
      if (res.success) {
        const currentStatus = res.content;
        this.setData({
          currentStatus: currentStatus
        });
        if (currentStatus === 5) {
          this.fetchTerminatedIrrigationData(this.data.planId);
        } else {
          this.fetchNormalIrrigationData(this.data.planId);
        }
      } else {
        wx.showToast({
          title: res.msg || '获取状态失败',
          icon: 'none'
        });
      }
      // 完成刷新
      this.setData({
        isRefreshing: false
      });
    }, 1000);
    }).catch(err => {
      console.error('获取状态失败:', err);
      wx.showToast({
        title: '获取状态失败',
        icon: 'none'
      });
      this.setData({
        isRefreshing: false
      });
    });
  },
  /**
pages/irrigationDetail/irrigationDetail.wxml
@@ -27,6 +27,12 @@
      <text class="value">{{stopTime}}</text>
    </view>
    
    <!-- 实际中止时间信息 -->
    <view class="time-info" wx:if="{{planStatusClass === 'terminated' && realStopTime}}">
      <text class="label">实际中止时间:</text>
      <text class="value highlight-text">{{realStopTime}}</text>
    </view>
    <!-- 取水口命令发布失败数 -->
    <view class="time-info" wx:if="{{failureCount > 0}}">
      <text class="label">命令发布失败数:</text>
@@ -48,6 +54,7 @@
          <!-- 轮灌组信息 -->
          <view class="group-info">
            <view class="group-name-row">
              <text class="group-index">{{index + 1}}.</text>
              <text class="group-label">轮灌组:</text>
              <text class="group-name">{{group.name}}</text>
              <!-- 轮灌组状态标识 -->
@@ -56,7 +63,9 @@
                <text class="status-text">{{group.statusText}}</text>
              </view>
            </view>
            <view class="group-time-info">
            <!-- 轮灌时间信息 - 只有在取消开阀状态时不显示时间信息 -->
            <!-- 其他所有状态(包括中途关阀)都显示时间信息 -->
            <view class="group-time-info" wx:if="{{group.status !== 'canceled'}}">
              <view class="time-row">
                <text class="time-label">开始时间:</text>
                <text class="time-value">{{group.startTime}}</text>
pages/irrigationDetail/irrigationDetail.wxss
@@ -86,6 +86,15 @@
  font-weight: 500;
}
/* 实际中止时间高亮样式 */
.time-info .highlight-text {
  color: #F44336;
  font-weight: bold;
  background-color: rgba(244, 67, 54, 0.1);
  padding: 4rpx 12rpx;
  border-radius: 4rpx;
}
/* 命令发布失败数样式 */
.time-info .error-text {
  color: #ff4d4f;
@@ -209,6 +218,14 @@
  background-color: #2196F3;
}
.group-item.terminated .status-dot {
  background-color: #F44336;
}
.group-item.canceled .status-dot {
  background-color: #9E9E9E;
}
.status-text {
  font-size: 26rpx;
  color: #666;
@@ -227,6 +244,14 @@
  color: #2196F3;
}
.group-item.terminated .status-text {
  color: #F44336;
}
.group-item.canceled .status-text {
  color: #9E9E9E;
}
/* 根据不同状态显示不同背景色 */
.group-item.pending .group-status-indicator {
  background-color: rgba(255, 215, 0, 0.1);
@@ -240,6 +265,14 @@
  background-color: rgba(33, 150, 243, 0.1);
}
.group-item.terminated .group-status-indicator {
  background-color: rgba(244, 67, 54, 0.1);
}
.group-item.canceled .group-status-indicator {
  background-color: rgba(158, 158, 158, 0.1);
}
/* 轮灌组信息样式 */
.group-info {
  margin-top: 12rpx;
@@ -250,6 +283,12 @@
  align-items: center;
  margin-bottom: 12rpx;
  width: 100%;
}
.group-index {
  color: #1890FF;
  margin-right: 8rpx;
  font-size: 32rpx;
}
.group-label {
@@ -280,7 +319,8 @@
.time-label {
  color: #666;
  font-size: 26rpx;
  width: 160rpx;
  width: 140rpx;
  flex-shrink: 0;
}
.time-value {
pages/valveList/valveList.js
@@ -1,21 +1,28 @@
// pages/valveList/valveList.js 开关阀记录
const {
  get,
  post
} = require('../../api/request.js');
Page({
  /**
   * 页面的初始数据
   */
  data: {
    listData: [{
      intakeNum: "1023356646612"
    }, {
      intakeNum: "1023356646612"
    }, {
      intakeNum: "1023356646612"
    }, {
      intakeNum: "1023356646612"
    }, {
      intakeNum: "1023356646612"
    }]
    listVirtualData: [],
    listPhysicalData: [],
    currentTab: 0,
    isVirtualRefreshing: false, //虚拟卡刷新中
    isPhysicalRefreshing: false, //实体卡刷新中
    physicalPageCurr: 1, //实体卡当前页数
    pageSize: 20,
    virtualPageCurr: 1, //虚拟卡当前页数
    virtualhasMore: true,
    physicalHasMore: true,
    virtualIsLoding: false,
    physicalIsLoding: false,
    useTestData: false, // 添加测试数据标志
  },
  /**
@@ -29,7 +36,8 @@
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady() {
    this.getPhysicalListData();
    this.getVirtualListData();
  },
  /**
@@ -72,5 +80,183 @@
   */
  onShareAppMessage() {
  },
  switchTab(e) {
    const tab = parseInt(e.currentTarget.dataset.tab);
    this.setData({
      currentTab: tab
    });
  },
  //虚拟卡刷新
  onPullVirtualDownRefresh() {
    this.setData({
      isVirtualRefreshing: true,
    })
    this.getVirtualListData(true);
  },
  //实体卡刷新
  onPullPhysicalDownRefresh() {
    this.setData({
      isPhysicalRefreshing: true,
    })
    this.getPhysicalListData(true);
  },
  // 生成虚拟卡测试数据
  generateVirtualTestData() {
    return Array(10).fill().map((_, index) => ({
      expense: (Math.random() * 100).toFixed(2),
      cardNum: `VC${Math.floor(Math.random() * 10000).toString().padStart(4, '0')}`,
      intakeNum: `IN${Math.floor(Math.random() * 1000).toString().padStart(3, '0')}`,
      openType: ['手动开阀', '自动开阀', '计划开阀'][Math.floor(Math.random() * 3)],
      openTime: this.generateRandomTime(),
      closeTime: this.generateRandomTime(),
      duration: Math.floor(Math.random() * 120),
      amount: (Math.random() * 50).toFixed(2)
    }));
  },
  // 生成实体卡测试数据
  generatePhysicalTestData() {
    return Array(10).fill().map((_, index) => ({
      expense: (Math.random() * 100).toFixed(2),
      cardNum: `PC${Math.floor(Math.random() * 10000).toString().padStart(4, '0')}`,
      intakeNum: `IN${Math.floor(Math.random() * 1000).toString().padStart(3, '0')}`,
      openType: ['手动开阀', '自动开阀', '计划开阀'][Math.floor(Math.random() * 3)],
      openTime: this.generateRandomTime(),
      closeTime: this.generateRandomTime(),
      duration: Math.floor(Math.random() * 120),
      amount: (Math.random() * 50).toFixed(2)
    }));
  },
  // 生成随机时间
  generateRandomTime() {
    const now = new Date();
    const randomHours = Math.floor(Math.random() * 24);
    const randomMinutes = Math.floor(Math.random() * 60);
    const randomSeconds = Math.floor(Math.random() * 60);
    const date = new Date(now);
    date.setHours(randomHours);
    date.setMinutes(randomMinutes);
    date.setSeconds(randomSeconds);
    return date.toLocaleString();
  },
  //获取实体卡列表
  getPhysicalListData(isRefresh) {
    if (this.data.useTestData) {
      // 使用测试数据
      const testData = this.generatePhysicalTestData();
      this.setData({
        listPhysicalData: isRefresh ? testData : this.data.listPhysicalData.concat(testData),
        isPhysicalRefreshing: false,
        physicalIsLoding: false,
        physicalHasMore: this.data.physicalPageCurr < 3 // 模拟3页数据
      });
      return;
    }
    get({
        url: 'wx/intake/getCardOpenClose',
        data: {
          clientId: getApp().globalData.clientId,
          pageCurr: this.data.physicalPageCurr,
          pageSize: this.data.pageSize
        }
      })
      .then((data) => {
        this.setData({
          isPhysicalRefreshing: false,
          physicalIsLoding: false
        });
        if (data.success && data.code === "0001") {
          const filteredData = data.content.obj.filter(item => item.openTime !== null && item.closeTime !== null);
          this.setData({
            listPhysicalData: isRefresh ? filteredData : this.data.listPhysicalData.concat(filteredData),
            physicalHasMore: this.data.physicalPageCurr < data.content.pageTotal,
          });
        } else {
          wx.showToast({
            title: data.msg,
          })
        }
      })
      .catch((error) => {
        this.setData({
          isPhysicalRefreshing: false
        });
        console.error('Failed to add item:', error);
      });
  },
  //获取虚拟卡开关阀记录
  getVirtualListData(isRefresh) {
    if (this.data.useTestData) {
      // 使用测试数据
      const testData = this.generateVirtualTestData();
      this.setData({
        listVirtualData: isRefresh ? testData : this.data.listVirtualData.concat(testData),
        isVirtualRefreshing: false,
        virtualIsLoding: false,
        virtualhasMore: this.data.virtualPageCurr < 3 // 模拟3页数据
      });
      return;
    }
    get({
        url: 'wx/intake/getVcCardOpenClose',
        data: {
          clientId: getApp().globalData.clientId,
          pageCurr: this.data.physicalPageCurr,
          pageSize: this.data.pageSize
        }
      })
      .then((data) => {
        this.setData({
          isVirtualRefreshing: false,
          virtualIsLoding: false
        });
        if (data.success && data.code === "0001") {
          const filteredData = data.content.obj.filter(item => item.openTime !== null && item.closeTime !== null);
          this.setData({
            listVirtualData: isRefresh ? filteredData : this.data.listVirtualData.concat(filteredData),
            virtualhasMore: this.data.virtualPageCurr < data.content.pageTotal,
          });
        } else {
          wx.showToast({
            title: data.msg,
          })
        }
      })
      .catch((error) => {
        this.setData({
          isVirtualRefreshing: false
        });
        console.error('Failed to add item:', error);
      });
  },
  //加载更多的实体卡
  loadPhysicalMore() {
    if (this.data.physicalHasMore) {
      this.setData({
        physicalIsLoding: true,
        physicalPageCurr: this.data.physicalPageCurr + 1
      })
      this.getPhysicalListData();
    }
  },
  //加载更多的虚拟卡
  loadVirtualMore() {
    if (this.data.virtualhasMore) {
      this.setData({
        virtualIsLoding: true,
        virtualPageCurr: this.data.virtualPageCurr + 1
      })
      this.getVirtualListData();
    }
  }
})
pages/valveList/valveList.wxml
@@ -1,30 +1,79 @@
<!--pages/valveList/valveList.wxml 开关阀记录-->
<view>
  <scroll-view class="list-container" scroll-y="true" scroll-x="false">
    <block wx:if="{{listData.length > 0}}" wx:for="{{listData}}" wx:key="index">
      <view class="list-item" wx:for="{{listData}}" wx:for-item="item" wx:for-index="index">
<view  class="container">
  <!-- 顶部 Tabs -->
  <view class="tabs">
   <view class="tab" bindtap="switchTab" data-tab="0" id="tab0">
      虚拟卡
      <view class="indicator" wx:if="{{currentTab === 0}}"></view>
    </view>
  <view class="tab" bindtap="switchTab" data-tab="1" id="tab1">
      水卡
      <view class="indicator" wx:if="{{currentTab === 1}}"></view>
    </view>
 </view>
  <scroll-view class="list-container" enable-flex="true" wx:if="{{currentTab === 0}}" scroll-y="true" scroll-x="false" refresher-enabled="true" bindrefresherrefresh="onPullVirtualDownRefresh"  refresher-triggered="{{isVirtualRefreshing}}" bindscrolltolower="loadVirtualMore">
    <block wx:if="{{listVirtualData.length > 0}}" wx:for="{{listVirtualData}}" wx:key="index">
      <view class="list-item" >
        <!-- <image class="item-img" src="/images/pipeline.svg" /> -->
        <view class="item-time">
          <text class="item-text">消费金额:</text>
          <view>
            <text class="item-morny">50</text>
            <text class="item-morny">{{item.expense}}</text>
            <text class="item-text">  元</text>
          </view>
        </view>
        <text class="item-text">虚拟卡编号:{{item.intakeNum}}</text>
        <text class="item-text">取水口编号:</text>
        <text class="item-text">开阀时间:</text>
        <text class="item-text">关阀时间:</text>
        <text class="item-text">水卡编号:{{item.cardNum}}</text>
        <text class="item-text">取水口编号:{{item.intakeNum}}</text>
        <text class="item-text">开阀类型:{{item.openType}}</text>
        <text class="item-text">开阀时间:{{item.openTime}}</text>
        <text class="item-text">关阀时间:{{item.closeTime}}</text>
        <view class="item-time">
          <text class="item-text">用水时长:120 分钟</text>
          <text class="item-text">用水量:2 m³</text>
          <text class="item-text">用水时长:{{item.duration}}分钟</text>
          <text class="item-text">用水量:{{item.amount}} m³</text>
        </view>
      </view>
    </block>
    <view wx:if="{{listData.length === 0}}" class="noMore-View">
    <view wx:if="{{listVirtualData.length === 0}}" class="noMore-View">
      <image class="noMore-img" src="/images/no_more.svg" />
      <text class="noMore-text">没有数据</text>
    </view>
    <view wx:if="{{virtualIsLoding}}" class="loading">加载中...</view> <!-- 加载指示器 -->
    <view wx:if="{{ !virtualhasMore && listVirtualData.length > 0}}" class="no-more-data">
      <text>— 已加载全部数据 —</text>
    </view>
  </scroll-view>
  <scroll-view class="list-container" wx:else enable-flex="true" scroll-y="true" scroll-x="false" refresher-enabled="true" bindrefresherrefresh="onPullPhysicalDownRefresh" scroll-x="false" refresher-triggered="{{isPhysicalRefreshing}}" bindscrolltolower="loadPhysicalMore">
    <block wx:if="{{listPhysicalData.length > 0}}" wx:for="{{listPhysicalData}}" wx:key="index">
      <view class="list-item" >
        <!-- <image class="item-img" src="/images/pipeline.svg" /> -->
        <view class="item-time">
          <text class="item-text">消费金额:</text>
          <view>
            <text class="item-morny">{{item.expense}}</text>
            <text class="item-text">  元</text>
          </view>
        </view>
        <text class="item-text">水卡编号:{{item.cardNum}}</text>
        <text class="item-text">取水口编号:{{item.intakeNum}}</text>
        <text class="item-text">开阀类型:{{item.openType}}</text>
        <text class="item-text">开阀时间:{{item.openTime}}</text>
        <text class="item-text">关阀时间:{{item.closeTime}}</text>
        <view class="item-time">
          <text class="item-text">用水时长:{{item.duration}}分钟</text>
          <text class="item-text">用水量:{{item.amount}} m³</text>
        </view>
      </view>
    </block>
    <view wx:if="{{listPhysicalData.length === 0}}" class="noMore-View">
      <image class="noMore-img" src="/images/no_more.svg" />
      <text class="noMore-text">没有数据</text>
    </view>
    <view wx:if="{{physicalIsLoding}}" class="loading">加载中...</view> <!-- 加载指示器 -->
    <view wx:if="{{!physicalHasMore && listPhysicalData.length > 0}}" class="no-more-data">
      <text>— 已加载全部数据 —</text>
    </view>
  </scroll-view>
</view>
pages/valveList/valveList.wxss
@@ -1,4 +1,16 @@
/* pages/valveList/valveList.wxss */
.container {
  display: flex;
  flex-direction: column;
  height: 100vh;
  width: 100%;
  padding-left: 20rpx;
  padding-right: 20rpx;
  padding-top: 5rpx;
  padding-bottom: 5rpx;
  background-color: #fff;
}
.list-item {
  display: flex;
  flex-direction: column;
@@ -26,4 +38,75 @@
  color: #FFFF00;
  font-size: 50rpx;
  font-weight: bold;
}
.tab {
  font-size: 35rpx;
  padding: 10px;
  cursor: pointer;
  position: relative;
  width: 50%;
  /* Tabs 平分整个横向屏幕 */
  text-align: center;
  /* 文字居中 */
}
.tabs {
  display: flex;
  justify-content: space-around;
  position: relative;
  width: 100%;
  border-bottom: 1px solid #eee;
  /* Tabs 占满整个横向屏幕 */
}
.list-container {
  flex: 1;
  width: 100%;
  display: flex;
  flex-direction: column;
}
.noMore-View {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  height: 100%;
  padding: 40rpx 0;
  width: 100%;
  text-align: center;
}
.noMore-img {
  width: 200rpx;
  height: 200rpx;
  margin-bottom: 20rpx;
}
.noMore-text {
  font-size: 32rpx;
  color: #999;
}
.indicator {
  width: 100%;
  height: 3px;
  background-color: #1890FF;
  position: absolute;
  bottom: 0;
  left: 0;
  transform: translateX(0);
  /* 初始化位置 */
}
.no-more-data {
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 20rpx 0;
  color: #999;
  font-size: 28rpx;
  width: 100%;
  text-align: center;
}
pages/waterIntake/waterIntake.json
@@ -2,7 +2,7 @@
  "component": true,
  "usingComponents": {
    "t-avatar": "tdesign-miniprogram/avatar/avatar",
    "t-switch": "tdesign-miniprogram/switch/switch",
    "t-button": "tdesign-miniprogram/button/button",
    "t-dialog": "tdesign-miniprogram/dialog/dialog",
    "t-input": "tdesign-miniprogram/input/input",
utils/projectConfig.js
@@ -3,7 +3,8 @@
    JYG: {
        tag: 'ym',
        displayName: '嘉峪关项目',
        needLogin: true // 需要登录
        operatorId: '2025040415305200007', // 统一ID用于operator和clientId
        needLogin: false // 不需要登录
    },
    MQ: {
        tag: 'mq',
@@ -22,7 +23,19 @@
        tag: 'XX',
        displayName: '学校项目',
        operatorId: '2025040215305200006', // 统一ID用于operator和clientId
        needLogin: true // 不需要登录
        needLogin: false // 不需要登录
    },
    JC: {
        tag: 'jc',
        displayName: '金昌项目',
        operatorId: '2025041710412400006', // 统一ID用于operator和clientId
        needLogin: false // 不需要登录
    },
    GSCLT:{
      tag: 'test',
      displayName: '甘肃农科院-崔',
      operatorId: '2025041912201400006', // 统一ID用于operator和clientId
      needLogin: false // 不需要登录
    }
};