index.vue 11 KB

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