index.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770
  1. <template>
  2. <view style="height: 100vh">
  3. <view v-if="!connected">
  4. <scroll-view class="main-container" scroll-y="true"
  5. :refresher-enabled="false">
  6. <view v-for="(item, index) in deviceListDataShow" :key="item.id" class="list-item" hover-class="list-item-hover"
  7. hover-start-time="0" hover-stay-time="100" @click="listViewTap(item.id)">
  8. <image v-if="item.manufacturer==='eciot'" src="/static/img/ecble.png" class="list-item-img"></image>
  9. <image v-else src="/static/img/ble.png" class="list-item-img"></image>
  10. <text class="list-item-name">{{item.name}}</text>
  11. <image v-if="item.rssi >= -41" src="/static/img/s5.png" mode="aspectFit" class="list-item-rssi-img"></image>
  12. <image v-else-if="item.rssi >= -55" src="/static/img/s4.png" mode="aspectFit" class="list-item-rssi-img"></image>
  13. <image v-else-if="item.rssi >= -65" src="/static/img/s3.png" mode="aspectFit" class="list-item-rssi-img"></image>
  14. <image v-else-if="item.rssi >= -75" src="/static/img/s2.png" mode="aspectFit" class="list-item-rssi-img"></image>
  15. <image v-else="item.rssi < -75" src="/static/img/s1.png" mode="aspectFit" class="list-item-rssi-img"></image>
  16. <text class="list-item-rssi">{{item.rssi}}</text>
  17. <view class="list-item-line"></view>
  18. </view>
  19. <u-popup :show="showSendData" >
  20. <view class="slot-content">
  21. <view>
  22. <u--input
  23. :placeholder="i18('请输入值')"
  24. border="surround"
  25. v-model="sendData"
  26. ></u--input>
  27. </view>
  28. <view style="margin:10px;text-decoration: underline;margin-bottom: 0px" @click="sendLanyaData">
  29. <u-button>发送</u-button>
  30. </view>
  31. </view>
  32. </u-popup>
  33. <view v-if="deviceListDataShow.length==0" class="notice"> - {{ $t('buletooth.nodevice') }} -</view>
  34. <view class="gap"></view>
  35. </scroll-view>
  36. </view>
  37. <view v-if="connected">
  38. <view class="text-area">
  39. <u--form v-if="isCompanyUser()" style="width: 100%;"
  40. labelPosition="left"
  41. ref="uForm"
  42. >
  43. <u-form-item
  44. label="WIFI名称:"
  45. borderBottom
  46. labelWidth="auto"
  47. @click="openChooseWifi"
  48. ref="item1"
  49. >
  50. <u--input
  51. v-model="SSID"
  52. disabled
  53. disabledColor="#ffffff"
  54. placeholder="请选择wifi:"
  55. border="none"
  56. ></u--input>
  57. <u-icon
  58. slot="right"
  59. name="arrow-right"
  60. ></u-icon>
  61. </u-form-item>
  62. <u-form-item
  63. label="密码:"
  64. borderBottom
  65. ref="item1"
  66. >
  67. <u--input
  68. v-model="password"
  69. border="none"
  70. ></u--input>
  71. </u-form-item>
  72. </u--form>
  73. <u--form v-else style="width: 100%;"
  74. labelPosition="left"
  75. ref="uForm"
  76. >
  77. <u-form-item
  78. label="WIFI名称:"
  79. borderBottom
  80. labelWidth="auto"
  81. @click="openChooseWifi"
  82. ref="item1"
  83. >
  84. <u--input
  85. v-model="SSID"
  86. disabled
  87. disabledColor="#ffffff"
  88. placeholder="请选择wifi:"
  89. border="none"
  90. ></u--input>
  91. <u-icon
  92. slot="right"
  93. name="arrow-right"
  94. ></u-icon>
  95. </u-form-item>
  96. <u-form-item
  97. label="密码:"
  98. borderBottom
  99. ref="item1"
  100. >
  101. <u--input
  102. v-model="password"
  103. border="none"
  104. ></u--input>
  105. </u-form-item>
  106. <u-form-item
  107. label="二维码ID:"
  108. borderBottom
  109. ref="item1"
  110. labelWidth="auto"
  111. >
  112. <u--input
  113. v-model="qrcodeid"
  114. border="none"
  115. ></u--input>
  116. </u-form-item>
  117. <u-form-item
  118. @click="showProductList = true"
  119. label="产品类型:"
  120. borderBottom
  121. ref="item1"
  122. labelWidth="auto"
  123. >
  124. <u--input disabled
  125. v-model="productName"
  126. border="none"
  127. ></u--input>
  128. </u-form-item>
  129. </u--form>
  130. </view>
  131. <view style="margin:10px">
  132. <u-button text="开始配网" v-if="isCompanyUser()" @click="doConnectUser(1)" size="small" type="primary"></u-button>
  133. <u-button text="开始配网" v-else @click="doConnect(2)" size="small" type="primary"></u-button>
  134. </view>
  135. <u-picker @cancel="showWiftList=false" @confirm="chooseWifi" :show="showWiftList" :columns="wifiList"></u-picker>
  136. <u-picker @cancel="showProductList=false" keyName="text" @confirm="chooseProduct" :show="showProductList" :columns="chooseProductList"></u-picker>
  137. </view>
  138. </view>
  139. </template>
  140. <script>
  141. import authObj from '@/plugins/auth.js';
  142. // #ifdef APP
  143. import ecUI from '@/utils/ecUI.js'
  144. import ecBLE from '@/utils/ecBLE/ecBLE.js'
  145. // #endif
  146. // #ifdef MP
  147. const ecUI = require('@/utils/ecUI.js')
  148. const ecBLE = require('@/utils/ecBLE/ecBLE.js')
  149. // #endif
  150. import i18 from '@/utils/i18.js'
  151. let ctx
  152. let deviceListData = []
  153. export default {
  154. data() {
  155. return {
  156. showProductList:false,
  157. showPwd:false,
  158. rightPwd:"",
  159. pwd:"",
  160. timer:"",
  161. buleid:"",
  162. deviceListDataShow: [],
  163. showTimer:null,
  164. connected:false,
  165. uuid:"",
  166. showDeviceNo:false,
  167. inputDeviceNo:"",
  168. commonCode:"",
  169. showSendData:false,
  170. sendData:"",
  171. qrcodeid:"",
  172. productName:"",
  173. deviceno:"",
  174. SSID:"",
  175. password:"",
  176. showWiftList:false,
  177. productId:56,
  178. chooseProductList:[[ {
  179. id:56,text:"3"
  180. },
  181. {
  182. id:56,text:"4"
  183. },
  184. {
  185. id:57,text:"5"
  186. }
  187. ]],
  188. wifiList: [
  189. []
  190. ],
  191. }
  192. },
  193. onLoad() {
  194. uni.setNavigationBarTitle({
  195. title: "蓝牙配网"
  196. })
  197. this.deviceno = this.generateTimestamp();
  198. ecUI.showLoading("正在初始化蓝牙模块")
  199. ctx = this
  200. clearInterval(this.timer);
  201. this.timer = setInterval(() => {
  202. ctx.deviceListDataShow = JSON.parse(JSON.stringify(deviceListData))
  203. }, 800)
  204. console.log(this.commonCode)
  205. this.productName = this.chooseProductList[0][0].text;
  206. },
  207. onUnload(){
  208. ecBLE.stopBluetoothDevicesDiscovery();
  209. ecBLE.closeBLEConnection()
  210. },
  211. onShow() {
  212. if(this.showTimer!= null){
  213. clearTimeout(this.showTimer);
  214. }
  215. this.showTimer = setTimeout(() => {
  216. ctx.openBluetoothAdapter()
  217. }, 100)
  218. },
  219. methods: {
  220. isCompanyUser(){
  221. return authObj.authRoleAdmin(["companymgr"]) || authObj.authRoleAdmin(["companyuser"]);
  222. },
  223. chooseProduct(e){
  224. this.productId = e.value[0].id;
  225. this.productName = e.value[0].text;
  226. this.showProductList= false;
  227. },
  228. generateTimestamp() {
  229. const date = new Date();
  230. const year = date.getFullYear().toString().substr(2);
  231. const month = date.getMonth() + 1;
  232. const day = date.getDate();
  233. const hours = date.getHours();
  234. const minutes = date.getMinutes();
  235. // 生成6位随机数字
  236. const randomNum = Math.floor(Math.random() * 900000) + 100000;
  237. // 将数字拼接成字符串
  238. const timestamp = `${year}${month < 10 ? '0' + month : month}${day < 10 ? '0' + day : day}${hours}${minutes < 10 ? '0' + minutes : minutes}${randomNum}`;
  239. return timestamp;
  240. },
  241. getAuth(){
  242. wx.getSetting({
  243. success(res) {
  244. if (!res.authSetting['scope.userLocation']) {
  245. wx.authorize({
  246. scope: 'scope.userLocation',
  247. success () {
  248. // 用户已经同意小程序使用录音功能,后续调用 wx.startRecord 接口不会弹窗询问
  249. }
  250. })
  251. }
  252. }
  253. })
  254. },
  255. chooseWifi(e){
  256. this.SSID = e.value[0];
  257. this.showWiftList= false;
  258. },
  259. openChooseWifi(){
  260. if(this.wifiList[0].length == 0){
  261. this.getWifiList();
  262. }else{
  263. this.showWiftList = true;
  264. }
  265. },
  266. openWifi(){
  267. let self = this;
  268. // #ifdef MP-WEIXIN
  269. wx.startWifi({
  270. success(res) {
  271. console.log(res);
  272. // self.getWifiList();
  273. },
  274. fail(res) {
  275. console.log(res)
  276. uni.showToast({
  277. title: '请打开WIFI',
  278. icon: 'none',
  279. duration: 3000
  280. });
  281. },
  282. })
  283. // #endif
  284. },
  285. getWifi(){
  286. // #ifdef MP-WEIXIN
  287. var that = this
  288. wx.getConnectedWifi({
  289. success(res) {
  290. console.log(res)
  291. that.BSSID = res.wifi.BSSID
  292. that.WIFIName = res.wifi.SSID
  293. },
  294. fail(res) {
  295. console.log(res)
  296. //报错的相关处理
  297. },
  298. })
  299. // #endif
  300. },
  301. getWifiList(){
  302. // #ifdef MP-WEIXIN
  303. var that = this
  304. uni.showLoading();
  305. wx.getWifiList({
  306. success(res) {
  307. console.log(res)
  308. wx.onGetWifiList(function(res) {
  309. that.showWiftList = true;
  310. uni.hideLoading();
  311. console.log("获取wifi列表");
  312. that.wifiList = [[]];
  313. console.log(res.wifiList); //在这里提取列表数据
  314. //通过遍历将WIFI名字存入集合,以便下卡框等组件使用
  315. for (var i = 0; i < res.wifiList.length; i++) {
  316. that.wifiList[0].push(res.wifiList[i].SSID)
  317. }
  318. })
  319. },
  320. fail(res) {
  321. console.log(res)
  322. uni.showToast({
  323. title: '获取wifi失败,请检查wifi',
  324. icon: 'none',
  325. duration: 2000
  326. });
  327. },
  328. })
  329. // #endif
  330. },
  331. doConnectUser(){
  332. if(this.SSID == ""){
  333. uni.showToast({
  334. title: '请选择WIFI',
  335. icon: 'none',
  336. duration: 3000
  337. });
  338. return;
  339. }
  340. if(this.password == ""){
  341. uni.showToast({
  342. title: '请输入wifi密码',
  343. icon: 'none',
  344. duration: 3000
  345. });
  346. return;
  347. }
  348. /**
  349. * ID:XXX+回车换行(设备编号)
  350. * QR:XXXX+回车换行(二维码ID)
  351. * ssid:WiFi名字+回车换行
  352. * psd:wifi密码+回车换行
  353. * 最后+OK
  354. */
  355. let self = this;
  356. let endStr = "$$";
  357. ecUI.showLoading("正在配置网络信息")
  358. setTimeout(function(){
  359. self.sendBlueData("ssid:"+self.SSID+endStr);
  360. },400);
  361. setTimeout(function(){
  362. self.sendBlueData("psd:"+self.password+endStr);
  363. },600);
  364. setTimeout(function(){
  365. self.sendBlueData("OK");
  366. },800);
  367. },
  368. doConnect(){
  369. if(this.SSID == ""){
  370. uni.showToast({
  371. title: '请选择WIFI',
  372. icon: 'none',
  373. duration: 3000
  374. });
  375. return;
  376. }
  377. if(this.password == ""){
  378. uni.showToast({
  379. title: '请输入wifi密码',
  380. icon: 'none',
  381. duration: 3000
  382. });
  383. return;
  384. }
  385. if(this.qrcodeid == ""){
  386. uni.showToast({
  387. title: '请输入二维码ID',
  388. icon: 'none',
  389. duration: 3000
  390. });
  391. return;
  392. }
  393. if(this.deviceno == ""){
  394. uni.showToast({
  395. title: '请输入设备编号',
  396. icon: 'none',
  397. duration: 3000
  398. });
  399. return;
  400. }
  401. /**
  402. * ID:XXX+回车换行(设备编号)
  403. * QR:XXXX+回车换行(二维码ID)
  404. * ssid:WiFi名字+回车换行
  405. * psd:wifi密码+回车换行
  406. * 最后+OK
  407. */
  408. let self = this;
  409. let endStr = "$$";
  410. ecUI.showLoading("正在配置网络信息")
  411. setTimeout(function(){
  412. self.sendBlueData("ID:"+self.deviceno+endStr);
  413. },200);
  414. setTimeout(function(){
  415. self.sendBlueData("QR:"+self.qrcodeid+endStr);
  416. },400);
  417. setTimeout(function(){
  418. self.sendBlueData("ssid:"+self.SSID+endStr);
  419. },600);
  420. setTimeout(function(){
  421. self.sendBlueData("psd:"+self.password+endStr);
  422. },800);
  423. setTimeout(function(){
  424. self.sendBlueData("pid:"+self.productId+endStr);
  425. },1000);
  426. setTimeout(function(){
  427. self.sendBlueData("OK");
  428. },1200);
  429. },
  430. stringToHex(str) {
  431. let hex = '';
  432. for (let i = 0; i < str.length; i++) {
  433. const char = str.charCodeAt(i);
  434. const hexChar = char.toString(16).padStart(2, '0');
  435. hex += hexChar;
  436. }
  437. return hex;
  438. },
  439. doByTime(func,time){
  440. setTimeout(function (){
  441. func();
  442. },time);
  443. },
  444. sendLanyaData(){
  445. this.$modal.showToast("正在发送");
  446. this.sendBlueData(this.sendData);
  447. },
  448. i18(text){
  449. return text;
  450. },
  451. cancel(){
  452. this.showPwd = false;
  453. uni.navigateBack({
  454. });
  455. },
  456. resetPwd(){
  457. let self = this;
  458. if(!this.inputDeviceNo){
  459. self.$modal.showToast("请输入序列号");
  460. return;
  461. }
  462. let uuidRight = false;
  463. if(this.inputDeviceNo == this.commonCode || this.uuid == this.inputDeviceNo){
  464. uuidRight = true;
  465. }
  466. if(!uuidRight){
  467. self.$modal.showToast("序列号有误");
  468. return;
  469. }
  470. if(uuidRight){
  471. this.$modal.confirm("密码将被重置为123456").then(res=>{
  472. setPwd("123456")
  473. self.$modal.showToast("密码修改成功");
  474. this.rightPwd = "123456";
  475. self.loginSuccess();
  476. });
  477. }
  478. },
  479. getBeijingTime() {
  480. const date = new Date();
  481. const utcTime = date.getTime() + (date.getTimezoneOffset() * 60 * 1000);
  482. const beijingTime = new Date(utcTime + (8 * 60 * 60 * 1000));
  483. return beijingTime;
  484. },
  485. generateUniqueNumber(date) {
  486. let dateString = date.toISOString().slice(0, 10).replace(/-/g, '');
  487. console.log(dateString)
  488. let hash = w_md5.hex_md5_32(dateString);
  489. console.log(hash);//32位小写
  490. let str = "";
  491. for (let i = 0; i < 6; i++) {
  492. const c = hash.charCodeAt(i);
  493. str = str+""+c+""
  494. }
  495. return str.substr(0,6);
  496. },
  497. goBack(){
  498. uni.navigateBack({
  499. });
  500. },
  501. $t(title){
  502. return title;
  503. },
  504. inputPwd(){
  505. if(!this.pwd ){
  506. this.$modal.showToast(this.$t('buletooth.errpwd'));
  507. }else{
  508. if(this.rightPwd && this.rightPwd === this.pwd){
  509. this.loginSuccess();
  510. }else{
  511. this.$modal.showToast(this.$t('buletooth.errpwd'));
  512. }
  513. }
  514. },
  515. loginSuccess(){
  516. this.showPwd = false;
  517. this.showDeviceNo = false;
  518. uni.setStorageSync("pwd",this.rightPwd);
  519. uni.setStorageSync('blueid', this.buleid);
  520. this.pwd = "";
  521. ecBLE.stopBluetoothDevicesDiscovery();
  522. uni.navigateTo({
  523. url: '/pages/weitiandi/bluetooth/status'
  524. });
  525. },
  526. getLocalPwd(){
  527. let pwd = uni.getStorageSync("pwd");
  528. return pwd;
  529. },
  530. sendBlueData(tempSendData){
  531. tempSendData = this.stringToHex(tempSendData);
  532. let data = tempSendData
  533. .replace(/\s*/g, '')
  534. .replace(/\n/g, '')
  535. .replace(/\r/g, '')
  536. console.log("写入数据:"+data);
  537. ecBLE.writeBLECharacteristicValue(data, true)
  538. },
  539. listViewTap(id){
  540. let self = this;
  541. ecUI.showLoading("正在连接蓝牙")
  542. ecBLE.onBLEConnectionStateChange(res => {
  543. console.log(res);
  544. if (res.ok) {
  545. self.connected = true;
  546. self.openWifi();
  547. ecUI.hideLoading()
  548. self.showSendData = true;
  549. ecBLE.stopBluetoothDevicesDiscovery();
  550. //
  551. } else {
  552. ecUI.hideLoading()
  553. this.$modal.showToast("请检查是否配置成功");
  554. }
  555. });
  556. //receive data
  557. ecBLE.onBLECharacteristicValueChange((str, strHex) => {
  558. console.log("数据来了")
  559. let isCheckRevHex = true;
  560. let data =
  561. (isCheckRevHex ? strHex.replace(/[0-9a-fA-F]{2}/g, ' $&') : str)
  562. console.log(data)
  563. self.$modal.closeLoading();
  564. data = parseDataObj(data);
  565. })
  566. self.connected = false;
  567. ecBLE.createBLEConnection(id);
  568. setTimeout(function (){
  569. if(!self.connected){
  570. self.$modal.showToast(i18('连接失败'));
  571. self.startBluetoothDevicesDiscovery()
  572. }
  573. },10000);
  574. },
  575. showInputPwd(){
  576. this.showPwd = true;
  577. },
  578. messageCallback(data){
  579. let self = this;
  580. console.log(data);
  581. let type = data.type;
  582. let real_data = data.real_data;
  583. if(type == 253){
  584. self.$modal.closeLoading();
  585. self.uuid = real_data.substr(0,6);
  586. }
  587. self.$forceUpdate();
  588. console.log('收到服务器内容:' + JSON.stringify(data));
  589. },
  590. forgetPwd(){
  591. this.$modal.loading("正在读取设备ID");
  592. getUUID()
  593. this.showDeviceNo = true;
  594. },
  595. openBluetoothAdapter() {
  596. let self = this;
  597. ecBLE.onBluetoothAdapterStateChange(res => {
  598. ecUI.hideLoading()
  599. if (res.ok) {
  600. ctx.startBluetoothDevicesDiscovery()
  601. } else {
  602. ecUI.showModal(
  603. this.$t('buletooth.tip'),
  604. `Bluetooth adapter error | ${res.errCode} | ${res.errMsg}`,
  605. () => {
  606. }
  607. )
  608. }
  609. })
  610. ecBLE.openBluetoothAdapter()
  611. },
  612. startBluetoothDevicesDiscovery() {
  613. ecBLE.stopBluetoothDevicesDiscovery();
  614. console.log('start search')
  615. ecBLE.onBluetoothDeviceFound(res => {
  616. let isRight = true;
  617. // if(res.name.startsWith('BT_') || res.name.startsWith('FC41D')){
  618. // isRight = true;
  619. // }
  620. if(!isRight){
  621. return;
  622. }
  623. for (const item of deviceListData) {
  624. if (item.id === res.id) {
  625. item.name = res.name
  626. item.rssi = res.rssi
  627. return
  628. }
  629. }
  630. let manufacturer = ''
  631. if (res.name.length === 11 && res.name.startsWith('@')) {
  632. manufacturer = 'eciot'
  633. }
  634. if (res.name.length === 15 && res.name.startsWith('BT_')) {
  635. manufacturer = 'eciot'
  636. }
  637. manufacturer = 'eciot'
  638. deviceListData.push({
  639. id: res.id,
  640. name: res.name,
  641. rssi: res.rssi,
  642. manufacturer,
  643. })
  644. })
  645. ecBLE.startBluetoothDevicesDiscovery()
  646. },
  647. }
  648. }
  649. </script>
  650. <style>
  651. .main-container {
  652. height: 100vh;
  653. }
  654. .list-item {
  655. height: 57px;
  656. position: relative;
  657. }
  658. .list-item-hover {
  659. background-color: #e5e4e9;
  660. }
  661. .list-item-img {
  662. position: absolute;
  663. width: 36px;
  664. height: 36px;
  665. left: 20px;
  666. top: 10px;
  667. }
  668. .list-item-name {
  669. position: absolute;
  670. font-size: 22px;
  671. left: 76px;
  672. top: 0px;
  673. line-height: 56px;
  674. }
  675. .list-item-rssi-img {
  676. position: absolute;
  677. width: 20px;
  678. height: 20px;
  679. right: 20px;
  680. top: 13px;
  681. }
  682. .list-item-rssi {
  683. position: absolute;
  684. width: 40px;
  685. height: 20px;
  686. right: 10px;
  687. top: 33px;
  688. font-size: 12px;
  689. font-weight: bold;
  690. display: flex;
  691. justify-content: center;
  692. }
  693. .list-item-line {
  694. position: absolute;
  695. height: 1px;
  696. width: 100vw;
  697. left: 20px;
  698. top: 56px;
  699. background-color: #c6c6c8;
  700. }
  701. .notice {
  702. display: flex;
  703. justify-content: center;
  704. align-items: center;
  705. margin-top: 10px;
  706. font-size: 13px;
  707. color: #909399;
  708. }
  709. .gap {
  710. height: 57px;
  711. }
  712. .text-area {
  713. display: flex;
  714. justify-content: center;
  715. background: white;
  716. width: 100%;
  717. height: 100%;
  718. }
  719. </style>