更新创建灌溉计划页面,添加API通信模块,优化项目选择器和时间选择功能;增强用户体验,修复轮灌组显示逻辑,调整样式和配置文件。
| | |
| | | |
| | | 4. **云开发**:项目可能使用了微信小程序云开发功能,用于数据存储和云函数。 |
| | | |
| | | ## API通信模块 |
| | | |
| | | API目录包含了项目中所有与后端通信相关的文件,提供了统一的网络请求处理机制。 |
| | | |
| | | ### 文件结构 |
| | | |
| | | - **request.js**: 网络请求核心模块,封装了微信小程序的`wx.request`接口 |
| | | - `request()`: 基础请求函数,处理请求配置、请求头设置和响应处理 |
| | | - `get()`: GET请求简化方法 |
| | | - `post()`: POST请求简化方法 |
| | | - 自动处理token验证、错误处理和loading状态 |
| | | |
| | | - **config.js**: 配置文件,定义API基础URL和环境配置 |
| | | - 支持多项目环境:嘉峪关(JYG)、民勤(MQ)、测试环境(TEST) |
| | | - `setBaseUrl()`: 动态切换项目环境的函数 |
| | | |
| | | - **env.js**: 环境变量配置,定义当前运行环境(生产/测试) |
| | | |
| | | - **statusCode.js**: HTTP状态码常量定义,用于统一处理响应状态 |
| | | |
| | | ### 使用方法 |
| | | |
| | | 1. **GET请求**: |
| | | ```javascript |
| | | const { get } = require('../../api/request') |
| | | |
| | | // 获取项目列表 |
| | | get({ |
| | | url: '/wx/irrigation/getSimpleProjects', |
| | | isShowLoding: true |
| | | }).then(res => { |
| | | if (res.success) { |
| | | // 处理成功响应 |
| | | console.log(res.content) |
| | | } else { |
| | | wx.showToast({ |
| | | title: res.msg || '请求失败', |
| | | icon: 'none' |
| | | }) |
| | | } |
| | | }).catch(err => { |
| | | console.error('请求失败:', err) |
| | | wx.showToast({ |
| | | title: '请求失败', |
| | | icon: 'none' |
| | | }) |
| | | }) |
| | | ``` |
| | | |
| | | 2. **POST请求**: |
| | | ```javascript |
| | | const { post } = require('../../api/request') |
| | | |
| | | // 获取轮灌组列表 |
| | | post({ |
| | | url: '/wx/irrigation/getSimpleGroups', |
| | | data: { |
| | | projectId: '2025032017240700001', |
| | | planName: '2025032501', |
| | | startupMode: 1, |
| | | operatorId: 2024090516595200300, |
| | | schedules: [ |
| | | { |
| | | groupId: 2025032017371700000, |
| | | duration: 5 |
| | | } |
| | | ] |
| | | }, |
| | | isShowLoding: true |
| | | }).then(res => { |
| | | if (res.success) { |
| | | // 处理成功响应 |
| | | console.log(res.content) |
| | | } else { |
| | | wx.showToast({ |
| | | title: res.msg || '请求失败', |
| | | icon: 'none' |
| | | }) |
| | | } |
| | | }).catch(err => { |
| | | console.error('请求失败:', err) |
| | | wx.showToast({ |
| | | title: '请求失败', |
| | | icon: 'none' |
| | | }) |
| | | }) |
| | | ``` |
| | | |
| | | 3. **切换项目环境**: |
| | | ```javascript |
| | | const { setBaseUrl } = require('../../api/config') |
| | | |
| | | // 切换到民勤项目 |
| | | setBaseUrl('MQ') |
| | | |
| | | // 切换到嘉峪关项目 |
| | | setBaseUrl('JYG') |
| | | |
| | | // 切换到测试环境 |
| | | setBaseUrl('TEST') |
| | | ``` |
| | | |
| | | 所有网络请求会自动处理: |
| | | - token 认证(通过请求头 Authorization) |
| | | - 项目标识(通过请求头 tag) |
| | | - 应用标识(通过请求头 appId) |
| | | - 错误处理和响应解析 |
| | | - 加载状态显示(通过 isShowLoding 参数控制) |
| | | |
| | | ## 代码风格和规范 |
| | | |
| | | 1. **文件命名**: |
| | |
| | | let BASEURL |
| | | |
| | | const PROJECT_URLS = { |
| | | JYG: 'https://irrigate.dayuyanjiuyuan.top/', // 嘉峪关项目 |
| | | MQ: 'https://shifanqu1.dayuyanjiuyuan.top/' , // 民勤项目 |
| | | TEST:'https://no253541tf71.vicp.fun/'// test项目 |
| | | // TEST:'http://192.168.40.182:8087/'// test项目 |
| | | // MQ: 'https://no253541tf71.vicp.fun/' // 民勤项目 |
| | | JYG: 'https://irrigate.dayuyanjiuyuan.top/', // 嘉峪关项目 |
| | | MQ: 'https://shifanqu1.dayuyanjiuyuan.top/', // 民勤项目 |
| | | // TEST:'https://no253541tf71.vicp.fun/'// test项目 |
| | | // TEST:'http://192.168.40.182:8087/'// test项目 |
| | | // MQ: 'https://no253541tf71.vicp.fun/' // 民勤项目 |
| | | TEST: 'http://192.168.40.166:54321/' |
| | | } |
| | | |
| | | // 尝试从本地存储获取已选择的项目 |
| | | let selectedProject = 'JYG'; // 默认为嘉峪关项目 |
| | | try { |
| | | // 尝试从本地存储获取已选择的项目 |
| | | if (typeof wx !== 'undefined') { |
| | | try { |
| | | const selectedProjectFromStorage = wx.getStorageSync('selectedProject'); |
| | | if (selectedProjectFromStorage) { |
| | | selectedProject = selectedProjectFromStorage; |
| | | console.log('从本地存储加载项目设置:', selectedProject); |
| | | } |
| | | } catch (e) { |
| | | console.error('从本地存储获取项目失败:', e); |
| | | // 尝试从本地存储获取已选择的项目 |
| | | if (typeof wx !== 'undefined') { |
| | | try { |
| | | const selectedProjectFromStorage = wx.getStorageSync('selectedProject'); |
| | | if (selectedProjectFromStorage) { |
| | | selectedProject = selectedProjectFromStorage; |
| | | console.log('从本地存储加载项目设置:', selectedProject); |
| | | } |
| | | } catch (e) { |
| | | console.error('从本地存储获取项目失败:', e); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 如果全局应用已初始化,也尝试从全局变量获取 |
| | | const app = getApp(); |
| | | if (app && app.globalData && app.globalData.selectedProject) { |
| | | selectedProject = app.globalData.selectedProject; |
| | | console.log('从全局变量加载项目设置:', selectedProject); |
| | | } |
| | | |
| | | // 如果全局应用已初始化,也尝试从全局变量获取 |
| | | const app = getApp(); |
| | | if (app && app.globalData && app.globalData.selectedProject) { |
| | | selectedProject = app.globalData.selectedProject; |
| | | console.log('从全局变量加载项目设置:', selectedProject); |
| | | } |
| | | } catch (e) { |
| | | console.error('获取已选择项目失败:', e); |
| | | console.error('获取已选择项目失败:', e); |
| | | } |
| | | |
| | | switch (ENV) { |
| | | case 'production': |
| | | BASEURL = PROJECT_URLS[selectedProject] || PROJECT_URLS.JYG; |
| | | break; |
| | | case 'test': |
| | | // BASEURL 将根据用户选择的项目动态设置 |
| | | BASEURL = PROJECT_URLS[selectedProject] || PROJECT_URLS.JYG; |
| | | break; |
| | | default: |
| | | BASEURL = PROJECT_URLS[selectedProject] || PROJECT_URLS.JYG; |
| | | break; |
| | | case 'production': |
| | | BASEURL = PROJECT_URLS[selectedProject] || PROJECT_URLS.JYG; |
| | | break; |
| | | case 'test': |
| | | // BASEURL 将根据用户选择的项目动态设置 |
| | | BASEURL = PROJECT_URLS[selectedProject] || PROJECT_URLS.JYG; |
| | | break; |
| | | default: |
| | | BASEURL = PROJECT_URLS[selectedProject] || PROJECT_URLS.JYG; |
| | | break; |
| | | } |
| | | |
| | | // 导出动态设置 BASEURL 的函数 |
| | | function setBaseUrl(project) { |
| | | if (PROJECT_URLS[project]) { |
| | | BASEURL = PROJECT_URLS[project]; |
| | | console.log('动态设置 BASEURL:', BASEURL); |
| | | return true; |
| | | } |
| | | return false; |
| | | if (PROJECT_URLS[project]) { |
| | | BASEURL = PROJECT_URLS[project]; |
| | | console.log('动态设置 BASEURL:', BASEURL); |
| | | return true; |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | module.exports = { |
| | | BASEURL,// 项目接口地址,支持多域名 |
| | | PROJECT_URLS, |
| | | setBaseUrl |
| | | BASEURL,// 项目接口地址,支持多域名 |
| | | PROJECT_URLS, |
| | | setBaseUrl |
| | | } |
New file |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| | | <path d="M19 13H13V19H11V13H5V11H11V5H13V11H19V13Z" fill="#FFFFFF"/> |
| | | </svg> |
New file |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| | | <path d="M12 2C6.48 2 2 6.48 2 12C2 17.52 6.48 22 12 22C17.52 22 22 17.52 22 12C22 6.48 17.52 2 12 2ZM12 20C7.59 20 4 16.41 4 12C4 7.59 7.59 4 12 4C16.41 4 20 7.59 20 12C20 16.41 16.41 20 12 20Z" fill="#666666"/> |
| | | <path d="M12 6V12L16.5 14.25L17.25 13.02L13.5 10.75V6H12Z" fill="#666666"/> |
| | | </svg> |
New file |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| | | <path d="M8 5V19L19 12L8 5Z" fill="#FFFFFF"/> |
| | | </svg> |
New file |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| | | <path d="M12 2C6.48 2 2 6.48 2 12C2 17.52 6.48 22 12 22C17.52 22 22 17.52 22 12C22 6.48 17.52 2 12 2ZM12 20C7.59 20 4 16.41 4 12C4 7.59 7.59 4 12 4C16.41 4 20 7.59 20 12C20 16.41 16.41 20 12 20Z" fill="#666666"/> |
| | | <path d="M12 6C8.69 6 6 8.69 6 12C6 15.31 8.69 18 12 18C15.31 18 18 15.31 18 12C18 8.69 15.31 6 12 6ZM12 16C9.79 16 8 14.21 8 12C8 9.79 9.79 8 12 8C14.21 8 16 9.79 16 12C16 14.21 14.21 16 12 16Z" fill="#666666"/> |
| | | </svg> |
New file |
| | |
| | | <?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="M7 4H41" stroke="#333" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/><path d="M7 44H41" stroke="#333" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/><path d="M11 44C13.6667 30.6611 18 23.9944 24 24C30 24.0056 34.3333 30.6722 37 44H11Z" fill="none" stroke="#333" stroke-width="4" stroke-linejoin="round"/><path d="M37 4C34.3333 17.3389 30 24.0056 24 24C18 23.9944 13.6667 17.3278 11 4H37Z" fill="none" stroke="#333" stroke-width="4" stroke-linejoin="round"/><path d="M21 15H27" stroke="#333" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/><path d="M19 38H29" stroke="#333" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/></svg> |
New file |
| | |
| | | <?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 44C29.5228 44 34.5228 41.7614 38.1421 38.1421C41.7614 34.5228 44 29.5228 44 24C44 18.4772 41.7614 13.4772 38.1421 9.85786C34.5228 6.23858 29.5228 4 24 4C18.4772 4 13.4772 6.23858 9.85786 9.85786C6.23858 13.4772 4 18.4772 4 24C4 29.5228 6.23858 34.5228 9.85786 38.1421C13.4772 41.7614 18.4772 44 24 44Z" fill="none" stroke="#333" stroke-width="4" stroke-linejoin="round"/><path fill-rule="evenodd" clip-rule="evenodd" d="M24 11C25.3807 11 26.5 12.1193 26.5 13.5C26.5 14.8807 25.3807 16 24 16C22.6193 16 21.5 14.8807 21.5 13.5C21.5 12.1193 22.6193 11 24 11Z" fill="#333"/><path d="M24.5 34V20H23.5H22.5" stroke="#333" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/><path d="M21 34H28" stroke="#333" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/></svg> |
New file |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| | | <path d="M12 2C6.48 2 2 6.48 2 12C2 17.52 6.48 22 12 22C17.52 22 22 17.52 22 12C22 6.48 17.52 2 12 2ZM12 20C7.59 20 4 16.41 4 12C4 7.59 7.59 4 12 4C16.41 4 20 7.59 20 12C20 16.41 16.41 20 12 20Z" fill="#666666"/> |
| | | <path d="M12 6V12L16.5 14.25L17.25 13.02L13.5 10.75V6H12Z" fill="#666666"/> |
| | | <path d="M12 2C6.48 2 2 6.48 2 12C2 17.52 6.48 22 12 22C17.52 22 22 17.52 22 12C22 6.48 17.52 2 12 2ZM12 20C7.59 20 4 16.41 4 12C4 7.59 7.59 4 12 4C16.41 4 20 7.59 20 12C20 16.41 16.41 20 12 20Z" fill="#666666" fill-opacity="0.3"/> |
| | | </svg> |
New file |
| | |
| | | <?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="M42 6L4 20.1383L24 24.0083L29.0052 44L42 6Z" stroke="#fff" stroke-width="4" stroke-linejoin="round"/><path d="M24.0083 24.0084L29.6651 18.3516" stroke="#fff" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/></svg> |
New file |
| | |
| | | <?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.5 8C13.8406 8.37652 13.2062 8.79103 12.6 9.24051C11.5625 10.0097 10.6074 10.8814 9.75 11.8402C6.79377 15.1463 5 19.4891 5 24.2455C5 34.6033 13.5066 43 24 43C34.4934 43 43 34.6033 43 24.2455C43 19.4891 41.2062 15.1463 38.25 11.8402C37.3926 10.8814 36.4375 10.0097 35.4 9.24051C34.7938 8.79103 34.1594 8.37652 33.5 8" stroke="#fff" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/><path d="M24 4V24" stroke="#fff" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/></svg> |
New file |
| | |
| | | <?xml version="1.0" encoding="UTF-8"?> |
| | | <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> |
| | | <path d="M12 2C6.48 2 2 6.48 2 12C2 17.52 6.48 22 12 22C17.52 22 22 17.52 22 12C22 6.48 17.52 2 12 2ZM12 20C7.59 20 4 16.41 4 12C4 7.59 7.59 4 12 4C16.41 4 20 7.59 20 12C20 16.41 16.41 20 12 20Z" fill="#666666"/> |
| | | <path d="M12.5 7H11V13L16.25 16.15L17 14.92L12.5 12.25V7Z" fill="#666666"/> |
| | | </svg> |
| | |
| | | var __REQUIRE__ = function(modId, source) { if(!__MODS__[modId]) return require(source); if(!__MODS__[modId].status) { var m = __MODS__[modId].m; m._exports = m._tempexports; var desp = Object.getOwnPropertyDescriptor(m, "exports"); if (desp && desp.configurable) Object.defineProperty(m, "exports", { set: function (val) { if(typeof val === "object" && val !== m._exports) { m._exports.__proto__ = val.__proto__; Object.keys(val).forEach(function (k) { m._exports[k] = val[k]; }); } m._tempexports = val }, get: function () { return m._tempexports; } }); __MODS__[modId].status = 1; __MODS__[modId].func(__MODS__[modId].req, m, m.exports); } return __MODS__[modId].m.exports; }; |
| | | var __REQUIRE_WILDCARD__ = function(obj) { if(obj && obj.__esModule) { return obj; } else { var newObj = {}; if(obj != null) { for(var k in obj) { if (Object.prototype.hasOwnProperty.call(obj, k)) newObj[k] = obj[k]; } } newObj.default = obj; return newObj; } }; |
| | | var __REQUIRE_DEFAULT__ = function(obj) { return obj && obj.__esModule ? obj.default : obj; }; |
| | | __DEFINE__(1742351136645, function(require, module, exports) { |
| | | __DEFINE__(1742956904314, function(require, module, exports) { |
| | | !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).dayjs=e()}(this,(function(){var t=1e3,e=6e4,n=36e5,r="millisecond",i="second",s="minute",u="hour",a="day",o="week",c="month",f="quarter",h="year",d="date",l="Invalid Date",$=/^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[Tt\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/,y=/\[([^\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g,M={name:"en",weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),ordinal:function(t){var e=["th","st","nd","rd"],n=t%100;return"["+t+(e[(n-20)%10]||e[n]||e[0])+"]"}},m=function(t,e,n){var r=String(t);return!r||r.length>=e?t:""+Array(e+1-r.length).join(n)+t},v={s:m,z:function(t){var e=-t.utcOffset(),n=Math.abs(e),r=Math.floor(n/60),i=n%60;return(e<=0?"+":"-")+m(r,2,"0")+":"+m(i,2,"0")},m:function t(e,n){if(e.date()<n.date())return-t(n,e);var r=12*(n.year()-e.year())+(n.month()-e.month()),i=e.clone().add(r,c),s=n-i<0,u=e.clone().add(r+(s?-1:1),c);return+(-(r+(n-i)/(s?i-u:u-i))||0)},a:function(t){return t<0?Math.ceil(t)||0:Math.floor(t)},p:function(t){return{M:c,y:h,w:o,d:a,D:d,h:u,m:s,s:i,ms:r,Q:f}[t]||String(t||"").toLowerCase().replace(/s$/,"")},u:function(t){return void 0===t}},g="en",D={};D[g]=M;var p="$isDayjsObject",S=function(t){return t instanceof _||!(!t||!t[p])},w=function t(e,n,r){var i;if(!e)return g;if("string"==typeof e){var s=e.toLowerCase();D[s]&&(i=s),n&&(D[s]=n,i=s);var u=e.split("-");if(!i&&u.length>1)return t(u[0])}else{var a=e.name;D[a]=e,i=a}return!r&&i&&(g=i),i||!r&&g},O=function(t,e){if(S(t))return t.clone();var n="object"==typeof e?e:{};return n.date=t,n.args=arguments,new _(n)},b=v;b.l=w,b.i=S,b.w=function(t,e){return O(t,{locale:e.$L,utc:e.$u,x:e.$x,$offset:e.$offset})};var _=function(){function M(t){this.$L=w(t.locale,null,!0),this.parse(t),this.$x=this.$x||t.x||{},this[p]=!0}var m=M.prototype;return m.parse=function(t){this.$d=function(t){var e=t.date,n=t.utc;if(null===e)return new Date(NaN);if(b.u(e))return new Date;if(e instanceof Date)return new Date(e);if("string"==typeof e&&!/Z$/i.test(e)){var r=e.match($);if(r){var i=r[2]-1||0,s=(r[7]||"0").substring(0,3);return n?new Date(Date.UTC(r[1],i,r[3]||1,r[4]||0,r[5]||0,r[6]||0,s)):new Date(r[1],i,r[3]||1,r[4]||0,r[5]||0,r[6]||0,s)}}return new Date(e)}(t),this.init()},m.init=function(){var t=this.$d;this.$y=t.getFullYear(),this.$M=t.getMonth(),this.$D=t.getDate(),this.$W=t.getDay(),this.$H=t.getHours(),this.$m=t.getMinutes(),this.$s=t.getSeconds(),this.$ms=t.getMilliseconds()},m.$utils=function(){return b},m.isValid=function(){return!(this.$d.toString()===l)},m.isSame=function(t,e){var n=O(t);return this.startOf(e)<=n&&n<=this.endOf(e)},m.isAfter=function(t,e){return O(t)<this.startOf(e)},m.isBefore=function(t,e){return this.endOf(e)<O(t)},m.$g=function(t,e,n){return b.u(t)?this[e]:this.set(n,t)},m.unix=function(){return Math.floor(this.valueOf()/1e3)},m.valueOf=function(){return this.$d.getTime()},m.startOf=function(t,e){var n=this,r=!!b.u(e)||e,f=b.p(t),l=function(t,e){var i=b.w(n.$u?Date.UTC(n.$y,e,t):new Date(n.$y,e,t),n);return r?i:i.endOf(a)},$=function(t,e){return b.w(n.toDate()[t].apply(n.toDate("s"),(r?[0,0,0,0]:[23,59,59,999]).slice(e)),n)},y=this.$W,M=this.$M,m=this.$D,v="set"+(this.$u?"UTC":"");switch(f){case h:return r?l(1,0):l(31,11);case c:return r?l(1,M):l(0,M+1);case o:var g=this.$locale().weekStart||0,D=(y<g?y+7:y)-g;return l(r?m-D:m+(6-D),M);case a:case d:return $(v+"Hours",0);case u:return $(v+"Minutes",1);case s:return $(v+"Seconds",2);case i:return $(v+"Milliseconds",3);default:return this.clone()}},m.endOf=function(t){return this.startOf(t,!1)},m.$set=function(t,e){var n,o=b.p(t),f="set"+(this.$u?"UTC":""),l=(n={},n[a]=f+"Date",n[d]=f+"Date",n[c]=f+"Month",n[h]=f+"FullYear",n[u]=f+"Hours",n[s]=f+"Minutes",n[i]=f+"Seconds",n[r]=f+"Milliseconds",n)[o],$=o===a?this.$D+(e-this.$W):e;if(o===c||o===h){var y=this.clone().set(d,1);y.$d[l]($),y.init(),this.$d=y.set(d,Math.min(this.$D,y.daysInMonth())).$d}else l&&this.$d[l]($);return this.init(),this},m.set=function(t,e){return this.clone().$set(t,e)},m.get=function(t){return this[b.p(t)]()},m.add=function(r,f){var d,l=this;r=Number(r);var $=b.p(f),y=function(t){var e=O(l);return b.w(e.date(e.date()+Math.round(t*r)),l)};if($===c)return this.set(c,this.$M+r);if($===h)return this.set(h,this.$y+r);if($===a)return y(1);if($===o)return y(7);var M=(d={},d[s]=e,d[u]=n,d[i]=t,d)[$]||1,m=this.$d.getTime()+r*M;return b.w(m,this)},m.subtract=function(t,e){return this.add(-1*t,e)},m.format=function(t){var e=this,n=this.$locale();if(!this.isValid())return n.invalidDate||l;var r=t||"YYYY-MM-DDTHH:mm:ssZ",i=b.z(this),s=this.$H,u=this.$m,a=this.$M,o=n.weekdays,c=n.months,f=n.meridiem,h=function(t,n,i,s){return t&&(t[n]||t(e,r))||i[n].slice(0,s)},d=function(t){return b.s(s%12||12,t,"0")},$=f||function(t,e,n){var r=t<12?"AM":"PM";return n?r.toLowerCase():r};return r.replace(y,(function(t,r){return r||function(t){switch(t){case"YY":return String(e.$y).slice(-2);case"YYYY":return b.s(e.$y,4,"0");case"M":return a+1;case"MM":return b.s(a+1,2,"0");case"MMM":return h(n.monthsShort,a,c,3);case"MMMM":return h(c,a);case"D":return e.$D;case"DD":return b.s(e.$D,2,"0");case"d":return String(e.$W);case"dd":return h(n.weekdaysMin,e.$W,o,2);case"ddd":return h(n.weekdaysShort,e.$W,o,3);case"dddd":return o[e.$W];case"H":return String(s);case"HH":return b.s(s,2,"0");case"h":return d(1);case"hh":return d(2);case"a":return $(s,u,!0);case"A":return $(s,u,!1);case"m":return String(u);case"mm":return b.s(u,2,"0");case"s":return String(e.$s);case"ss":return b.s(e.$s,2,"0");case"SSS":return b.s(e.$ms,3,"0");case"Z":return i}return null}(t)||i.replace(":","")}))},m.utcOffset=function(){return 15*-Math.round(this.$d.getTimezoneOffset()/15)},m.diff=function(r,d,l){var $,y=this,M=b.p(d),m=O(r),v=(m.utcOffset()-this.utcOffset())*e,g=this-m,D=function(){return b.m(y,m)};switch(M){case h:$=D()/12;break;case c:$=D();break;case f:$=D()/3;break;case o:$=(g-v)/6048e5;break;case a:$=(g-v)/864e5;break;case u:$=g/n;break;case s:$=g/e;break;case i:$=g/t;break;default:$=g}return l?$:b.a($)},m.daysInMonth=function(){return this.endOf(c).$D},m.$locale=function(){return D[this.$L]},m.locale=function(t,e){if(!t)return this.$L;var n=this.clone(),r=w(t,e,!0);return r&&(n.$L=r),n},m.clone=function(){return b.w(this.$d,this)},m.toDate=function(){return new Date(this.valueOf())},m.toJSON=function(){return this.isValid()?this.toISOString():null},m.toISOString=function(){return this.$d.toISOString()},m.toString=function(){return this.$d.toUTCString()},M}(),k=_.prototype;return O.prototype=k,[["$ms",r],["$s",i],["$m",s],["$H",u],["$W",a],["$M",c],["$y",h],["$D",d]].forEach((function(t){k[t[1]]=function(e){return this.$g(e,t[0],t[1])}})),O.extend=function(t,e){return t.$i||(t(e,_,O),t.$i=!0),O},O.locale=w,O.isDayjs=S,O.unix=function(t){return O(1e3*t)},O.en=D[g],O.Ls=D,O.p={},O})); |
| | | }, function(modId) {var map = {}; return __REQUIRE__(map[modId], modId); }) |
| | | return __REQUIRE__(1742351136645); |
| | | return __REQUIRE__(1742956904314); |
| | | })() |
| | | //miniprogram-npm-outsideDeps=[] |
| | | //# sourceMappingURL=index.js.map |
| | |
| | | const app = getApp(); |
| | | const { get, post } = require('../../api/request'); |
| | | const dayjs = require('dayjs'); |
| | | |
| | | Page({ |
| | | /** |
| | | * 页面的初始数据 |
| | | */ |
| | | data: { |
| | | // 表单数据 |
| | | planCode: '', // 计划编号 |
| | | startTime: '', // 灌溉开始时间 |
| | | pickerValue: '', // 时间选择器的值 |
| | | timePickerVisible: false, // 时间选择器是否可见 |
| | | // 项目选择器相关 |
| | | projectPickerVisible: false, |
| | | projectPickerValue: [], |
| | | selectedProject: null, |
| | | projectOptions: [], |
| | | totalDuration: 0, // 添加总灌溉时间 |
| | | // 测试数据 |
| | | projectList: [ |
| | | { |
| | | id: 1, |
| | | name: '测试项目一', |
| | | groups: [ |
| | | { |
| | | id: 101, |
| | | name: '轮灌组A', |
| | | duration: 30, |
| | | selected: false |
| | | }, |
| | | { |
| | | id: 102, |
| | | name: '轮灌组B', |
| | | duration: 45, |
| | | selected: false |
| | | }, |
| | | { |
| | | id: 103, |
| | | name: '轮灌组C', |
| | | duration: 60, |
| | | selected: false |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | id: 2, |
| | | name: '测试项目二', |
| | | groups: [ |
| | | { |
| | | id: 201, |
| | | name: '轮灌组1', |
| | | duration: 40, |
| | | selected: false |
| | | }, |
| | | { |
| | | id: 202, |
| | | name: '轮灌组2', |
| | | duration: 50, |
| | | selected: false |
| | | } |
| | | ] |
| | | }, |
| | | { |
| | | id: 3, |
| | | name: '测试项目三', |
| | | groups: [ |
| | | { |
| | | id: 301, |
| | | name: '东区轮灌组', |
| | | duration: 35, |
| | | selected: false |
| | | }, |
| | | { |
| | | id: 302, |
| | | name: '西区轮灌组', |
| | | duration: 55, |
| | | selected: false |
| | | }, |
| | | { |
| | | id: 303, |
| | | name: '南区轮灌组', |
| | | duration: 25, |
| | | selected: false |
| | | } |
| | | ] |
| | | } |
| | | ] |
| | | }, |
| | | /** |
| | | * 页面的初始数据 |
| | | */ |
| | | data: { |
| | | // 表单数据 |
| | | planCode: '', // 计划编号 |
| | | startTime: '', // 灌溉开始时间 |
| | | pickerValue: '', // 时间选择器的值 |
| | | timePickerVisible: false, // 时间选择器是否可见 |
| | | timeInfoVisible: false, // 时间提示弹窗是否可见 |
| | | // 项目选择器相关 |
| | | projectPickerVisible: false, |
| | | projectPickerValue: [], |
| | | selectedProject: null, |
| | | projectOptions: [], |
| | | totalDuration: 0, // 添加总灌溉时间 |
| | | // 项目列表 |
| | | projectList: [], |
| | | // 时间选择器选项 |
| | | timeOptions: [], |
| | | // 轮灌组列表刷新状态 |
| | | isRefreshing: false |
| | | }, |
| | | |
| | | /** |
| | | * 生命周期函数--监听页面加载 |
| | | */ |
| | | onLoad: function (options) { |
| | | // 初始化项目选择器选项 |
| | | const projectOptions = this.data.projectList.map(project => ({ |
| | | label: project.name, |
| | | value: project.id |
| | | })); |
| | | |
| | | this.setData({ |
| | | projectOptions: projectOptions // 直接使用一维数组,不需要包装成二维数组 |
| | | }); |
| | | }, |
| | | /** |
| | | * 生命周期函数--监听页面加载 |
| | | */ |
| | | onLoad: function (options) { |
| | | // 生成计划编号 |
| | | this.generatePlanCode(); |
| | | // 设置时间选择器的初始值 |
| | | const now = dayjs(); |
| | | this.setData({ |
| | | pickerValue: now.add(8.5, 'hour').format('YYYY-MM-DD HH:mm') |
| | | }); |
| | | // 获取项目列表 |
| | | this.fetchProjects(); |
| | | }, |
| | | |
| | | /** |
| | | * 获取项目和轮灌组数据 |
| | | */ |
| | | fetchProjectsAndGroups: function () { |
| | | // 这里可以添加API请求逻辑,获取真实数据 |
| | | // wx.request({ |
| | | // url: 'your-api-url', |
| | | // success: (res) => { |
| | | // this.setData({ |
| | | // projectList: res.data |
| | | // }); |
| | | // } |
| | | // }); |
| | | }, |
| | | /** |
| | | * 生成计划编号 |
| | | */ |
| | | 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 }); |
| | | }, |
| | | |
| | | /** |
| | | * 处理计划编号输入 |
| | | */ |
| | | onPlanCodeInput: function (e) { |
| | | this.setData({ |
| | | planCode: e.detail.value |
| | | }); |
| | | }, |
| | | /** |
| | | * 获取项目列表 |
| | | */ |
| | | fetchProjects: function () { |
| | | return get({ |
| | | url: '/wx/irrigation/getSimpleProjects', |
| | | isShowLoding: true |
| | | }).then(res => { |
| | | if (res.success) { |
| | | const projectList = res.content.obj.map(project => ({ |
| | | id: project.projectId, |
| | | name: project.projectName, |
| | | groupCount: project.groupCount, |
| | | groups: [] |
| | | })); |
| | | |
| | | /** |
| | | * 显示时间选择器 |
| | | */ |
| | | showTimePicker: function () { |
| | | this.setData({ |
| | | timePickerVisible: true |
| | | }); |
| | | }, |
| | | const projectOptions = projectList.map(project => ({ |
| | | label: project.name, |
| | | value: project.id |
| | | })); |
| | | |
| | | /** |
| | | * 时间选择器确认回调 |
| | | */ |
| | | onTimePickerConfirm: function (e) { |
| | | const { value } = e.detail; |
| | | this.setData({ |
| | | timePickerVisible: false, |
| | | startTime: value |
| | | }); |
| | | }, |
| | | 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); |
| | | }); |
| | | }, |
| | | |
| | | /** |
| | | * 时间选择器取消回调 |
| | | */ |
| | | onTimePickerCancel: function () { |
| | | this.setData({ |
| | | timePickerVisible: false |
| | | }); |
| | | }, |
| | | /** |
| | | * 获取轮灌组列表 |
| | | */ |
| | | fetchGroups: function (projectId) { |
| | | return get({ |
| | | url: '/wx/irrigation/getSimpleGroups', |
| | | data: { |
| | | projectId: projectId, |
| | | }, |
| | | isShowLoding: true |
| | | }).then(res => { |
| | | if (res.success) { |
| | | console.log('轮灌组数据:', res.content.obj); |
| | | |
| | | /** |
| | | * 切换项目展开/折叠状态 |
| | | */ |
| | | 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 |
| | | }); |
| | | }, |
| | | // 更新选中项目的轮灌组信息 |
| | | 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; |
| | | }); |
| | | |
| | | /** |
| | | * 切换轮灌组选中状态 |
| | | */ |
| | | 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); |
| | | }, |
| | | // 更新选中的项目 |
| | | const selectedProject = projectList.find(project => project.id === projectId); |
| | | console.log('更新后的选中项目:', selectedProject); |
| | | |
| | | /** |
| | | * 处理时长输入 |
| | | */ |
| | | 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(); |
| | | }); |
| | | }, |
| | | 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); |
| | | }); |
| | | }, |
| | | |
| | | /** |
| | | * 计算并更新项目总时长 |
| | | */ |
| | | 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 |
| | | }); |
| | | }, |
| | | /** |
| | | * 显示时间选择器 |
| | | */ |
| | | showTimePicker: function () { |
| | | // 如果没有选择时间,使用当前时间 |
| | | if (!this.data.pickerValue) { |
| | | const now = dayjs(); |
| | | this.setData({ |
| | | pickerValue: now.format('YYYY-MM-DD HH:mm') |
| | | }); |
| | | } |
| | | |
| | | /** |
| | | * 阻止事件冒泡 |
| | | */ |
| | | stopPropagation: function () { |
| | | // 阻止事件冒泡,防止点击输入框时触发父元素的点击事件 |
| | | }, |
| | | this.setData({ |
| | | timePickerVisible: true |
| | | }); |
| | | }, |
| | | |
| | | /** |
| | | * 跳转到轮灌组详情页 |
| | | */ |
| | | navigateToGroupDetail: function (e) { |
| | | const { groupIndex } = e.currentTarget.dataset; |
| | | // TODO: 实现跳转逻辑 |
| | | }, |
| | | /** |
| | | * 时间选择器确认回调 |
| | | */ |
| | | onTimePickerConfirm: function (e) { |
| | | const { value } = e.detail; |
| | | this.setData({ |
| | | timePickerVisible: false, |
| | | startTime: value |
| | | }); |
| | | }, |
| | | |
| | | /** |
| | | * 确认按钮点击事件 |
| | | */ |
| | | onConfirm: function () { |
| | | const { planCode, startTime, selectedProject } = this.data; |
| | | |
| | | if (!planCode) { |
| | | wx.showToast({ |
| | | title: '请输入计划编号', |
| | | icon: 'none' |
| | | }); |
| | | return; |
| | | } |
| | | |
| | | if (!startTime) { |
| | | wx.showToast({ |
| | | title: '请选择灌溉开始时间', |
| | | icon: 'none' |
| | | }); |
| | | return; |
| | | } |
| | | |
| | | if (!selectedProject) { |
| | | wx.showToast({ |
| | | title: '请选择项目', |
| | | icon: 'none' |
| | | }); |
| | | return; |
| | | } |
| | | /** |
| | | * 时间选择器取消回调 |
| | | */ |
| | | onTimePickerCancel: function () { |
| | | this.setData({ |
| | | timePickerVisible: false |
| | | }); |
| | | }, |
| | | |
| | | // TODO: 实现确认逻辑 |
| | | console.log('提交数据:', { |
| | | planCode, |
| | | startTime, |
| | | project: selectedProject |
| | | }); |
| | | }, |
| | | /** |
| | | * 切换项目展开/折叠状态 |
| | | */ |
| | | toggleProject: function (e) { |
| | | const index = e.currentTarget.dataset.index; |
| | | const currentValue = this.data.projectList[index].expanded; |
| | | |
| | | // 显示项目选择器 |
| | | showProjectPicker() { |
| | | this.setData({ |
| | | projectPickerVisible: true |
| | | }); |
| | | }, |
| | | // 创建新的项目列表,先将所有项目设为折叠状态 |
| | | const newProjectList = this.data.projectList.map((item, idx) => { |
| | | return { |
| | | ...item, |
| | | expanded: false |
| | | }; |
| | | }); |
| | | |
| | | // 项目选择器确认 |
| | | onProjectPickerConfirm(e) { |
| | | const { value } = e.detail; |
| | | const selectedProject = this.data.projectList.find(project => project.id === value[0]); |
| | | |
| | | this.setData({ |
| | | projectPickerVisible: false, |
| | | selectedProject: selectedProject, |
| | | projectPickerValue: value |
| | | }, () => { |
| | | // 选择项目后计算总时间 |
| | | this.calculateTotalDuration(); |
| | | }); |
| | | }, |
| | | // 如果当前点击的项目已经是展开状态,则保持所有项目折叠 |
| | | // 否则,将当前点击的项目设为展开状态 |
| | | if (!currentValue) { |
| | | newProjectList[index].expanded = true; |
| | | } |
| | | |
| | | // 项目选择器取消 |
| | | onProjectPickerCancel() { |
| | | this.setData({ |
| | | projectPickerVisible: false |
| | | }); |
| | | }, |
| | | this.setData({ |
| | | projectList: newProjectList |
| | | }); |
| | | }, |
| | | |
| | | // 计算总灌溉时间 |
| | | calculateTotalDuration() { |
| | | if (!this.data.selectedProject) return; |
| | | |
| | | const totalDuration = this.data.selectedProject.groups.reduce((sum, group) => { |
| | | return sum + (parseInt(group.duration) || 0); |
| | | }, 0); |
| | | |
| | | this.setData({ |
| | | totalDuration |
| | | }); |
| | | }, |
| | | /** |
| | | * 切换轮灌组选中状态 |
| | | */ |
| | | 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(() => { |
| | | wx.navigateBack(); |
| | | }, 1500); |
| | | } else { |
| | | wx.showToast({ |
| | | title: res.msg || '创建失败', |
| | | icon: 'none' |
| | | }); |
| | | } |
| | | }).catch(err => { |
| | | console.error('创建计划失败:', err); |
| | | wx.showToast({ |
| | | title: '创建失败', |
| | | icon: 'none' |
| | | }); |
| | | }); |
| | | }, |
| | | |
| | | // 显示项目选择器 |
| | | showProjectPicker() { |
| | | 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 |
| | | }); |
| | | }, |
| | | |
| | | /** |
| | | * 关闭时间提示弹窗 |
| | | */ |
| | | onTimeInfoConfirm: function () { |
| | | this.setData({ |
| | | timeInfoVisible: false |
| | | }); |
| | | }, |
| | | }); |
| | |
| | | { |
| | | "navigationBarTitleText": "新建灌溉计划", |
| | | "navigationBarTitleText": "创建灌溉计划", |
| | | "usingComponents": { |
| | | "t-date-time-picker": "tdesign-miniprogram/date-time-picker/date-time-picker", |
| | | "t-picker": "tdesign-miniprogram/picker/picker", |
| | | "t-picker-item": "tdesign-miniprogram/picker-item/picker-item" |
| | | } |
| | | "t-picker-item": "tdesign-miniprogram/picker-item/picker-item", |
| | | "t-input": "tdesign-miniprogram/input/input", |
| | | "t-button": "tdesign-miniprogram/button/button", |
| | | "t-dialog": "tdesign-miniprogram/dialog/dialog", |
| | | "t-toast": "tdesign-miniprogram/toast/toast" |
| | | }, |
| | | "enablePullDownRefresh": false, |
| | | "backgroundColor": "#f5f5f5", |
| | | "backgroundTextStyle": "dark" |
| | | } |
| | |
| | | </view> |
| | | |
| | | <!-- 灌溉开始时间 --> |
| | | <view class="form-item" bindtap="showTimePicker"> |
| | | <view class="form-label">灌溉开始时间</view> |
| | | <view class="form-input time-input"> |
| | | <view class="form-item"> |
| | | <view class="form-label"> |
| | | 灌溉开始时间(选填) |
| | | <image |
| | | class="info-icon" |
| | | src="/images/info.svg" |
| | | mode="aspectFit" |
| | | bindtap="showTimeInfo" |
| | | ></image> |
| | | </view> |
| | | <view class="form-input time-input" bindtap="showTimePicker"> |
| | | <view class="time-text {{startTime ? '' : 'placeholder'}}">{{startTime || '请选择灌溉开始时间'}}</view> |
| | | <image class="arrow-icon" src="/images/arrow-right.svg" mode="aspectFit"></image> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- 时间提示弹窗 --> |
| | | <t-dialog |
| | | visible="{{timeInfoVisible}}" |
| | | title="时间设置说明" |
| | | content="• 设置两小时后的灌溉时间:\n在此处选择具体的开始时间\n\n• 设置两小时内的灌溉时间:\n创建完成后点击发布即可立即开始灌溉" |
| | | confirmBtn="我知道了" |
| | | bind:confirm="onTimeInfoConfirm" |
| | | bind:cancel="onTimeInfoConfirm" |
| | | /> |
| | | |
| | | <!-- 选择项目 --> |
| | | <view class="form-item" bindtap="showProjectPicker"> |
| | |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <scroll-view scroll-y="true" class="group-list"> |
| | | <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}}</view> |
| | | <scroll-view |
| | | scroll-y="true" |
| | | class="group-list" |
| | | refresher-enabled="{{true}}" |
| | | refresher-triggered="{{isRefreshing}}" |
| | | bindrefresherrefresh="onGroupListRefresh" |
| | | > |
| | | <block wx:if="{{selectedProject.groups && selectedProject.groups.length > 0}}"> |
| | | <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> |
| | | </view> |
| | | <view class="group-duration"> |
| | | <input |
| | | class="duration-input" |
| | | type="number" |
| | | value="{{group.duration}}" |
| | | bindinput="onDurationInput" |
| | | data-group-index="{{groupIndex}}" |
| | | placeholder="0" |
| | | catchtap="stopPropagation" |
| | | /> |
| | | <text class="duration-unit">分钟</text> |
| | | </view> |
| | | </view> |
| | | <view class="group-duration"> |
| | | <input |
| | | class="duration-input" |
| | | type="number" |
| | | value="{{group.duration}}" |
| | | bindinput="onDurationInput" |
| | | data-group-index="{{groupIndex}}" |
| | | placeholder="0" |
| | | catchtap="stopPropagation" |
| | | /> |
| | | <text class="duration-unit">分钟</text> |
| | | </view> |
| | | </view> |
| | | </block> |
| | | </block> |
| | | <view wx:else class="empty-container"> |
| | | <image class="empty-image" src="/images/empty.png" mode="aspectFit"></image> |
| | | <view class="empty-text">暂无轮灌组数据</view> |
| | | <view class="empty-text">请刷新或稍后再试</view> |
| | | </view> |
| | | </scroll-view> |
| | | </view> |
| | | |
| | |
| | | visible="{{timePickerVisible}}" |
| | | mode="{{['date', 'minute']}}" |
| | | value="{{pickerValue}}" |
| | | start="{{pickerValue}}" |
| | | format="YYYY-MM-DD HH:mm" |
| | | bindconfirm="onTimePickerConfirm" |
| | | bindcancel="onTimePickerCancel" |
| | | catchtouchmove="stopPropagation" |
| | | z-index="{{1000}}" |
| | | /> |
| | | |
| | | <!-- 项目选择器弹窗 --> |
| | | <t-picker |
| | | title="选择项目" |
| | | visible="{{projectPickerVisible}}" |
| | | value="{{projectPickerValue}}" |
| | | title="选择项目" |
| | | cancelBtn="取消" |
| | | confirmBtn="确认" |
| | | bindconfirm="onProjectPickerConfirm" |
| | | bindcancel="onProjectPickerCancel" |
| | | bind:confirm="onProjectPickerConfirm" |
| | | bind:cancel="onProjectPickerCancel" |
| | | bind:touchmove="stopPropagation" |
| | | bind:touchstart="stopPropagation" |
| | | bind:touchend="stopPropagation" |
| | | z-index="{{1000}}" |
| | | > |
| | | <t-picker-item options="{{projectOptions}}" /> |
| | | <t-picker-item options="{{projectOptions}}" value="{{projectPickerValue}}" /> |
| | | </t-picker> |
| | | |
| | | |
| | | </view> |
| | |
| | | box-sizing: border-box; |
| | | } |
| | | |
| | | /* 选择器容器样式 */ |
| | | .picker-container { |
| | | position: fixed; |
| | | top: 0; |
| | | left: 0; |
| | | width: 100%; |
| | | height: 100%; |
| | | z-index: 9999; |
| | | pointer-events: none; |
| | | } |
| | | |
| | | /* 蒙层样式 */ |
| | | .picker-mask { |
| | | position: absolute; |
| | | top: 0; |
| | | left: 0; |
| | | width: 100%; |
| | | height: 100%; |
| | | background-color: rgba(0, 0, 0, 0.5); |
| | | pointer-events: auto; |
| | | } |
| | | |
| | | .picker-container .t-date-time-picker, |
| | | .picker-container .t-picker { |
| | | pointer-events: auto; |
| | | } |
| | | |
| | | /* 当选择器显示时 */ |
| | | .t-date-time-picker[visible], |
| | | .t-picker[visible] { |
| | | position: absolute; |
| | | bottom: 0; |
| | | left: 0; |
| | | width: 100%; |
| | | background-color: #fff; |
| | | border-radius: 24rpx 24rpx 0 0; |
| | | } |
| | | |
| | | /* 表单项样式 */ |
| | | .form-item { |
| | | display: flex; |
| | |
| | | } |
| | | |
| | | .form-label { |
| | | display: flex; |
| | | align-items: center; |
| | | font-size: 28rpx; |
| | | color: #333; |
| | | font-weight: 500; |
| | | width: 200rpx; /* 固定标签宽度 */ |
| | | flex-shrink: 0; /* 防止标签宽度被压缩 */ |
| | | margin-bottom: 16rpx; |
| | | } |
| | | |
| | | .info-icon { |
| | | width: 32rpx; |
| | | height: 32rpx; |
| | | margin-left: 8rpx; |
| | | } |
| | | |
| | | .form-input { |
| | |
| | | font-size: 32rpx; |
| | | color: #1890FF; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .empty-container { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | justify-content: center; |
| | | padding: 40rpx 0; |
| | | } |
| | | |
| | | .empty-image { |
| | | width: 200rpx; |
| | | height: 200rpx; |
| | | margin-bottom: 20rpx; |
| | | } |
| | | |
| | | .empty-text { |
| | | color: #999; |
| | | font-size: 30rpx; |
| | | } |
| | | |
| | | .empty-tip { |
| | | font-size: 28rpx; |
| | | color: #999; |
| | | } |
| | | |
| | | .dialog-content { |
| | | padding: 20rpx 0; |
| | | } |
| | | |
| | | .dialog-section { |
| | | margin-bottom: 24rpx; |
| | | } |
| | | |
| | | .dialog-section:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | .dialog-title { |
| | | font-size: 28rpx; |
| | | color: #333; |
| | | font-weight: 500; |
| | | margin-bottom: 8rpx; |
| | | } |
| | | |
| | | .dialog-desc { |
| | | font-size: 26rpx; |
| | | color: #666; |
| | | line-height: 1.6; |
| | | padding-left: 20rpx; |
| | | } |
| | |
| | | * 生命周期函数--监听页面初次渲染完成 |
| | | */ |
| | | onReady() { |
| | | if (this.data.options.param === "1") { |
| | | this.setData({ |
| | | showTipDialog: true, |
| | | tipData: "开阀命令下发成功,因开阀需要时间,约20-60秒后可刷新快速关阀列表查看执行结果。" |
| | | }) |
| | | setTimeout(() => { |
| | | this.getOpenList(); |
| | | }, 20000) |
| | | |
| | | } else if (this.data.options.param === "2") { |
| | | this.setData({ |
| | | showTipDialog: true, |
| | | tipData: "预约开阀命令下发成功,当到达预约时间并且成功开阀后快速关阀列表会显示未关阀记录" |
| | | }) |
| | | // 检查是否有options和param |
| | | if (this.data.options && this.data.options.param) { |
| | | if (this.data.options.param === "1" || this.data.options.param === "2") { |
| | | this.getOpenList(); |
| | | } |
| | | } |
| | | }, |
| | | |
| | | /** |
| | |
| | | // pages/irrigation/irrigation.js |
| | | const { get, post } = require('../../api/request'); |
| | | const app = getApp(); |
| | | |
| | | Page({ |
| | | /** |
| | | * 页面的初始数据 |
| | |
| | | completedList: [], // 已完成的轮灌列表 |
| | | currentList: [], // 当前显示的列表 |
| | | isRefreshing: false, // 是否正在刷新 |
| | | isWXRefreshing: false // 微信原生下拉刷新状态 |
| | | isWXRefreshing: false, // 微信原生下拉刷新状态 |
| | | projectId: null // Added to store projectId |
| | | }, |
| | | |
| | | /** |
| | | * 生命周期函数--监听页面加载 |
| | | */ |
| | | onLoad: function (options) { |
| | | // 获取项目ID |
| | | if (options.projectId) { |
| | | this.setData({ |
| | | projectId: options.projectId |
| | | }); |
| | | } |
| | | this.loadIrrigationData(); |
| | | this.loadCompletedIrrigationData(); |
| | | }, |
| | | |
| | | /** |
| | |
| | | */ |
| | | onShow: function () { |
| | | this.loadIrrigationData(); |
| | | this.loadCompletedIrrigationData(); |
| | | }, |
| | | |
| | | /** |
| | | * 加载轮灌数据 |
| | | */ |
| | | loadIrrigationData: function () { |
| | | // 这里应该调用API获取数据 |
| | | // 模拟数据 |
| | | const mockData = { |
| | | activeList: [ |
| | | { |
| | | id: '1', |
| | | title: 'LG-2023-001', |
| | | status: '未发布', |
| | | irrigationTime: '2023-05-20 08:00 - 17:00' |
| | | }, |
| | | { |
| | | id: '2', |
| | | title: 'LG-2023-002', |
| | | status: '已发布', |
| | | irrigationTime: '2023-05-22 09:00 - 18:00' |
| | | }, |
| | | { |
| | | id: '2', |
| | | title: 'LG-2023-002', |
| | | status: '已发布', |
| | | irrigationTime: '2023-05-22 09:00 - 18:00' |
| | | }, { |
| | | id: '2', |
| | | title: 'LG-2023-002', |
| | | status: '已发布', |
| | | irrigationTime: '2023-05-22 09:00 - 18:00' |
| | | }, { |
| | | id: '2', |
| | | title: 'LG-2023-002', |
| | | status: '已发布', |
| | | irrigationTime: '2023-05-22 09:00 - 18:00' |
| | | }, |
| | | { |
| | | id: '3', |
| | | title: 'LG-2023-003', |
| | | status: '执行中', |
| | | irrigationTime: '2023-05-18 07:30 - 16:30', |
| | | irrigatedTime: '3小时25分钟', |
| | | irrigatedGroups: '1组、2组、3组' |
| | | }, { |
| | | id: '2', |
| | | title: 'LG-2023-002', |
| | | status: '已发布', |
| | | irrigationTime: '2023-05-22 09:00 - 18:00' |
| | | }, |
| | | { |
| | | id: '3', |
| | | title: 'LG-2023-003', |
| | | status: '执行中', |
| | | irrigationTime: '2023-05-18 07:30 - 16:30', |
| | | irrigatedTime: '3小时25分钟', |
| | | irrigatedGroups: '1组、2组、3组' |
| | | }, { |
| | | id: '2', |
| | | title: 'LG-2023-002', |
| | | status: '已发布', |
| | | irrigationTime: '2023-05-22 09:00 - 18:00' |
| | | }, |
| | | { |
| | | id: '3', |
| | | title: 'LG-2023-003', |
| | | status: '执行中', |
| | | irrigationTime: '2023-05-18 07:30 - 16:30', |
| | | irrigatedTime: '3小时25分钟', |
| | | irrigatedGroups: '1组、2组、3组' |
| | | } |
| | | |
| | | ] |
| | | // completedList: [ |
| | | // { |
| | | // id: '4', |
| | | // title: 'LG-2023-004', |
| | | // status: '已完成', |
| | | // irrigationTime: '2023-05-10 10:00 - 19:00' |
| | | // } |
| | | // ] |
| | | }; |
| | | get({ |
| | | url: '/wx/plan/getNotCompletePlans' |
| | | }).then(res => { |
| | | if (res.success) { |
| | | const activeList = res.content.map(item => ({ |
| | | id: item.planId, |
| | | title: item.planName, |
| | | projectName: item.projectName || '未分配项目', |
| | | status: item.planState, |
| | | planStartTime: item.planStartTime, |
| | | planStopTime: item.planStopTime, |
| | | duration: item.duration, |
| | | startupMode: item.startupMode |
| | | })); |
| | | |
| | | // 模拟网络请求延迟 |
| | | setTimeout(() => { |
| | | this.setData({ |
| | | activeList: mockData.activeList || [], |
| | | completedList: mockData.completedList || [], |
| | | currentList: this.data.currentTab === 0 ? mockData.activeList || [] : mockData.completedList || [], |
| | | isRefreshing: false, // 结束刷新状态 |
| | | isWXRefreshing: false // 结束微信原生下拉刷新状态 |
| | | console.log('轮灌计划数据:', activeList); |
| | | |
| | | this.setData({ |
| | | activeList: activeList, |
| | | currentList: this.data.currentTab === 0 ? activeList : this.data.completedList, |
| | | isRefreshing: false, |
| | | isWXRefreshing: false |
| | | }); |
| | | } else { |
| | | wx.showToast({ |
| | | title: res.msg || '加载失败', |
| | | icon: 'none' |
| | | }); |
| | | } |
| | | }).catch(err => { |
| | | wx.showToast({ |
| | | title: '加载失败', |
| | | icon: 'none' |
| | | }); |
| | | }, 1000); |
| | | this.setData({ |
| | | isRefreshing: false, |
| | | isWXRefreshing: false |
| | | }); |
| | | }); |
| | | }, |
| | | |
| | | /** |
| | | * 加载已完成的轮灌数据 |
| | | */ |
| | | loadCompletedIrrigationData: function () { |
| | | get({ |
| | | url: '/wx/plan/getCompletedPlans' |
| | | }).then(res => { |
| | | if (res.success) { |
| | | const completedList = res.content.map(item => ({ |
| | | id: item.planId, |
| | | title: item.planName, |
| | | projectName: item.projectName || '未分配项目', |
| | | status: item.planState, |
| | | planStartTime: item.planStartTime, |
| | | planStopTime: item.planStopTime, |
| | | duration: item.duration, |
| | | startupMode: item.startupMode |
| | | })); |
| | | |
| | | console.log('已完成轮灌计划数据:', completedList); |
| | | |
| | | this.setData({ |
| | | completedList: completedList, |
| | | currentList: this.data.currentTab === 1 ? completedList : this.data.activeList, |
| | | isRefreshing: false, |
| | | isWXRefreshing: false |
| | | }); |
| | | } else { |
| | | wx.showToast({ |
| | | title: res.msg || '加载失败', |
| | | icon: 'none' |
| | | }); |
| | | } |
| | | }).catch(err => { |
| | | wx.showToast({ |
| | | title: '加载失败', |
| | | icon: 'none' |
| | | }); |
| | | this.setData({ |
| | | isRefreshing: false, |
| | | isWXRefreshing: false |
| | | }); |
| | | }); |
| | | }, |
| | | |
| | | /** |
| | |
| | | content: '确定要发布该轮灌计划吗?', |
| | | success: (res) => { |
| | | if (res.confirm) { |
| | | // 这里应该调用API发布轮灌计划 |
| | | wx.showToast({ |
| | | title: '发布成功', |
| | | icon: 'success' |
| | | // 调用发布接口 |
| | | post({ |
| | | url: '/wx/plan/publishPlan', |
| | | data: { |
| | | planId: id, |
| | | operatorId: app.globalData.clientId |
| | | }, |
| | | isShowLoding: true |
| | | }).then(res => { |
| | | if (res.success) { |
| | | wx.showToast({ |
| | | title: '发布成功', |
| | | icon: 'success' |
| | | }); |
| | | // 刷新数据 |
| | | this.loadIrrigationData(); |
| | | } else { |
| | | wx.showToast({ |
| | | title: res.msg || '发布失败', |
| | | icon: 'none' |
| | | }); |
| | | } |
| | | }).catch(err => { |
| | | console.error('发布失败:', err); |
| | | wx.showToast({ |
| | | title: '发布失败', |
| | | icon: 'none' |
| | | }); |
| | | }); |
| | | // 刷新数据 |
| | | this.loadIrrigationData(); |
| | | } |
| | | } |
| | | }); |
| | |
| | | */ |
| | | onAddIrrigation: function () { |
| | | wx.navigateTo({ |
| | | url: '/pages/createIrrigation/createIrrigation' |
| | | url: '/pages/createIrrigation/createIrrigation?projectId=' + this.data.projectId |
| | | }); |
| | | }, |
| | | |
| | |
| | | isRefreshing: true |
| | | }); |
| | | this.loadIrrigationData(); |
| | | this.loadCompletedIrrigationData(); |
| | | } |
| | | }, |
| | | |
| | |
| | | isWXRefreshing: true |
| | | }); |
| | | this.loadIrrigationData(); |
| | | this.loadCompletedIrrigationData(); |
| | | } |
| | | }) |
| | |
| | | </view> |
| | | <view class="scroll-bg"> |
| | | <block wx:if="{{currentList.length > 0}}"> |
| | | <!-- 统一显示所有列表项,不再按状态分组 --> |
| | | <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> |
| | | <view class="info-value">{{item.title}}</view> |
| | | </view> |
| | | <!-- 根据状态显示不同的图标 --> |
| | | <view class="item-status"> |
| | | <block wx:if="{{item.status === '已发布'}}"> |
| | | <image class="status-icon" src="/images/published-icon.svg" mode="aspectFit"></image> |
| | | </block> |
| | | <block wx:elif="{{item.status === '执行中'}}"> |
| | | <image class="status-icon" src="/images/progress.svg" mode="aspectFit"></image> |
| | | </block> |
| | | <block wx:elif="{{item.status === '未发布'}}"> |
| | | <text>{{item.status}}</text> |
| | | </block> |
| | | </view> |
| | | <!-- 状态标签 --> |
| | | <view class="status-tag {{item.status === '1' ? 'draft' : item.status === '2' ? 'published' : item.status === '3' ? 'executing' : 'completed'}}"> |
| | | {{item.status === '1' ? '草稿' : item.status === '2' ? '未执行' : item.status === '3' ? '执行中' : '已完成'}} |
| | | </view> |
| | | <view class="item-info"> |
| | | <view class="info-row"> |
| | | <view class="info-label">灌溉时间:</view> |
| | | <view class="info-value">{{item.irrigationTime}}</view> |
| | | |
| | | <!-- 主要内容区 --> |
| | | <view class="item-content"> |
| | | <!-- 标题区域 --> |
| | | <view class="item-header"> |
| | | <view class="title-section"> |
| | | <view class="plan-title">{{item.title}}</view> |
| | | <view class="project-name">{{item.projectName}}</view> |
| | | </view> |
| | | </view> |
| | | <!-- 仅在执行中状态显示额外信息 --> |
| | | <block wx:if="{{item.status === '执行中'}}"> |
| | | <view class="info-row irrigated-row"> |
| | | <view class="info-label">已灌溉时间:</view> |
| | | <view class="info-value-time">{{item.irrigatedTime}}</view> |
| | | |
| | | <!-- 信息区域 --> |
| | | <view class="info-section"> |
| | | <!-- 草稿状态(1)时横向排列,其他状态纵向排列 --> |
| | | <view class="info-grid {{item.status === '1' ? '' : 'vertical-layout'}} {{currentTab === 1 ? 'history-grid' : ''}}"> |
| | | <view class="info-item"> |
| | | <view class="info-icon"> |
| | | <image src="/images/time-icon.svg" mode="aspectFit"></image> |
| | | </view> |
| | | <view class="info-content"> |
| | | <view class="info-label">灌溉时间</view> |
| | | <view class="info-value">{{(item.planStartTime ? item.planStartTime : '手动发布') + (item.planStopTime ? ' - ' + item.planStopTime : '')}}</view> |
| | | </view> |
| | | </view> |
| | | <view class="info-item"> |
| | | <view class="info-icon duration-icon"> |
| | | <image src="/images/hourglass.svg" mode="aspectFit"></image> |
| | | </view> |
| | | <view class="info-content"> |
| | | <view class="info-label">灌溉时长</view> |
| | | <view class="info-value">{{item.duration}}分钟</view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <view class="info-row irrigated-row"> |
| | | <view class="info-label">已灌溉轮组:</view> |
| | | <view class="info-value-time">{{item.irrigatedGroups}}</view> |
| | | </view> |
| | | </block> |
| | | </view> |
| | | <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> |
| | | </block> |
| | | <block wx:if="{{item.status === '执行中' || item.status === '已发布'}}"> |
| | | <button class="action-button stop-button" hover-class="stop-button-hover" bindtap="onStop" data-id="{{item.id}}">终止</button> |
| | | </block> |
| | | <block wx:if="{{item.status === '已发布'}}"> |
| | | <button class="action-button execute-button" hover-class="execute-button-hover" bindtap="onExecute" data-id="{{item.id}}">立即执行</button> |
| | | </block> |
| | | |
| | | <!-- 执行中状态额外信息 --> |
| | | <block wx:if="{{item.status === '3'}}"> |
| | | <view class="executing-info"> |
| | | <view class="info-item"> |
| | | <view class="info-icon"> |
| | | <image src="/images/progress-icon.svg" mode="aspectFit"></image> |
| | | </view> |
| | | <view class="info-content"> |
| | | <view class="info-label">已灌溉时间</view> |
| | | <view class="info-value">{{item.irrigatedTime}}</view> |
| | | </view> |
| | | </view> |
| | | <view class="info-item"> |
| | | <view class="info-icon"> |
| | | <image src="/images/group-icon.svg" mode="aspectFit"></image> |
| | | </view> |
| | | <view class="info-content"> |
| | | <view class="info-label">已灌溉轮组</view> |
| | | <view class="info-value">{{item.irrigatedGroups}}</view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </block> |
| | | </view> |
| | | |
| | | <!-- 操作按钮区域 --> |
| | | <view class="action-section" catchtap="stopPropagation" wx:if="{{item.status !== '4'}}"> |
| | | <block wx:if="{{item.status === '1'}}"> |
| | | <view class="action-buttons"> |
| | | <button class="action-button publish-button" hover-class="publish-button-hover" bindtap="onPublish" data-id="{{item.id}}"> |
| | | <image src="/images/publish-icon.svg" mode="aspectFit"></image> |
| | | <text>发布</text> |
| | | </button> |
| | | </view> |
| | | </block> |
| | | <block wx:if="{{item.status === '2'}}"> |
| | | <view class="action-buttons"> |
| | | <button class="action-button stop-button" hover-class="stop-button-hover" bindtap="onStop" data-id="{{item.id}}"> |
| | | <image src="/images/stop-icon.svg" mode="aspectFit"></image> |
| | | <text>终止</text> |
| | | </button> |
| | | </view> |
| | | </block> |
| | | <block wx:if="{{item.status === '3'}}"> |
| | | <view class="action-buttons"> |
| | | <button class="action-button stop-button" hover-class="stop-button-hover" bindtap="onStop" data-id="{{item.id}}"> |
| | | <image src="/images/stop-icon.svg" mode="aspectFit"></image> |
| | | <text>终止</text> |
| | | </button> |
| | | </view> |
| | | </block> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </block> |
| | |
| | | |
| | | <!-- 底部新建按钮 --> |
| | | <view class="bottom-button"> |
| | | <button class="add-button" hover-class="add-button-hover" bindtap="onAddIrrigation">创建灌溉计划</button> |
| | | <button class="add-button" hover-class="add-button-hover" bindtap="onAddIrrigation"> |
| | | <image src="/images/add-icon.svg" mode="aspectFit"></image> |
| | | <text>创建灌溉计划</text> |
| | | </button> |
| | | </view> |
| | | </view> |
| | |
| | | flex-direction: column; |
| | | height: 100vh; |
| | | background-color: #f5f5f5; |
| | | padding: 20rpx; |
| | | box-sizing: border-box; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | /* 顶部标签页样式 */ |
| | | /* 标签页样式 */ |
| | | .tabs { |
| | | display: flex; |
| | | background-color: #fff; |
| | | border-radius: 12rpx; |
| | | margin-bottom: 20rpx; |
| | | overflow: hidden; |
| | | box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05); |
| | | padding: 20rpx 0; |
| | | width: 100%; |
| | | flex-shrink: 0; /* 防止被压缩 */ |
| | | box-shadow: 0 4rpx 8rpx rgba(0, 0, 0, 0.05); |
| | | border-bottom: 1rpx solid #eaeaea; |
| | | position: relative; |
| | | z-index: 10; |
| | | } |
| | | |
| | | .tab { |
| | | flex: 1; |
| | | text-align: center; |
| | | padding: 30rpx 0; |
| | | font-size: 28rpx; |
| | | color: #666; |
| | | position: relative; |
| | | transition: all 0.2s ease; |
| | | } |
| | | |
| | | .tab-hover { |
| | | opacity: 0.8; |
| | | background-color: rgba(0, 0, 0, 0.03); |
| | | } |
| | | |
| | | .tab:active { |
| | | opacity: 0.8; |
| | | background-color: rgba(0, 0, 0, 0.03); |
| | | padding: 20rpx 0; |
| | | } |
| | | |
| | | .tab.active { |
| | | color: rgba(45, 139, 247, 1); |
| | | font-weight: bold; |
| | | color: #0052d9; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .tab.active::after { |
| | |
| | | bottom: 0; |
| | | left: 50%; |
| | | transform: translateX(-50%); |
| | | width: 50vw; |
| | | height: 6rpx; |
| | | background-color: rgba(45, 139, 247, 1); |
| | | border-radius: 3rpx; |
| | | width: 40rpx; |
| | | height: 4rpx; |
| | | background-color: #0052d9; |
| | | border-radius: 2rpx; |
| | | } |
| | | |
| | | /* 刷新按钮和分隔线 */ |
| | | .refresh-header { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | padding: 10rpx 20rpx; |
| | | } |
| | | |
| | | .refresh-button { |
| | | font-size: 28rpx; |
| | | color: #fff; |
| | | background-color: rgba(45, 139, 247, 1); |
| | | border: none; |
| | | border-radius: 5px; |
| | | padding: 10rpx 20rpx; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .refresh-button:active { |
| | | background-color: #1a6fc7; |
| | | } |
| | | |
| | | .divider { |
| | | height: 1rpx; |
| | | background-color: #e0e0e0; |
| | | margin: 10rpx 0; |
| | | } |
| | | |
| | | /* 下拉刷新动画 */ |
| | | .refresh-view { |
| | | text-align: center; |
| | | padding: 30rpx; |
| | | display: flex; |
| | | justify-content: center; |
| | | align-items: center; |
| | | } |
| | | |
| | | .dot { |
| | | width: 20rpx; |
| | | height: 20rpx; |
| | | background-color: rgba(45, 139, 247, 1); |
| | | border-radius: 50%; |
| | | margin: 0 5px; |
| | | animation: blink 1.4s infinite both; |
| | | } |
| | | |
| | | .dot:nth-child(2) { |
| | | animation-delay: 0.2s; |
| | | } |
| | | |
| | | .dot:nth-child(3) { |
| | | animation-delay: 0.4s; |
| | | } |
| | | |
| | | @keyframes blink { |
| | | 0%, 80%, 100% { |
| | | opacity: 0; |
| | | } |
| | | 40% { |
| | | opacity: 1; |
| | | } |
| | | } |
| | | |
| | | /* scroll-view样式 */ |
| | | /* 列表容器样式 */ |
| | | .scroll-view { |
| | | flex: 1; |
| | | overflow-y: auto; |
| | | margin-bottom: 20rpx; |
| | | height: calc(100vh - 180rpx); /* 减去顶部标签页和底部按钮的高度 */ |
| | | overflow: hidden; |
| | | padding-bottom: 140rpx; /* 增加底部内边距,为按钮留出更多空间 */ |
| | | background-color: #f5f5f5; /* 确保背景色与tabs不同 */ |
| | | margin-top: 10rpx; /* 与顶部tab保持一点距离 */ |
| | | } |
| | | |
| | | .scroll-bg { |
| | | padding: 10rpx 0; |
| | | height: 100%; |
| | | display: flex; |
| | | flex-direction: column; |
| | | } |
| | | |
| | | /* 中间列表样式 */ |
| | | .irrigation-list { |
| | | flex: 1; |
| | | background-color: transparent; |
| | | margin-bottom: 20rpx; |
| | | overflow: hidden; |
| | | display: flex; |
| | | flex-direction: column; |
| | | padding: 0; |
| | | } |
| | | |
| | | .list-title { |
| | | font-size: 28rpx; |
| | | font-weight: bold; |
| | | color: #333; |
| | | padding: 20rpx; |
| | | background-color: #f8f8f8; |
| | | border-bottom: 1rpx solid #eee; |
| | | padding-bottom: 40rpx; /* 添加底部内边距,防止最后一项被遮挡 */ |
| | | } |
| | | |
| | | /* 列表项样式 */ |
| | | .list-item { |
| | | padding: 30rpx; |
| | | padding-bottom: 90rpx; |
| | | position: relative; |
| | | background-color: #fff; |
| | | border-radius: 12rpx; |
| | | margin-bottom: 16rpx; |
| | | box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05); |
| | | border-radius: 16rpx; |
| | | margin-bottom: 20rpx; |
| | | position: relative; |
| | | overflow: hidden; |
| | | box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05); |
| | | } |
| | | |
| | | .item-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | margin-bottom: 10rpx; |
| | | margin-top: 10rpx; |
| | | } |
| | | |
| | | .item-title { |
| | | font-size: 28rpx; |
| | | font-weight: bold; |
| | | color: #333; |
| | | } |
| | | |
| | | .item-status { |
| | | font-size: 24rpx; |
| | | color: #999; |
| | | padding: 4rpx 12rpx; |
| | | /* 状态标签样式 */ |
| | | .status-tag { |
| | | position: absolute; |
| | | top: 20rpx; |
| | | right: 20rpx; |
| | | padding: 4rpx 16rpx; |
| | | border-radius: 20rpx; |
| | | |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | .status-icon { |
| | | width: 70rpx; |
| | | height: 70rpx; |
| | | |
| | | } |
| | | |
| | | .status-active { |
| | | font-size: 24rpx; |
| | | color: #fff; |
| | | background-color: rgba(45, 139, 247, 1); |
| | | } |
| | | |
| | | .status-draft { |
| | | color: #fff; |
| | | .status-tag.draft { |
| | | background-color: #ff9d00; |
| | | } |
| | | |
| | | .status-tag.published { |
| | | background-color: #0052d9; |
| | | } |
| | | |
| | | .status-tag.executing { |
| | | background-color: #00a870; |
| | | } |
| | | |
| | | .status-tag.completed { |
| | | background-color: #999; |
| | | } |
| | | |
| | | .status-published { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | color: #00AD45; |
| | | background-color: rgba(0, 173, 69, 0.1); |
| | | /* 内容区域样式 */ |
| | | .item-content { |
| | | padding: 30rpx; |
| | | } |
| | | |
| | | .status-published-icon { |
| | | width: 34rpx; |
| | | height: 34rpx; |
| | | margin-right: 6rpx; |
| | | /* 标题区域样式 */ |
| | | .title-section { |
| | | margin-bottom: 30rpx; |
| | | } |
| | | |
| | | .item-info { |
| | | font-size: 24rpx; |
| | | color: #666; |
| | | margin-right: 160rpx; |
| | | } |
| | | |
| | | .info-row { |
| | | display: flex; |
| | | margin-bottom: 8rpx; |
| | | align-items: flex-end; /* 添加底部对齐 */ |
| | | } |
| | | |
| | | /* 编号行样式 - 作为标题突出显示 */ |
| | | .title-row { |
| | | margin-bottom: 10rpx; |
| | | } |
| | | |
| | | .title-row .info-label, |
| | | .title-row .info-value { |
| | | font-size: 26rpx; |
| | | font-weight: bold; |
| | | .plan-title { |
| | | font-size: 32rpx; |
| | | font-weight: 500; |
| | | color: #333; |
| | | margin-bottom: 8rpx; |
| | | } |
| | | |
| | | .project-name { |
| | | font-size: 26rpx; |
| | | color: #666; |
| | | } |
| | | |
| | | /* 信息区域样式 */ |
| | | .info-section { |
| | | margin-bottom: 30rpx; |
| | | } |
| | | |
| | | /* 信息网格 */ |
| | | .info-grid { |
| | | display: flex; |
| | | flex-direction: row; |
| | | justify-content: space-between; |
| | | width: 100%; |
| | | margin-top: 12rpx; |
| | | } |
| | | |
| | | .info-item { |
| | | display: flex; |
| | | align-items: flex-start; |
| | | /* 横向布局时占据一半宽度 */ |
| | | width: 48%; |
| | | } |
| | | |
| | | /* 纵向布局的信息网格 */ |
| | | .vertical-layout { |
| | | flex-direction: column; |
| | | gap: 16rpx; |
| | | } |
| | | |
| | | .vertical-layout .info-item { |
| | | width: 100%; |
| | | margin-bottom: 16rpx; |
| | | } |
| | | |
| | | /* 历史列表特定样式 */ |
| | | .history-grid { |
| | | flex-direction: column; |
| | | gap: 20rpx; |
| | | } |
| | | |
| | | .info-icon { |
| | | width: 40rpx; |
| | | height: 40rpx; |
| | | margin-right: 16rpx; |
| | | } |
| | | |
| | | .info-icon.duration-icon { |
| | | width: 35rpx; |
| | | height: 35rpx; |
| | | margin-right: 16rpx; |
| | | } |
| | | |
| | | .info-icon image { |
| | | width: 100%; |
| | | height: 100%; |
| | | } |
| | | |
| | | .info-content { |
| | | flex: 1; |
| | | } |
| | | |
| | | .info-label { |
| | | font-size: 24rpx; |
| | | color: #999; |
| | | width: 150rpx; |
| | | margin-right: 10rpx; /* 添加右侧间距 */ |
| | | margin-bottom: 4rpx; |
| | | } |
| | | |
| | | /* 为已灌溉时间和轮组添加特殊样式 */ |
| | | .info-row.irrigated-row { |
| | | margin-top: 12rpx; |
| | | margin-bottom: 12rpx; |
| | | align-items: center !important; /* 强制垂直居中对齐 */ |
| | | display: flex; |
| | | justify-content: flex-start; /* 水平方向起点对齐 */ |
| | | height: 50rpx; /* 固定行高 */ |
| | | .info-value { |
| | | font-size: 28rpx; |
| | | color: #333; |
| | | } |
| | | |
| | | .info-row.irrigated-row .info-label { |
| | | /* 执行中状态额外信息样式 */ |
| | | .executing-info { |
| | | margin-top: 20rpx; |
| | | padding-top: 20rpx; |
| | | border-top: 1rpx solid #f5f5f5; |
| | | } |
| | | |
| | | /* 操作按钮区域样式 */ |
| | | .action-section { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | gap: 20rpx; |
| | | padding-top: 20rpx; |
| | | border-top: 1rpx solid #f5f5f5; |
| | | width: 100%; |
| | | position: relative; |
| | | z-index: 1; |
| | | } |
| | | |
| | | .action-buttons { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | gap: 20rpx; |
| | | width: 100%; |
| | | } |
| | | |
| | | .action-button { |
| | | display: inline-flex; |
| | | align-items: center; |
| | | height: 100%; /* 使用百分比高度 */ |
| | | justify-content: center; |
| | | gap: 8rpx; |
| | | padding: 12rpx 24rpx; |
| | | border-radius: 8rpx; |
| | | font-size: 28rpx; |
| | | line-height: 1; |
| | | min-width: 160rpx; |
| | | height: 60rpx; |
| | | margin: 0; |
| | | background-color: #1890FF; |
| | | color: #fff; |
| | | border: none; |
| | | position: relative; |
| | | z-index: 2; |
| | | } |
| | | |
| | | .info-value-time { |
| | | font-size: 30rpx; |
| | | font-weight: bold; |
| | | color: rgb(42, 130, 228); |
| | | display: flex; |
| | | align-items: center; |
| | | height: 100%; /* 使用与info-label相同的高度 */ |
| | | .action-button::after { |
| | | display: none; |
| | | } |
| | | |
| | | /* 空列表容器 */ |
| | | .action-button image { |
| | | width: 32rpx; |
| | | height: 32rpx; |
| | | display: block; |
| | | } |
| | | |
| | | .action-button text { |
| | | color: #fff; |
| | | display: block; |
| | | } |
| | | |
| | | .publish-button { |
| | | background-color: #1890FF !important; |
| | | } |
| | | |
| | | .stop-button { |
| | | background-color: #ff4d4f !important; |
| | | } |
| | | |
| | | .execute-button { |
| | | background-color: #1890FF !important; |
| | | } |
| | | |
| | | /* 空状态样式 */ |
| | | .empty-list { |
| | | flex: 1; |
| | | display: flex; |
| | | flex-direction: column; |
| | | justify-content: center; |
| | | align-items: center; |
| | | background-color: #fff; |
| | | border-radius: 12rpx; |
| | | box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05); |
| | | width: 100%; |
| | | height: calc(100vh - 250rpx); /* 减去顶部标签页、底部按钮和内边距的高度 */ |
| | | min-height: 500rpx; |
| | | justify-content: center; |
| | | padding: 100rpx 0; |
| | | } |
| | | |
| | | .empty-icon { |
| | |
| | | |
| | | /* 底部按钮样式 */ |
| | | .bottom-button { |
| | | padding: 20rpx 0; |
| | | position: fixed; |
| | | bottom: 0; |
| | | left: 0; |
| | | right: 0; |
| | | padding: 20rpx; |
| | | background-color: #fff; |
| | | box-shadow: 0 -2rpx 12rpx rgba(0, 0, 0, 0.05); |
| | | z-index: 100; |
| | | } |
| | | |
| | | .add-button { |
| | | background-color: rgba(45, 139, 247, 1); |
| | | color: #fff; |
| | | font-size: 32rpx; |
| | | border-radius: 12rpx; |
| | | width: 100%; |
| | | transition: all 0.2s ease; |
| | | } |
| | | |
| | | .add-button-hover { |
| | | background-color: rgba(35, 110, 200, 1); |
| | | transform: scale(0.98); |
| | | } |
| | | |
| | | .add-button:active { |
| | | background-color: rgba(35, 110, 200, 1); |
| | | transform: scale(0.98); |
| | | } |
| | | |
| | | /* 列表项操作按钮 */ |
| | | .item-actions { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | align-items: center; |
| | | position: absolute; |
| | | bottom: 20rpx; |
| | | right: 30rpx; |
| | | z-index: 2; |
| | | justify-content: center; |
| | | background-color: #1890FF; |
| | | color: #fff; |
| | | border-radius: 8rpx; |
| | | font-size: 30rpx; |
| | | padding: 5rpx 0; |
| | | } |
| | | |
| | | .action-button { |
| | | font-size: 24rpx; |
| | | padding: 6rpx 20rpx; |
| | | margin-left: 16rpx; |
| | | border-radius: 30rpx; |
| | | background-color: #fff; |
| | | line-height: 1.5; |
| | | min-height: auto; |
| | | box-shadow: 0 2rpx 6rpx rgba(0, 0, 0, 0.1); |
| | | transition: all 0.2s ease; |
| | | .add-button image { |
| | | width: 36rpx; |
| | | height: 36rpx; |
| | | margin-right: 8rpx; |
| | | } |
| | | |
| | | .action-button-hover { |
| | | transform: scale(0.95); |
| | | box-shadow: 0 1rpx 3rpx rgba(0, 0, 0, 0.1); |
| | | } |
| | | |
| | | .action-button:active { |
| | | transform: scale(0.95); |
| | | box-shadow: 0 1rpx 3rpx rgba(0, 0, 0, 0.1); |
| | | } |
| | | |
| | | .publish-button { |
| | | color: rgba(45, 139, 247, 1); |
| | | border: 1rpx solid rgba(45, 139, 247, 1); |
| | | } |
| | | |
| | | /* 按钮点击效果 */ |
| | | .publish-button-hover { |
| | | background-color: rgba(45, 139, 247, 0.1); |
| | | } |
| | | |
| | | .publish-button:active { |
| | | background-color: rgba(45, 139, 247, 0.1); |
| | | } |
| | | |
| | | .stop-button { |
| | | color: #f56c6c; |
| | | border: 1rpx solid #f56c6c; |
| | | opacity: 0.8 !important; |
| | | } |
| | | |
| | | .stop-button-hover { |
| | | background-color: rgba(245, 108, 108, 0.1); |
| | | } |
| | | |
| | | .stop-button:active { |
| | | background-color: rgba(245, 108, 108, 0.1); |
| | | } |
| | | |
| | | .execute-button { |
| | | color: rgba(45, 139, 247, 1); |
| | | border: 1rpx solid rgba(45, 139, 247, 1); |
| | | opacity: 0.8 !important; |
| | | } |
| | | |
| | | .execute-button-hover { |
| | | background-color: rgba(45, 139, 247, 0.1); |
| | | opacity: 0.8 !important; |
| | | } |
| | | |
| | | .execute-button:active { |
| | | background-color: rgba(45, 139, 247, 0.1); |
| | | .add-button-hover { |
| | | opacity: 0.8; |
| | | } |