fastbee/yack-mini/miniprogram/pages/mine/mine.js
2026-09-27 15:17:17 +08:00

235 lines
6.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* 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,
});
},
});