index.vue 15 KB

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