index.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. <template>
  2. <view class="content">
  3. <view class="cz-box" @click="toWork">
  4. <view :class="loading?'turn':''">
  5. <u-image width="100rpx" height="100rpx" src="/static/chengzhong.png"></u-image>
  6. <view class="tits">投放称重</view>
  7. </view>
  8. </view>
  9. <view class="bindDev" @click="toInit">
  10. {{statusStr}}
  11. </view>
  12. <view class="devList">
  13. <view v-for="item in deviceList" :key="item.deviceId">
  14. <view class="names">
  15. <view>{{item.name}}</view>
  16. <view class="texts">MAC:{{item.deviceId}}</view>
  17. </view>
  18. <view class="btns" @click="connectBlue(item)" v-if="!connectStatus">点击连接</view>
  19. <view class="btns" @click="closeBlue" v-else>断开连接</view>
  20. </view>
  21. </view>
  22. </view>
  23. </template>
  24. <script>
  25. export default {
  26. data() {
  27. return {
  28. deviceList:[], // 设备列表
  29. deviceId: null,
  30. connectedDeviceId: '',
  31. services: [],
  32. readsId:'',
  33. writeId:'',
  34. notifyServicweId: '',
  35. writeDatas: '',
  36. balanceData: '',
  37. hexstr: '',
  38. statusStr: '绑定电子秤',
  39. connectStatus: false ,// 设备连接状态
  40. loading: false ,// 正在连接
  41. }
  42. },
  43. onLoad() {
  44. console.log('onload')
  45. let _this = this
  46. uni.$on('blueReConnect',function(){
  47. uni.showLoading({
  48. mask: true,
  49. title: '正在重连中...'
  50. })
  51. _this.connectBlue()
  52. })
  53. },
  54. onUnload() {
  55. uni.$off('blueReConnect')
  56. },
  57. methods: {
  58. // 去认证用户并开始称重
  59. toWork(){
  60. let _this = this
  61. // 连接成功
  62. if(this.connectStatus){
  63. uni.navigateTo({
  64. url: '/pages/userAuth/userAuth?deviceId=' + this.deviceId
  65. })
  66. }else{
  67. let hasDev = this.deviceList.length
  68. uni.showModal({
  69. title:'提示',
  70. content:hasDev ? '请先连接设备':'请先绑定设备',
  71. confirmText: hasDev ? '确定':'去绑定',
  72. complete(e) {
  73. console.log(e)
  74. if(e.confirm){
  75. if(hasDev == 1){
  76. _this.connectBlue(_this.deviceList[0])
  77. }
  78. if(hasDev == 0){
  79. _this.toInit()
  80. }
  81. }
  82. }
  83. })
  84. }
  85. },
  86. // 初始化蓝牙
  87. toInit(){
  88. let _this = this
  89. console.log(this.connectStatus,this.deviceList.length,this.loading)
  90. if(this.connectStatus || this.deviceList.length > 0 || this.loading){
  91. return
  92. }
  93. uni.openBluetoothAdapter({
  94. success(res) {
  95. console.log(res, 'openBluetoothAdapter success')
  96. _this.onBluetoothAdapterStateChange()
  97. _this.loading = true
  98. setTimeout(()=>{
  99. _this.toFindDev()
  100. },600)
  101. },
  102. fail(err){
  103. console.log(err,'openBluetoothAdapter error')
  104. _this.loading = false
  105. uni.showModal({
  106. title:'提示',
  107. content:'请开启手机蓝牙',
  108. showCancel: false,
  109. complete(e) {
  110. console.log(e)
  111. _this.statusStr = '请开启手机蓝牙'
  112. }
  113. })
  114. }
  115. })
  116. },
  117. toFindDev(){
  118. let _this = this
  119. _this.statusStr = '开始搜寻附近的电子秤,请确认设备已开启'
  120. uni.getBluetoothAdapterState({
  121. success(res) {
  122. console.log(res)
  123. if(res.available){
  124. // 开始搜寻附近的蓝牙外围设备
  125. _this.startBluetoothDevicesDiscovery()
  126. }else{
  127. _this.statusStr = '请开启手机蓝牙'
  128. }
  129. },
  130. fail(err) {
  131. console.log(err)
  132. }
  133. })
  134. },
  135. // 监听蓝牙状态
  136. onBluetoothAdapterStateChange(){
  137. let _this = this
  138. // 监听蓝牙适配器状态变化事件
  139. uni.onBluetoothAdapterStateChange(function (res) {
  140. console.log(res,'适配器变化')
  141. if(!res.available){
  142. // 关闭连接
  143. _this.statusStr = '蓝牙已关闭,请开启手机蓝牙'
  144. _this.connectedDeviceId = null
  145. _this.closeConnect()
  146. }else{
  147. if(!res.discovering && !_this.loading){
  148. _this.statusStr = '蓝牙已启用,请绑定设备'
  149. }
  150. }
  151. })
  152. },
  153. startBluetoothDevicesDiscovery(){
  154. let _this = this
  155. uni.startBluetoothDevicesDiscovery({
  156. services: [],
  157. success(res) {
  158. console.log(res)
  159. // 监听寻找到新设备的事件
  160. uni.onBluetoothDeviceFound(function (res) {
  161. console.log(res,'devices list')
  162. let devices = res.devices.filter(item => item.name == 'FAYA')
  163. console.log(devices,'devices list')
  164. if(devices.length){
  165. _this.statusStr = '已发现设备'
  166. _this.deviceList = res.devices
  167. _this.loading = false
  168. }
  169. })
  170. }
  171. })
  172. },
  173. // 连接蓝牙设备
  174. connectBlue(item){
  175. if(item){
  176. this.deviceId = item.deviceId
  177. }
  178. this.statusStr = '正在连接设备...'
  179. this.loading = true
  180. this.createBLEConnection()
  181. },
  182. // 断开蓝牙设备
  183. closeBlue(){
  184. this.statusStr = '连接已断开,请重新绑定设备'
  185. this.closeConnect()
  186. },
  187. // 开始连接指定设备
  188. createBLEConnection(){
  189. let _this = this
  190. uni.createBLEConnection({
  191. // 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
  192. deviceId:this.deviceId,
  193. success(res) {
  194. console.log(res)
  195. _this.connectedDeviceId = _this.deviceId
  196. // 获取连接设备的service服务
  197. setTimeout(()=>{
  198. _this.getBLEDeviceServices()
  199. },1000)
  200. },
  201. fail(err) {
  202. console.log(err,'createBLEConnection error')
  203. _this.statusStr = '设备连接失败,请检查后重试'
  204. _this.connectStatus = false
  205. _this.loading = false
  206. uni.$emit('blueConnectCallback',0)
  207. uni.hideLoading()
  208. }
  209. })
  210. },
  211. // 获取连接设备的service服务
  212. getBLEDeviceServices(){
  213. let _this = this
  214. uni.getBLEDeviceServices({
  215. // 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
  216. deviceId: _this.deviceId,
  217. success(res) {
  218. console.log('device services:', res.services)
  219. // _this.statusStr = '获取连接设备的service服务成功'
  220. _this.services = res.services
  221. /* 获取连接设备的所有特征值 */
  222. setTimeout(()=>{
  223. _this.getBLEDeviceCharacteristics()
  224. },500)
  225. // 停止搜索
  226. uni.stopBluetoothDevicesDiscovery({
  227. success: function(res) {
  228. console.log(res, '停止搜索')
  229. }
  230. })
  231. }
  232. })
  233. },
  234. // 获取连接设备的所有特征值
  235. getBLEDeviceCharacteristics(){
  236. let _this = this
  237. this.notifyServicweId = this.services[1].uuid
  238. uni.getBLEDeviceCharacteristics({
  239. deviceId: this.connectedDeviceId,
  240. serviceId: this.notifyServicweId,
  241. success: function(res) {
  242. console.log(res)
  243. // _this.statusStr = '获取连接设备的所有特征值成功'
  244. for (let i = 0; i < res.characteristics.length; i++) {
  245. let properties = res.characteristics[i].properties
  246. // 读id
  247. if(properties.notify&&!properties.read&&!properties.write){
  248. _this.readsId = res.characteristics[i].uuid
  249. }
  250. // 写id
  251. if(!properties.notify&&!properties.read&&properties.write){
  252. _this.writeId = res.characteristics[i].uuid
  253. }
  254. console.log(_this.readsId,_this.writeId, '蓝牙特征值 ==========')
  255. // 启用低功耗蓝牙设备特征值变化时的 notify 功能
  256. setTimeout(()=>{
  257. _this.notifyBLECharacteristicValueChange()
  258. },500)
  259. }
  260. },
  261. fail: function(res) {
  262. console.log(res)
  263. }
  264. })
  265. },
  266. // 启用低功耗蓝牙设备特征值变化时的 notify 功能
  267. notifyBLECharacteristicValueChange() {
  268. let that = this;
  269. uni.notifyBLECharacteristicValueChange({
  270. state: true,
  271. deviceId: that.connectedDeviceId,
  272. serviceId: that.notifyServicweId,
  273. characteristicId: that.readsId,
  274. success(res) {
  275. console.log(res,'notifyBLECharacteristicValueChange')
  276. that.statusStr = '连接成功,请投放称重'
  277. that.connectStatus = true
  278. that.loading = false
  279. uni.$emit('blueConnectCallback',1)
  280. uni.hideLoading()
  281. /*用来监听手机蓝牙设备的数据变化*/
  282. uni.onBLECharacteristicValueChange(function(res) {
  283. // console.log(res,'read data')
  284. that.balanceData = that.buf2string(res.value)
  285. that.$u.vuex('vuex_balanceData',that.balanceData)
  286. })
  287. // 该方法回调中可以用于处理连接意外断开等异常情况
  288. uni.onBLEConnectionStateChange(function (res) {
  289. console.log(`device ${res.deviceId} state has changed, connected: ${res.connected}`)
  290. if(!res.connected){
  291. uni.$emit('blueConnectClose',res)
  292. that.statusStr = '设备连接已断开,请重新连接'
  293. that.connectStatus = false
  294. that.loading = false
  295. }
  296. })
  297. },
  298. fail(res) {
  299. console.log(res, '启用低功耗蓝牙设备监听失败')
  300. that.statusStr = '设备连接失败,请点击重试'
  301. that.closeConnect()
  302. }
  303. })
  304. },
  305. /*转换成需要的格式*/
  306. buf2string(buffer) {
  307. let arr = Array.prototype.map.call(new Uint8Array(buffer), x => x)
  308. return arr.map((char, i) => {
  309. return String.fromCharCode(char);
  310. }).join('');
  311. },
  312. receiveData(buf) {
  313. return this.hexCharCodeToStr(this.ab2hex(buf))
  314. },
  315. /*转成二进制*/
  316. ab2hex (buffer) {
  317. let hexArr = Array.prototype.map.call(
  318. new Uint8Array(buffer), function (bit) {
  319. return ('00' + bit.toString(16)).slice(-2)
  320. }
  321. )
  322. return hexArr.join('')
  323. },
  324. /*转成可展会的文字*/
  325. hexCharCodeToStr(hexCharCodeStr) {
  326. let trimedStr = hexCharCodeStr.trim();
  327. let rawStr = trimedStr.substr(0, 2).toLowerCase() === '0x' ? trimedStr.substr(2) : trimedStr;
  328. let len = rawStr.length;
  329. let curCharCode;
  330. let resultStr = [];
  331. for (let i = 0; i < len; i = i + 2) {
  332. curCharCode = parseInt(rawStr.substr(i, 2), 16);
  333. resultStr.push(String.fromCharCode(curCharCode));
  334. }
  335. return resultStr.join('');
  336. },
  337. // 发送数据
  338. sendData(str) {
  339. let that = this;
  340. let dataBuffer = new ArrayBuffer(3)
  341. let dataView = new DataView(dataBuffer)
  342. dataView.setUint8(0, 0x02)
  343. dataView.setUint8(1, 0x41)
  344. dataView.setUint8(2, 0x03)
  345. let dataHex = that.ab2hex(dataBuffer);
  346. this.writeDatas = that.hexCharCodeToStr(dataHex);
  347. uni.writeBLECharacteristicValue({
  348. deviceId: that.connectedDeviceId,
  349. serviceId: that.notifyServicweId,
  350. characteristicId: that.writeId,
  351. value: dataBuffer,
  352. success: function (res) {
  353. console.log('发送数据成功:' + that.writeDatas)
  354. },
  355. fail: function (res) {
  356. console.log('发送失败:' + res)
  357. },
  358. complete: function (res) {
  359. }
  360. })
  361. },
  362. // 断开设备连接
  363. closeConnect() {
  364. let that = this;
  365. if (that.connectedDeviceId) {
  366. uni.closeBLEConnection({
  367. deviceId: that.connectedDeviceId,
  368. success: function(res) {
  369. console.log(res)
  370. that.deviceId = null
  371. that.closeBluetoothAdapter()
  372. },
  373. fail(res) {
  374. console.log(res)
  375. }
  376. })
  377. } else {
  378. that.closeBluetoothAdapter()
  379. }
  380. },
  381. // 关闭蓝牙模块
  382. closeBluetoothAdapter() {
  383. let that = this;
  384. uni.closeBluetoothAdapter({
  385. success: function(res) {
  386. console.log(res,'closeBluetoothAdapter')
  387. that.connectStatus = false
  388. that.loading = false
  389. that.balanceData = ''
  390. that.deviceList = []
  391. },
  392. fail: function(err) {
  393. }
  394. })
  395. },
  396. },
  397. onUnload() {
  398. this.closeConnect()
  399. }
  400. }
  401. </script>
  402. <style>
  403. .content{
  404. display: flex;
  405. align-items: center;
  406. justify-content: center;
  407. flex-direction: column;
  408. background-image: radial-gradient( #2ab4e5 0%, #0081c1 100%);
  409. height: 100vh;
  410. width: 100%;
  411. }
  412. .cz-box{
  413. text-align: center;
  414. background: #fff;
  415. border-radius: 300rpx;
  416. box-shadow: 3rpx 3rpx 10rpx rgba(0,0,0,0.4);
  417. }
  418. .cz-box > view{
  419. width: 250rpx;
  420. height: 250rpx;
  421. padding: 50rpx 50rpx 30rpx;
  422. display: flex;
  423. align-items: center;
  424. justify-content: center;
  425. flex-direction: column;
  426. }
  427. .tits{
  428. padding: 20rpx 0;
  429. color: #ef9f2e;
  430. }
  431. .devList{
  432. width: 80%;
  433. padding:10rpx 30rpx;
  434. }
  435. .bindDev{
  436. margin: 20rpx 0;
  437. padding: 20rpx 40rpx;
  438. background: rgba(255,255,255,0.8);
  439. box-shadow: 2rpx 2rpx 8rpx rgba(0,0,0,0.2);
  440. border-radius: 100rpx;
  441. color: #666666;
  442. }
  443. .devList > view{
  444. display: flex;
  445. align-items: center;
  446. color: #666666;
  447. border-radius: 20rpx;
  448. background: rgba(255,255,255,0.8);
  449. box-shadow: 2rpx 2rpx 5rpx rgba(0,0,0,0.2);
  450. }
  451. .devList > view .names{
  452. flex-grow: 1;
  453. padding: 15rpx 40rpx;
  454. }
  455. .devList > view .texts{
  456. font-size: 24rpx;
  457. }
  458. .devList > view .btns{
  459. text-align: center;
  460. padding: 15rpx 40rpx;
  461. color: #ff5500;
  462. }
  463. .turn{
  464. animation:turn 1s linear infinite;
  465. }
  466. @keyframes turn{
  467. 0%{-webkit-transform:rotate(0deg);}
  468. 25%{-webkit-transform:rotate(90deg);}
  469. 50%{-webkit-transform:rotate(180deg);}
  470. 75%{-webkit-transform:rotate(270deg);}
  471. 100%{-webkit-transform:rotate(360deg);}
  472. }
  473. </style>