<template> <view class="page"> <u-navbar title="添加设备" :border-bottom="false" :background="bgc" title-color='#262B37' title-size='38' height='50'></u-navbar> <view class="iptbox" @click="backpage()"> <input type="text" class="ips" v-model="mac" placeholder=" " style="margin-left: 32rpx;" disabled placeholder-class="my-placeholder" /> <view class="iconfont icon-xiangyou1 "> </view> </view> <view class="iptbox"> <view class="qrcode" @click="qrcode()"> <image src="https://api.ccttiot.com/smartmeter/img/static/uy7BNwAMIKwvstqFnRhs" mode="aspectFit"> </image> </view> <input type="text" class="ips" v-model="sn" placeholder="请扫描设备上的二维码" style="margin-left: 32rpx;" placeholder-class="my-placeholder" /> </view> <view class="iptbox" @click="show = true"> <view class="" v-if="hardwareInfo.version"> 版本:{{ hardwareInfo.version }} 版本id:{{ hardwareInfo.id }} </view> <view class="" v-else> 请点击选择版本 </view> </view> <view class="tips" v-if="hardwareInfo.version"> 版本介绍:{{ hardwareInfo.instructions }} </view> <u-select v-model="show" :list="list" title='选择运营区' @confirm="confirm"></u-select> <view class="imgs" style="margin-top: 330rpx;"> <image src="https://lxnapi.ccttiot.com/bike/img/static/u9wFJhLZGm7rboSDySV4" mode="aspectFit" @click="qrcode()"></image> </view> <view class="btn" @click="bind()"> 确认添加 </view> <view class="bot_btn"> <view class="btn1" @click="Binddevice()"> 蓝牙链接 </view> <view class="btn1" @click="ring()" v-if="carstause"> 响铃寻车 </view> <view class="btn1" @click="open()" v-if="carstause"> 蓝牙开锁 </view> <view class="btn1" @click="close()" v-if="carstause"> 蓝牙关锁 </view> <view class="btn1" @click="reboot()" v-if="carstause"> 设备重启 </view> </view> <u-mask :show="showbind" :z-index='100' /> <view class="tip_box" v-if="showbind"> <view class="top" v-if="showbind"> <view class="tip"> 操作提示 </view> <view class="ipt_box" style="justify-content: center;"> <view class="text" style="width: 80%;text-align: center;"> 该mac号已有绑定sn码是否修改为当前sn码 </view> </view> </view> <view class="bots"> <view class="bot_left" @click="showbind = false"> 取消 </view> <view class="bot_right" @click="changeBind()"> 确定 </view> </view> </view> <!-- <view class="bot"> <view class="btn"> 退款 </view> </view> --> </view> </template> <script> import xBlufi from '@/utils/blufi/xBlufi.js' export default { data() { return { // 蓝牙相关数据 devices: [], isSearching: false, isConnecting: false, bluetoothStatus: '未初始化', selectedDevice: null, hasConnectedDevice: false, serviceId: '000000FF-0000-1000-8000-00805F9B34FB', characteristicId: '0000FF01-0000-1000-8000-00805F9B34FB', // 原有的业务数据 mac: '', sn: '', carstause: false, show: false, list: [], hardwareInfo: {}, showbind: false, bgc: { backgroundColor: "#F7FAFE", } } }, onLoad(e) { this.mac = e.mac this.initBluetooth() this.getlist() // 添加自动连接 if (this.mac) { setTimeout(() => { this.Binddevice() }, 1000) // 延迟1秒执行,确保蓝牙初始化完成 } // 添加蓝牙状态监听 my.onBluetoothAdapterStateChange((res) => { console.log('蓝牙适配器状态:', res); if (!res.available) { this.isSearching = false; uni.showToast({ title: '蓝牙已关闭', icon: 'none' }); } }); my.onBLEConnectionStateChanged((res) => { console.log('蓝牙连接状态变化:', res); if (!res.connected) { this.carstause = false; this.hasConnectedDevice = false; } else { this.carstause = true; this.hasConnectedDevice = true; } }); }, onUnload() { this.cleanupBluetooth() }, onHide() { this.cleanupBluetooth() }, methods: { initBluetooth() { xBlufi.initXBlufi(xBlufi.XMQTT_SYSTEM.Alis); xBlufi.listenDeviceMsgEvent(true, (res) => { console.log('设备消息:', res); switch (res.type) { case xBlufi.XBLUFI_TYPE.TYPE_GET_DEVICE_LISTS: if (res.result && res.data) { console.log("搜索到设备:", res.data); const bbleDevices = res.data.filter(device => { const name = device.name || device.deviceName || ''; return name.startsWith('BBLE'); }); this.devices = bbleDevices; } break; case xBlufi.XBLUFI_TYPE.TYPE_STATUS_CONNECTED: if (res.result) { this.carstause = true; this.hasConnectedDevice = true; uni.showToast({ title: '连接成功', icon: 'success', duration: 1000 }); } else { this.carstause = false; this.hasConnectedDevice = false; uni.showToast({ title: '连接断开', icon: 'none', duration: 1000 }); } break; case xBlufi.XBLUFI_TYPE.TYPE_SEND_CUSTOM_DATA_RESULT: console.log('发送自定义数据结果:', res); if (res.result) { uni.showToast({ title: '命令发送成功', icon: 'success', duration: 1000 }); } else { uni.showToast({ title: '命令发送失败', icon: 'none', duration: 1000 }); } break; } }); }, // 蓝牙连接方法 Binddevice() { uni.showLoading({ title: '连接中..' }); this.devices = []; this.isSearching = true; xBlufi.notifyStartDiscoverBle({ 'isStart': true }); setTimeout(() => { xBlufi.notifyStartDiscoverBle({ 'isStart': false }); setTimeout(() => { uni.hideLoading(); if (this.devices.length == 0) { uni.showToast({ title: '暂无发现对应设备,请靠近设备', icon: 'none' }); } else { const matchedDevice = this.devices.find(device => { const macFromName = device.name.substring(device.name.length - 12); return macFromName === this.mac; }); if (matchedDevice) { console.log('找到匹配设备:', matchedDevice); this.selectedDevice = matchedDevice; // 连接设备 xBlufi.notifyConnectBle({ connect: true, deviceId: matchedDevice.deviceId }); // 初始化设备 xBlufi.notifyInitBleEsp32({ deviceId: matchedDevice.deviceId }); } else { console.log('未找到匹配设备'); uni.showToast({ title: '未找到对应设备', icon: 'none' }); } } }, 200); }, 2000); }, // 响铃寻车 ring() { if (!this.hasConnectedDevice || !this.selectedDevice) { uni.showToast({ title: '请先连接设备', icon: 'none' }); return; } my.getBLEDeviceServices({ deviceId: this.selectedDevice.deviceId, success: (res) => { console.log('设备的所有服务:', res.services); xBlufi.notifySendCustomData({ customData: "11play1@" }); }, fail: (error) => { console.error('获取服务列表失败:', error); uni.showToast({ title: '获取服务失败', icon: 'none' }); } }); }, // 蓝牙开锁 open() { if (!this.hasConnectedDevice || !this.selectedDevice) { uni.showToast({ title: '请先连接设备', icon: 'none' }); return; } xBlufi.notifySendCustomData({ customData: "11open" }); }, // 蓝牙关锁 close() { if (!this.hasConnectedDevice || !this.selectedDevice) { uni.showToast({ title: '请先连接设备', icon: 'none' }); return; } xBlufi.notifySendCustomData({ customData: "11close" }); }, // 设备重启 reboot() { if (!this.hasConnectedDevice || !this.selectedDevice) { uni.showToast({ title: '请先连接设备', icon: 'none' }); return; } xBlufi.notifySendCustomData({ customData: "11reboot" }); }, // 获取硬件版本列表 getlist() { this.$u.get('/app/hardwareVersion/list').then((res) => { if (res.code === 200) { this.Versionlist = res.data const hardwareVersionId = uni.getStorageSync('hardwareVersionId'); if (hardwareVersionId) { this.hardwareVersionId = hardwareVersionId const matchedVersion = this.Versionlist.find(version => version.id === hardwareVersionId); if (matchedVersion) { this.hardwareInfo = matchedVersion; } } this.list = res.data.map(item => ({ value: item.id, label: item.version })); } else { uni.showToast({ title: res.msg, icon: 'none', duration: 2000 }); } }) }, // 版本选择确认 confirm(e) { uni.setStorageSync('hardwareVersionId', e[0].value); this.hardwareVersionId = e[0].value if (this.hardwareVersionId) { const matchedVersion = this.Versionlist.find(version => version.id === this.hardwareVersionId); if (matchedVersion) { this.hardwareInfo = matchedVersion; } } }, // 绑定设备 bind() { if (!this.sn || this.sn.length !== 7 || !/^\d+$/.test(this.sn)) { uni.showToast({ title: '请输入正确的SN码', icon: 'none' }); return; } this.$u.post(`/appVerify/band?sn=${this.sn}&mac=${this.mac}&hardwareVersionId=${this.hardwareVersionId}`).then((res) => { if (res.code === 200) { uni.showToast({ title: '绑定成功', icon: 'none', duration: 2000 }); setTimeout(() => { uni.navigateTo({ url: '/pages_admin/controlDevice?sn=' + this.sn }) }, 2000) } else { if (res.msg === '该MAC号已经存在') { this.showbind = true; } else { uni.showToast({ title: res.msg, icon: 'none', duration: 2000 }); } } }) }, // 修改绑定 changeBind() { this.$u.post(`/appVerify/updateSn?sn=${this.sn}&mac=${this.mac}&hardwareVersionId=${this.hardwareVersionId}`).then((res) => { if (res.code === 200) { uni.showToast({ title: '绑定成功', icon: 'none', duration: 2000 }); setTimeout(() => { uni.navigateTo({ url: '/pages_admin/controlDevice?sn=' + this.sn }) }, 2000) } else { uni.showToast({ title: res.msg, icon: 'none', duration: 2000 }); } }) }, // 扫描二维码 qrcode() { uni.scanCode({ onlyFromCamera: true, scanType: ['qrCode'], success: res => { let sn = null; let queryParams = res.result.split('?')[1]; if (queryParams) { let params = queryParams.split('&'); params.forEach(param => { let [key, value] = param.split('='); if (key === 'sn') { sn = value; } }); } this.sn = sn; if (!this.sn) { uni.showToast({ title: '无效的二维码', icon: 'none' }); } }, fail: err => { console.error('扫描失败:', err); uni.showToast({ title: '扫描失败', icon: 'none' }); } }); }, // 返回上一页 backpage() { uni.navigateBack({ delta: 1 }); }, // 生命周期钩子和清理方法 // 清理蓝牙相关资源 cleanupBluetooth() { xBlufi.listenDeviceMsgEvent(false); xBlufi.notifyStartDiscoverBle({ 'isStart': false }); if (this.hasConnectedDevice && this.selectedDevice) { xBlufi.notifyConnectBle({ connect: false, deviceId: this.selectedDevice.deviceId }); } } } } </script> <style lang="scss"> page { overflow-x: hidden; background-color: #F3F3F3; } .page { padding-bottom: 250rpx; width: 750rpx; .tip_box { position: fixed; left: 72rpx; top: 628rpx; width: 610rpx; // height: 282rpx; background: #FFFFFF; border-radius: 30rpx 30rpx 30rpx 30rpx; z-index: 110; padding-bottom: 100rpx; .top { padding: 52rpx 38rpx 42rpx 36rpx; .ipt_box { margin-top: 22rpx; display: flex; flex-wrap: nowrap; align-items: center; .text { width: 350rpx; font-weight: 400; font-size: 32rpx; color: #3D3D3D; } .ipt { padding: 10rpx 18rpx; display: flex; align-items: center; justify-content: space-between; margin-left: 26rpx; width: 420rpx; height: 64rpx; border-radius: 0rpx 0rpx 0rpx 0rpx; border: 2rpx solid #979797; .input { width: 80%; } } } .tip { width: 100%; text-align: center; font-weight: 700; font-size: 32rpx; color: #3D3D3D; } .txt { margin-top: 32rpx; width: 100%; text-align: center; font-weight: 500; font-size: 32rpx; color: #3D3D3D; } } .bots { position: absolute; width: 610rpx; // border-top: 2rpx solid #D8D8D8; display: flex; flex-wrap: nowrap; // height: 100%; bottom: -20rpx; .bot_left { border-radius: 0rpx 0rpx 0rpx 30rpx; width: 50%; height: 86rpx; display: flex; align-items: center; justify-content: center; font-weight: 500; font-size: 32rpx; color: #3D3D3D; background: #EEEEEE; } .bot_right { border-radius: 0rpx 0rpx 30rpx 0rpx; width: 50%; height: 86rpx; background: #4C97E7; display: flex; align-items: center; justify-content: center; color: #FFFFFF; // border-left: 2rpx solid #D8D8D8; font-weight: 500; font-size: 32rpx; // color: #4C97E7; } } } .imgs { margin-top: 50rpx; width: 100%; display: flex; justify-content: center; image { width: 400rpx; height: 400rpx; } } .btn { margin: 160rpx auto; margin-top: 30rpx; // position: fixed; display: flex; align-items: center; justify-content: center; // bottom: 100rpx; // left: 46rpx; width: 658rpx; height: 88rpx; background: #27c2fd; border-radius: 20rpx 20rpx 20rpx 20rpx; font-weight: 500; font-size: 32rpx; color: #FFFFFF; } .tips { margin: 28rpx auto 0; width: 658rpx; } .iptbox { display: flex; align-items: center; flex-wrap: nowrap; padding: 22rpx; margin: 28rpx 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 { width: 630rpx; } image { width: 18rpx; height: 32rpx; } .my-placeholder { font-weight: 400; font-size: 32rpx; color: #808080; } } .bot_btn { position: fixed; bottom: 0; display: flex; flex-wrap: wrap; padding: 40rpx 18rpx; width: 750rpx; // height: 330rpx; background: #fff; // background: linear-gradient( 180deg, #FFFFFF 0%, rgba(255,255,255,0) 100%); box-shadow: 0rpx 10rpx 64rpx 0rpx rgba(0, 0, 0, 0.08); border-radius: 0rpx 0rpx 0rpx 0rpx; .btn:nth-child(4n) { margin-right: 0; } .btn1 { margin-top: 10rpx; margin-right: 12rpx; display: flex; align-items: center; justify-content: center; width: 164rpx; height: 66rpx; background: #E2F2FF; border-radius: 0rpx 0rpx 0rpx 0rpx; border: 2rpx solid #4C97E7; font-weight: 400; font-size: 28rpx; color: #3D3D3D; } } } </style>