// index.js Page({ data: { // 导航栏高度数据 navBarHeight: getApp().globalData.navBarHeight, statusBarHeight: getApp().globalData.statusBarHeight, menuBottom: getApp().globalData.menuBottom, menuHeight: getApp().globalData.menuHeight, // MQTT 连接状态 mqttStatus: '未连接', isConnected: false, // 数据显示 temperature: '--', humidity: '--', foodWeight: 0, waterLevel: 0, systemMode: 'auto', // auto: 自动, manual: 手动 // 设置数据 feedTimes: [], // 喂食时间点 singleFeedWeight: 50, // 单次喂食重量(克) // 弹窗控制 showTimePicker: false, showSettings: false, currentEditingTimeIndex: -1, // 加载状态 loading: false, // 消息日志 messages: [], // MQTT 主题 topics: { sensor: 'petfeeder/sensor', // 传感器数据 control: 'petfeeder/control', // 控制指令 config: 'petfeeder/config', // 配置更新 status: 'petfeeder/status' // 状态查询 } }, onLoad() { // 获取导航栏高度数据 const app = getApp(); this.setData({ navBarHeight: app.globalData.navBarHeight, statusBarHeight: app.globalData.statusBarHeight, menuBottom: app.globalData.menuBottom, menuHeight: app.globalData.menuHeight }); // 页面加载时获取MQTT连接状态 this.updateConnectionStatus(); // 加载保存的设置 this.loadSettings(); // 请求当前状态 this.requestStatus(); // 延迟检查连接状态(确保MQTT初始化完成) setTimeout(() => { this.updateConnectionStatus(); }, 1000); }, onShow() { // 页面显示时更新状态 this.updateConnectionStatus(); }, /** * 更新连接状态 */ updateConnectionStatus() { const app = getApp(); const isConnected = app.globalData.isMQTTConnected; console.log('更新连接状态:', isConnected); this.setData({ isConnected: isConnected, mqttStatus: isConnected ? '已连接' : '未连接' }); }, /** * MQTT消息回调函数 */ onMQTTMessage(topic, message) { try { const messageStr = message.toString().trim(); const messageData = JSON.parse(messageStr); console.log('收到MQTT消息:', topic, messageData); // 更新连接状态(收到消息说明连接正常) const app = getApp(); this.setData({ isConnected: app.globalData.isMQTTConnected, mqttStatus: app.globalData.isMQTTConnected ? '已连接' : '未连接' }); // 处理传感器数据 if (topic.includes('sensor')) { this.handleSensorData(messageData); } // 处理状态数据 else if (topic.includes('status')) { this.handleStatusData(messageData); } // 处理配置确认 else if (topic.includes('config')) { this.handleConfigResponse(messageData); } // 添加到消息日志 this.addMessageLog(topic, messageStr); } catch (error) { console.error('处理MQTT消息失败:', error); } }, /** * 处理传感器数据 */ handleSensorData(data) { console.log('处理传感器数据:', data); console.log('当前页面数据:', this.data); this.setData({ temperature: data.temperature || '--', humidity: data.humidity || '--', foodWeight: data.foodWeight || 0, waterLevel: data.waterLevel || 0 }, () => { console.log('setData 回调执行完成'); console.log('更新后页面数据:', this.data); }); }, /** * 处理状态数据 */ handleStatusData(data) { if (data.mode) { this.setData({ systemMode: data.mode }); } }, /** * 处理配置响应 */ handleConfigResponse(data) { if (data.success) { wx.showToast({ title: '配置保存成功', icon: 'success' }); } else { wx.showToast({ title: '配置保存失败', icon: 'error' }); } }, /** * 添加消息日志 */ addMessageLog(topic, message) { const logItem = { topic: topic, message: message, time: new Date().toLocaleTimeString() }; const messages = this.data.messages; messages.unshift(logItem); if (messages.length > 10) { messages.pop(); } this.setData({ messages }); }, /** * 切换系统模式 */ toggleMode() { const newMode = this.data.systemMode === 'auto' ? 'manual' : 'auto'; // 先发送控制命令,成功后再更新UI const sent = this.sendControlCommand({ action: 'setMode', mode: newMode }); if (sent) { this.setData({ systemMode: newMode }); } }, /** * 手动喂食 */ manualFeed() { if (this.data.systemMode === 'auto') { wx.showModal({ title: '提示', content: '当前为自动模式,是否要切换到手动模式进行喂食?', success: (res) => { if (res.confirm) { this.toggleMode(); setTimeout(() => { this.executeFeed(); }, 500); } } }); } else { this.executeFeed(); } }, /** * 执行喂食命令 */ executeFeed() { this.sendControlCommand({ action: 'feed', amount: this.data.singleFeedWeight }); wx.showToast({ title: `喂食${this.data.singleFeedWeight}克`, icon: 'loading', duration: 2000 }); }, /** * 手动补水 */ manualWater() { this.sendControlCommand({ action: 'addWater' }); wx.showToast({ title: '补水中...', icon: 'loading', duration: 3000 }); }, /** * 刷新数据 */ refreshData() { this.setData({ loading: true }); // 请求最新数据 this.requestStatus(); setTimeout(() => { this.setData({ loading: false }); wx.showToast({ title: '数据已刷新', icon: 'success' }); }, 1000); }, /** * 发送控制命令 */ sendControlCommand(command) { const app = getApp(); if (!app.globalData.isMQTTConnected) { wx.showToast({ title: 'MQTT未连接', icon: 'none' }); return false; } const message = { ...command, timestamp: new Date().toISOString() }; return app.publishMQTT(this.data.topics.control, message); }, /** * 请求状态 */ requestStatus() { this.sendControlCommand({ action: 'getStatus' }); }, /** * 打开设置 */ openSettings() { this.setData({ showSettings: true }); }, /** * 关闭设置 */ closeSettings() { this.setData({ showSettings: false }); }, /** * 添加喂食时间 */ addFeedTime() { if (this.data.feedTimes.length >= 2) { wx.showToast({ title: '最多设置2个时间点', icon: 'none' }); return; } this.setData({ currentEditingTimeIndex: -1, showTimePicker: true }); }, /** * 编辑喂食时间 */ editFeedTime(e) { const index = e.currentTarget.dataset.index; this.setData({ currentEditingTimeIndex: index, showTimePicker: true }); }, /** * 删除喂食时间 */ deleteFeedTime(e) { const index = e.currentTarget.dataset.index; const feedTimes = this.data.feedTimes; feedTimes.splice(index, 1); this.setData({ feedTimes }); }, /** * 时间选择确认 */ onTimeConfirm(e) { console.log('时间选择返回值:', e.detail); const time = e.detail; let hours, minutes; // type="time" 时,Vant 返回的可能是对象、字符串或数组 if (Array.isArray(time)) { // 如果是数组格式 [hours, minutes] hours = time[0]; minutes = time[1]; } else if (typeof time === 'object' && time !== null) { // 如果是对象格式 { hours, minutes } 或 { hour, minute } hours = time.hours !== undefined ? time.hours : time.hour; minutes = time.minutes !== undefined ? time.minutes : time.minute; } else if (typeof time === 'string' && time.includes(':')) { // 如果是字符串格式 "HH:mm" const parts = time.split(':'); hours = parseInt(parts[0], 10); minutes = parseInt(parts[1], 10); } else { // 其他情况作为时间戳处理 const date = new Date(time); hours = date.getHours(); minutes = date.getMinutes(); } console.log('解析结果 hours:', hours, 'minutes:', minutes); const timeString = `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}`; console.log('时间字符串:', timeString); const feedTimes = this.data.feedTimes; if (this.data.currentEditingTimeIndex === -1) { // 新增 feedTimes.push(timeString); feedTimes.sort(); } else { // 编辑 feedTimes[this.data.currentEditingTimeIndex] = timeString; feedTimes.sort(); } this.setData({ feedTimes, showTimePicker: false, currentEditingTimeIndex: -1 }); }, /** * 时间选择取消 */ onTimeCancel() { this.setData({ showTimePicker: false, currentEditingTimeIndex: -1 }); }, /** * 单次喂食重量改变 */ onFeedWeightChange(e) { this.setData({ singleFeedWeight: e.detail }); }, /** * 保存设置 */ saveSettings() { const config = { feedTimes: this.data.feedTimes, singleFeedWeight: this.data.singleFeedWeight }; // 发送配置到设备 const app = getApp(); if (app.globalData.isMQTTConnected) { app.publishMQTT(this.data.topics.config, config); } // 保存到本地存储 wx.setStorageSync('petfeeder_config', config); this.setData({ showSettings: false }); wx.showToast({ title: '设置已保存', icon: 'success' }); }, /** * 加载设置 */ loadSettings() { const config = wx.getStorageSync('petfeeder_config'); if (config) { this.setData({ feedTimes: config.feedTimes || [], singleFeedWeight: config.singleFeedWeight || 50 }); } }, /** * 格式化水位显示 */ getWaterLevelText(level) { return level === 1 ? '满水' : '缺水'; }, getWaterLevelType(level) { return level === 1 ? 'success' : 'danger'; }, /** * 格式化模式显示 */ getModeText(mode) { return mode === 'auto' ? '自动模式' : '手动模式'; }, /** * 格式化模式类型 */ getModeType(mode) { return mode === 'auto' ? 'success' : 'primary'; } });