deviceInfo.nvue 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173
  1. <template>
  2. <view class="infoBox">
  3. <image class="content-bg" src="/static/device/devicebg.png" mode="scaleToFill"></image>
  4. <view class="pageContent">
  5. <view class="status-bar" :style="{height: statusBarHeight + 'px'}"></view>
  6. <view class="customHead">
  7. <view class="back-wrap" @click="goBack">
  8. <image src="/static/public/back.png" mode="aspectFill" class="backimg"></image>
  9. </view>
  10. <text class="customTitle">{{picMode===1?'我的艾灸椅':'穴位编辑'}}</text>
  11. <view class="headRight">
  12. <view class="userSwitchBtn" @click="goUserManage">
  13. <text class="userSwitchTxt">{{currentUserName || '选择用户'}}</text>
  14. </view>
  15. <navigator :url="'/pages/device/detail/detail?name='+deviceName+'&deviceId='+deviceId+'&rssi='+rssi"
  16. class="plus">
  17. <image v-if="picMode===1" src="/static/public/view-list.png" mode="aspectFill" class="menuimg"></image>
  18. </navigator>
  19. </view>
  20. </view>
  21. <scroll-view class="boxs" scroll-y="true">
  22. <view class="proBox" v-if="picMode == 1">
  23. <image class="proimg" src="/static/device/aijiuyi2.png" mode="aspectFill"></image>
  24. <view class="pointbox" v-if="deviceStatus == 3">
  25. <view class="pointContainer">
  26. <text class="pointLabel" v-if="acupointList.length > 0 && curCaseIndex < acupointList.length">{{acupointList[curCaseIndex].name}}</text>
  27. </view>
  28. </view>
  29. <text class="prostatus">蓝牙{{linked?'已':'未'}}连接</text>
  30. </view>
  31. <!-- 座椅角度 -->
  32. <view class="angleSection" v-if="picMode == 1">
  33. <text class="angleLabel">座椅角度(拖动滑块调整)</text>
  34. <l-sliderRange ref="slideRange" :anglenum="chairAngle" :min="90" :max="150" :step="15" @change="onSliderAngleChange"></l-sliderRange>
  35. </view>
  36. <!-- 模式选择 -->
  37. <view class="controlMode" v-if="picMode == 1">
  38. <text class="modetxt">选择模式</text>
  39. <view class="modechange" @click="isShowDrawer2 = true">
  40. <text class="modeName">{{modelist[modeType]}}</text>
  41. <view class="changeBtn">
  42. <text class="changetxt">切换</text>
  43. <image class="changeinmg" src="/static/device/change.png" mode="aspectFill"></image>
  44. </view>
  45. </view>
  46. </view>
  47. <!-- 方案选择 -->
  48. <view class="planSection" v-if="modeType != 0 && picMode == 1">
  49. <text class="planSectionTitle">选择方案</text>
  50. <view class="planCard" @click="showPlanDrawer">
  51. <view class="planCardLeft">
  52. <text class="planCardName">{{selectedPlan ? selectedPlan.name : '点击选择方案'}}</text>
  53. <text class="planCardDesc" v-if="selectedPlan && selectedPlan.description">{{selectedPlan.description}}</text>
  54. </view>
  55. <view class="planCardRight">
  56. <text class="planCardArrow">›</text>
  57. </view>
  58. </view>
  59. </view>
  60. <!-- 其他功能 -->
  61. <view class="otherSetting" v-if="modeType != 0 && picMode == 1">
  62. <text class="otherTxt">其他功能</text>
  63. <view class="func">
  64. <navigator v-if="modeType == 3" url="/pages/device/mycases/mycases" class="funcitem" hover-class="none">
  65. <image class="funcimg" src="/static/device/gongneng3.png" mode="aspectFill"></image>
  66. <text class="functxt">我的方案</text>
  67. </navigator>
  68. <navigator :url="`/pages/device/moxibustion/moxibustion?p1=${otherSetting.aijiuNum}&tab=p1`" class="funcitem" hover-class="none">
  69. <image class="funcimg" src="/static/device/gongneng1.png" mode="aspectFill"></image>
  70. <text class="functxt">艾灸余量</text>
  71. </navigator>
  72. <navigator :url="`/pages/device/moxibustion/moxibustion?p2=${otherSetting.lvxinNum}&tab=p2`" class="funcitem" hover-class="none">
  73. <image class="funcimg" src="/static/device/gongneng2.png" mode="aspectFill"></image>
  74. <text class="functxt">滤芯状态</text>
  75. </navigator>
  76. <navigator :url="`/pages/device/moxibustion/moxibustion?p3=${otherSetting.huishouNum}&tab=p3`" class="funcitem" hover-class="none">
  77. <image class="funcimg" src="/static/device/gongneng2.png" mode="aspectFill"></image>
  78. <text class="functxt">回收仓占用</text>
  79. </navigator>
  80. </view>
  81. </view>
  82. <!-- 自定义模式切换按钮 -->
  83. <view class="modeChange" v-if="modeType == 2">
  84. <view class="modeBtn" v-if="picMode===2" @click="picModeChange(1)" :class="picMode===1?'curBtn':''">
  85. <text class="modeBtnTxt" :style="{color:picMode===1?'#545F71':'#fff'}">设备</text>
  86. </view>
  87. <view class="modeBtn" @click="picModeChange(2)" :class="picMode===2?'curBtn':''">
  88. <text class="modeBtnTxt" :style="{color:picMode===2?'#545F71':'#fff'}">穴位</text>
  89. </view>
  90. </view>
  91. <!-- 穴位图 -->
  92. <view class="acupointPic" v-if="modeType == 2 && picMode == 2">
  93. <image class="acupointBg" src="/static/device/persionbg.png" mode="aspectFill"></image>
  94. <view class="acupoint" :class="index == acupointIndex ? 'curAcupoint':''" @click="showTimeDraw(index)"
  95. v-for="(item,index) in acupointList" :key="index"
  96. :style="{left:item.x+'rpx',top:item.y+'rpx'}">
  97. </view>
  98. <view class="tipsbox" v-if="acupointIndex != -1"
  99. :style="{left:50+acupointList[acupointIndex].x+'rpx',top:-50+acupointList[acupointIndex].y+'rpx'}">
  100. <text class="tipsTxt">{{acupointList[acupointIndex].name}}</text>
  101. </view>
  102. </view>
  103. <!-- 白噪音 -->
  104. <view class="musicCard" v-if="modeType == 0 && picMode == 1">
  105. <text class="musicname">白噪音</text>
  106. <view class="musliclist">
  107. <text class="musictxt" :class="{'current':curAudioInx==inx}" v-for="(itm,inx) in audiolist"
  108. :key="inx" @click="changeAudio(itm.url,inx)">{{itm.name}}</text>
  109. </view>
  110. </view>
  111. <!-- 开始/暂停/停止 -->
  112. <view class="startbox" v-if="modeType != 0">
  113. <view class="stop" v-if="deviceStatus==0">
  114. <image class="startbtn" @click="startDeviceEvt()" src="/static/device/start.png" mode="aspectFill"></image>
  115. <text class="starttxt">开始</text>
  116. </view>
  117. <view class="hot" v-if="deviceStatus==1">
  118. <view class="hotone">
  119. <text class="hoting">{{ispreHot == false?'正在预热':'点火中'}}</text>
  120. <text class="hotnum">{{hotPercentage}}</text>
  121. </view>
  122. <view class="stopbox" @click="stopPreHot">
  123. <image class="stopimg" src="/static/device/stop.png" mode="aspectFill"></image>
  124. <text class="stoptext">结束</text>
  125. </view>
  126. </view>
  127. <view class="hot" v-if="deviceStatus==3 || deviceStatus==5">
  128. <view class="hotone" v-if="deviceStatus==3">
  129. <text class="hoting">正在艾灸</text>
  130. <text class="hotnum">{{subTime}}</text>
  131. </view>
  132. <view class="hotone" v-if="deviceStatus==5">
  133. <text class="hoting">已暂停</text>
  134. <text class="hotnum">{{subTime}}</text>
  135. </view>
  136. <view class="pausebox" @click="stopAijiu">
  137. <image class="pauseimg" :src="deviceStatus==5?'/static/device/start.png':'/static/device/pause.png'" mode="aspectFill"></image>
  138. <text class="pausetxt">{{deviceStatus==5?'开始':'暂停'}}</text>
  139. </view>
  140. <view class="stopbox" @click="stopPreHot">
  141. <image class="stopimg" src="/static/device/stop.png" mode="aspectFill"></image>
  142. <text class="stoptext">结束</text>
  143. </view>
  144. </view>
  145. <view class="hot" v-if="deviceStatus==4">
  146. <view class="hotone">
  147. <text class="hoting unfire">正在灭火中,请勿操作</text>
  148. </view>
  149. </view>
  150. </view>
  151. <view class="empty" v-if="modeType == 0"></view>
  152. </scroll-view>
  153. </view>
  154. <!-- 音乐播放器 - 固定底部 -->
  155. <view class="musicPlayerFixed" v-if="modeType == 0">
  156. <view class="musicPlayer">
  157. <view class="leftbox">
  158. <image class="playerimg" :src="audiolist[curAudioInx].posterimg" mode="aspectFill"></image>
  159. <view class="musicnamebox">
  160. <text class="mtime">{{formatTime(currentTime)}}</text>
  161. </view>
  162. </view>
  163. <view class="rightbox">
  164. <view class="playBtn" @click="playAudio">
  165. <image class="playericon"
  166. :src="ispause?'/static/device/playerbtn.png':'/static/device/pauseicon.png'"
  167. mode="aspectFit"></image>
  168. </view>
  169. <image @click="isShowDrawer3 = true" class="menuicon" src="/static/device/menubtn.png"
  170. mode="aspectFill"></image>
  171. </view>
  172. </view>
  173. </view>
  174. <!-- 异常提示弹框 -->
  175. <customPopup :isShow="excepDrawer" @closePop="excepDrawer=false">
  176. <text class="tip1 toptip" v-if="exceTxt == 1">检查到有异物</text>
  177. <text class="tip1" v-if="exceTxt == 1">已暂停艾灸,清理后重试</text>
  178. <text class="tip1 toptip" v-if="exceTxt == 2">艾条识别错误</text>
  179. <text class="tip1" v-if="exceTxt == 2">已暂停艾灸,重新插入艾条后重试</text>
  180. <text class="tip1 toptip" v-if="exceTxt == 3">上艾失败</text>
  181. <text class="tip1 toptip" v-if="exceTxt == 4">点火失败</text>
  182. <view class="confirmBtnWrap">
  183. <text class="confirmBtn" @click="excepDrawer = false; exceTxt = 0;">我知道了</text>
  184. </view>
  185. </customPopup>
  186. <!-- 确认结束弹框 -->
  187. <customPopup :isShow="isShowConfirm" @closePop="isShowConfirm=false">
  188. <text class="confirmTxt toptip">确认结束艾灸?</text>
  189. <view class="confirmBtns">
  190. <view class="cbtn" @click="isShowConfirm=false">
  191. <text class="cbtnTxt">取消</text>
  192. </view>
  193. <view class="cbtn redbtn" @click="confirmStop">
  194. <text class="cbtnTxt">结束</text>
  195. </view>
  196. </view>
  197. </customPopup>
  198. <!-- 模式选择弹框 -->
  199. <customPopup :isShow="isShowDrawer2" @closePop="isShowDrawer2=false">
  200. <view class="modeList">
  201. <view class="modeItem" @click="changeMode(0)">
  202. <text class="modeItemTxt">无艾灸模式</text>
  203. <view class="checkboxCustom">
  204. <view v-if="modeType == 0" class="checkboxCircle"></view>
  205. </view>
  206. </view>
  207. <view class="modeItem" @click="changeMode(1)">
  208. <text class="modeItemTxt">专业模式</text>
  209. <view class="checkboxCustom">
  210. <view v-if="modeType == 1" class="checkboxCircle"></view>
  211. </view>
  212. </view>
  213. <view class="modeItem" @click="changeMode(2)">
  214. <text class="modeItemTxt">自定义模式</text>
  215. <view class="checkboxCustom">
  216. <view v-if="modeType == 2" class="checkboxCircle"></view>
  217. </view>
  218. </view>
  219. <view class="modeItem" @click="changeMode(3)">
  220. <text class="modeItemTxt">专家模式</text>
  221. <view class="checkboxCustom">
  222. <view v-if="modeType == 3" class="checkboxCircle"></view>
  223. </view>
  224. </view>
  225. </view>
  226. </customPopup>
  227. <!-- 音乐弹窗 -->
  228. <customPopup :isShow="isShowDrawer3" @closePop="isShowDrawer3=false">
  229. <view class="audiolists">
  230. <text class="playname">当前播放</text>
  231. <view class="audiolist" :class="curAudioInx==inx?'curAudio':''" v-for="(itm,inx) in audiolist"
  232. :key="inx" @click="changeAudio(itm.url,inx)">
  233. <text class="audioTxt">{{itm.name}}</text>
  234. <view class="signal-container" v-if="curAudioInx==inx">
  235. <view class="signal-bar bar1"></view>
  236. <view class="signal-bar bar2"></view>
  237. <view class="signal-bar bar3"></view>
  238. </view>
  239. </view>
  240. </view>
  241. </customPopup>
  242. <!-- 方案选择弹框 -->
  243. <customPopup :isShow="isShowPlanDrawer" @closePop="isShowPlanDrawer=false">
  244. <text class="planDrawerTitle">选择方案</text>
  245. <text class="planDrawerSub">{{modelist[modeType]}} - 可用方案</text>
  246. <scroll-view class="planDrawerList" scroll-y="true">
  247. <view class="planDrawerEmpty" v-if="planList.length === 0 && !planLoading">
  248. <text class="planEmptyTxt">暂无可用方案</text>
  249. </view>
  250. <view class="planDrawerEmpty" v-if="planLoading">
  251. <text class="planEmptyTxt">加载中...</text>
  252. </view>
  253. <view class="planItem" :class="selectedPlan && selectedPlan.id === item.id ? 'planItemActive' : ''"
  254. v-for="(item, index) in planList" :key="index" @click="selectPlan(item)">
  255. <view class="planItemInfo">
  256. <text class="planItemName">{{item.name}}</text>
  257. <text class="planItemDesc" v-if="item.description">{{item.description}}</text>
  258. <view class="planItemMeta" v-if="item.steps || item.duration">
  259. <text class="planMetaTxt" v-if="item.steps">{{item.steps}}步</text>
  260. <text class="planMetaTxt" v-if="item.duration">约{{item.duration}}分钟</text>
  261. </view>
  262. </view>
  263. <view class="planItemCheck">
  264. <view class="checkboxCustom">
  265. <view v-if="selectedPlan && selectedPlan.id === item.id" class="checkboxCircle"></view>
  266. </view>
  267. </view>
  268. </view>
  269. </scroll-view>
  270. </customPopup>
  271. <!-- 时间配置器 -->
  272. <customPopup :isShow="isShowTimeDrawer" @closePop="isShowTimeDrawer=false">
  273. <text class="aijiuTime">选择灸疗时间</text>
  274. <view class="timePickerRow">
  275. <picker mode="multiSelector" :range="timeRange" @change="bindTimeChange">
  276. <text class="timePickerTxt">{{selectedHour}}小时 {{selectedMinute}}分钟</text>
  277. </picker>
  278. </view>
  279. <view class="timeBtns">
  280. <view class="tbtn" @click="cancelAijiuTime(0)">
  281. <text class="tbtnTxt">取消</text>
  282. </view>
  283. <view class="tbtn confirmBtn2" @click="cancelAijiuTime(1)">
  284. <text class="tbtnTxt confirmBtn2Txt">确认</text>
  285. </view>
  286. </view>
  287. </customPopup>
  288. <!-- 重连弹框 -->
  289. <view class="maskbg" v-if="reconnectDrawer" @click.stop="">
  290. <view class="maskbox">
  291. <text class="maskTxt">蓝牙连接断开,第{{reconnectCount}}次重连中...</text>
  292. </view>
  293. </view>
  294. <ay-toast ref="ayToast" />
  295. </view>
  296. </template>
  297. <script>
  298. import customPopup from '@/components/customPopup/customPopup.nvue'
  299. import ayToast from '@/components/ay-toast/ay-toast.nvue'
  300. import lSliderRange from '@/components/l-sliderRange/l-sliderRange.nvue'
  301. import bleMixin from './mixins/ble-mixin.js'
  302. import audioMixin from './mixins/audio-mixin.js'
  303. import acupointMixin from './mixins/acupoint-mixin.js'
  304. import planMixin from './mixins/plan-mixin.js'
  305. import bleManager, { CHAIR_ANGLE } from '@/utils/ble'
  306. export default {
  307. components: {
  308. customPopup,
  309. ayToast,
  310. lSliderRange
  311. },
  312. mixins: [bleMixin, audioMixin, acupointMixin, planMixin],
  313. data() {
  314. return {
  315. statusBarHeight: 44,
  316. deviceId: '',
  317. deviceCode: '',
  318. deviceName: '',
  319. rssi: '',
  320. subTime: '00:00:00',
  321. isShowDrawer2: false,
  322. modeType: 0, // 0无艾灸 1专业 2自定义 3专家
  323. modelist: ['无艾灸模式', '专业模式', '自定义模式', '专家模式'],
  324. chairAngle: 90,
  325. otherSetting: {
  326. aijiuNum: '0',
  327. lvxinNum: '0',
  328. huishouNum: '0'
  329. },
  330. currentUserName: ''
  331. }
  332. },
  333. onLoad(options) {
  334. const sysInfo = uni.getSystemInfoSync()
  335. this.statusBarHeight = sysInfo.statusBarHeight || 44
  336. this.deviceId = options.deviceId || ''
  337. this.deviceCode = options.deviceCode || ''
  338. this.deviceName = options.name || ''
  339. this.rssi = options.rssi || ''
  340. const currentDevice = uni.getStorageSync('current_device') || {}
  341. if (currentDevice.deviceCode && !this.deviceCode) {
  342. this.deviceCode = currentDevice.deviceCode
  343. }
  344. if (currentDevice.name && !this.deviceName) {
  345. this.deviceName = currentDevice.name
  346. }
  347. // TODO: 后续接口确定后实现 - 下载穴位列表
  348. // TODO: 后续接口确定后实现 - 下载专业模式推荐方案
  349. this.loadCurrentUser()
  350. this.initAudio()
  351. this.initBle()
  352. },
  353. onShow() {
  354. // 返回页面时刷新当前用户
  355. this.loadCurrentUser()
  356. },
  357. onUnload() {
  358. this.destroyAudio()
  359. this.disconnectBle()
  360. },
  361. methods: {
  362. goBack() {
  363. // 自定义模式下穴位编辑视图,返回切回设备视图而非真正返回页面
  364. if (this.modeType == 2 && this.picMode == 2) {
  365. this.picMode = 1
  366. return
  367. }
  368. uni.navigateBack()
  369. },
  370. /** 加载当前用户信息 */
  371. loadCurrentUser() {
  372. const currentDevice = uni.getStorageSync('current_device') || {}
  373. const user = uni.getStorageSync('current_manage_user')
  374. if (user && user.name) {
  375. this.currentUserName = user.name
  376. } else if (currentDevice.profile && currentDevice.profile.name) {
  377. uni.setStorageSync('current_manage_user', currentDevice.profile)
  378. uni.setStorageSync('current_manage_user_id', currentDevice.profile.profileId || currentDevice.profile.id)
  379. this.currentUserName = currentDevice.profile.name
  380. } else {
  381. this.currentUserName = ''
  382. }
  383. },
  384. /** 跳转用户管理页 */
  385. goUserManage() {
  386. uni.navigateTo({
  387. url: '/pages/device/userManage/userManage'
  388. })
  389. },
  390. // 座椅角度控制 - 来自 l-sliderRange 组件
  391. onSliderAngleChange(val) {
  392. this.chairAngle = val
  393. this._sendAngleCommand()
  394. },
  395. _sendAngleCommand() {
  396. const angleMap = {
  397. 90: CHAIR_ANGLE.LEVEL_1,
  398. 105: CHAIR_ANGLE.LEVEL_2,
  399. 120: CHAIR_ANGLE.LEVEL_3,
  400. 135: CHAIR_ANGLE.LEVEL_4,
  401. 150: CHAIR_ANGLE.LEVEL_5
  402. }
  403. const level = angleMap[this.chairAngle] || CHAIR_ANGLE.LEVEL_1
  404. if (this.linked) {
  405. bleManager.setChairAngle(level).catch(e => console.error('setAngle fail', e))
  406. }
  407. }
  408. }
  409. }
  410. </script>
  411. <style>
  412. .infoBox {
  413. flex: 1;
  414. position: relative;
  415. }
  416. .content-bg {
  417. position: absolute;
  418. left: 0;
  419. top: 0;
  420. width: 750rpx;
  421. height: 2000px;
  422. }
  423. .gradientBg {
  424. position: absolute;
  425. top: 0;
  426. left: 0;
  427. right: 0;
  428. bottom: 0;
  429. }
  430. .pageBg {
  431. position: absolute;
  432. top: 0;
  433. left: 0;
  434. width: 750rpx;
  435. height: 1400rpx;
  436. }
  437. .pageContent {
  438. flex: 1;
  439. background-image: linear-gradient(to bottom, rgba(56,149,136,1), rgba(56,149,136,0.5));
  440. /* background-color: #333; */
  441. }
  442. .status-bar {
  443. background-color: rgba(0,0,0,0);
  444. }
  445. .customHead {
  446. flex-direction: row;
  447. justify-content: space-between;
  448. align-items: center;
  449. height: 88rpx;
  450. padding-left: 30rpx;
  451. padding-right: 30rpx;
  452. }
  453. .back-wrap {
  454. width: 50rpx;
  455. height: 50rpx;
  456. justify-content: center;
  457. align-items: center;
  458. }
  459. .backimg {
  460. width: 50rpx;
  461. height: 50rpx;
  462. }
  463. .customTitle {
  464. font-weight: bold;
  465. font-size: 32rpx;
  466. color: #FFFFFF;
  467. }
  468. .plus {
  469. width: 50rpx;
  470. height: 50rpx;
  471. justify-content: center;
  472. align-items: center;
  473. }
  474. .menuimg {
  475. width: 40rpx;
  476. height: 40rpx;
  477. }
  478. .headRight {
  479. flex-direction: row;
  480. align-items: center;
  481. }
  482. .userSwitchBtn {
  483. background-color: rgba(255,255,255,0.2);
  484. border-radius: 24rpx;
  485. padding-left: 16rpx;
  486. padding-right: 16rpx;
  487. padding-top: 8rpx;
  488. padding-bottom: 8rpx;
  489. margin-right: 12rpx;
  490. }
  491. .userSwitchTxt {
  492. font-size: 24rpx;
  493. color: #FFFFFF;
  494. }
  495. .boxs {
  496. flex: 1;
  497. }
  498. .proBox {
  499. align-items: center;
  500. padding-top: 30rpx;
  501. padding-bottom: 20rpx;
  502. }
  503. .proimg {
  504. width: 600rpx;
  505. height: 500rpx;
  506. }
  507. .pointbox {
  508. margin-top: 20rpx;
  509. align-items: center;
  510. }
  511. .pointContainer {
  512. background-color: #389588;
  513. border-radius: 20rpx;
  514. padding-left: 24rpx;
  515. padding-right: 24rpx;
  516. padding-top: 8rpx;
  517. padding-bottom: 8rpx;
  518. }
  519. .pointLabel {
  520. color: #FFFFFF;
  521. font-size: 24rpx;
  522. }
  523. .prostatus {
  524. margin-top: 20rpx;
  525. font-size: 26rpx;
  526. color: #FFFFFF;
  527. }
  528. /* 座椅角度 */
  529. .angleSection {
  530. padding-left: 38rpx;
  531. padding-right: 38rpx;
  532. padding-top: 20rpx;
  533. padding-bottom: 30rpx;
  534. }
  535. .angleLabel {
  536. font-size: 26rpx;
  537. color: #FFFFFF;
  538. margin-bottom: 10rpx;
  539. }
  540. /* 模式选择 */
  541. .controlMode {
  542. margin-left: 38rpx;
  543. margin-right: 38rpx;
  544. margin-top: 20rpx;
  545. background-color: rgba(255,255,255,0.9);
  546. border-radius: 16rpx;
  547. padding: 30rpx;
  548. }
  549. .modetxt {
  550. font-size: 28rpx;
  551. color: #9BA5B7;
  552. margin-bottom: 20rpx;
  553. }
  554. .modechange {
  555. flex-direction: row;
  556. justify-content: space-between;
  557. align-items: center;
  558. background-color: #389588;
  559. border-radius: 40rpx;
  560. padding-left: 30rpx;
  561. padding-right: 20rpx;
  562. padding-top: 20rpx;
  563. padding-bottom: 20rpx;
  564. }
  565. .modeName {
  566. font-size: 30rpx;
  567. font-weight: bold;
  568. color: #ffffff;
  569. }
  570. .changeBtn {
  571. flex-direction: row;
  572. align-items: center;
  573. }
  574. .changetxt {
  575. font-size: 26rpx;
  576. color: #389588;
  577. margin-right: 8rpx;
  578. }
  579. .changeinmg {
  580. width: 20px;
  581. height: 20px;
  582. }
  583. /* 其他功能 */
  584. .otherSetting {
  585. margin-left: 38rpx;
  586. margin-right: 38rpx;
  587. margin-top: 20rpx;
  588. background-color: #ffffff;
  589. border-radius: 16rpx;
  590. padding: 30rpx;
  591. }
  592. .otherTxt {
  593. font-size: 28rpx;
  594. color: #9BA5B7;
  595. margin-bottom: 20rpx;
  596. }
  597. .func {
  598. flex-direction: row;
  599. flex-wrap: wrap;
  600. }
  601. .funcitem {
  602. width: 200rpx;
  603. align-items: center;
  604. margin-bottom: 20rpx;
  605. }
  606. .funcimg {
  607. width: 60rpx;
  608. height: 60rpx;
  609. }
  610. .functxt {
  611. font-size: 24rpx;
  612. color: #9BA5B7;
  613. margin-top: 10rpx;
  614. }
  615. /* 自定义模式切换 */
  616. .modeChange {
  617. flex-direction: row;
  618. justify-content: center;
  619. margin-top: 30rpx;
  620. margin-bottom: 20rpx;
  621. }
  622. .modeBtn {
  623. width: 160rpx;
  624. height: 60rpx;
  625. background-color: #545F71;
  626. justify-content: center;
  627. align-items: center;
  628. border-radius: 30rpx;
  629. margin-left: 10rpx;
  630. margin-right: 10rpx;
  631. }
  632. .curBtn {
  633. background-color: #FFFFFF;
  634. }
  635. .modeBtnTxt {
  636. font-size: 26rpx;
  637. }
  638. /* 穴位图 */
  639. .acupointPic {
  640. position: relative;
  641. margin-left: 38rpx;
  642. margin-right: 38rpx;
  643. height: 700rpx;
  644. align-items: center;
  645. }
  646. .acupointBg {
  647. width: 300rpx;
  648. height: 650rpx;
  649. }
  650. .acupoint {
  651. position: absolute;
  652. width: 20rpx;
  653. height: 20rpx;
  654. background-color: #389588;
  655. border-radius: 20rpx;
  656. }
  657. .curAcupoint {
  658. background-color: #F65252;
  659. width: 28rpx;
  660. height: 28rpx;
  661. border-radius: 28rpx;
  662. }
  663. .tipsbox {
  664. position: absolute;
  665. background-color: #333;
  666. border-radius: 8rpx;
  667. padding-left: 12rpx;
  668. padding-right: 12rpx;
  669. padding-top: 6rpx;
  670. padding-bottom: 6rpx;
  671. }
  672. .tipsTxt {
  673. color: #FFFFFF;
  674. font-size: 22rpx;
  675. }
  676. /* 白噪音 */
  677. .musicCard {
  678. margin-left: 38rpx;
  679. margin-right: 38rpx;
  680. margin-top: 20rpx;
  681. background-color: rgba(255,255,255,0.9);
  682. border-radius: 16rpx;
  683. padding: 30rpx;
  684. height:100px;
  685. }
  686. .musicname {
  687. font-size: 28rpx;
  688. color: #545F71;
  689. font-weight: bold;
  690. margin-bottom: 20rpx;
  691. }
  692. .musliclist {
  693. flex-direction: row;
  694. flex-wrap: wrap;
  695. }
  696. .musictxt {
  697. font-size: 26rpx;
  698. color: #9BA5B7;
  699. padding-left: 24rpx;
  700. padding-right: 24rpx;
  701. padding-top: 12rpx;
  702. padding-bottom: 12rpx;
  703. margin-right: 20rpx;
  704. border-radius: 24rpx;
  705. background-color: #F5F7FA;
  706. }
  707. .current {
  708. background-color: #389588;
  709. color: #FFFFFF;
  710. }
  711. .musicPlayerFixed {
  712. position: fixed;
  713. left: 0;
  714. right: 0;
  715. bottom: 0;
  716. }
  717. .musicPlayer {
  718. flex-direction: row;
  719. justify-content: space-between;
  720. align-items: center;
  721. background-color: rgba(255,255,255,0.5);
  722. padding-left: 20rpx;
  723. padding-right: 20rpx;
  724. padding-top: 50px;
  725. padding-bottom: 40px;
  726. border-radius:16px 16px 0 0;
  727. }
  728. .leftbox {
  729. flex-direction: row;
  730. align-items: center;
  731. }
  732. .playerimg {
  733. width: 100rpx;
  734. height: 100rpx;
  735. border-radius: 12rpx;
  736. }
  737. .musicnamebox {
  738. margin-left: 16rpx;
  739. }
  740. .mtime {
  741. font-size: 28rpx;
  742. color: #545F71;
  743. }
  744. .rightbox {
  745. flex-direction: row;
  746. align-items: center;
  747. }
  748. .playBtn {
  749. width: 60rpx;
  750. height: 60rpx;
  751. justify-content: center;
  752. align-items: center;
  753. }
  754. .playericon {
  755. width: 28rpx;
  756. height: 28rpx;
  757. }
  758. .menuicon {
  759. width: 80rpx;
  760. height: 80rpx;
  761. margin-left: 20rpx;
  762. }
  763. /* 开始/暂停/停止 */
  764. .startbox {
  765. align-items: center;
  766. margin-top: 40rpx;
  767. padding-bottom: 40rpx;
  768. }
  769. .stop {
  770. align-items: center;
  771. }
  772. .startbtn {
  773. width: 120rpx;
  774. height: 120rpx;
  775. }
  776. .starttxt {
  777. font-size: 28rpx;
  778. color: #FFFFFF;
  779. margin-top: 10rpx;
  780. }
  781. .hot {
  782. flex-direction: row;
  783. align-items: center;
  784. justify-content: space-between;
  785. align-self: stretch;
  786. padding: 0 80rpx;
  787. }
  788. .hotone {
  789. align-items: center;
  790. margin-right: 40rpx;
  791. }
  792. .hoting {
  793. font-size: 28rpx;
  794. color: #FFFFFF;
  795. }
  796. .unfire {
  797. color: #F65252;
  798. }
  799. .hotnum {
  800. font-size: 36rpx;
  801. color: #E0FFF8;
  802. font-weight: bold;
  803. margin-top: 8rpx;
  804. }
  805. .pausebox {
  806. align-items: center;
  807. margin-right: 40rpx;
  808. }
  809. .pauseimg {
  810. width: 80rpx;
  811. height: 80rpx;
  812. }
  813. .pausetxt {
  814. font-size: 24rpx;
  815. color: #FFFFFF;
  816. margin-top: 6rpx;
  817. }
  818. .stopbox {
  819. align-items: center;
  820. }
  821. .stopimg {
  822. width: 80rpx;
  823. height: 80rpx;
  824. }
  825. .stoptext {
  826. font-size: 24rpx;
  827. color: #F65252;
  828. margin-top: 6rpx;
  829. }
  830. .empty {
  831. height: 180rpx;
  832. }
  833. /* 方案选择区 */
  834. .planSection {
  835. margin-left: 38rpx;
  836. margin-right: 38rpx;
  837. margin-top: 20rpx;
  838. background-color: rgba(255,255,255,0.9);
  839. border-radius: 16rpx;
  840. padding: 30rpx;
  841. }
  842. .planSectionTitle {
  843. font-size: 28rpx;
  844. color: #9BA5B7;
  845. margin-bottom: 16rpx;
  846. }
  847. .planCard {
  848. flex-direction: row;
  849. justify-content: space-between;
  850. align-items: center;
  851. background-color: #389588;
  852. border-radius: 40rpx;
  853. padding-left: 30rpx;
  854. padding-right: 24rpx;
  855. padding-top: 20rpx;
  856. padding-bottom: 20rpx;
  857. }
  858. .planCardLeft {
  859. flex: 1;
  860. }
  861. .planCardName {
  862. font-size: 30rpx;
  863. font-weight: bold;
  864. color: #FFFFFF;
  865. }
  866. .planCardDesc {
  867. font-size: 22rpx;
  868. color: rgba(255,255,255,0.7);
  869. margin-top: 6rpx;
  870. }
  871. .planCardRight {
  872. width: 40rpx;
  873. align-items: center;
  874. }
  875. .planCardArrow {
  876. font-size: 40rpx;
  877. color: #FFFFFF;
  878. }
  879. /* 方案选择弹框 */
  880. .planDrawerTitle {
  881. font-size: 32rpx;
  882. color: #545F71;
  883. font-weight: bold;
  884. text-align: center;
  885. }
  886. .planDrawerSub {
  887. font-size: 24rpx;
  888. color: #9BA5B7;
  889. text-align: center;
  890. margin-top: 8rpx;
  891. margin-bottom: 24rpx;
  892. }
  893. .planDrawerList {
  894. max-height: 600rpx;
  895. }
  896. .planDrawerEmpty {
  897. align-items: center;
  898. padding-top: 60rpx;
  899. padding-bottom: 60rpx;
  900. }
  901. .planEmptyTxt {
  902. font-size: 28rpx;
  903. color: #9BA5B7;
  904. }
  905. .planItem {
  906. flex-direction: row;
  907. justify-content: space-between;
  908. align-items: center;
  909. padding-left: 20rpx;
  910. padding-right: 20rpx;
  911. padding-top: 24rpx;
  912. padding-bottom: 24rpx;
  913. border-bottom-width: 1px;
  914. border-bottom-style: solid;
  915. border-bottom-color: #EEF1F4;
  916. border-radius: 12rpx;
  917. }
  918. .planItemActive {
  919. background-color: #F0F8F7;
  920. }
  921. .planItemInfo {
  922. flex: 1;
  923. margin-right: 20rpx;
  924. }
  925. .planItemName {
  926. font-size: 30rpx;
  927. color: #545F71;
  928. font-weight: bold;
  929. }
  930. .planItemDesc {
  931. font-size: 24rpx;
  932. color: #9BA5B7;
  933. margin-top: 8rpx;
  934. }
  935. .planItemMeta {
  936. flex-direction: row;
  937. margin-top: 10rpx;
  938. }
  939. .planMetaTxt {
  940. font-size: 22rpx;
  941. color: #389588;
  942. margin-right: 20rpx;
  943. background-color: rgba(56,149,136,0.1);
  944. padding-left: 12rpx;
  945. padding-right: 12rpx;
  946. padding-top: 4rpx;
  947. padding-bottom: 4rpx;
  948. border-radius: 8rpx;
  949. }
  950. .planItemCheck {
  951. width: 50rpx;
  952. align-items: center;
  953. }
  954. /* 弹框样式 */
  955. .tip1 {
  956. font-size: 28rpx;
  957. color: #545F71;
  958. text-align: center;
  959. margin-bottom: 10rpx;
  960. }
  961. .toptip {
  962. margin-top: 20rpx;
  963. font-weight: bold;
  964. }
  965. .confirmBtnWrap {
  966. margin-top: 30rpx;
  967. align-items: center;
  968. }
  969. .confirmBtn {
  970. font-size: 28rpx;
  971. color: #FFFFFF;
  972. background-color: #389588;
  973. border-radius: 40rpx;
  974. padding-left: 60rpx;
  975. padding-right: 60rpx;
  976. padding-top: 16rpx;
  977. padding-bottom: 16rpx;
  978. }
  979. .confirmTxt {
  980. font-size: 32rpx;
  981. color: #545F71;
  982. font-weight: bold;
  983. text-align: center;
  984. }
  985. .confirmBtns {
  986. flex-direction: row;
  987. justify-content: center;
  988. margin-top: 40rpx;
  989. }
  990. .cbtn {
  991. width: 240rpx;
  992. height: 80rpx;
  993. border-radius: 40rpx;
  994. justify-content: center;
  995. align-items: center;
  996. margin-left: 20rpx;
  997. margin-right: 20rpx;
  998. background-color: #F3F3F3;
  999. }
  1000. .redbtn {
  1001. background-color: #F65252;
  1002. }
  1003. .cbtnTxt {
  1004. font-size: 28rpx;
  1005. color: #545F71;
  1006. }
  1007. /* 模式选择弹框 */
  1008. .modeList {
  1009. margin-top: 10rpx;
  1010. }
  1011. .modeItem {
  1012. flex-direction: row;
  1013. justify-content: space-between;
  1014. align-items: center;
  1015. height: 100rpx;
  1016. border-bottom-width: 1px;
  1017. border-bottom-style: solid;
  1018. border-bottom-color: #EEF1F4;
  1019. }
  1020. .modeItemTxt {
  1021. font-size: 30rpx;
  1022. color: #545F71;
  1023. }
  1024. .checkboxCustom {
  1025. width: 36rpx;
  1026. height: 36rpx;
  1027. border-radius: 36rpx;
  1028. border-width: 2px;
  1029. border-style: solid;
  1030. border-color: #389588;
  1031. justify-content: center;
  1032. align-items: center;
  1033. }
  1034. .checkboxCircle {
  1035. width: 20rpx;
  1036. height: 20rpx;
  1037. border-radius: 20rpx;
  1038. background-color: #389588;
  1039. }
  1040. /* 音乐弹窗 */
  1041. .audiolists {
  1042. margin-top: 10rpx;
  1043. }
  1044. .playname {
  1045. font-size: 28rpx;
  1046. color: #9BA5B7;
  1047. margin-bottom: 20rpx;
  1048. }
  1049. .audiolist {
  1050. flex-direction: row;
  1051. justify-content: space-between;
  1052. align-items: center;
  1053. height: 90rpx;
  1054. padding-left: 10rpx;
  1055. padding-right: 10rpx;
  1056. border-radius: 12rpx;
  1057. }
  1058. .curAudio {
  1059. background-color: #F0F8F7;
  1060. }
  1061. .audioTxt {
  1062. font-size: 30rpx;
  1063. color: #545F71;
  1064. }
  1065. .signal-container {
  1066. flex-direction: row;
  1067. align-items: flex-end;
  1068. }
  1069. .signal-bar {
  1070. width: 6rpx;
  1071. margin-left: 4rpx;
  1072. border-radius: 4rpx;
  1073. background-color: #389588;
  1074. }
  1075. .bar1 {
  1076. height: 16rpx;
  1077. }
  1078. .bar2 {
  1079. height: 24rpx;
  1080. }
  1081. .bar3 {
  1082. height: 32rpx;
  1083. }
  1084. /* 时间选择器 */
  1085. .aijiuTime {
  1086. font-size: 32rpx;
  1087. color: #545F71;
  1088. font-weight: bold;
  1089. text-align: center;
  1090. margin-bottom: 30rpx;
  1091. }
  1092. .timePickerRow {
  1093. align-items: center;
  1094. padding-top: 20rpx;
  1095. padding-bottom: 20rpx;
  1096. }
  1097. .timePickerTxt {
  1098. font-size: 32rpx;
  1099. color: #545F71;
  1100. }
  1101. .timeBtns {
  1102. flex-direction: row;
  1103. justify-content: center;
  1104. margin-top: 30rpx;
  1105. }
  1106. .tbtn {
  1107. width: 240rpx;
  1108. height: 80rpx;
  1109. border-radius: 40rpx;
  1110. justify-content: center;
  1111. align-items: center;
  1112. margin-left: 20rpx;
  1113. margin-right: 20rpx;
  1114. background-color: #F3F3F3;
  1115. }
  1116. .confirmBtn2 {
  1117. background-color: #389588;
  1118. }
  1119. .tbtnTxt {
  1120. font-size: 28rpx;
  1121. color: #545F71;
  1122. }
  1123. .confirmBtn2Txt {
  1124. color: #FFFFFF;
  1125. }
  1126. /* 重连遮罩 */
  1127. .maskbg {
  1128. position: fixed;
  1129. left: 0;
  1130. right: 0;
  1131. top: 0;
  1132. bottom: 0;
  1133. background-color: rgba(0,0,0,0.6);
  1134. justify-content: center;
  1135. align-items: center;
  1136. }
  1137. .maskbox {
  1138. background-color: #FFFFFF;
  1139. border-radius: 16rpx;
  1140. padding: 40rpx;
  1141. }
  1142. .maskTxt {
  1143. font-size: 28rpx;
  1144. color: #545F71;
  1145. }
  1146. </style>