Sprinkler-app/page_user/lanya.vue
2026-01-17 17:37:00 +08:00

738 lines
18 KiB
Vue
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.

<template>
<view>
<u-navbar :is-back="true" title=' ' title-color="#000" :border-bottom="false" :background="bgc"
id="navbar">
</u-navbar>
<view class="page">
<!-- 有搜索到设备 -->
<view class="you" v-if="flags">
<view class="topone">
<image src="https://api.ccttiot.com/smartmeter/img/static/ubrPcpGQEXTadkBa1gKh" mode=""></image>
扫描到以下设备点击添加
</view>
<view class="toptwo">
如未找到想添加的设备点击重新搜索
</view>
<view class="list">
<view class="list_item" v-for="(item,index) in sortedJiaohuaqi" :key="index" :class="{ show: item.show }">
<image :src="item.modelPicture" mode=""></image>
<view class="cen">
<view class="name" style="color: #ccc;" v-if="item.userId && item.userId != userid">
{{item.modelName == undefined ? '' : item.modelName}}
</view>
<view class="name" v-else>
{{item.modelName == undefined ? '' : item.modelName}}
</view>
<view class="devmac">
MAC{{item.mac == undefined ? item.name.slice(-12) : item.mac}}
</view>
<view class="devmac" style="display: flex;align-items: center;">
信号:
<!-- 最强信号:-50 及以上(-1 到 -50 -->
<image
style="width: 30rpx;height: 20rpx;"
v-if="item.ssid >= -50"
src="https://api.ccttiot.com/smartmeter/img/static/ueeDGk0mVPLUd0DHxrWj"
mode=""
></image>
<!-- 较强信号:-51 到 -60 -->
<image
style="width: 30rpx;height: 20rpx;"
v-else-if="item.ssid >= -60 && item.ssid <= -51"
src="https://api.ccttiot.com/smartmeter/img/static/uM1obZ76ittglMRKXWLq"
mode=""
></image>
<!-- 中等信号:-61 到 -70 -->
<image
style="width: 30rpx;height: 20rpx;"
v-else-if="item.ssid >= -70 && item.ssid <= -61"
src="https://api.ccttiot.com/smartmeter/img/static/ujO9AZIuUSQvHcCBKqc4"
mode=""
></image>
<!-- 较弱信号:-71 到 -80 -->
<image
style="width: 30rpx;height: 20rpx;"
v-else-if="item.ssid >= -80 && item.ssid <= -71"
src="https://api.ccttiot.com/smartmeter/img/static/uCSlbXZvho808NMCkIQP"
mode=""
></image>
<!-- 最弱信号:-81 到 -100 -->
<image
style="width: 30rpx;height: 20rpx;"
v-else-if="item.ssid >= -100 && item.ssid <= -81"
src="https://api.ccttiot.com/smartmeter/img/static/u8bj3ZNi8Zssunk69HWc"
mode=""
></image>
</view>
</view>
<view class="add" style="color: #ccc;border: 1px solid #ccc;" v-if="item.userId != 0 && item.userId">
已添加
</view>
<view class="add" @click="btnadd(item)" v-else>
添加
</view>
</view>
</view>
</view>
<!-- 未搜索到设备 -->
<view class="wei" v-else>
<image src="https://api.ccttiot.com/smartmeter/img/static/uQ4g6A27FGtF34ebOtea" mode=""></image>
<view class="sbname">
搜索附近的设备失败
</view>
<view class="sbwz">
搜索失败点击重新搜索注意打开蓝牙
</view>
</view>
<!-- 点击搜索 -->
<view class="btnss" @click="handleSearch">
重新搜索
</view>
</view>
<!-- 自定义名称弹框 -->
<u-popup v-model="showNameDialog" mode="center" border-radius="14" width="600rpx">
<view class="custom-name-dialog">
<view class="dialog-title">设备名称</view>
<u-input v-model="customDeviceName" placeholder="请输入设备名称" />
<view class="dialog-btns">
<view class="btn cancel" @click="showNameDialog = false">取消</view>
<view class="btn confirm" @click="confirmAddDevice">确定</view>
</view>
</view>
</u-popup>
</view>
</template>
<script>
var xBlufi = require("@/components/blufi/xBlufi.js");
export default {
data() {
return {
bgc: {
backgroundColor: "#fff",
},
active: 1,
flag: true,
devicesList: [],
newlist:[],
deviceId: '',
name: '',
mac: '',
flags: true,
userid: '',
arr: [],
jiaohuaqi: [],
getpre: [],
showNameDialog: false,
customDeviceName: '',
currentDevice: null,
searchTimer: null,
checkTimer: null,
isSearching: false,
searchTimeout: null,
throttleTimer: null,
lastSearchTime: 0,
searchInterval: 2000, // 搜索间隔2秒
displayQueue: [], // 显示队列
processingQueue: false, // 是否正在处理队列
}
},
computed: {
sortedJiaohuaqi() {
return this.jiaohuaqi.slice().sort((a, b) => {
if (a.ssid === undefined) return 1;
if (b.ssid === undefined) return -1;
return Math.abs(a.ssid) - Math.abs(b.ssid);
});
}
},
// 分享到好友(会话)
onShareAppMessage: function() {
return {
title: '绿小能',
path: '/pages/index/index'
}
},
// 分享到朋友圈
onShareTimeline: function() {
return {
title: '绿小能',
query: '',
path: '/pages/index/index'
}
},
onLoad() {
this.getmodel()
this.getinfo()
// 检查蓝牙状态
uni.getBluetoothAdapterState({
success: function(res) {
console.log('蓝牙适配器状态:', res)
if (!res.available) {
// 蓝牙不可用(关闭或故障)
uni.showModal({
title: '提示',
content: '蓝牙不可用,请检查手机蓝牙是否打开',
showCancel: false,
confirmText: '知道了'
})
} else {
// 蓝牙正常,但找不到设备(设备断电、距离远、设备故障)
console.log('蓝牙正常但未找到设备,设备可能断电')
}
},
fail: function(err) {
console.error('获取蓝牙状态失败', err)
// 获取状态失败,尝试重新打开适配器检测
uni.openBluetoothAdapter({
success: function (res) {
console.log('蓝牙适配器正常,但未发现设备');
},
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: '知道了'
})
}
}
})
}
})
},
onShow() {
this.startSearch()
},
onHide() {
this.stopSearch()
},
onUnload() {
this.stopSearch()
},
methods: {
// 获取用户信息
getinfo() {
this.$u.get(`/system/user/profile`).then((res) => {
if (res.code == 200) {
this.userid = res.data.userId
uni.setStorageSync('user',res.data)
uni.setStorageSync('userId',res.data.userId)
} else if (res.code == 401) {
uni.showModal({
title: '提示',
content: '您还未登录,是否前去登录?',
success: function(res) {
if (res.confirm) {
uni.navigateTo({
url: '/pages/login/login'
})
} else if (res.cancel) {
}
}
})
}
})
},
// 点击添加按钮
btnadd(e) {
this.currentDevice = e;
this.customDeviceName = e.modelName || '未知设备'; // 默认使用型号名称
this.showNameDialog = true;
},
// 确认添加设备
confirmAddDevice() {
if (!this.customDeviceName.trim()) {
uni.showToast({
title: '请输入设备名称',
icon: 'none'
});
return;
}
let mac = this.currentDevice.name.slice(-12);
let data = {
mac: mac,
// userId: this.userid,
pre: this.currentDevice.pre,
deviceName: this.customDeviceName
}
console.log(data,'参数');
this.$u.post(`/app/device/bindDeviceByBlueTooth`, data).then((res) => {
if (res.code == 200) {
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({
title: res.msg,
icon: 'none',
duration: 3000
})
}
})
},
getmodel() {
this.$u.get(`/app/getAllModelList`).then(res => {
if (res.code == 200) {
this.getpre = res.data
}
})
},
getpipei(pre) {
// 添加默认返回值防止undefined
return this.getpre.find(item => item.pre == pre) || {
modelName: '未知型号',
picture: ''
};
},
// 开始搜索
startSearch() {
if (this.isSearching) return
this.isSearching = true
this.jiaohuaqi = []
this.displayQueue = []
this.processingQueue = false
this.flag = false
// 开始蓝牙搜索
xBlufi.listenDeviceMsgEvent(true, this.funListenDeviceMsgEvent)
xBlufi.notifyStartDiscoverBle({ 'isStart': true })
// 30秒后自动停止搜索
this.searchTimeout = setTimeout(() => {
this.stopSearch()
}, 30000)
},
// 停止搜索
stopSearch() {
this.isSearching = false
if (this.checkTimer) {
clearInterval(this.checkTimer)
this.checkTimer = null
}
if (this.searchTimeout) {
clearTimeout(this.searchTimeout)
this.searchTimeout = null
}
if (this.throttleTimer) {
clearTimeout(this.throttleTimer)
this.throttleTimer = null
}
xBlufi.notifyStartDiscoverBle({ 'isStart': false })
this.flag = true
},
// 处理显示队列
processDisplayQueue() {
if (this.processingQueue || this.displayQueue.length === 0) return
this.processingQueue = true
const device = this.displayQueue.shift()
// 检查设备是否已存在
if (!this.jiaohuaqi.some(item => item.name === device.name)) {
this.jiaohuaqi.push(device)
}
// 延迟处理下一个设备
setTimeout(() => {
this.processingQueue = false
this.processDisplayQueue()
}, 500) // 每个设备显示间隔500ms
},
// 添加设备到显示队列
addToDisplayQueue(device) {
this.displayQueue.push(device)
if (!this.processingQueue) {
this.processDisplayQueue()
}
},
// 更新设备列表
updateDeviceList(existList) {
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)
})
newDevices.forEach(item => {
const mac = item.name.slice(-12)
const pre = item.name.slice(0, 5)
const ssid = item.RSSI
const matched = this.getpipei(pre)
const existDevice = existList.find(val => val.mac === mac)
const newDevice = {
name: mac,
modelName: matched.modelName,
modelPicture: matched.picture,
pre: pre,
userId: existDevice ? existDevice.userId : null,
ssid: ssid
}
this.addToDisplayQueue(newDevice)
})
},
// 获取附近蓝牙设备列表
funListenDeviceMsgEvent: function(options) {
switch (options.type) {
case xBlufi.XBLUFI_TYPE.TYPE_GET_DEVICE_LISTS:
if (options.result) {
const now = Date.now()
if (now - this.lastSearchTime < this.searchInterval) {
return
}
this.lastSearchTime = now
let devicesarr = []
this.devicesList = options.data
options.data.forEach(item => {
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
// 使用节流处理设备检查
if (this.throttleTimer) {
clearTimeout(this.throttleTimer)
}
this.throttleTimer = setTimeout(() => {
if (this.devicesList.length > 0) {
// const data = { macList: this.arr }
this.$u.get(`/app/device/list?macList=${this.arr}`)
.then(res => {
if (res.code === 200) {
this.updateDeviceList(res.data)
}
})
.catch(error => {
console.error('请求失败:', error)
})
}
}, 500) // 500ms的节流时间
}
break
case xBlufi.XBLUFI_TYPE.TYPE_GET_DEVICE_LISTS_START:
if (!options.result) {
uni.showToast({
title: '蓝牙初始化失败',
icon: 'none',
duration: 3000
})
this.flags = false
return
}
break
}
},
btnss() {
this.stopSearch()
this.jiaohuaqi = []
this.displayQueue = []
this.processingQueue = false
this.startSearch()
},
// 处理搜索按钮点击
handleSearch() {
this.btnss()
},
}
}
</script>
<style lang="less">
::v-deep .u-input__input{
border: 1px solid #ccc;
border-radius: 10rpx;
padding-left: 10rpx;
box-sizing: border-box;
}
::v-deep .u-title {
margin-bottom: 22rpx;
}
::v-deep .uicon-nav-back {
margin-bottom: 22rpx;
}
.page {
padding-bottom: 300rpx;
box-sizing: border-box;
}
.wei {
text-align: center;
image {
width: 380rpx;
height: 394rpx;
}
.sbname {
font-size: 40rpx;
color: #3D3D3D;
margin-top: 80rpx;
width: 100%;
text-align: center;
}
.sbwz {
font-size: 28rpx;
color: #737B80;
margin-top: 24rpx;
width: 100%;
text-align: center;
}
}
.btnss {
width: 512rpx;
height: 92rpx;
background: #48893B;
border-radius: 46rpx 46rpx 46rpx 46rpx;
border-radius: 50rpx;
text-align: center;
line-height: 92rpx;
font-weight: 600;
font-size: 40rpx;
color: #FFFFFF;
position: fixed;
left: 50%;
transform: translateX(-50%);
bottom: 106rpx;
transition: all 0.3s ease;
}
.list {
width: 100%;
border-radius: 20rpx;
margin: auto;
margin-top: 72rpx;
will-change: transform; // 优化动画性能
.list_item {
margin-top: 18rpx;
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
height: 152rpx;
background: #FFFFFF;
border-radius: 20rpx;
box-shadow: 0rpx 10rpx 64rpx 0rpx rgba(0, 0, 0, 0.08);
padding: 18rpx 30rpx;
box-sizing: border-box;
animation: slideIn 0.5s cubic-bezier(0.4, 0, 0.2, 1) forwards;
opacity: 0;
transform: translateX(-100%);
will-change: transform, opacity; // 优化动画性能
@keyframes slideIn {
from {
opacity: 0;
transform: translateX(-100%);
}
to {
opacity: 1;
transform: translateX(0);
}
}
image {
width: 94rpx;
height: 94rpx;
}
.cen {
.name {
font-size: 32rpx;
color: #50565A;
}
.devmac {
font-size: 24rpx;
color: #BDBCBC;
margin-top: 6rpx;
}
}
.add {
width: 108rpx;
height: 60rpx;
background: #FFFFFF;
border: 3rpx solid #48893B;
filter: blur(0px);
border-radius: 20rpx;
text-align: center;
line-height: 60rpx;
font-size: 28rpx;
color: #48893B;
}
}
}
page {
width: 100%;
padding: 20rpx 64rpx;
box-sizing: border-box;
background-color: #fff;
}
.topone {
font-size: 36rpx;
color: #3D3D3D;
display: flex;
image {
width: 48rpx;
height: 48rpx;
}
}
.toptwo {
font-size: 28rpx;
color: #737B7F;
margin-top: 14rpx;
width: 100%;
padding-left: 48rpx;
box-sizing: border-box;
}
.custom-name-dialog {
background: #fff;
padding: 40rpx;
.dialog-title {
font-size: 32rpx;
color: #333;
text-align: center;
margin-bottom: 30rpx;
}
.dialog-btns {
display: flex;
justify-content: space-between;
margin-top: 40rpx;
.btn {
width: 240rpx;
height: 80rpx;
line-height: 80rpx;
text-align: center;
border-radius: 40rpx;
font-size: 28rpx;
&.cancel {
background: #f5f5f5;
color: #666;
}
&.confirm {
background: #48893B;
color: #fff;
}
}
}
}
</style>