index.vue 14 KB

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