index.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640
  1. <template>
  2. <div id="playing_container">
  3. <!-- 计费面板模块-->
  4. <div class="game_panel padding-top-sm">
  5. <van-row gutter="16">
  6. <van-col span="8" offset="2">
  7. <view class="text-sm">
  8. <text class="title">已游玩时间</text>
  9. </view>
  10. <view class="text-lg padding-top">
  11. <van-count-down :time="mode_item.time" format="mm:ss" use-slot auto-start @finish="time_out"
  12. @change="watch_time" class="control-count-down"
  13. >
  14. <text>{{ timeData.minutes }}:{{ timeData.seconds }}</text>
  15. </van-count-down>
  16. </view>
  17. </van-col>
  18. <van-col span="10" offset="4">
  19. <view class="text-sm">
  20. <text class="title">计费模式</text>
  21. <text class="type padding-left-sm">{{ mode_item.name }}</text>
  22. </view>
  23. <button class="cu-btn bg-red text-white margin-top-sm" @click="game_finished">
  24. <img src="https://img.shuimuai.com/m_duankainaohuan.png" class="cut_brain_icon" alt="">
  25. <text class="padding-lr cut_text text-sm">停止游玩</text>
  26. </button>
  27. </van-col>
  28. </van-row>
  29. </div>
  30. <!-- 设备状态-->
  31. <div class="game_status padding-tb">
  32. <van-row>
  33. <van-col span="10" offset="2">
  34. <div class="flex flex-direction align-center justify-center">
  35. <img src="https://img.shuimuai.com/web/touhuanzhuangtai_2.png" alt="" class="device_img">
  36. <text class="text-default">已经正确佩戴</text>
  37. </div>
  38. </van-col>
  39. <van-col span="10">
  40. <div class="flex flex-direction align-center justify-center">
  41. <van-row class="elc_power_container text-center">
  42. <van-col v-for="(item,index) in elc_power/25" :key="index" span="6">
  43. <img src="https://img.shuimuai.com/web/dianchi_3.png" alt="" class="device_elc">
  44. </van-col>
  45. </van-row>
  46. <text class="text-default">{{ elc_power }}%</text>
  47. <text class="text-default">设备电量</text>
  48. </div>
  49. </van-col>
  50. </van-row>
  51. </div>
  52. <!-- 图标模块-->
  53. <div class="ec_container">
  54. <view class="chart_view_first margin-tb-xl">
  55. <view class="bar">
  56. <view>
  57. <view class="line"></view>
  58. <view class="title">大脑状态</view>
  59. </view>
  60. <view class="label">
  61. <view>
  62. <view class="dot dot-orange"></view>
  63. <view class="name">Att(专注度)</view>
  64. </view>
  65. <view>
  66. <view class="dot dot-pink"></view>
  67. <view class="name">Med(放松度)</view>
  68. </view>
  69. </view>
  70. </view>
  71. <view class="chart">
  72. <mpvue-echarts :echarts="echarts" :onInit="attCharts" canvasId="demo-canvas"/>
  73. </view>
  74. </view>
  75. <view class="chart_view_second margin-tb-xl">
  76. <view class="bar">
  77. <view>
  78. <view class="line"></view>
  79. <view class="title">基本脑波</view>
  80. </view>
  81. <view class="label">
  82. <view>
  83. <view class="dot dot-blue"></view>
  84. <view class="name">Delta</view>
  85. </view>
  86. <view>
  87. <view class="dot dot-green"></view>
  88. <view class="name">Theta</view>
  89. </view>
  90. <view>
  91. <view class="dot dot-yellow"></view>
  92. <view class="name">Beta</view>
  93. </view>
  94. <view>
  95. <view class="dot dot-orange-yellow"></view>
  96. <view class="name">Alpha</view>
  97. </view>
  98. </view>
  99. </view>
  100. <view class="chart">
  101. <mpvue-echarts :echarts="echarts" :onInit="medCharts" canvasId="demo-canvas-1"/>
  102. </view>
  103. </view>
  104. </div>
  105. <!-- 窗口弹出-->
  106. <van-popup :show="pop_show" @close="close_pop" round :close-on-click-overlay="false"
  107. overlay
  108. z-index="99">
  109. <div class="err_container flex flex-direction align-center justify-around">
  110. <view>
  111. <text class="title">
  112. 本次游玩时间已到
  113. </text>
  114. </view>
  115. <view>
  116. <text class="sub-title">
  117. 您的{{ mode_item.name }}消费已用完
  118. </text>
  119. </view>
  120. <img src="https://img.shuimuai.com/web/sign_notimeJfish.png" class="err_img" alt="">
  121. <button class="cu-btn lg bg-primary text-white" @click="game_finished">查看报告</button>
  122. </div>
  123. </van-popup>
  124. <van-toast id="van-toast"/>
  125. </div>
  126. </template>
  127. <script>
  128. import mpvueEcharts from 'mpvue-echarts'
  129. import echarts from '../../../static/echarts.min';
  130. import util, {formatSeconds} from '../../utils/index'
  131. import bluetooth from "../../utils/bluetooth";
  132. import game_store from "@/store/game";
  133. import Toast from '../../../static/vant/toast/toast';
  134. import {gameAddLine, gameEnd} from "../../requests/game";
  135. var att_charts,
  136. med_charts,
  137. $this
  138. // 大脑图表初始化
  139. function initAttChart(canvas, width, height) {
  140. att_charts = echarts.init(canvas, null, {
  141. width: width,
  142. height: height
  143. });
  144. canvas.setChart(att_charts);
  145. var option = util.getLineOption([0], [0]); // ECharts 配置项
  146. att_charts.setOption(option);
  147. return att_charts; // 返回 chart 后可以自动绑定触摸操作
  148. }
  149. // 我的设备图表初始化
  150. function initMedChart(canvas, width, height) {
  151. med_charts = echarts.init(canvas, null, {
  152. width: width,
  153. height: height
  154. });
  155. canvas.setChart(med_charts);
  156. var option = util.getBaseOption([0], [0], [0], [0]); // ECharts 配置项
  157. med_charts.setOption(option);
  158. return med_charts; // 返回 chart 后可以自动绑定触摸操作
  159. }
  160. export default {
  161. name: "index_container",
  162. components: {
  163. mpvueEcharts
  164. },
  165. data() {
  166. return {
  167. // 使用类型 1次数 2时间 0未选择
  168. mode: 0,
  169. timeData: {},
  170. mode_item: {},
  171. pop_show: false,
  172. elc_power: 100,
  173. // 折线图
  174. echarts,
  175. attCharts: initAttChart,
  176. medCharts: initMedChart,
  177. user_info: {},
  178. //设备值
  179. _deviceId: "",
  180. _serviceId: "",
  181. _characteristicId: "",
  182. toy_index: 0,
  183. toy_id: 0,
  184. toy: {},
  185. toy_hex: "",
  186. play_time: 0,
  187. //图标数据集合
  188. att_list: [0],
  189. med_list: [0],
  190. delta_list: [],
  191. alpha_list: [],
  192. beta_list: [],
  193. theta_list: [],
  194. //判断是否结束游戏
  195. is_end: false,
  196. // 消耗的时间
  197. played_time: 0,
  198. played_time_text: ""
  199. }
  200. },
  201. methods: {
  202. //游戏结束方法
  203. game_finished() {
  204. //停止传输数据
  205. bluetooth.sendPause($this._deviceId, $this._serviceId, $this._characteristicId)
  206. bluetooth.sendEnd($this._deviceId, $this._serviceId, $this._characteristicId)
  207. //停止控制游戏
  208. bluetooth.shutdownSendControl($this._deviceId, $this._serviceId, $this._characteristicId)
  209. const countDown = $this.$mp.page.selectComponent('.control-count-down');
  210. countDown.pause();
  211. //取消监听低功耗蓝牙设备
  212. wx.offBLECharacteristicValueChange()
  213. Toast.success('已成功断开')
  214. //设置游戏状态为 停止游戏
  215. game_store.setters.setGameStatus(3)
  216. //游戏结束重置游戏时间
  217. wx.removeStorageSync('play_time')
  218. //游戏结束重置游戏模式
  219. game_store.setters.setMode(0)
  220. //删除游戏得id
  221. game_store.setters.removeToyHex()
  222. //游戏结束传送一下数据
  223. $this.post_data()
  224. $this.game_over()
  225. $this.to_report()
  226. },
  227. // 关闭弹窗
  228. close_pop() {
  229. $this.pop_show = false
  230. },
  231. // 时间到
  232. time_out() {
  233. // $this.pop_show = true
  234. $this.game_finished()
  235. },
  236. to_report() {
  237. mpvue.reLaunch({
  238. url: "/pages/report/main"
  239. })
  240. },
  241. start_game() {
  242. wx.onBLECharacteristicValueChange((characteristic) => {
  243. console.log('监听蓝牙时间获取数据')
  244. // console.log("收到" + $this.ab2hex(characteristic.value));
  245. let hexStr = $this.ab2hex(characteristic.value)
  246. let $data = bluetooth.get_big_data(hexStr)
  247. //连接玩具
  248. if ($data) {
  249. $this.att_list.push($data['att'])
  250. $this.med_list.push($data['med'])
  251. $this.delta_list.push(Math.round($data['delta'] / 10000))
  252. $this.alpha_list.push(Math.round($data['alpha'] / 1000000))
  253. $this.theta_list.push(Math.round($data['theta'] / 10000))
  254. $this.beta_list.push(Math.round($data['beta']) / 1000000)
  255. //通过专注放松度 画图
  256. let $option = util.getLineOption($this.att_list, $this.med_list)
  257. att_charts.setOption($option)
  258. //通过基本脑波发送数据
  259. let $base_option = util.getBaseOption($this.delta_list, $this.theta_list, $this.alpha_list, $this.beta_list)
  260. med_charts.setOption($base_option)
  261. }
  262. //获取设备电量
  263. let $power = bluetooth.get_device_elc(hexStr)
  264. if ($power) {
  265. $this.elc_power = $power
  266. }
  267. bluetooth.sendControl($this._deviceId, $this._serviceId, $this._characteristicId)
  268. })
  269. },
  270. // ArrayBuffer转16进度字符串示例
  271. ab2hex(buffer) {
  272. var hexArr = Array.prototype.map.call(
  273. new Uint8Array(buffer),
  274. function (bit) {
  275. return ('00' + bit.toString(16)).slice(-2)
  276. }
  277. )
  278. return hexArr.join('');
  279. },
  280. // 监听时间发生变动
  281. watch_time(e) {
  282. let $datetime = e.mp.detail
  283. if ($datetime.seconds.length == 1) {
  284. $datetime.seconds = '0' + $datetime.seconds
  285. }
  286. $this.timeData = $datetime
  287. $this.played_time += 1
  288. console.log("玩了:" + $this.played_time + "秒")
  289. //时间倒数
  290. if ($datetime.seconds == '00') {
  291. // 时间满一分钟 则提交一次数据
  292. // 添加折线图的点
  293. $this.post_data()
  294. }
  295. },
  296. // 往后端推送一次定时数据
  297. post_data() {
  298. let $params = {
  299. game_record_id: game_store.getters.getGameRecordId(),
  300. line: $this.att_list,
  301. line_med: $this.med_list
  302. }
  303. if (!$params.line && !$params.line_med) {
  304. return false
  305. }
  306. gameAddLine($params).then((res) => {
  307. let $data = res.data
  308. if ($data.code == 0) {
  309. $this.att_list = []
  310. $this.med_list = []
  311. $this.delta_list = []
  312. $this.alpha_list = []
  313. $this.theta_list = []
  314. $this.beta_list = []
  315. console.log('推送数据成功')
  316. } else {
  317. console.log('推送数据失败')
  318. }
  319. })
  320. },
  321. // 结束游戏
  322. game_over() {
  323. let $params = {
  324. game_record_id: game_store.getters.getGameRecordId(),
  325. type: $this.mode,
  326. play_time: $this.played_time
  327. }
  328. console.log("结束游戏参数", $params)
  329. //
  330. gameEnd($params).then((res) => {
  331. let $data = res.data
  332. $this.played_time = 0
  333. //设置未结束游戏
  334. $this.is_end = false
  335. })
  336. }
  337. }
  338. ,
  339. mounted() {
  340. let $deviceId = $this._deviceId = game_store.getters.getDeviceId()
  341. let $serviceId = $this._serviceId = game_store.getters.getServiceId()
  342. let $cId = $this._characteristicId = game_store.getters.getCharacterId()
  343. console.log("游戏开始:", $deviceId, $serviceId, $cId)
  344. //判断是否结束游戏
  345. if ($this.is_end == true) {
  346. $this.game_finished()
  347. } else {
  348. // 筛选 玩具id
  349. $this.toy_hex = game_store.getters.getToyHex()
  350. // bluetooth.sendConnect($this.toy_hex, $this._deviceId, $this._serviceId, $this._characteristicId)
  351. //筛选模式
  352. $this.mode = game_store.getters.getMode()
  353. let mode_list = [
  354. {
  355. id: 1,
  356. name: "次卡(10分钟)",
  357. time: 10 * 60 * 1000,
  358. err_title: "您的会员消费时间已用完",
  359. },
  360. {
  361. id: 2,
  362. name: "会员时间消费",
  363. time: 30 * 60 * 1000,
  364. err_title: "本次游玩时间已用完"
  365. }
  366. ]
  367. //获取用户游玩时间
  368. let $played_time = $this.play_time = game_store.getters.getPlayTime() ? game_store.getters.getPlayTime() : 0
  369. $this.mode_item = mode_list[$this.mode - 1]
  370. let $origin_time = mode_list[$this.mode - 1]['time']
  371. $this.mode_item['time'] = $origin_time - ($played_time * 1000)
  372. $this.start_game()
  373. //打开蓝牙监听
  374. bluetooth.watch_bluetooth_status($this)
  375. }
  376. },
  377. created() {
  378. $this = this;
  379. },
  380. onShow() {
  381. },
  382. onLoad(options) {
  383. if (options.end == 1) {
  384. $this.is_end = true
  385. }
  386. },
  387. onUnload() {
  388. if (!$this.is_end) {
  389. // 返回 的时候 暂停
  390. const countDown = $this.$mp.page.selectComponent('.control-count-down');
  391. countDown.pause();
  392. //停止传输数据
  393. bluetooth.sendPause($this._deviceId, $this._serviceId, $this._characteristicId)
  394. bluetooth.sendEnd($this._deviceId, $this._serviceId, $this._characteristicId)
  395. wx.offBLECharacteristicValueChange()
  396. //存储时间
  397. game_store.setters.setPlayTime($this.played_time)
  398. this.pop_show = false
  399. //设置未结束游戏
  400. $this.is_end = false
  401. }
  402. }
  403. }
  404. </script>
  405. <style>
  406. .van-count-down {
  407. font-weight: bold;
  408. font-size: 30px !important;
  409. color: white !important;
  410. }
  411. </style>
  412. <style scoped>
  413. #playing_container {
  414. width: 100%;
  415. background: linear-gradient(0deg, rgba(40, 157, 206, 0.51), rgba(135, 145, 226, 0.26));
  416. background-color: #46425E;
  417. padding: 5px;
  418. height: 750px;
  419. }
  420. .game_panel {
  421. width: 100%;
  422. height: 76px;
  423. background: #46425E;
  424. box-shadow: 0px 3px 4px 0px #302D43;
  425. border-radius: 11px;
  426. margin: 0px auto;
  427. }
  428. .game_panel .title {
  429. color: #9A96B7;
  430. }
  431. .game_panel .type {
  432. color: #FFFFFF;
  433. }
  434. .cut_brain_icon {
  435. width: 11px;
  436. height: 11px;
  437. }
  438. .device_img {
  439. width: 36px;
  440. height: 36px;
  441. }
  442. .text-default {
  443. color: #9A95B7;
  444. font-size: 10px;
  445. }
  446. /*电量显示*/
  447. .elc_power_container {
  448. width: 28px;
  449. border: #9A95B7 3px solid;
  450. border-radius: 5px;
  451. height: 22px;
  452. }
  453. .device_elc {
  454. height: 22px;
  455. width: 4px;
  456. }
  457. /* 节标题 */
  458. .bar {
  459. width: 100%;
  460. height: 15px;
  461. display: flex;
  462. align-items: center;
  463. justify-content: space-between;
  464. padding: 0 7px;
  465. box-sizing: border-box;
  466. margin: 11px 0;
  467. }
  468. .bar view {
  469. display: flex;
  470. align-items: center;
  471. justify-content: start;
  472. }
  473. .bar .line {
  474. width: 4px;
  475. height: 15px;
  476. background-color: #FFB400;
  477. margin-right: 7px;
  478. }
  479. .bar .title {
  480. color: #fff;
  481. font-size: 15px;
  482. }
  483. .label {
  484. color: #9A95B7;
  485. font-size: 10px;
  486. }
  487. /*点图*/
  488. .dot {
  489. width: 8px;
  490. height: 8px;
  491. border-radius: 50%;
  492. margin-right: 4px;
  493. margin-left: 15px;
  494. }
  495. .dot-orange {
  496. background: #FFB400;
  497. }
  498. .dot-pink {
  499. background: #D4327A;
  500. }
  501. .dot-blue {
  502. background: #00CCFF;
  503. }
  504. .dot-green {
  505. background: #0CDA2E;
  506. }
  507. .dot-yellow {
  508. background: #D1D310;
  509. }
  510. .dot-orange-yellow {
  511. background: #F8A117;
  512. }
  513. /* 图表 */
  514. #mychart-dom-multi-line {
  515. width: 100%;
  516. height: 175px;
  517. }
  518. #mychart-dom-multi-line-med {
  519. width: 100%;
  520. height: 100px;
  521. }
  522. .chart {
  523. width: 360px;
  524. height: 193px;
  525. background: #302D43;
  526. opacity: 0.6;
  527. border-radius: 10px;
  528. }
  529. /*弹窗模块*/
  530. .err_container {
  531. width: 260px;
  532. height: 300px;
  533. border-radius: 5px;
  534. }
  535. /*标题*/
  536. .err_container .title {
  537. font-size: 20px;
  538. font-weight: bold;
  539. color: #4C4C4C;
  540. line-height: 24px;
  541. }
  542. /*子标题*/
  543. .err_container .sub-title {
  544. font-size: 12px;
  545. font-family: Microsoft YaHei;
  546. font-weight: 400;
  547. color: #4B4B4B;
  548. line-height: 24px;
  549. }
  550. .err_img {
  551. width: 73px;
  552. height: 83px;
  553. }
  554. .chart_view_first {
  555. position: relative;
  556. bottom: 10px;
  557. }
  558. .chart_view_second {
  559. position: relative;
  560. bottom: 5px;
  561. }
  562. </style>