235 lines
6.9 KiB
JavaScript
235 lines
6.9 KiB
JavaScript
/* 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,
|
||
});
|
||
},
|
||
});
|