index.vue 12 KB

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