335 lines
9.3 KiB
JavaScript
335 lines
9.3 KiB
JavaScript
App({
|
||
onLaunch() {
|
||
this.initPpScale();
|
||
},
|
||
|
||
globalData: {
|
||
// wx.request 请求的服务地址
|
||
wxRequestUrl: "https://device.shuziweidao.com/gateway/",
|
||
// wxRequestUrl: "http://192.168.1.207:8889/",
|
||
|
||
// 秤的所有信息
|
||
ppScale: {
|
||
version: "",
|
||
|
||
plugin: null,
|
||
activeProtocol: null,
|
||
domain1: "http://device.shuziweidao.com:80/gateway", // 老版本 没有鉴权
|
||
domain2: "http://device.shuziweidao.com:80/weight", // 新版本 有鉴权
|
||
// domain1: "http://192.168.1.207:8889", // 老版本 没有鉴权
|
||
// domain2: "http://192.168.1.207:8889/weight", // 新版本 有鉴权
|
||
wifi: {
|
||
ssid: "",
|
||
password: ""
|
||
},
|
||
options: {
|
||
key: "lefudc91611833e18d94",
|
||
secret: "eQ50JYimMp0X7uhNLj6D3lTEk4TUUvEG7dvaqKM9t1U="
|
||
},
|
||
device: {
|
||
setting: [{
|
||
"advLength": 999,
|
||
"calorieStatus": 0,
|
||
"createBy": null,
|
||
"deviceAccuracyType": 2,
|
||
"deviceCalcuteType": 3,
|
||
"deviceConnectType": 2,
|
||
"deviceFuncType": 223,
|
||
"deviceName": "CF568_G",
|
||
"devicePowerType": 3,
|
||
"deviceProtocolType": 3,
|
||
"deviceType": 1,
|
||
"deviceUnitType": "0,1,11",
|
||
"id": 65,
|
||
"imgUrl": null,
|
||
"macAddressStart": 6,
|
||
"remark": null,
|
||
"sign": "FF",
|
||
"status": 0,
|
||
"uhStatus": 1,
|
||
"updateBy": null
|
||
}, {
|
||
"advLength": 999,
|
||
"calorieStatus": 0,
|
||
"createBy": null,
|
||
"deviceAccuracyType": 2,
|
||
"deviceCalcuteType": 3,
|
||
"deviceConnectType": 2,
|
||
"deviceFuncType": 223,
|
||
"deviceName": "YX-B4-568-BW",
|
||
"devicePowerType": 3,
|
||
"deviceProtocolType": 3,
|
||
"deviceType": 1,
|
||
"deviceUnitType": "0,1,11",
|
||
"id": 65,
|
||
"imgUrl": null,
|
||
"macAddressStart": 6,
|
||
"remark": null,
|
||
"sign": "FF",
|
||
"status": 0,
|
||
"uhStatus": 1,
|
||
"updateBy": null
|
||
}, {
|
||
"advLength": 999,
|
||
"calorieStatus": 0,
|
||
"createBy": null,
|
||
"deviceAccuracyType": 2,
|
||
"deviceCalcuteType": 4,
|
||
"deviceConnectType": 2,
|
||
"deviceFuncType": 65759,
|
||
"deviceName": "CF636_G",
|
||
"devicePowerType": 3,
|
||
"deviceProtocolType": 3,
|
||
"deviceType": 1,
|
||
"deviceUnitType": "0,1,2",
|
||
"id": 216,
|
||
"imgUrl": null,
|
||
"macAddressStart": 6,
|
||
"remark": null,
|
||
"sign": "FF",
|
||
"status": 0,
|
||
"uhStatus": 1,
|
||
"updateBy": null
|
||
}, {
|
||
"advLength": 999,
|
||
"calorieStatus": 0,
|
||
"createBy": null,
|
||
"deviceAccuracyType": 2,
|
||
"deviceCalcuteType": 4,
|
||
"deviceConnectType": 2,
|
||
"deviceFuncType": 65759,
|
||
"deviceName": "YX-B8-636-BW",
|
||
"devicePowerType": 3,
|
||
"deviceProtocolType": 3,
|
||
"deviceType": 1,
|
||
"deviceUnitType": "0,1,2",
|
||
"id": 216,
|
||
"imgUrl": null,
|
||
"macAddressStart": 6,
|
||
"remark": null,
|
||
"sign": "FF",
|
||
"status": 0,
|
||
"uhStatus": 1,
|
||
"updateBy": null
|
||
}, {
|
||
"advLength": 999,
|
||
"calorieStatus": 0,
|
||
"createBy": null,
|
||
"deviceAccuracyType": 2,
|
||
"deviceCalcuteType": 4,
|
||
"deviceConnectType": 2,
|
||
"deviceFuncType": 223,
|
||
"deviceName": "CF577",
|
||
"devicePowerType": 3,
|
||
"deviceProtocolType": 3,
|
||
"deviceType": 1,
|
||
"deviceUnitType": "0,1,11",
|
||
"id": 51,
|
||
"imgUrl": null,
|
||
"macAddressStart": 6,
|
||
"remark": null,
|
||
"sign": "FF",
|
||
"status": 0,
|
||
"uhStatus": 1,
|
||
"updateBy": null
|
||
}], // 即将要搜索周边秤的配置
|
||
list: [], // 根据配置搜索到秤的列表
|
||
name: "",
|
||
mac: null, // 选中的设备mac地址/SN码
|
||
connection: null, // 默认选中连接的设备
|
||
connectState: null, // 当前连接设备的状态
|
||
},
|
||
reconnect: {
|
||
count: 0, // 当前已重连次数
|
||
max: 3, // 最大重连次数
|
||
timer: null // 重连定时器
|
||
}
|
||
},
|
||
|
||
_callbacks: {} // 用于存储所有 globalData 属性的监听回调
|
||
},
|
||
|
||
initPpScale() {
|
||
this.globalData.ppScale.plugin = requirePlugin('ppScale-plugin');
|
||
},
|
||
|
||
// 保活定时器引用
|
||
_keepAliveTimer: null,
|
||
|
||
/**
|
||
* 启动保活定时器,每 15 秒发送一次保活指令
|
||
* 内部已做去重处理,重复调用安全
|
||
*/
|
||
startKeepAlive() {
|
||
this.stopKeepAlive();
|
||
this._keepAliveTimer = setInterval(() => {
|
||
if (this.globalData.ppScale.activeProtocol) {
|
||
this.globalData.ppScale.activeProtocol.sendKeepAliveCode();
|
||
}
|
||
}, 15000);
|
||
},
|
||
|
||
/**
|
||
* 清除保活定时器
|
||
*/
|
||
stopKeepAlive() {
|
||
if (this._keepAliveTimer) {
|
||
clearInterval(this._keepAliveTimer);
|
||
this._keepAliveTimer = null;
|
||
}
|
||
},
|
||
|
||
/**
|
||
* 页面离开时的统一清理:停止保活 + 重置重连计数 + connectState 置空 + 停止蓝牙
|
||
*/
|
||
cleanupConnection() {
|
||
this.stopKeepAlive();
|
||
this.resetReconnectCount();
|
||
this.setGlobalData('ppScale.device.connectState', null);
|
||
this.globalData.ppScale.plugin.Blue.stop();
|
||
},
|
||
|
||
/**
|
||
* 注册全局 bus 事件监听(connectState / syncDeviceTimeSuccess / deviceWillDisconnect)
|
||
* 依赖 Blue.stop() 清空订阅,onShow 时直接调用,无需标志位
|
||
*/
|
||
registerBusListeners() {
|
||
const plugin = this.globalData.ppScale.plugin;
|
||
|
||
// 蓝牙连接状态监听
|
||
plugin.bus.subscribe('connectState', (res) => {
|
||
console.log("app.js ===> connectState", res);
|
||
this.setGlobalData('ppScale.device.connectState', res);
|
||
if (res == plugin.BLUE_STATE.CONNECTSUCCESS) {
|
||
this.globalData.ppScale.reconnect.count = 0;
|
||
this.startKeepAlive();
|
||
}
|
||
if (res == plugin.BLUE_STATE.CONNECTFAILED) {
|
||
this.stopKeepAlive();
|
||
this.reconnectDevice();
|
||
}
|
||
wx.hideLoading();
|
||
});
|
||
|
||
// 同步时间
|
||
plugin.bus.subscribe('syncDeviceTimeSuccess', (res) => {
|
||
console.log("app.js ===> syncDeviceTimeSuccess", res);
|
||
});
|
||
|
||
// 设备自动断开监听
|
||
plugin.bus.subscribe('deviceWillDisconnect', (res) => {
|
||
console.log("app.js ===> deviceWillDisconnect", res);
|
||
this.stopKeepAlive();
|
||
this.setGlobalData('ppScale.device.connectState', plugin.BLUE_STATE.CONNECTFAILED);
|
||
});
|
||
},
|
||
|
||
/**
|
||
* 自动重连设备,最多重试 max 次,超过后停止,由用户手动重连
|
||
* 只在配置页(configureDevice)活跃时执行,防止跨页面干扰
|
||
*/
|
||
reconnectDevice() {
|
||
const reconnect = this.globalData.ppScale.reconnect;
|
||
|
||
// 仅在配置页活跃时执行重连
|
||
const pages = getCurrentPages();
|
||
const currentPage = pages[pages.length - 1];
|
||
if (!currentPage || !currentPage.route || !currentPage.route.includes('configureDevice')) {
|
||
console.log("app.js ===> 非配置页,跳过自动重连");
|
||
return;
|
||
}
|
||
|
||
if (reconnect.count >= reconnect.max) {
|
||
console.log("app.js ===> 自动重连已达上限,等待用户手动重试");
|
||
return;
|
||
}
|
||
|
||
reconnect.count++;
|
||
console.log(`app.js ===> 自动重连第 ${reconnect.count}/${reconnect.max} 次`);
|
||
|
||
// 延迟 2 秒后重连,避免连续冲突
|
||
if (reconnect.timer) {
|
||
clearTimeout(reconnect.timer);
|
||
}
|
||
reconnect.timer = setTimeout(() => {
|
||
this.globalData.ppScale.plugin.Blue.disconnect((disres) => {
|
||
if (disres.errCode == 0) {
|
||
console.log("app.js ===> 断开成功,开始重新扫描设备");
|
||
this.globalData.ppScale.plugin.Blue.startBluetoothDevicesDiscovery();
|
||
} else {
|
||
console.log("app.js ===> 断开失败,errCode:", disres.errCode);
|
||
}
|
||
});
|
||
}, 2000);
|
||
},
|
||
|
||
/**
|
||
* 重置重连计数,用于用户手动点击重试或页面离开时调用
|
||
*/
|
||
resetReconnectCount() {
|
||
const reconnect = this.globalData.ppScale.reconnect;
|
||
reconnect.count = 0;
|
||
if (reconnect.timer) {
|
||
clearTimeout(reconnect.timer);
|
||
reconnect.timer = null;
|
||
}
|
||
},
|
||
|
||
/**
|
||
* 注册 globalData 某个属性的监听
|
||
* @param {string} keyPath 要监听的 globalData 属性路径,例如 'ppScale.device.connectState'
|
||
* @param {function} callback 属性变化时执行的回调函数 (newValue, oldValue) => {}
|
||
*/
|
||
watch(keyPath, callback) {
|
||
if (!this.globalData._callbacks[keyPath]) {
|
||
this.globalData._callbacks[keyPath] = [];
|
||
}
|
||
this.globalData._callbacks[keyPath].push(callback);
|
||
},
|
||
|
||
/**
|
||
* 取消 globalData 某个属性的监听
|
||
* @param {string} keyPath 要取消监听的 globalData 属性路径
|
||
* @param {function} callback 之前注册的回调函数
|
||
*/
|
||
unwatch(keyPath, callback) {
|
||
if (this.globalData._callbacks[keyPath]) {
|
||
this.globalData._callbacks[keyPath] = this.globalData._callbacks[keyPath].filter(cb => cb !== callback);
|
||
}
|
||
},
|
||
|
||
/**
|
||
* 设置 globalData 的值并触发所有相关监听器
|
||
* 支持点表示法设置嵌套属性,例如 'ppScale.device.connectState'
|
||
* @param {string} keyPath 要设置的 globalData 属性路径
|
||
* @param {*} value 要设置的新值
|
||
*/
|
||
setGlobalData(keyPath, value) {
|
||
const keys = keyPath.split('.');
|
||
let current = this.globalData;
|
||
let oldValue = undefined;
|
||
|
||
// 遍历到目标属性的父级
|
||
for (let i = 0; i < keys.length - 1; i++) {
|
||
if (!current[keys[i]]) {
|
||
current[keys[i]] = {}; // 如果路径不存在,创建空对象
|
||
}
|
||
current = current[keys[i]];
|
||
}
|
||
|
||
// 获取旧值
|
||
oldValue = current[keys[keys.length - 1]];
|
||
|
||
// 只有当值发生变化时才更新并通知
|
||
if (oldValue !== value) {
|
||
current[keys[keys.length - 1]] = value; // 设置新值
|
||
|
||
// 触发监听器
|
||
if (this.globalData._callbacks[keyPath]) {
|
||
this.globalData._callbacks[keyPath].forEach(callback => {
|
||
callback(value, oldValue);
|
||
});
|
||
}
|
||
}
|
||
},
|
||
}) |