index.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628
  1. <template>
  2. <view class="bg">
  3. <view class="bgimg">
  4. <u-image width="622rpx" height="953rpx" src="/static/ldbg.png"></u-image>
  5. </view>
  6. <!-- 称重 -->
  7. <view class="content">
  8. <view @click="toHelp" class="tdrecord">使用帮助</view>
  9. <view class="cz-box" @click="toWork">
  10. <view :class="loading?'turn':''">
  11. <u-image width="100rpx" height="100rpx" src="/static/chengzhong.png"></u-image>
  12. <view class="tits">投放称重</view>
  13. </view>
  14. </view>
  15. <view class="bindDev" @click="toInit">
  16. {{statusStr}}
  17. </view>
  18. <view class="devList">
  19. <view v-for="item in deviceList" :key="item.deviceId">
  20. <view class="names">
  21. <view>设备名称:{{item.name}}</view>
  22. <view class="texts">MAC:{{item.deviceId}}</view>
  23. </view>
  24. <view class="btns" @click="connectBlue(item)" v-if="!connectStatus">点击连接</view>
  25. <view class="btns" @click="closeBlue('连接已断开,请重新连接设备')" v-else>断开连接</view>
  26. </view>
  27. </view>
  28. </view>
  29. </view>
  30. </template>
  31. <script>
  32. import {getLookUpDatas} from '@/api/data.js'
  33. import { getUserInfo } from '@/api/user.js'
  34. export default {
  35. data() {
  36. return {
  37. deviceList:[], // 设备列表
  38. deviceId: null,
  39. iosMac: null,
  40. connectedDeviceId: '',
  41. services: [],
  42. readsId:'',
  43. writeId:'',
  44. notifyServicweId: '',
  45. writeDatas: '',
  46. balanceData: '',
  47. hexstr: '',
  48. statusStr: '绑定电子秤',
  49. connectStatus: false ,// 设备连接状态
  50. loading: false ,// 正在连接
  51. }
  52. },
  53. onLoad() {
  54. let _this = this
  55. uni.$on('blueReConnect',function(){
  56. uni.showLoading({
  57. mask: true,
  58. title: '正在重连中...'
  59. })
  60. _this.connectBlue()
  61. })
  62. // 系统信息
  63. const sysinfo = uni.getSystemInfoSync();
  64. this.platform = sysinfo.platform
  65. console.log(sysinfo,'sysinfo')
  66. },
  67. onShow() {
  68. // 获取订单状态数据字典
  69. // this.getCodeList('RUBBISH_TYPE','vuex_rubbishType')
  70. this.getUserInfo()
  71. uni.getSetting({
  72. success(res) {
  73. if(!res.authSetting['scope.userLocation']){
  74. uni.authorize({
  75. scope: 'scope.userLocation',
  76. success() {
  77. console.log('scope.userLocation success')
  78. },
  79. fail(res) {
  80. console.log('scope.userLocation fail')
  81. }
  82. })
  83. }
  84. }
  85. })
  86. },
  87. onUnload() {
  88. uni.$off('blueReConnect')
  89. },
  90. methods: {
  91. // 获取用户信息
  92. getUserInfo(){
  93. getUserInfo().then(res => {
  94. if(res.status == 200){
  95. this.$u.vuex('vuex_userData', res.data);
  96. }
  97. })
  98. },
  99. // 获取数据字典
  100. getCodeList(code,key) {
  101. getLookUpDatas({
  102. type: code
  103. }).then(res => {
  104. if (res.status == 200) {
  105. this.$u.vuex(key, res.data)
  106. }
  107. })
  108. },
  109. // 使用帮助
  110. toHelp(){
  111. uni.navigateTo({
  112. url: '/pages/help/help'
  113. })
  114. },
  115. // 去认证用户并开始称重
  116. toWork(){
  117. let _this = this
  118. // 连接成功
  119. if(this.connectStatus){
  120. // ios 设备无法获取mac地址,请手动扫描电子秤的MAC条形码
  121. if(this.platform == 'ios'&&this.iosMac==null){
  122. uni.showModal({
  123. title:'提示',
  124. content: '苹果手机无法获取mac地址,请扫描电子秤的MAC二维码',
  125. confirmText: '去扫描',
  126. complete(e) {
  127. if(e.confirm){
  128. uni.scanCode({
  129. success(res) {
  130. console.log(res)
  131. _this.iosMac = res.result
  132. uni.navigateTo({
  133. url: '/pages/userAuth/userAuth?macAddress=' + _this.iosMac + '&id=' + _this.deviceId
  134. })
  135. }
  136. })
  137. }
  138. }
  139. })
  140. }else{
  141. // 安卓系统直接跳转
  142. uni.navigateTo({
  143. url: '/pages/userAuth/userAuth?macAddress=' + (this.platform == 'ios' ? _this.iosMac : _this.deviceId) + '&id=' + _this.deviceId
  144. })
  145. }
  146. }else{
  147. let hasDev = this.deviceList.length
  148. if(!this.loading){
  149. uni.showModal({
  150. title:'提示',
  151. content:hasDev ? '请先连接设备':'请先绑定设备',
  152. confirmText: hasDev ? '确定':'去绑定',
  153. complete(e) {
  154. console.log(e)
  155. if(e.confirm){
  156. if(hasDev == 1){
  157. _this.connectBlue(_this.deviceList[0])
  158. }
  159. if(hasDev == 0){
  160. _this.toInit()
  161. }
  162. }
  163. }
  164. })
  165. }
  166. uni.getBluetoothDevices({
  167. success(res) {
  168. console.log(res,'getBluetoothDevices')
  169. }
  170. })
  171. }
  172. },
  173. // 初始化蓝牙
  174. toInit(){
  175. let _this = this
  176. if(this.connectStatus || this.deviceList.length > 0 || this.loading){
  177. return
  178. }
  179. uni.openBluetoothAdapter({
  180. success(res) {
  181. console.log(res, 'openBluetoothAdapter success')
  182. _this.loading = true
  183. setTimeout(()=>{
  184. _this.toFindDev()
  185. },500)
  186. },
  187. fail(err){
  188. console.log(err,'openBluetoothAdapter error')
  189. _this.loading = false
  190. uni.showModal({
  191. title:'提示',
  192. content: _this.platform == 'ios' ? '请开启蓝牙(如果已开启,还是无法使用,请打开系统设置->微信->蓝牙开关再试)' : '请开启手机蓝牙',
  193. showCancel: false,
  194. complete(e) {
  195. console.log(e)
  196. _this.statusStr = '请开启手机蓝牙'
  197. }
  198. })
  199. }
  200. })
  201. _this.onBluetoothAdapterStateChange()
  202. },
  203. toFindDev(){
  204. let _this = this
  205. _this.statusStr = '开始搜寻附近的电子秤,请确认设备已开启'
  206. uni.getBluetoothAdapterState({
  207. success(res) {
  208. console.log(res)
  209. if(res.available){
  210. // 开始搜寻附近的蓝牙外围设备
  211. _this.startBluetoothDevicesDiscovery()
  212. }else{
  213. _this.statusStr = '请开启手机蓝牙'
  214. }
  215. },
  216. fail(err) {
  217. console.log(err)
  218. }
  219. })
  220. },
  221. // 监听蓝牙状态
  222. onBluetoothAdapterStateChange(){
  223. let _this = this
  224. // 监听蓝牙适配器状态变化事件
  225. uni.onBluetoothAdapterStateChange(function (res) {
  226. console.log(res,'适配器变化')
  227. if(!res.available){
  228. // 关闭连接
  229. _this.loading = false
  230. if(_this.connectedDeviceId){
  231. _this.closeBlue('蓝牙已关闭,请开启手机蓝牙')
  232. }else{
  233. _this.statusStr = '蓝牙已关闭,请开启手机蓝牙'
  234. }
  235. }else{
  236. if(!res.discovering && !_this.loading){
  237. _this.statusStr = _this.connectedDeviceId ? '蓝牙已启用,请连接设备':'蓝牙已启用,请绑定设备'
  238. }
  239. }
  240. })
  241. },
  242. startBluetoothDevicesDiscovery(){
  243. let _this = this
  244. uni.startBluetoothDevicesDiscovery({
  245. services: [],
  246. success(res) {
  247. console.log(res,'startBluetoothDevicesDiscovery')
  248. },
  249. fail(res){
  250. console.log(res,'startBluetoothDevicesDiscovery error')
  251. }
  252. })
  253. // 监听寻找到新设备的事件
  254. uni.onBluetoothDeviceFound(function (res) {
  255. console.log(res,'onBluetoothDeviceFound')
  256. let devices = res.devices.filter(item => item.name == 'FAYA')
  257. const hasDev = _this.deviceList.find(item => item.deviceId == res.devices[0].deviceId)
  258. console.log(devices,hasDev,'devices list')
  259. if(devices.length&&!hasDev){
  260. _this.statusStr = '已发现设备'
  261. _this.deviceList = _this.deviceList.concat(res.devices)
  262. _this.loading = false
  263. }
  264. })
  265. },
  266. // 连接蓝牙设备
  267. connectBlue(item){
  268. if(this.connectStatus){
  269. return
  270. }
  271. // ios 的deviceid 不是真正的mac 地址
  272. if(item){
  273. this.deviceId = item.deviceId
  274. }
  275. this.statusStr = '正在连接设备...'
  276. this.loading = true
  277. this.createBLEConnection()
  278. },
  279. // 断开蓝牙设备
  280. closeBlue(msg){
  281. let _this = this
  282. uni.closeBLEConnection({
  283. deviceId: _this.connectedDeviceId,
  284. success: function(res) {
  285. console.log(res,msg)
  286. _this.connectedDeviceId = null
  287. _this.statusStr = msg
  288. _this.connectStatus = false
  289. },
  290. fail(res) {
  291. console.log(res)
  292. }
  293. })
  294. },
  295. // 开始连接指定设备
  296. createBLEConnection(){
  297. let _this = this
  298. uni.createBLEConnection({
  299. // 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
  300. deviceId:this.deviceId,
  301. success(res) {
  302. console.log(res)
  303. _this.connectedDeviceId = _this.deviceId
  304. // 获取连接设备的service服务
  305. setTimeout(()=>{
  306. _this.getBLEDeviceServices()
  307. },1000)
  308. },
  309. fail(err) {
  310. console.log(err,'createBLEConnection error')
  311. _this.statusStr = '连接失败,请检查蓝牙是否开启后重试'
  312. _this.connectStatus = false
  313. _this.loading = false
  314. uni.$emit('blueConnectCallback',0)
  315. uni.hideLoading()
  316. }
  317. })
  318. },
  319. // 获取连接设备的service服务
  320. getBLEDeviceServices(){
  321. let _this = this
  322. uni.getBLEDeviceServices({
  323. // 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
  324. deviceId: _this.deviceId,
  325. success(res) {
  326. console.log('device services:', res.services)
  327. // _this.statusStr = '获取连接设备的service服务成功'
  328. _this.services = res.services
  329. /* 获取连接设备的所有特征值 */
  330. setTimeout(()=>{
  331. _this.getBLEDeviceCharacteristics()
  332. },500)
  333. // 停止搜索
  334. uni.stopBluetoothDevicesDiscovery({
  335. success: function(res) {
  336. console.log(res, '停止搜索')
  337. }
  338. })
  339. }
  340. })
  341. },
  342. // 获取连接设备的所有特征值
  343. getBLEDeviceCharacteristics(){
  344. let _this = this
  345. this.notifyServicweId = this.services[1].uuid
  346. uni.getBLEDeviceCharacteristics({
  347. deviceId: this.connectedDeviceId,
  348. serviceId: this.notifyServicweId,
  349. success: function(res) {
  350. console.log(res)
  351. // _this.statusStr = '获取连接设备的所有特征值成功'
  352. for (let i = 0; i < res.characteristics.length; i++) {
  353. let properties = res.characteristics[i].properties
  354. // 读id
  355. if(properties.notify&&!properties.read&&!properties.write){
  356. _this.readsId = res.characteristics[i].uuid
  357. }
  358. // 写id
  359. if(!properties.notify&&!properties.read&&properties.write){
  360. _this.writeId = res.characteristics[i].uuid
  361. }
  362. console.log(_this.readsId,_this.writeId, '蓝牙特征值 ==========')
  363. // 启用低功耗蓝牙设备特征值变化时的 notify 功能
  364. setTimeout(()=>{
  365. _this.notifyBLECharacteristicValueChange()
  366. },500)
  367. }
  368. },
  369. fail: function(res) {
  370. console.log(res)
  371. }
  372. })
  373. },
  374. // 启用低功耗蓝牙设备特征值变化时的 notify 功能
  375. notifyBLECharacteristicValueChange() {
  376. let that = this;
  377. uni.notifyBLECharacteristicValueChange({
  378. state: true,
  379. deviceId: that.connectedDeviceId,
  380. serviceId: that.notifyServicweId,
  381. characteristicId: that.readsId,
  382. success(res) {
  383. console.log(res,'notifyBLECharacteristicValueChange')
  384. that.statusStr = '连接成功,请投放称重'
  385. if(!that.connectStatus){
  386. uni.$emit('blueConnectCallback',1)
  387. that.connectStatus = true
  388. uni.hideLoading()
  389. }
  390. that.loading = false
  391. /*用来监听手机蓝牙设备的数据变化*/
  392. uni.onBLECharacteristicValueChange(function(res) {
  393. // console.log(res,'read data')
  394. that.balanceData = that.buf2string(res.value)
  395. that.$u.vuex('vuex_balanceData',that.balanceData)
  396. })
  397. // 该方法回调中可以用于处理连接意外断开等异常情况
  398. uni.onBLEConnectionStateChange(function (res) {
  399. // console.log(`device ${res.deviceId} state has changed, connected: ${res.connected}`)
  400. if(!res.connected&&that.connectedDeviceId){
  401. uni.$emit('blueConnectClose',res)
  402. that.statusStr = '连接已断开,请检查蓝牙或电子秤是否开启'
  403. that.connectStatus = false
  404. that.loading = false
  405. }
  406. })
  407. },
  408. fail(res) {
  409. console.log(res, '启用低功耗蓝牙设备监听失败')
  410. that.statusStr = '连接失败,请点击重试'
  411. that.closeConnect()
  412. }
  413. })
  414. },
  415. /*转换成需要的格式*/
  416. buf2string(buffer) {
  417. let arr = Array.prototype.map.call(new Uint8Array(buffer), x => x)
  418. return arr.map((char, i) => {
  419. return String.fromCharCode(char);
  420. }).join('');
  421. },
  422. receiveData(buf) {
  423. return this.hexCharCodeToStr(this.ab2hex(buf))
  424. },
  425. /*转成二进制*/
  426. ab2hex (buffer) {
  427. let hexArr = Array.prototype.map.call(
  428. new Uint8Array(buffer), function (bit) {
  429. return ('00' + bit.toString(16)).slice(-2)
  430. }
  431. )
  432. return hexArr.join('')
  433. },
  434. /*转成可展会的文字*/
  435. hexCharCodeToStr(hexCharCodeStr) {
  436. let trimedStr = hexCharCodeStr.trim();
  437. let rawStr = trimedStr.substr(0, 2).toLowerCase() === '0x' ? trimedStr.substr(2) : trimedStr;
  438. let len = rawStr.length;
  439. let curCharCode;
  440. let resultStr = [];
  441. for (let i = 0; i < len; i = i + 2) {
  442. curCharCode = parseInt(rawStr.substr(i, 2), 16);
  443. resultStr.push(String.fromCharCode(curCharCode));
  444. }
  445. return resultStr.join('');
  446. },
  447. // 发送数据
  448. sendData(str) {
  449. let that = this;
  450. let dataBuffer = new ArrayBuffer(3)
  451. let dataView = new DataView(dataBuffer)
  452. dataView.setUint8(0, 0x02)
  453. dataView.setUint8(1, 0x41)
  454. dataView.setUint8(2, 0x03)
  455. let dataHex = that.ab2hex(dataBuffer);
  456. this.writeDatas = that.hexCharCodeToStr(dataHex);
  457. uni.writeBLECharacteristicValue({
  458. deviceId: that.connectedDeviceId,
  459. serviceId: that.notifyServicweId,
  460. characteristicId: that.writeId,
  461. value: dataBuffer,
  462. success: function (res) {
  463. console.log('发送数据成功:' + that.writeDatas)
  464. },
  465. fail: function (res) {
  466. console.log('发送失败:' + res)
  467. },
  468. complete: function (res) {
  469. }
  470. })
  471. },
  472. // 断开设备连接
  473. closeConnect() {
  474. let that = this;
  475. if (that.connectedDeviceId) {
  476. uni.closeBLEConnection({
  477. deviceId: that.connectedDeviceId,
  478. success: function(res) {
  479. console.log(res)
  480. that.deviceId = null
  481. that.iosMac = null
  482. that.closeBluetoothAdapter()
  483. },
  484. fail(res) {
  485. console.log(res)
  486. }
  487. })
  488. } else {
  489. that.closeBluetoothAdapter()
  490. }
  491. },
  492. // 关闭蓝牙模块
  493. closeBluetoothAdapter() {
  494. let that = this;
  495. uni.closeBluetoothAdapter({
  496. success: function(res) {
  497. console.log(res,'closeBluetoothAdapter')
  498. that.connectStatus = false
  499. that.loading = false
  500. that.balanceData = ''
  501. that.deviceList = []
  502. that.deviceId = null
  503. that.iosMac = null
  504. },
  505. fail: function(err) {
  506. }
  507. })
  508. },
  509. },
  510. onUnload() {
  511. this.closeConnect()
  512. },
  513. onShareAppMessage() {
  514. },
  515. onShareTimeline() {
  516. }
  517. }
  518. </script>
  519. <style lang="less">
  520. // @import url("bg.less");
  521. .bg{
  522. height: 100vh;
  523. width: 100%;
  524. position: relative;
  525. background-color: #015a50;
  526. }
  527. .bgimg{
  528. position: absolute;
  529. z-index: 100;
  530. width: 100%;
  531. height: 100vh;
  532. top: 0;
  533. left: 0;
  534. display: flex;
  535. justify-content: center;
  536. align-items: center;
  537. }
  538. .content{
  539. display: flex;
  540. align-items: center;
  541. justify-content: center;
  542. flex-direction: column;
  543. height: 100vh;
  544. width: 100%;
  545. position: absolute;
  546. z-index: 1000;
  547. }
  548. .tdrecord{
  549. position: absolute;
  550. right: 0;
  551. top: 5%;
  552. background: rgba(255,255,255,0.6);
  553. border-radius: 150rpx 0 0 150rpx;
  554. box-shadow: 2rpx 2rpx 6rpx rgba(0,0,0,0.4);
  555. padding: 15rpx 20rpx 15rpx 30rpx;
  556. font-size: 26rpx;
  557. }
  558. .cz-box{
  559. text-align: center;
  560. background: #01c9b2;
  561. border-radius: 300rpx;
  562. box-shadow: 3rpx 3rpx 10rpx rgba(0,0,0,0.4);
  563. }
  564. .cz-box > view{
  565. width: 250rpx;
  566. height: 250rpx;
  567. padding: 50rpx 50rpx 30rpx;
  568. display: flex;
  569. align-items: center;
  570. justify-content: center;
  571. flex-direction: column;
  572. }
  573. .tits{
  574. padding: 20rpx 0;
  575. color: #FFFFFF;
  576. }
  577. .devList{
  578. width: 80%;
  579. padding:10rpx 30rpx;
  580. max-height: 50vh;
  581. overflow: auto;
  582. }
  583. .bindDev{
  584. margin: 20rpx 0;
  585. padding: 15rpx 40rpx;
  586. background: rgba(19,22,30,0.8);
  587. box-shadow: 2rpx 2rpx 8rpx rgba(0,0,0,0.2);
  588. border-radius: 100rpx;
  589. color: #FFFFFF;
  590. }
  591. .devList > view{
  592. display: flex;
  593. align-items: center;
  594. color: #666666;
  595. border-radius: 20rpx;
  596. background: rgba(255,255,255,0.8);
  597. box-shadow: 2rpx 2rpx 5rpx rgba(0,0,0,0.2);
  598. margin-bottom: 20rpx;
  599. }
  600. .devList > view .names{
  601. flex-grow: 1;
  602. padding: 15rpx 40rpx;
  603. }
  604. .devList > view .texts{
  605. font-size: 24rpx;
  606. }
  607. .devList > view .btns{
  608. text-align: center;
  609. padding: 15rpx 20rpx;
  610. color: #ff5500;
  611. }
  612. .turn{
  613. animation:turn 1s linear infinite;
  614. }
  615. @keyframes turn{
  616. 0%{-webkit-transform:rotate(0deg);}
  617. 25%{-webkit-transform:rotate(90deg);}
  618. 50%{-webkit-transform:rotate(180deg);}
  619. 75%{-webkit-transform:rotate(270deg);}
  620. 100%{-webkit-transform:rotate(360deg);}
  621. }
  622. </style>