/* pages/mine/mine.js */ const storage = require('../../utils/storage.js'); const auth = require('../../utils/auth.js'); const { gateway } = require('../../services/gateway.js'); const { mqttClient } = require('../../services/mqtt-client.js'); const app = getApp(); Page({ data: { userInfo: null, activeDevice: '无', mqttStatus: '未连接', mqttStatusColor: '#999', bleStatus: '未运行', bleStatusColor: '#999', pendingCount: 0, appVersion: '1.0.0', // MQTT 连接配置(产品凭证,clientId 依据设备 SN) mqttForm: { serialNumber: '', productId: '', productSecret: '', }, mqttConnecting: false, mqttConnectingLocal: false, mqttConnected: false, }, onLoad() { this.loadUserInfo(); }, onShow() { if (!this._unsub) { this._unsub = gateway.subscribe(() => this.checkStatus()); } this.loadUserInfo(); this._loadMqttConfig(); this.checkStatus(); }, onHide() { if (this._unsub) { this._unsub(); this._unsub = null; } }, // 加载用户信息 loadUserInfo() { const userInfo = storage.getUserInfo(); this.setData({ userInfo }); }, // 回填 MQTT 配置(已保存的产品凭证),SN 默认带出当前启用设备 _loadMqttConfig() { const saved = storage.getMqttConfig(); const enabled = storage.getEnabledDevice(); this.setData({ mqttForm: { serialNumber: (saved && saved.serialNumber) || (enabled && enabled.serialNumber) || '', productId: saved && saved.productId != null ? String(saved.productId) : '', productSecret: (saved && saved.productSecret) || '', }, }); }, // MQTT 配置输入 onMqttInput(e) { const field = e.currentTarget.dataset.field; this.setData({ [`mqttForm.${field}`]: e.detail.value }); }, // 连接 MQTT("我的"页独立连接,与 BLE 采集解耦) async handleMqttConnect() { if (this.data.mqttConnectingLocal) return; const { serialNumber, productId, productSecret } = this.data.mqttForm; if (!serialNumber) { wx.showToast({ title: '请输入设备编号(SN)', icon: 'none' }); return; } if (!productId) { wx.showToast({ title: '请输入产品ID', icon: 'none' }); return; } if (!productSecret) { wx.showToast({ title: '请输入产品密钥', icon: 'none' }); return; } // productId 是上报 topic 的第 1 段,必须是正整数。 // parseInt 会把 '12.5' 截成 12、把 'abc' 变成 NaN,而网关侧的判空 // (cfg.productId == null / === '')两个都挡不住 NaN —— 会一路构造出 // /NaN/{sn}/{测点}/measure/post 这样的脏 topic 并持续上报 const pid = Number(productId); if (!Number.isInteger(pid) || pid <= 0) { wx.showToast({ title: '产品ID必须是正整数', icon: 'none' }); return; } if (!this.data.userInfo || !this.data.userInfo.userId) { wx.showToast({ title: '请先登录', icon: 'none' }); return; } this.setData({ mqttConnectingLocal: true }); try { const creds = auth.getMqttCredentials(serialNumber, pid, productSecret); if (!creds) { throw new Error('生成 MQTT 凭证失败,请重新登录'); } // 保存配置(加密 productSecret),下次进入自动回填 storage.setMqttConfig({ serialNumber, productId: pid, productSecret }); await mqttClient.connect(creds); wx.showToast({ title: 'MQTT 已连接', icon: 'success' }); } catch (err) { console.error('[Mine] MQTT 连接失败:', err); wx.showModal({ title: 'MQTT 连接失败', content: (err.message || '未知错误') + '\n\n底层仍在自动重试;若凭证有误会一直失败,请核对后重新连接。', showCancel: false, }); } finally { this.setData({ mqttConnectingLocal: false }); this.checkStatus(); } }, // 断开 MQTT(保留配置) // 这是"用户意图"标记:网关的自动连接此后不再拉起它,需手动再点「连接」 async handleMqttDisconnect() { await mqttClient.disconnect(); wx.showToast({ title: '已断开,不会自动重连', icon: 'none' }); }, // 检查连接状态(统一读网关快照,修复旧字符串/对象 API 回归) checkStatus() { const snap = gateway.getSnapshot(); const devName = snap.device ? (snap.device.name || snap.device.serialNumber || '') : ''; // MQTT let mqttStatus = '未连接'; let mqttStatusColor = '#999'; let mqttConnecting = false; if (snap.mqttConnected) { mqttStatus = '已连接'; mqttStatusColor = '#52c41a'; } else if (snap.mqttState === 'connecting') { mqttStatus = '连接中'; mqttConnecting = true; mqttStatusColor = '#1890ff'; } else if (snap.mqttUserDisconnected) { // 用户主动断开:不是异常,用中性色,避免被当成故障反复点重连 mqttStatus = '已手动断开'; mqttStatusColor = '#fa8c16'; } // 蓝牙/采集 let bleStatus = '未运行'; let bleStatusColor = '#999'; if (snap.bleConnected && devName) { bleStatus = '采集中'; bleStatusColor = '#52c41a'; } else if (snap.phase === 'starting') { bleStatus = '连接中'; bleStatusColor = '#1890ff'; } else if (snap.phase === 'error') { bleStatus = '异常'; bleStatusColor = '#ff4d4f'; } else if (snap.device && !snap.bleConnected) { bleStatus = '未连接'; bleStatusColor = '#fa8c16'; } const pendingData = storage.getPendingData(); const pendingCount = pendingData ? pendingData.length : 0; this.setData({ activeDevice: devName || '无', mqttStatus, mqttStatusColor, bleStatus, bleStatusColor, pendingCount, mqttConnecting, mqttConnected: !!snap.mqttConnected, }); }, // 清除缓存 clearCache() { wx.showModal({ title: '提示', content: '确定要清除缓存吗?这将清除所有离线数据。', success: (res) => { if (res.confirm) { storage.clearPendingData(); wx.showToast({ title: '清除成功', icon: 'success', }); this.checkStatus(); } }, }); }, // 退出登录 async logout() { wx.showModal({ title: '提示', content: '确定要退出登录吗?', success: async (res) => { if (res.confirm) { // 统一走 app.clearLoginInfo:停网关 + 断 MQTT + 清全部本地数据 await app.clearLoginInfo(); // 跳转到登录页 wx.reLaunch({ url: '/pages/login/login', }); } }, }); }, // 关于我们 showAbout() { wx.showModal({ title: '岩安测控网关', content: '版本:' + this.data.appVersion + '\n\n轻量化蓝牙网关,采集 BLE 设备数据透传上报至 yack 平台。', showCancel: false, }); }, });