diff --git a/common/http.interceptor.js b/common/http.interceptor.js index e5cc646..8e011db 100644 --- a/common/http.interceptor.js +++ b/common/http.interceptor.js @@ -1,27 +1,7 @@ const install = (Vue, vm) => { - - // Vue.prototype.$u.http.setConfig({ - - // baseURL: 'https://yruibao.com/admin', - - // // baseUrl: 'http://192.168.10.104:8088', - // method: 'POST', - // // 设置为json,返回后会对数据进行一次JSON.parse() - // dataType: 'json', - // showLoading: true, // 是否显示请求中的loading - // loadingText: '...', // 请求loading中的文字提示 - // loadingTime: 800, // 在此时间内,请求还没回来的话,就显示加载中动画,单位ms - // originalData: false, // 是否在拦截器中返回服务端的原始数据 - // loadingMask: true, // 展示loading的时候,是否给一个透明的蒙层,防止触摸穿透 - // // 配置请求头信息 - // header: { - // 'content-type': 'application/json;charset=UTF-8', - - // }, - // }); Vue.prototype.$u.http.setConfig({ - baseUrl: 'https://yxd.ccttiot.com/prod-api', - // baseUrl: 'http://192.168.1.7:8081', + // baseUrl: 'https://yxd.ccttiot.com/prod-api', + baseUrl: 'http://192.168.1.3:8081', loadingText: '努力加载中~', loadingTime: 800, // 设置自定义头部content-type @@ -33,23 +13,7 @@ const install = (Vue, vm) => { // 请求拦截部分,如配置,每次请求前都会执行 Vue.prototype.$u.http.interceptor.request = (config) => { - // 引用token - // 方式一,存放在vuex的token,假设使用了uView封装的vuex方式 - // 见:https://uviewui.com/components/globalVariable.html - // config.header.token = vm.token; - - // 方式二,如果没有使用uView封装的vuex方法,那么需要使用$store.state获取 - // config.header.token = vm.$store.state.token; - - // 方式三,如果token放在了globalData,通过getApp().globalData获取 - - // 方式四,如果token放在了Storage本地存储中,拦截是每次请求都执行的 - // 所以哪怕您重新登录修改了Storage,下一次的请求将会是最新值 const token = uni.getStorageSync('token'); - - // const token = " eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6ImE1ZmE2YzM0LWM0Y2YtNGEwMS05YjY2LTE1M2M4YWY1YzU1YSJ9.Wze_tAjY7cCfw2K6mtDpTSd-QFLRF4A49Fx7bq7g2tVLKL4v5bqqHfpG0VQy7_a_CUQch5RPBTBIKMVCDupIqg" - - // console.log("我是token", token) config.header.Authorization = token; // config.header.Tenant-Id=1 // #ifdef H5 @@ -59,93 +23,10 @@ const install = (Vue, vm) => { if(config.url == '/user/login') config.header.noToken = true; // 最后需要将config进行return return config; - - // 如果return一个false值,则会取消本次请求 - // if(config.url == '/user/rest') return false; // 取消某次请求 } - // 响应拦截,如配置,每次请求结束都会执行本方法 Vue.prototype.$u.http.interceptor.response = (res) => { - // if(res.code == 10022 || res.code == 10023) { - // // res为服务端返回值,可能有code,result等字段 - // // 这里对res.result进行返回,将会在this.$u.post(url).then(res => {})的then回调中的res的到 - // // 如果配置了originalData为true,请留意这里的返回值 - // uni.redirectTo({ - // url:"/pages/login/login", - // fail:function(mes){ - // console.log(mes) - // }, - // success:function(mes){ - // console.log(mes) - // } - // }) - // // return res.result; - // } - if(res.code == 401) { - // res为服务端返回值,可能有code,result等字段 - // 这里对res.result进行返回,将会在this.$u.post(url).then(res => {})的then回调中的res的到 - // 如果配置了originalData为true,请留意这里的返回值 - - // return res.result; - - uni.login({ - success: function(ret) { - console.log("main.js==>res", ret) - // vm.$u.post('/user/login',{"js_code": ret.code}).then(res=>{ - // if (res.code == 10003) { - // // console.log("新用户登录") - // uni.setStorageSync('token', res.data); - - // } else if (res.code == 200) { - // // console.log("老用户登录",res.data) - // uni.setStorageSync('token', res.data); - - // } - // }); - } - }); - wx.login({ - success(res) { - if (res.code) { - console.log('登录!', res); - let data = { - loginCode: res.code, - - }; - vm.$u.post(`/wxLogin`,data).then(res=>{ - if (res.code == 10003) { - // uni.navigateTo({ - // url:'/pages/login/login' - // }) - - } else if (res.code == 200) { - // console.log("老用户登录",res.data) - // uni.switchTab({ - // url:'/pages/index/index' - // }) - - } - }); - } - }, - - }); - - } return res; - // else if(res.code == 201) { - // // 假设201为token失效,这里跳转登录 - // vm.$u.toast('验证失败,请重新登录'); - // setTimeout(() => { - // // 此为uView的方法,详见路由相关文档 - // vm.$u.route('/pages/user/login') - // }, 1500) - // return false; - // } else { - // // 如果返回false,则会调用Promise的reject回调, - // // 并将进入this.$u.post(url).then().catch(res=>{})的catch回调中,res为服务端的返回值 - // return false; - // } } } diff --git a/components/blufi/xBlufi-wx-impl.js b/components/blufi/xBlufi-wx-impl.js index d3f4b5f..cdd459f 100644 --- a/components/blufi/xBlufi-wx-impl.js +++ b/components/blufi/xBlufi-wx-impl.js @@ -577,7 +577,7 @@ function write_cmd_program(deviceId, serviceId, characteristicId, data) { var dv = 0; let result; console.log("更新122") - const mtu = 512; + const mtu = 212; uni.setBLEMTU({ deviceId: self .data @@ -664,7 +664,7 @@ function write_cmd_program_dd(deviceId, serviceId, characteristicId, data) { var dv = 0; let result; console.log("更新122") - const mtu = 512; + const mtu = 212; uni.setBLEMTU({ deviceId: self .data @@ -752,7 +752,7 @@ function write_cmd_program_zy(deviceId, serviceId, characteristicId, data) { var dv = 0; let result; console.log("更新122") - const mtu = 512; + const mtu = 212; uni.setBLEMTU({ deviceId: self .data @@ -839,7 +839,7 @@ function write_cmd_program_yk(deviceId, serviceId, characteristicId, data) { var dv = 0; let result; console.log("更新122") - const mtu = 512; + const mtu = 212; uni.setBLEMTU({ deviceId: self .data @@ -927,7 +927,7 @@ function write_cmd_program_fg(web, deviceId, serviceId, characteristicId, data) var dv = 0; let result; console.log("更新122") - const mtu = 512; + const mtu = 212; uni.setBLEMTU({ deviceId: self .data @@ -1130,24 +1130,24 @@ function writeRouterSsid(deviceId, serviceId, characteristicId, data) { }, fail: function (res) { //console.log(257); } - }) + }); } function writeDevicePwd(deviceId, serviceId, characteristicId, data) { - var obj = {} + var obj = {}, frameControl = 0; sequenceControl = parseInt(sequenceControl) + 1; if (!util._isEmpty(data)) { - obj = util.isSubcontractor(data, self.data.isChecksum, sequenceControl, self.data.isEncrypt) - frameControl = util.getFrameCTRLValue(self.data.isEncrypt, self.data.isChecksum, util.DIRECTION_OUTPUT, false, obj.flag) + obj = util.isSubcontractor(data, self.data.isChecksum, sequenceControl, self.data.isEncrypt); + frameControl = util.getFrameCTRLValue(self.data.isEncrypt, self.data.isChecksum, util.DIRECTION_OUTPUT, false, obj.flag); } else { - var pwdData = getCharCodeat(self.data.password) - obj = util.isSubcontractor(pwdData, self.data.isChecksum, sequenceControl, self.data.isEncrypt) - frameControl = util.getFrameCTRLValue(self.data.isEncrypt, self.data.isChecksum, util.DIRECTION_OUTPUT, false, obj.flag) + var pwdData = getCharCodeat(self.data.password); + obj = util.isSubcontractor(pwdData, self.data.isChecksum, sequenceControl, self.data.isEncrypt); + frameControl = util.getFrameCTRLValue(self.data.isEncrypt, self.data.isChecksum, util.DIRECTION_OUTPUT, false, obj.flag); } - var defaultData = util.encrypt(aesjs, self.data.md5Key, sequenceControl, obj.lenData, true) + var defaultData = util.encrypt(aesjs, self.data.md5Key, sequenceControl, obj.lenData, true); var value = util.writeData(util.PACKAGE_VALUE, util.SUBTYPE_SET_PWD, frameControl, sequenceControl, obj.len, defaultData); var typedArray = new Uint8Array(value); @@ -1169,8 +1169,8 @@ function writeDevicePwd(deviceId, serviceId, characteristicId, data) { function writeDeviceEnd(deviceId, serviceId, characteristicId) { sequenceControl = parseInt(sequenceControl) + 1; - var frameControl = util.getFrameCTRLValue(self.data.isEncrypt, false, util.DIRECTION_OUTPUT, false, false) - var value = util.writeData(self.data.PACKAGE_CONTROL_VALUE, util.SUBTYPE_END, frameControl, sequenceControl, 0, null) + var frameControl = util.getFrameCTRLValue(self.data.isEncrypt, false, util.DIRECTION_OUTPUT, false, false); + var value = util.writeData(self.data.PACKAGE_CONTROL_VALUE, util.SUBTYPE_END, frameControl, sequenceControl, 0, null); var typedArray = new Uint8Array(value); uni.writeBLECharacteristicValue({ deviceId: deviceId, @@ -1237,7 +1237,6 @@ function init() { devicesList.push(devices); } } else if (devices.devices) { - // console.log(devices.devices[0]) if (devices.devices[0].name != '开发板' && devices.devices[0].name != '无线钉钉' && devices.devices[0].name != '无线工具' @@ -1369,7 +1368,7 @@ function init() { } }); mDeviceEvent.listenConnectBle(true, function (options) { - console.log("我要连接?", options.isStart,options); + console.log("我要连接?", options.isStart); if (options.isStart) uni.createBLEConnection({ deviceId: options.deviceId, success: function (res) { @@ -1453,7 +1452,7 @@ function init() { self.data.deviceId = options.deviceId; mac_id = options.deviceId; setTimeout(() => { - var mtu = 512 + var mtu = 212 uni.setBLEMTU({ deviceId: self .data @@ -1516,7 +1515,7 @@ setTimeout(() => { success: function(res) { console.log("成功", res) writeCutomsData(self.data.deviceId, self.data.service_uuid, self.data.characteristic_write_uuid, "get_fw"); - const mtu = 512; + const mtu = 212; uni.onBLECharacteristicValueChange(function(res) { var my_str = Utf8ArrayToStr(res.value) if(my_str.indexOf("wifi_ok") != -1) diff --git a/components/tab-bar/tab-bar.vue b/components/tab-bar/tab-bar.vue index c4959ac..4ab7594 100644 --- a/components/tab-bar/tab-bar.vue +++ b/components/tab-bar/tab-bar.vue @@ -63,7 +63,7 @@ getver(){ this.$u.get(`/system/config/configKey/app.version`).then(res => { if (res.code == 200) { - if(res.data == '1.0.59'){ + if(res.data == '1.0.60'){ this.flag = true }else{ this.flag = false diff --git a/page_newyemian/wgkongzhi.vue b/page_newyemian/wgkongzhi.vue new file mode 100644 index 0000000..2396fac --- /dev/null +++ b/page_newyemian/wgkongzhi.vue @@ -0,0 +1,872 @@ + + + + \ No newline at end of file diff --git a/page_newyemian/wgluru-add.vue b/page_newyemian/wgluru-add.vue index c9cba49..fa57571 100644 --- a/page_newyemian/wgluru-add.vue +++ b/page_newyemian/wgluru-add.vue @@ -1,288 +1,1308 @@ - + .tips { + margin: 28rpx auto 0; + width: 658rpx; + } + + .iptbox { + display: flex; + align-items: center; + flex-wrap: nowrap; + padding: 22rpx; + margin: 15rpx auto 0; + width: 658rpx; + height: 88rpx; + background: #FFFFFF; + box-shadow: 0rpx 0rpx 8rpx 0rpx rgba(0, 0, 0, 0.15); + border-radius: 20rpx 20rpx 20rpx 20rpx; + + .qrcode { + padding-right: 20rpx; + border-right: 2rpx solid #D8D8D8; + + image { + width: 54rpx; + height: 54rpx; + } + } + + .ips { + flex: 1; + min-width: 0; + } + + image { + width: 18rpx; + height: 32rpx; + } + + .my-placeholder { + font-weight: 400; + font-size: 32rpx; + color: #808080; + } + .mini-btn { + min-width: 140rpx; + padding: 0 20rpx; + height: 60rpx; + line-height: 60rpx; + text-align: center; + background: #52c41a; + color: #fff; + font-size: 26rpx; + border-radius: 30rpx; + margin-left: 10rpx; + flex-shrink: 0; + } + } + + .bot_btn { + position: fixed; + bottom: 30rpx; + left: 0; + width: 100%; + display: flex; + flex-wrap: wrap; + padding: 20rpx 46rpx; + box-sizing: border-box; + justify-content: space-between; + background: transparent; + box-shadow: none; + pointer-events: none; /* Let clicks pass through empty space */ + + .btn1 { + pointer-events: auto; + margin-top: 20rpx; + margin-right: 0; + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 80rpx; + background: #fff; + border-radius: 40rpx; + border: 2rpx solid #52c41a; + font-weight: 500; + font-size: 28rpx; + color: #52c41a; + box-shadow: 0 4rpx 10rpx rgba(0,0,0,0.1); + } + } + + + + } + \ No newline at end of file diff --git a/page_newyemian/wgluru.vue b/page_newyemian/wgluru.vue index 5aa47bd..0ab20b6 100644 --- a/page_newyemian/wgluru.vue +++ b/page_newyemian/wgluru.vue @@ -1,844 +1,622 @@ - \ No newline at end of file diff --git a/page_user/dingshi.vue b/page_user/dingshi.vue index 68aed53..92e784f 100644 --- a/page_user/dingshi.vue +++ b/page_user/dingshi.vue @@ -64,7 +64,6 @@ - 浇水设置 @@ -228,16 +227,16 @@ methods: { // 请求浇花器数据 getxq(){ - this.$u.get(`/app/getDeviceInfo/${this.shebid}`).then(res => { + this.$u.get(`/app/device/getDetail?deviceId=${this.shebid}`).then(res => { if (res.code == 200) { if(this.pre != 'WATER'){ - this.shi = res.data.parameters.h.length < 10 ? '0' + res.data.parameters.h.value : res.data.parameters.h.value - this.fen = res.data.parameters.m.length < 10 ? '0' + res.data.parameters.m.value : res.data.parameters.m.value - this.miao = res.data.parameters.t.value - this.tian = res.data.parameters.d.value + this.shi = res.data.iotData.h.length < 10 ? '0' + res.data.iotData.h.value : res.data.iotData.h.value + this.fen = res.data.iotData.m.length < 10 ? '0' + res.data.iotData.m.value : res.data.iotData.m.value + this.miao = res.data.iotData.t.value + this.tian = res.data.iotData.d.value } else { // 单阀 WATER,从后台字段 h1/m1/s1/o1...(以及可选 d1..d6) 组装展示结构 - const params = res.data.parameters + const params = res.data.iotData const mapped = this.buildListFromBackend(params) // u-switch 需要布尔值,已在构建阶段转换 this.list = mapped diff --git a/page_user/dongtai/index.vue b/page_user/dongtai/index.vue index 5f3bd5a..f91a004 100644 --- a/page_user/dongtai/index.vue +++ b/page_user/dongtai/index.vue @@ -1,46 +1,46 @@ diff --git a/page_user/lanya.vue b/page_user/lanya.vue index d019620..14167e6 100644 --- a/page_user/lanya.vue +++ b/page_user/lanya.vue @@ -122,12 +122,13 @@ active: 1, flag: true, devicesList: [], + newlist:[], deviceId: '', name: '', mac: '', flags: true, userid: '', - arr: '', + arr: [], jiaohuaqi: [], getpre: [], showNameDialog: false, @@ -317,30 +318,39 @@ deviceName: this.customDeviceName } console.log(data,'参数'); - this.$u.post(`/app/device/addDevice`, data).then((res) => { + this.$u.post(`/app/device/bindDeviceByBlueTooth`, data).then((res) => { if (res.code == 200) { - let datas = { - mac:mac - } - this.$u.post(`/app/device/bindDevice`, datas).then(resp =>{ - if(resp.code == 200){ - uni.showToast({ - title:'绑定成功', - icon: 'none', - duration: 3000 - }) - this.showNameDialog = false; - setTimeout(() => { - uni.navigateBack() - }, 2000) - }else{ - uni.showToast({ - title: resp.msg, - icon: 'none', - duration: 3000 - }) - } + uni.showToast({ + title:'绑定成功', + icon: 'none', + duration: 3000 }) + this.showNameDialog = false; + setTimeout(() => { + uni.navigateBack() + }, 2000) + // let datas = { + // mac:mac + // } + // this.$u.post(`/app/device/bindDevice`, datas).then(resp =>{ + // if(resp.code == 200){ + // uni.showToast({ + // title:'绑定成功', + // icon: 'none', + // duration: 3000 + // }) + // this.showNameDialog = false; + // setTimeout(() => { + // uni.navigateBack() + // }, 2000) + // }else{ + // uni.showToast({ + // title: resp.msg, + // icon: 'none', + // duration: 3000 + // }) + // } + // }) } else { console.log(res,'报错'); uni.showToast({ @@ -434,7 +444,7 @@ // 更新设备列表 updateDeviceList(existList) { - const newDevices = this.devicesList.filter(item => { + const newDevices = this.newlist.filter(item => { const mac = item.name.slice(-12) return !this.jiaohuaqi.some(device => device.name === mac) && !this.displayQueue.some(device => device.name === mac) @@ -474,9 +484,12 @@ let devicesarr = [] this.devicesList = options.data options.data.forEach(item => { - devicesarr.push(item.name.slice(-12)) + if(item.localName.slice(0,5) == 'WATER' || item.localName.slice(0,5) == 'SMSJ:'){ + devicesarr.push(item.localName.slice(-12)) + this.newlist.push(item) + } }) - this.arr = devicesarr.join(',') + this.arr = devicesarr // 使用节流处理设备检查 if (this.throttleTimer) { @@ -485,8 +498,8 @@ this.throttleTimer = setTimeout(() => { if (this.devicesList.length > 0) { - const data = { mac: this.arr } - this.$u.post(`/app/getExistListByMacs`, data) + // const data = { macList: this.arr } + this.$u.get(`/app/device/list?macList=${this.arr}`) .then(res => { if (res.code === 200) { this.updateDeviceList(res.data) diff --git a/page_user/upload.vue b/page_user/upload.vue index 9b965e5..1281edb 100644 --- a/page_user/upload.vue +++ b/page_user/upload.vue @@ -17,7 +17,7 @@ MAC {{user.mac == undefined ? '--' : user.mac}} - + 息屏 {{xinpin == null ? '--' : xinpin + '秒'}} @@ -116,7 +116,8 @@ version:'', xinpin:'', imgpic:'', - varflag:'' + varflag:'', + pre:'' } }, // 分享到好友(会话) @@ -135,8 +136,8 @@ } }, onLoad(option) { + console.log(option,'000000000000000000000000000000000000000000'); this.varflag = option.varflag - console.log(option,'0000'); xBlufi.listenDeviceMsgEvent(true, this.funListenDeviceMsgEvent) xBlufi.notifySendCustomData({ customData: "11get" @@ -252,7 +253,7 @@ }, // 获取设备信息 getshebxq() { - this.$u.get(`/app/getDeviceInfo/${this.deviceid}`).then(res => { + this.$u.get(`/app/device/getDetail?deviceId=${this.deviceid}`).then(res => { if (res.code == 200) { this.user = res.data this.getbanbens() @@ -274,6 +275,7 @@ getbanbens(){ this.$u.get(`/app/model/${this.user.modelId}`).then(res => { if (res.code == 200) { + this.pre = res.data.pre this.version = res.data.version console.log(this.ver,'当前蓝牙版本号',this.version,'最新蓝牙版本号'); this.file = res.data.asDeviceVersion.file @@ -427,11 +429,38 @@ } }else{ console.log('jiexijiexi',options); - const inputString = options.data.slice(0, -1) + ";" - const hasAtSymbol = inputString.includes(','); - let processedString = inputString; - let currentDay = 0; - const pairs = processedString.split(';').filter(Boolean); + const inputString = options.data.slice(0, -1) + ";" + // 检查是否有 @ 分隔符 + const hasAtSymbol = inputString.includes('@'); + let processedString; + let currentDay = 0; + if (hasAtSymbol) { + // 只分割第一个 @,保留后面的所有内容 + const firstAtIndex = inputString.indexOf('@'); + let vvv = inputString.substring(0, firstAtIndex) || '' + this.ver = 'V' + vvv.slice(3) + processedString = inputString.substring(firstAtIndex + 1) || ''; + } else { + processedString = inputString; + this.ver = ''; + } + + // 检查并删除 @low:0 或 low:0 + if (processedString.includes('@low:0') || processedString.includes('low:0')) { + // 删除 @low:0(可能在开头或中间) + processedString = processedString.replace(/@low:0@?/g, ''); + // 删除 low:0@(在开头,后面跟着@) + processedString = processedString.replace(/^low:0@/g, ''); + // 删除 low:0(处理各种位置的情况) + processedString = processedString.replace(/^low:0;?/g, ''); // 开头 + processedString = processedString.replace(/;low:0;?/g, ';'); // 中间 + processedString = processedString.replace(/;low:0$/g, ''); // 结尾 + processedString = processedString.replace(/^low:0$/g, ''); // 只有 low:0 + // 清理可能出现的连续分号或开头结尾的分号 + processedString = processedString.replace(/;;+/g, ';').replace(/^;+|;+$/g, ''); + } + + const pairs = processedString.split(';').filter(Boolean); const showObject = {}; const pSetObjects = {}; // 初始化所有p_set为默认值 @@ -455,11 +484,13 @@ } }) console.log(showObject,'showObjectshowObject'); - if(this.ver == 'ver290' || this.ver == 'ver290'){ - this.xinpin = showObject.showArray[showObject.showArray.length - 1] - }else{ - this.xinpin = showObject.showArray[showObject.showArray.length - 2] - } + // 从 this.ver 中提取数字 + const verNumber = parseInt(this.ver.replace(/\D/g, '')) || 0; + if(verNumber >= 290){ + this.xinpin = showObject.showArray[showObject.showArray.length - 1] + }else{ + this.xinpin = showObject.showArray[showObject.showArray.length - 2] + } } break; case xBlufi.XBLUFI_TYPE.TYPE_GET_DEVICE_LISTS_START: diff --git a/pages.json b/pages.json index 4882792..87d7c36 100644 --- a/pages.json +++ b/pages.json @@ -262,6 +262,13 @@ "enablePullDownRefresh": false, "navigationStyle": "custom" } + },{ + "path": "wgkongzhi", + "style": { + "navigationBarTitleText": "设备录入", + "enablePullDownRefresh": false, + "navigationStyle": "custom" + } },{ "path": "sehzhi", "style": { diff --git a/pages/gateway/list.vue b/pages/gateway/list.vue index bb3fc20..7177b82 100644 --- a/pages/gateway/list.vue +++ b/pages/gateway/list.vue @@ -7,7 +7,7 @@ - + @@ -15,8 +15,8 @@ {{ item.modelName }} - - {{ (item.onlineStatus == 1 || item.onlineStatus == 0) ? '在线' : '离线' }} + + {{ item.onlineStatus == 1 ? '在线' : '离线' }} @@ -64,7 +64,7 @@ // 获取网关列表 getlist(){ let userId = uni.getStorageSync('userId') - this.$u.get(`/app/getDeviceInfoByUser?userId=${userId}&classifyCodeList=6`).then((res) => { + this.$u.get(`/app/device/list?userId=${userId}&classifyCodeList=6`).then((res) => { if (res.code == 200) { this.gatewayList = res.data } diff --git a/pages/gateway/xq.vue b/pages/gateway/xq.vue index c0d461b..442d10d 100644 --- a/pages/gateway/xq.vue +++ b/pages/gateway/xq.vue @@ -8,8 +8,8 @@ {{ wgxq.deviceName || '未命名设备' }} - - {{ (wgxq.onlineStatus == 1 || wgxq.onlineStatus == 0) ? '在线' : '离线' }} + + {{ wgxq.onlineStatus == 1 ? '在线' : '离线' }} @@ -57,7 +57,7 @@ {{ item.deviceName || '未命名设备' }} {{ item.modelName || '--' }} - + 暂无设备 @@ -122,7 +122,7 @@ }) }, getxq(){ - this.$u.get(`/app/getDeviceInfo/${this.id}`).then((res) => { + this.$u.get(`/app/device/getDetail?deviceId=${this.id}`).then((res) => { if (res.code == 200) { this.wgxq = res.data console.log(11); diff --git a/pages/index/index.vue b/pages/index/index.vue index bdeb3a4..7ecef58 100644 --- a/pages/index/index.vue +++ b/pages/index/index.vue @@ -464,7 +464,6 @@ {{item.deviceName}} - MAC:{{item.mac}} @@ -501,6 +500,31 @@ + + + + + + ⚠️ + {{errorModalData.title}} + + + {{errorModalData.message}} + + 处理建议: + {{errorModalData.userAction}} + + + + + {{errorModalData.cancelText || '取消'}} + + + {{errorModalData.confirmText || '确定'}} + + + + @@ -521,8 +545,8 @@ twos: true, jsked:true, jskeds:false, - yschecked: true, - etchecked: true, + yschecked: false, + etchecked: false, kgflag: true, activeshu: 0, xuanzeflag: false, @@ -589,6 +613,13 @@ searchTimer: null, // 搜索定时器 isSearching: false, // 是否正在搜索中 dataTimeoutTimer: null ,// 5秒数据看门狗定时器 + connectionStartTime: 0, // 记录连接开始时间 + connectionTimeout: null, // 连接超时定时器 + connectTimeout: null, // 配对超时定时器 + errorModalShown: false, // 错误弹窗是否已显示(防止重复弹出) + currentErrorType: null, // 当前检测到的错误类型 + showErrorModal: false, // 是否显示自定义错误弹窗 + errorModalData: {}, // 错误弹窗数据 dianya:0, sydl:'--', zaixianobj:{}, @@ -596,7 +627,9 @@ jsobj:{}, isLoading: false ,// 设备请求加载状态 vatatxt:'', - sn:'' + sn:'', + onlineTime:'', + onlineStatus:'' } }, // 分享到好友(会话) @@ -637,7 +670,9 @@ showCancel: false, confirmText: '知道了' }) - }else{ + }else if(res.code == 401){ + this.jmlogin() + } else{ uni.showModal({ title: '提示', content: res.msg, @@ -666,12 +701,14 @@ this.clearTimer() this.clearDisconnectTimer() this.clearDataTimeoutTimer() + this.clearConnectionTimeout() }, onUnload() { // 页面卸载时清除定时器 this.clearTimer() this.clearDisconnectTimer() this.clearDataTimeoutTimer() + this.clearConnectionTimeout() }, methods: { @@ -683,9 +720,9 @@ }, // 请求浇花器数据 getsj(){ - this.$u.get(`/app/getDeviceInfo/${this.shebid}`).then(res => { + this.$u.get(`/app/device/getDetail?deviceId=${this.shebid}`).then(res => { if (res.code == 200) { - this.zaixianobj = res.data.parameters + this.zaixianobj = res.data.iotData this.modelId = res.data.modelId console.log(this.vardataflag,this.zaixianobj); // 非蓝牙模式时,用后台数据组装渲染结构 @@ -696,17 +733,21 @@ this.ver_data = this.buildVerDataFromBackend(this.zaixianobj) console.log(this.ver_data); } - if (res.data && res.data.parameters && res.data.parameters.xinp !== undefined) { - this.xinp = res.data.parameters.xinp.value == undefined ? '--' : res.data.parameters.xinp.value + if (res.data && res.data.iotData && res.data.iotData.xinp !== undefined) { + this.xinp = res.data.iotData.xinp.value == undefined ? '--' : res.data.iotData.xinp.value } - if (res.data && res.data.parameters && res.data.parameters.yudi !== undefined) { - this.yschecked = res.data.parameters.yudi.value == 0 ? true : false + if (res.data && res.data.iotData && res.data.iotData.yudi !== undefined) { + this.yschecked = res.data.iotData.yudi.value == 0 ? true : false } - if (res.data && res.data.parameters && res.data.parameters.lock !== undefined) { - this.etchecked = res.data.parameters.lock.value == 0 ? true : false + if (res.data && res.data.iotData && res.data.iotData.lock !== undefined) { + this.etchecked = res.data.iotData.lock.value == 0 ? true : false } - this.devicetime = res.data.parameters.time.value - } + this.devicetime = res.data.iotData.time.value + + // 取值 + this.onlineTime = res.data.onlineTime + this.onlineStatus = res.data.onlineStatus + } }) }, // 点击保存设置 @@ -801,8 +842,10 @@ if (res.code == 200) { taht.getinfo() uni.setStorageSync('token', res.token) - }else{ - + }else if(res.code == 10001){ + uni.reLaunch({ + url:'/pages/login/login' + }) } }) } @@ -829,7 +872,7 @@ }, // 获取设备列表 getlist(){ - this.$u.get(`/app/getDeviceInfoByUser?userId=${this.userobj.userId}&classifyCodeList=1`).then((res) => { + this.$u.get(`/app/device/list?userId=${this.userobj.userId}&classifyCodeList=1`).then((res) => { if (res.code == 200) { if(res.data.length > 0 || res.data != ''){ this.bjflag = false @@ -848,6 +891,8 @@ this.bjflag = true } this.isLoading = false // 请求完成后隐藏加载状态 + }else{ + this.isLoading = false } }).catch(() => { this.isLoading = false // 请求异常时隐藏加载状态 @@ -855,14 +900,51 @@ }, // 点击连接蓝牙函数 btnlj() { + // 如果正在连接中,不重复连接 + if (this.vardataflag === 2) { + return + } + // 如果已连接,提示用户 + if (this.vardataflag === 3) { + uni.showToast({ + title: '设备已连接', + icon: 'none', + duration: 2000 + }) + return + } + + // 重置错误状态(允许重新检查错误) + this.errorModalShown = false + this.currentErrorType = null this.shibainum = 0 - xBlufi.initXBlufi(1) - xBlufi.listenDeviceMsgEvent(true, this.funListenDeviceMsgEvent) - xBlufi.notifyStartDiscoverBle({ - 'isStart': true + this.connectionStartTime = Date.now() // 记录连接开始时间 + this.connectionTimeout = null // 连接超时定时器 + + // 先检查蓝牙状态并尝试自动修复 + this.checkAndFixBluetooth().then(() => { + // 蓝牙正常,开始连接流程 + xBlufi.initXBlufi(1) + xBlufi.listenDeviceMsgEvent(true, this.funListenDeviceMsgEvent) + xBlufi.notifyStartDiscoverBle({ + 'isStart': true + }) + this.vardataflag = 2 + + // 设置连接超时(30秒) + this.connectionTimeout = setTimeout(() => { + if (this.vardataflag === 2) { + this.handleConnectionTimeout() + } + }, 30000) + + this.findDevice() + }).catch((error) => { + // 蓝牙检查失败,显示错误提示(只显示一次) + if (!this.errorModalShown) { + this.handleConnectionError(error) + } }) - this.vardataflag = 2 - this.findDevice() }, // ios递归函数匹配 findDevice() { @@ -872,13 +954,14 @@ // 如果已经尝试了10次及以上,直接返回不执行 if (that.shibainum > 10) { that.vardataflag = 1 + that.clearConnectionTimeout() xBlufi.notifyStartDiscoverBle({ 'isStart': false }); - // that.shibainum = 0; + // 诊断连接失败原因 + that.diagnoseConnectionFailure(); return; } - // that.vardataflag = 2 that.vatatxt = '设备查找中...'; const matchedDevice = that.devicesarr.find(device => { if (device.name) { @@ -888,6 +971,7 @@ if (matchedDevice) { // 找到设备的处理逻辑... that.vatatxt = '查找成功,配对中...'; + that.clearConnectionTimeout() // 清除超时定时器 xBlufi.notifyStartDiscoverBle({ 'isStart': false }); @@ -898,14 +982,19 @@ name: matchedDevice.name }); that.deviceId = matchedDevice.deviceId; - setTimeout(() => { - console.log(that.vardataflag, '连接状态2'); - if (that.vardataflag !== 3) { - that.vardataflag = 1 + // 设置连接超时(8秒) + that.connectTimeout = setTimeout(() => { + if (that.vardataflag !== 3 && !that.errorModalShown) { + that.vardataflag = 1 that.shibainum = 0; - + that.handleConnectionError({ + type: 'CONNECT_TIMEOUT', + message: '设备配对超时', + userAction: '可能原因:\n1. 设备未开机\n2. 设备距离过远\n3. 设备已连接其他设备\n\n处理建议:\n1. 确保设备已开机\n2. 靠近设备(1米内)\n3. 重启设备后重试', + canAutoFix: false + }) } - }, 4000); + }, 8000); } else { // 未找到设备,递增计数器并继续尝试 that.shibainum++; @@ -914,109 +1003,14 @@ that.findDeviceTimer = setTimeout(findDevices, 1000); } else { that.vardataflag = 1 + that.clearConnectionTimeout() that.shibainum = 0; - // 检查蓝牙状态 - uni.getBluetoothAdapterState({ - success: function(res) { - console.log('蓝牙适配器状态:', res) - if (!res.available) { - // 蓝牙不可用(关闭或故障) - uni.showModal({ - title: '提示', - content: '蓝牙不可用,请检查手机蓝牙是否打开', - showCancel: false, - confirmText: '知道了' - }) - } else { - // 蓝牙正常,但找不到设备(设备断电、距离远、设备故障) - console.log('蓝牙正常但未找到设备,设备可能断电') - uni.showModal({ - title: '提示', - content: '蓝牙适配器正常,但未发现设备', - showCancel: false, - confirmText: '知道了' - }) - } - }, - fail: function(err) { - console.error('获取蓝牙状态失败', err) - // 获取状态失败,尝试重新打开适配器检测 - uni.openBluetoothAdapter({ - success: function (res) { - console.log('蓝牙适配器正常,但未发现设备'); - uni.showModal({ - title: '提示', - content: '蓝牙适配器正常,但未发现设备', - showCancel: false, - confirmText: '知道了' - }) - }, - fail: function (err) { - console.error('蓝牙适配器初始化失败', err) - console.log('错误码:', err.errCode, '错误信息:', err.errMsg) - const errMsg = err.errMsg || '' - let content = '' - if(errMsg.includes('auth deny') || errMsg.includes('authorize')){ - content = '蓝牙权限未授权,请在微信设置中开启蓝牙权限' - uni.showModal({ - title: '提示', - content: content, - showCancel: false, - confirmText: '知道了' - }) - }else if(errMsg.includes('not available') || errMsg.includes('unavailable')){ - content = '蓝牙不可用,请检查手机蓝牙是否打开' - uni.showModal({ - title: '提示', - content: content, - showCancel: false, - confirmText: '知道了' - }) - }else if(errMsg.includes('open fail')){ - content = '蓝牙打开失败,请检查手机蓝牙是否正常' - uni.showModal({ - title: '提示', - content: content, - showCancel: false, - confirmText: '知道了' - }) - }else if(errMsg.includes('already opened')){ - console.log('蓝牙适配器已打开,但未找到设备') - }else if(errMsg.includes('system permission denied')){ - content = '系统蓝牙权限被拒绝,请在设置中允许微信使用蓝牙' - uni.showModal({ - title: '提示', - content: content, - showCancel: false, - confirmText: '知道了' - }) - }else if(errMsg.includes('bluetooth service unavailable')){ - content = '蓝牙服务不可用,请重启小程序后重试' - uni.showModal({ - title: '提示', - content: content, - showCancel: false, - confirmText: '知道了' - }) - }else{ - content = '蓝牙初始化失败:' + (err.errMsg || '未知错误,请重试') - uni.showModal({ - title: '提示', - content: content, - showCancel: false, - confirmText: '知道了' - }) - } - - } - }) - } - }) + // 诊断连接失败原因 + that.diagnoseConnectionFailure(); } } }; // 重置计数器后开始查找 - // that.shibainum = 0; findDevices(); }, // 获取附近蓝牙设备列表 @@ -1026,7 +1020,17 @@ if (!options.result) { this.vardataflag = 1 this.clearDisconnectTimer() - console.log('111111111','断断断'); + this.clearConnectionTimeout() + console.log('设备连接断开', options); + // 如果是在连接过程中断开,且还没显示过错误,才显示提示 + if (this.connectionStartTime && (Date.now() - this.connectionStartTime) < 5000 && !this.errorModalShown) { + this.handleConnectionError({ + type: 'CONNECTION_DISCONNECTED', + message: '设备连接已断开', + userAction: '可能原因:\n1. 设备距离过远\n2. 设备断电\n3. 连接不稳定\n\n处理建议:\n1. 靠近设备重试\n2. 检查设备是否开机\n3. 重新连接', + canAutoFix: false + }) + } } break; case xBlufi.XBLUFI_TYPE.TYPE_GET_DEVICE_LISTS: @@ -1037,6 +1041,7 @@ break; case xBlufi.XBLUFI_TYPE.TYPE_CONNECTED: console.log("连接回调:" + JSON.stringify(options)) + this.clearConnectionTimeout() // 清除连接超时定时器 xBlufi.notifyInitBleEsp32({ deviceId: this.deviceId }) @@ -1050,14 +1055,27 @@ xBlufi.notifySendCustomData({ customData: "11get" }) + // 连接成功提示 + uni.showToast({ + title: '连接成功', + icon: 'success', + duration: 2000 + }) }else{ - this.vatatxt = '蓝牙服务发现失败,请重试' - console.log('服务发现失败:', options.data); + // 服务发现失败 + this.vardataflag = 1 this.clearDisconnectTimer() + this.clearConnectionTimeout() this.jiance = true - setTimeout(()=>{ - this.vardataflag = 1 - },5000) + // 如果还没显示过错误,才显示 + if (!this.errorModalShown) { + this.handleConnectionError({ + type: 'SERVICE_DISCOVERY_FAILED', + message: '蓝牙服务发现失败', + userAction: '可能原因:\n1. 设备不支持该服务\n2. 设备故障\n3. 连接不稳定\n\n处理建议:\n1. 重启设备后重试\n2. 靠近设备重试\n3. 如问题持续,请联系客服', + canAutoFix: false + }) + } } break case xBlufi.XBLUFI_TYPE.TYPE_INIT_ESP32_RESULT: @@ -1119,10 +1137,19 @@ break case xBlufi.XBLUFI_TYPE.TYPE_GET_DEVICE_LISTS_START: if (!options.result) { - // this.vardataflag = 1 + this.vardataflag = 1 this.jiance = true - console.log('蓝牙初始化失败') - + this.clearConnectionTimeout() + console.log('蓝牙搜索启动失败', options) + // 如果还没显示过错误,才显示 + if (!this.errorModalShown) { + this.handleConnectionError({ + type: 'SEARCH_START_FAILED', + message: '蓝牙搜索启动失败', + userAction: '可能原因:\n1. 蓝牙权限未授权\n2. 蓝牙服务异常\n3. 系统限制\n\n处理建议:\n1. 检查蓝牙权限设置\n2. 重启小程序后重试\n3. 重启手机蓝牙后重试', + canAutoFix: false + }) + } return } break @@ -1139,14 +1166,7 @@ uni.showLoading({ title: '开启中...' }) - // let parameters = { - // command:'yudi' - // } - // let data = { - // deviceId:this.shebid, - // instructionKey:'yudi', - // // parameters:parameters - // } + this.$u.post(`/app/device/yudi/${this.shebid}`).then(res => { if (res.code == 200) { uni.hideLoading() @@ -1196,13 +1216,11 @@ }) this.devicetime = this.getCurrentTime(); console.log(this.devicetime); - let parameters = { - date:this.devicetime + ';' - } + let data = { deviceId:this.shebid, time:this.devicetime, - // parameters:parameters + } this.$u.post(`/app/device/syncTime`,data).then(res => { if (res.code == 200) { @@ -1293,13 +1311,11 @@ title: '设置中...' }) this.devicetime = e.hour + ':' + e.minute - let parameters = { - date:this.devicetime + ';' - } + let data = { deviceId:this.shebid, time:this.devicetime, - // parameters:parameters + } this.$u.post(`/app/device/syncTime`,data).then(res => { if (res.code == 200) { @@ -1588,13 +1604,11 @@ } }) }else{ - // let parameters = { - // time: '@' + this.jstime + '@' - // } + let data = { deviceId:this.shebid, second:this.jstime, - // parameters:parameters + } this.$u.post(`/app/device/time`,data).then(res => { if (res.code == 200) { @@ -1640,9 +1654,14 @@ // 如果剩余秒数为0,则停止定时器 if (remainingSeconds <= 0) { clearInterval(this.timer) - this.btnkq() - this.sdminutes = '' - this.sdseconds = '' + // this.btnkq() + setTimeout(()=>{ + this.sdminutes = '' + this.sdseconds = '' + this.kgflag = true + this.jsked = true + this.jskeds = false + },1000) } }, 1000) }, @@ -1779,7 +1798,7 @@ }, // 获取设备信息 getshebxq(){ - this.$u.get(`/app/getDeviceInfo/${this.shebid}`).then(res => { + this.$u.get(`/app/device/getDetail?deviceId=${this.shebid}`).then(res => { if(res.code == 200){ this.pre = res.data.pre this.mac = res.data.mac @@ -1875,52 +1894,51 @@ const hours = parseInt(timeParts[4]) || 0; const minutes = parseInt(timeParts[5]) || 0; this.devicetime = `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}`; - - this.ver_data = {...this.csbobj}; - // 生成当前时间字符串 yyyy-MM-dd HH:mm:ss - const now = new Date(); - const yyyy = now.getFullYear(); - const MM = String(now.getMonth() + 1).padStart(2, '0'); - const dd = String(now.getDate()).padStart(2, '0'); - const HH = String(now.getHours()).padStart(2, '0'); - const mm = String(now.getMinutes()).padStart(2, '0'); - const ss = String(now.getSeconds()).padStart(2, '0'); - const at = `${yyyy}-${MM}-${dd} ${HH}:${mm}:${ss}`; - // 仅在已连接(vardataflag==3)且距离上次上传≥60秒时推送 - console.log(this.ver_data); - if(this.vardataflag == 3){ - const nowTs = Date.now(); - if(!this.lastUploadTs || (nowTs - this.lastUploadTs) >= 2000){ - let data = { - mac: this.mac, - params: { - h: { - value: String(this.ver_data.hour), - at - }, - m: { - value: String(this.ver_data.minute), - at - }, - t: { - value: String(this.ver_data.second), - at - }, - d: { - value: String(this.ver_data.day), - at - }, - time: { - value: String(this.devicetime), - at - }, - } - } - data.params.xinp = { value: String(this.xinp), at } - this.$u.put(`/app/updateDeviceParam`, data).then(res => {}) //上传数据 - this.lastUploadTs = nowTs; - } - } + this.ver_data = {...this.csbobj}; + // 生成当前时间字符串 yyyy-MM-dd HH:mm:ss + const now = new Date(); + const yyyy = now.getFullYear(); + const MM = String(now.getMonth() + 1).padStart(2, '0'); + const dd = String(now.getDate()).padStart(2, '0'); + const HH = String(now.getHours()).padStart(2, '0'); + const mm = String(now.getMinutes()).padStart(2, '0'); + const ss = String(now.getSeconds()).padStart(2, '0'); + const at = `${yyyy}-${MM}-${dd} ${HH}:${mm}:${ss}`; + // 仅在已连接(vardataflag==3)且距离上次上传≥60秒时推送 + console.log(this.ver_data); + if(this.vardataflag == 3){ + const nowTs = Date.now(); + if(!this.lastUploadTs || (nowTs - this.lastUploadTs) >= 2000){ + let data = { + mac: this.mac, + params: { + h: { + value: String(this.ver_data.hour), + at + }, + m: { + value: String(this.ver_data.minute), + at + }, + t: { + value: String(this.ver_data.second), + at + }, + d: { + value: String(this.ver_data.day), + at + }, + time: { + value: String(this.devicetime), + at + }, + } + } + data.params.xinp = { value: String(this.xinp), at } + this.$u.put(`/app/updateDeviceParam`, data).then(res => {}) //上传数据 + this.lastUploadTs = nowTs; + } + } console.log('设备时间:', this.devicetime); }, // 获取电量 @@ -1940,111 +1958,130 @@ getchuli() { const inputString = this.datalist; // console.log('接收到的数据:', inputString); - // 检查是否有 @ 分隔符 - const hasAtSymbol = inputString.includes('@'); - let processedString; - let currentDay = 0; - if (hasAtSymbol) { - const [ver, restOfString] = inputString.split('@'); - this.ver = ver || ''; - processedString = restOfString || ''; - // 解析当前天数 - const showMatch = processedString.match(/show:([^;]+)/); - if (showMatch) { - const showValues = showMatch[1].split(','); - currentDay = parseInt(showValues[showValues.length - 2]) || 0; - } - } else { - processedString = inputString; - this.ver = ''; - } - console.log(this.ver,'ververver'); - const version = this.ver; - // 使用正则表达式提取数字部分 - const versionNumber = version.match(/\d+/); // 匹配连续的数字 - const pairs = processedString.split(';').filter(Boolean); - // console.log('分割后的数据对:', pairs); - const showObject = {}; - const pSetObjects = {}; + // 检查是否有 @ 分隔符 + const hasAtSymbol = inputString.includes('@'); + let processedString; + let currentDay = 0; + if (hasAtSymbol) { + // 只分割第一个 @,保留后面的所有内容 + const firstAtIndex = inputString.indexOf('@'); + this.ver = inputString.substring(0, firstAtIndex) || ''; + processedString = inputString.substring(firstAtIndex + 1) || ''; + // 解析当前天数 + const showMatch = processedString.match(/show:([^;]+)/); + if (showMatch) { + const showValues = showMatch[1].split(','); + currentDay = parseInt(showValues[showValues.length - 2]) || 0; + } + } else { + processedString = inputString; + this.ver = ''; + } + console.log(this.ver,'ververver'); + const version = this.ver; + // 使用正则表达式提取数字部分 + const versionNumber = version.match(/\d+/); // 匹配连续的数字 + + // 检查并删除 @low:0 或 low:0 + if (processedString.includes('@low:0') || processedString.includes('low:0')) { + // 删除 @low:0(可能在开头或中间) + processedString = processedString.replace(/@low:0@?/g, ''); + // 删除 low:0@(在开头,后面跟着@) + processedString = processedString.replace(/^low:0@/g, ''); + // 删除 low:0(处理各种位置的情况) + processedString = processedString.replace(/^low:0;?/g, ''); // 开头 + processedString = processedString.replace(/;low:0;?/g, ';'); // 中间 + processedString = processedString.replace(/;low:0$/g, ''); // 结尾 + processedString = processedString.replace(/^low:0$/g, ''); // 只有 low:0 + // 清理可能出现的连续分号或开头结尾的分号 + processedString = processedString.replace(/;;+/g, ';').replace(/^;+|;+$/g, ''); + } + + const pairs = processedString.split(';').filter(Boolean) + console.log('分割后的数据对:', pairs) + const showObject = {} + const pSetObjects = {} // 初始化所有p_set为默认值 for (let i = 1; i <= 6; i++) { - pSetObjects[`p_set${i}`] = [0, 0, 0, 0, 0]; + pSetObjects[`p_set${i}`] = [0, 0, 0, 0, 0] } // 解析字符串 pairs.forEach(pair => { - const [key, value] = pair.split(':'); + const [key, value] = pair.split(':') + console.log(key,'555555555555555555555555') if (key === 'show') { - showObject.showArray = value.split(',').map(Number); + showObject.showArray = value.split(',').map(Number) } else if (key.startsWith('p_set')) { - const values = value.split(',').map(Number); + const values = value.split(',').map(Number) // 确保数组长度为5 while (values.length < 5) { - values.push(0); + values.push(0) } - pSetObjects[key] = values; + pSetObjects[key] = values } }) - this.ver_data = pSetObjects; - this.jstimeobj = pSetObjects; - this.showobj = showObject; - // 设置开关状态 - if(this.showobj.showArray[1]){ - this.yschecked = this.showobj.showArray[1] !== 1; - this.etchecked = this.showobj.showArray[0] !== 1; - } - + this.ver_data = pSetObjects + this.jstimeobj = pSetObjects + this.showobj = showObject + console.log(this.showobj.showArray,'this.showobj.showArraythis.showobj.showArraythis.showobj.showArray') + // 设置开关状态 + if(this.showobj.showArray && this.showobj.showArray.length >= 2){ + this.yschecked = this.showobj.showArray[1] == 0 ? true : false + this.etchecked = this.showobj.showArray[0] == 0 ? true : false + } this.dianya = this.showobj.showArray[this.showobj.showArray.length - 1] - console.log('电压',this.dianya); + console.log('this.yscheckedthis.yschecked',this.yschecked,this.etchecked) this.getdianliang() // 计算浇水时间 const calculateTimeDifference = (date1, date2) => { - const diffMs = Math.abs(date1 - date2); - const diffMinutes = Math.floor(diffMs / (1000 * 60)); - const diffHours = Math.floor(diffMinutes / 60); - const remainingMinutes = diffMinutes % 60; - return { hours: diffHours, minutes: remainingMinutes }; - }; + const diffMs = Math.abs(date1 - date2) + const diffMinutes = Math.floor(diffMs / (1000 * 60)) + const diffHours = Math.floor(diffMinutes / 60) + const remainingMinutes = diffMinutes % 60 + return { hours: diffHours, minutes: remainingMinutes } + } const formatTime = (seconds) => { - const minutes = Math.floor(seconds / 60); - const remainingSeconds = seconds % 60; - return `${minutes}分${remainingSeconds}秒`; - }; + const minutes = Math.floor(seconds / 60) + const remainingSeconds = seconds % 60 + return `${minutes}分${remainingSeconds}秒` + } + const getTimeFromArray = (timeArray) => { - if (!timeArray || timeArray.length < 2) return null; - const [hour, minute] = timeArray; - const date = new Date(); - date.setHours(hour, minute, 0, 0); - return date; - }; - let nextTime = null; - let nextTimeDiff = null; - let nextWaterDuration = null; - let prevTime = null; + if (!timeArray || timeArray.length < 2) return null + const [hour, minute] = timeArray + const date = new Date() + date.setHours(hour, minute, 0, 0) + return date + } + let nextTime = null + let nextTimeDiff = null + let nextWaterDuration = null + let prevTime = null for (const key in this.ver_data) { if (this.ver_data.hasOwnProperty(key) && this.ver_data[key][3] === 1) { - const timeArray = this.ver_data[key]; - const timeDate = getTimeFromArray(timeArray); - if (!timeDate) continue; - const diff = calculateTimeDifference(timeDate, new Date()); - const interval = timeArray[4] || 0; + const timeArray = this.ver_data[key] + const timeDate = getTimeFromArray(timeArray) + if (!timeDate) continue + const diff = calculateTimeDifference(timeDate, new Date()) + const interval = timeArray[4] || 0 // 检查是否应该在这一天浇水 - const shouldWaterToday = interval === 0 || (currentDay % interval === 0); + const shouldWaterToday = interval === 0 || (currentDay % interval === 0) if (timeDate > new Date() && shouldWaterToday) { if (!nextTime || (diff.hours * 60 + diff.minutes < (nextTimeDiff?.hours || 0) * 60 + (nextTimeDiff?.minutes || 0))) { - nextTimeDiff = diff; - nextTime = timeDate; - nextWaterDuration = formatTime(timeArray[2]); + nextTimeDiff = diff + nextTime = timeDate + nextWaterDuration = formatTime(timeArray[2]) } } else if (!prevTime || timeDate > prevTime) { - prevTime = timeDate; + prevTime = timeDate } } } // 输出结果 - this.xctime = nextTime ? `${nextTimeDiff.hours}时${nextTimeDiff.minutes}分` : '无距离下次浇水时间'; - this.xctimesc = nextWaterDuration || '未知'; - this.sctimejs = prevTime ? prevTime.toTimeString().slice(0, 5) : '无上次浇水时间'; - this.xctimesj = nextTime ? nextTime.toTimeString().slice(0, 5) : '无下次浇水时间'; + this.xctime = nextTime ? `${nextTimeDiff.hours}时${nextTimeDiff.minutes}分` : '无距离下次浇水时间' + this.xctimesc = nextWaterDuration || '未知' + this.sctimejs = prevTime ? prevTime.toTimeString().slice(0, 5) : '无上次浇水时间' + this.xctimesj = nextTime ? nextTime.toTimeString().slice(0, 5) : '无下次浇水时间' console.log('解析后的数据:', { ver_data: this.ver_data, showobj: this.showobj, @@ -2262,6 +2299,334 @@ } return result }, + // 检查并修复蓝牙状态 + checkAndFixBluetooth() { + return new Promise((resolve, reject) => { + uni.getBluetoothAdapterState({ + success: (res) => { + if (res.available) { + // 蓝牙可用,直接继续 + resolve() + } else { + // 蓝牙不可用,尝试重新打开 + this.fixBluetoothAdapter().then(resolve).catch(reject) + } + }, + fail: (err) => { + // 获取状态失败,尝试重新初始化 + this.fixBluetoothAdapter().then(resolve).catch(reject) + } + }) + }) + }, + // 修复蓝牙适配器 + fixBluetoothAdapter() { + return new Promise((resolve, reject) => { + uni.openBluetoothAdapter({ + success: () => { + console.log('蓝牙适配器重新初始化成功') + resolve() + }, + fail: (err) => { + const errMsg = err.errMsg || '' + let errorType = 'UNKNOWN' + let errorMessage = '蓝牙初始化失败' + let canAutoFix = false + let userAction = '' + + if (errMsg.includes('auth deny') || errMsg.includes('authorize')) { + errorType = 'PERMISSION_DENIED' + errorMessage = '蓝牙权限未授权' + userAction = '请在微信设置中开启蓝牙权限:设置 > 隐私 > 蓝牙' + } else if (errMsg.includes('not available') || errMsg.includes('unavailable')) { + errorType = 'BLUETOOTH_UNAVAILABLE' + errorMessage = '蓝牙不可用' + userAction = '请检查手机蓝牙是否已打开:设置 > 蓝牙' + } else if (errMsg.includes('open fail')) { + errorType = 'OPEN_FAILED' + errorMessage = '手机蓝牙打开失败' + userAction = '请检查手机蓝牙功能是否打开' + } else if (errMsg.includes('system permission denied')) { + errorType = 'SYSTEM_PERMISSION_DENIED' + errorMessage = '系统蓝牙权限被拒绝' + userAction = '请在系统设置中允许微信使用蓝牙:设置 > 应用 > 微信 > 权限' + } else if (errMsg.includes('bluetooth service unavailable')) { + errorType = 'SERVICE_UNAVAILABLE' + errorMessage = '蓝牙服务不可用' + userAction = '请重启小程序后重试' + canAutoFix = true + } else if (errMsg.includes('already opened')) { + // 已经打开,可以继续 + resolve() + return + } + reject({ + type: errorType, + message: errorMessage, + errMsg: errMsg, + canAutoFix: canAutoFix, + userAction: userAction + }) + } + }) + }) + }, + // 诊断连接失败原因(按优先级逐个检查,找到第一个错误就停止) + diagnoseConnectionFailure() { + // 如果已经显示过错误弹窗,不再重复诊断 + if (this.errorModalShown) { + return + } + + // 按优先级检查错误,找到第一个就停止 + // 1. 首先检查蓝牙适配器状态 + uni.getBluetoothAdapterState({ + success: (res) => { + // 2. 检查蓝牙是否可用 + if (!res.available) { + // 找到第一个错误:蓝牙不可用 + this.handleConnectionError({ + type: 'BLUETOOTH_UNAVAILABLE', + message: '蓝牙不可用', + userAction: '请检查手机蓝牙是否已打开:设置 > 蓝牙', + canAutoFix: true + }) + return // 找到错误,停止检查 + } + + // 3. 蓝牙可用,检查是否找到设备 + const deviceCount = this.devicesarr ? this.devicesarr.length : 0 + + if (deviceCount === 0) { + // 找到第二个错误:未搜索到任何设备 + this.handleConnectionError({ + type: 'NO_DEVICES_FOUND', + message: '未搜索到任何蓝牙设备', + userAction: '请检查:\n1. 设备是否已开机\n2. 设备是否在附近(建议距离1米内)\n3. 手机蓝牙是否已打开\n\n处理建议:\n1. 确保设备已开机\n2. 靠近设备重试\n3. 重启设备后重试', + canAutoFix: false + }) + return // 找到错误,停止检查 + } + + // 4. 有设备但找不到目标设备 + const matchedDevice = this.devicesarr.find(device => { + if (device.name) { + return device.name.slice(-12) === this.mac.slice(-12) + } + return false + }) + + if (!matchedDevice) { + // 找到第三个错误:未找到目标设备 + this.handleConnectionError({ + type: 'TARGET_DEVICE_NOT_FOUND', + message: `搜索到${deviceCount}个设备,但未找到目标设备`, + userAction: '可能原因:\n1. 设备未开机\n2. 设备距离过远\n3. 设备已连接其他设备\n\n处理建议:\n1. 检查设备是否开机\n2. 靠近设备重试\n3. 确认设备MAC地址是否正确', + canAutoFix: false + }) + return // 找到错误,停止检查 + } + + // 如果所有检查都通过但没有连接成功,可能是其他原因 + // 这种情况不应该发生,但为了安全起见还是处理一下 + if (!this.errorModalShown) { + this.handleConnectionError({ + type: 'UNKNOWN_ERROR', + message: '连接失败,原因未知', + userAction: '请重试连接,如问题持续,请联系客服', + canAutoFix: false + }) + } + }, + fail: (err) => { + // 获取状态失败,尝试重新初始化 + this.fixBluetoothAdapter().then(() => { + // 修复成功,提示用户重试 + if (!this.errorModalShown) { + this.handleConnectionError({ + type: 'ADAPTER_ERROR', + message: '蓝牙适配器异常,已自动修复', + userAction: '请点击"连接设备"按钮重试', + canAutoFix: true, + autoFixed: true + }) + } + }).catch((error) => { + // 修复失败,显示错误 + if (!this.errorModalShown) { + this.handleConnectionError(error) + } + }) + } + }) + }, + // 处理连接错误(只显示一次) + handleConnectionError(error) { + // 如果已经显示过错误弹窗,不再重复显示 + if (this.errorModalShown) { + return + } + + const errorInfo = error || {} + const type = errorInfo.type || 'UNKNOWN' + + // 如果错误类型相同,不再重复显示 + if (this.currentErrorType === type) { + return + } + + // 标记错误弹窗已显示 + this.errorModalShown = true + this.currentErrorType = type + + const message = errorInfo.message || '连接失败' + const userAction = errorInfo.userAction || '请重试' + const canAutoFix = errorInfo.canAutoFix || false + const autoFixed = errorInfo.autoFixed || false + + // 清除连接状态 + this.vardataflag = 1 + this.clearConnectionTimeout() + xBlufi.notifyStartDiscoverBle({ + 'isStart': false + }) + + // 如果已自动修复,显示成功提示 + if (autoFixed) { + this.showCustomErrorModal({ + title: '已自动修复', + message: message, + userAction: userAction, + showCancel: false, + confirmText: '知道了', + onConfirm: () => { + // 重置错误状态,允许下次检查 + this.errorModalShown = false + this.currentErrorType = null + // 可以自动重试 + if (canAutoFix) { + setTimeout(() => { + this.btnlj() + }, 1000) + } + } + }) + return + } + + // 根据错误类型决定是否可以自动修复 + if (canAutoFix && type === 'BLUETOOTH_UNAVAILABLE') { + this.showCustomErrorModal({ + title: '连接失败', + message: message, + userAction: userAction, + showCancel: true, + cancelText: '取消', + confirmText: '自动修复', + onConfirm: () => { + // 重置错误状态 + this.errorModalShown = false + this.currentErrorType = null + // 尝试自动修复 + this.fixBluetoothAdapter().then(() => { + uni.showToast({ + title: '修复成功,请重试', + icon: 'success', + duration: 2000 + }) + // 修复成功后,允许重新检查错误 + setTimeout(() => { + this.errorModalShown = false + this.currentErrorType = null + }, 2000) + }).catch((err) => { + // 修复失败,重新显示错误(重置状态后) + this.errorModalShown = false + this.currentErrorType = null + this.handleConnectionError(err) + }) + } + }) + } else { + // 需要用户手动处理 + this.showCustomErrorModal({ + title: '连接失败', + message: message, + userAction: userAction, + showCancel: true, + cancelText: '取消', + confirmText: '重试', + onConfirm: () => { + // 重置错误状态,允许下次检查 + this.errorModalShown = false + this.currentErrorType = null + // 用户点击重试 + setTimeout(() => { + this.btnlj() + }, 500) + } + }) + } + }, + // 显示自定义错误弹窗 + showCustomErrorModal(data) { + this.errorModalData = { + title: data.title || '提示', + message: data.message || '', + userAction: data.userAction || '', + showCancel: data.showCancel !== undefined ? data.showCancel : true, + cancelText: data.cancelText || '取消', + confirmText: data.confirmText || '确定', + onConfirm: data.onConfirm || (() => {}) + } + this.showErrorModal = true + }, + // 关闭错误弹窗 + closeErrorModal() { + this.showErrorModal = false + // 重置错误状态 + this.errorModalShown = false + this.currentErrorType = null + }, + // 处理错误弹窗确认 + handleErrorConfirm() { + if (this.errorModalData.onConfirm) { + this.errorModalData.onConfirm() + } + this.showErrorModal = false + }, + // 处理连接超时 + handleConnectionTimeout() { + // 如果已经显示过错误弹窗,不再重复显示 + if (this.errorModalShown) { + return + } + + this.vardataflag = 1 + this.clearConnectionTimeout() + xBlufi.notifyStartDiscoverBle({ + 'isStart': false + }) + + const elapsedTime = Date.now() - (this.connectionStartTime || Date.now()) + this.handleConnectionError({ + type: 'CONNECTION_TIMEOUT', + message: `连接超时(已等待${Math.floor(elapsedTime / 1000)}秒)`, + userAction: '可能原因:\n1. 设备距离过远\n2. 设备未开机\n3. 蓝牙信号干扰\n\n处理建议:\n1. 靠近设备(1米内)\n2. 检查设备是否开机\n3. 重启设备后重试', + canAutoFix: false + }) + }, + // 清除连接超时定时器 + clearConnectionTimeout() { + if (this.connectionTimeout) { + clearTimeout(this.connectionTimeout) + this.connectionTimeout = null + } + if (this.connectTimeout) { + clearTimeout(this.connectTimeout) + this.connectTimeout = null + } + }, } } @@ -2863,4 +3228,143 @@ color: #666; text-align: center; } + + /* 自定义错误弹窗样式 */ + .error-modal-mask { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100vh; + background-color: rgba(0, 0, 0, 0.5); + display: flex; + align-items: center; + justify-content: center; + z-index: 10000; + animation: fadeIn 0.3s ease; + } + + @keyframes fadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } + } + + .error-modal-container { + width: 640rpx; + background: #FFFFFF; + border-radius: 24rpx; + overflow: hidden; + animation: slideUp 0.3s ease; + box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.15); + } + + @keyframes slideUp { + from { + transform: translateY(100rpx); + opacity: 0; + } + to { + transform: translateY(0); + opacity: 1; + } + } + + .error-modal-header { + display: flex; + align-items: center; + justify-content: center; + padding: 40rpx 40rpx 30rpx; + border-bottom: 1rpx solid #F0F0F0; + } + + .error-icon { + font-size: 48rpx; + margin-right: 16rpx; + } + + .error-modal-title { + font-size: 36rpx; + font-weight: 600; + color: #333333; + } + + .error-modal-content { + padding: 40rpx; + max-height: 60vh; + overflow-y: auto; + } + + .error-message { + font-size: 32rpx; + color: #FF6B6B; + font-weight: 500; + line-height: 1.6; + margin-bottom: 30rpx; + word-break: break-all; + } + + .error-action { + background: #F8F9FA; + border-radius: 12rpx; + padding: 24rpx; + border-left: 4rpx solid #7FAD76; + } + + .action-label { + font-size: 28rpx; + color: #7FAD76; + font-weight: 600; + display: block; + margin-bottom: 16rpx; + } + + .action-text { + font-size: 28rpx; + color: #666666; + line-height: 1.8; + white-space: pre-line; + word-break: break-all; + } + + .error-modal-footer { + display: flex; + border-top: 1rpx solid #F0F0F0; + } + + .error-btn { + flex: 1; + height: 100rpx; + display: flex; + align-items: center; + justify-content: center; + font-size: 32rpx; + font-weight: 500; + cursor: pointer; + transition: all 0.3s; + } + + .error-btn-cancel { + color: #999999; + border-right: 1rpx solid #F0F0F0; + background: #FAFAFA; + } + + .error-btn-cancel:active { + background: #F0F0F0; + } + + .error-btn-confirm { + color: #FFFFFF; + background: linear-gradient(135deg, #7FAD76 0%, #6A9A65 100%); + font-weight: 600; + } + + .error-btn-confirm:active { + background: linear-gradient(135deg, #6A9A65 0%, #5A8A55 100%); + opacity: 0.9; + } \ No newline at end of file diff --git a/pages/my.vue b/pages/my.vue index bfae4c3..6b3290b 100644 --- a/pages/my.vue +++ b/pages/my.vue @@ -8,7 +8,10 @@ - {{userobj.nickName == undefined ? '' : userobj.nickName}} + + {{userobj.nickName == undefined ? '' : userobj.nickName}} + {{formatPhone(userobj.userName)}} + 网关录入 @@ -64,25 +67,25 @@ - - - - + + + + {{item.title && item.title.length > 10 ? item.title.slice(0,20) + '...' : item.title}} @@ -101,25 +104,25 @@ - - - - + + + + {{item.title && item.title.length > 10 ? item.title.slice(0,20) + '...' : item.title}} @@ -312,7 +315,7 @@ this.feedList = this.feedList.concat(res.rows) this.pageNum ++ } - console.log(this.feedList); + console.log(this.feedList) } }) }, @@ -558,7 +561,24 @@ } }) } - } + }, + // 格式化手机号,将中间四位数替换为* + formatPhone(phone) { + if (!phone || typeof phone !== 'string') return '' + // 移除所有非数字字符 + const phoneNumber = phone.replace(/\D/g, '') + // 如果是11位手机号,格式化为:前3位 + **** + 后4位 + if (phoneNumber.length === 11) { + return phoneNumber.substring(0, 3) + '****' + phoneNumber.substring(7) + } + // 如果不是11位,但长度大于7位,也进行中间四位替换 + if (phoneNumber.length > 7) { + const start = Math.floor((phoneNumber.length - 4) / 2) + return phoneNumber.substring(0, start) + '****' + phoneNumber.substring(start + 4) + } + // 其他情况直接返回原值 + return phone + } } } @@ -848,11 +868,21 @@ font-size: 40rpx; color: #3D3D3D; font-weight: 600; - .name{ + .name-info{ position: absolute; left: 220rpx; display: flex; - align-items: center; + flex-direction: column; + .name{ + display: flex; + align-items: center; + } + .phone{ + font-size: 28rpx; + color: #767676; + font-weight: 400; + margin-top: 8rpx; + } } }