index.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666
  1. <template>
  2. <view class="page" :style="{'min-height':h+'px', 'padding-top':mt+'px'}">
  3. <cus-header title='智慧空调' bgColor='transparent'></cus-header>
  4. <image class="bg" :src="imgBase+'home/kongtiao_bg.png'" mode="widthFix"></image>
  5. <div class="nums">
  6. <div class="pre">空调:<span class="mr">{{ktNum}}</span></div>
  7. <div class="pre">正常:<span class="zc">{{zcNum}}</span></div>
  8. <div class="pre">离线:<span class="lx">{{lxNum}}</span></div>
  9. </div>
  10. <div class="boxs" v-if="list.length">
  11. <div class="box" v-for="(item,index) in list" :key="index" :style="{'background':modeCfg[item.attributeList[2].value].color}" @tap="showDetail(item,index)">
  12. <image :src="modeCfg[item.attributeList[2].value].icon.split(';')[0]" class="type" mode="widthFix"></image>
  13. <div class="place">{{item.installSite}}{{item.roomNumbers}}</div>
  14. <div class="position">{{item.airConditionerName}}</div>
  15. <div class="temperature" :class="{'off':item.opStatus==0}">{{item.attributeList[5].value}}℃</div>
  16. <div class="text">温度</div>
  17. <div class="btn" v-if="item.opStatus==1" @tap.stop="switchOpenClose(1,item.deviceId, index,item.attributeList[3].sensorAddress)">
  18. <div class="circle"></div>
  19. <text style="margin-left: 4rpx;">ON</text>
  20. </div>
  21. <div class="btn" v-else-if="item.opStatus==0" @tap.stop="switchOpenClose(0,item.deviceId, index,item.attributeList[3].sensorAddress)">
  22. <text style="margin-right: 4rpx;">OFF</text>
  23. <div class="circle off"></div>
  24. </div>
  25. </div>
  26. </div>
  27. <template v-else>
  28. <page-empty :height="'calc(100vh - 200px)'"></page-empty>
  29. </template>
  30. <u-popup :show="show" mode="bottom" :round="40" @close="ktClose">
  31. <div class="kt_info">
  32. <div class="top">
  33. <div class="left">
  34. <image :src="imgBase+'home/kongtiao_kt.png'"></image>
  35. <div class="addr">
  36. <text>{{ktInfo.installSite}}{{ktInfo.roomNumbers}}</text>
  37. <text class="ts">{{ktInfo.airConditionerName}}</text>
  38. </div>
  39. </div>
  40. <div class="right" @tap="ktClose">
  41. <u-icon name="close" color="#333333" size="48"></u-icon>
  42. </div>
  43. </div>
  44. <template v-if="!setShow">
  45. <image class="setting" :src="imgBase+'home/kongtiao_info.png'" @tap="showInfo"></image>
  46. <div class="wendu">
  47. <TemperatureControl :temperature="temperature" @changeTemperature="changeTemperature" ref="tcRef"></TemperatureControl>
  48. </div>
  49. <div class="type" v-if="ktInfo.attributeList&&ktInfo.attributeList.length">
  50. <div class="pre" v-for="item in modeList" :key="item.id" :style="{'width':'calc(100% / '+modeList.length+' - 20rpx)'}"
  51. :class="{'active':temperature&&modeValue==item.dictValue}" @tap="changeType(item.dictValue)">
  52. <image :src="item.icon.split(';')[2]" v-if="temperature&&modeValue==item.dictValue"></image>
  53. <image :src="item.icon.split(';')[1]" v-else></image>
  54. <text>{{item.dictLabel}}</text>
  55. </div>
  56. </div>
  57. <div class="speend">
  58. <text>风速</text>
  59. <image class="jian" :src="imgBase+'home/kongtiao_jian.png'" @tap="changeWindSpeend(1)"></image>
  60. <div class="area" v-if="speendList.length">
  61. <div class="pre" :class="{'active':temperature&&speendValue==item.dictValue}"
  62. :style="{'width':'calc(100% / '+speendList.length+' - 3rpx)'}"
  63. v-for="item in speendList" :key="item.id">
  64. <div class="text" v-if="temperature&&speendValue==item.dictValue">{{item.dictLabel}}</div>
  65. </div>
  66. </div>
  67. <image class="jia" :src="imgBase+'home/kongtiao_jia.png'" @tap="changeWindSpeend(2)"></image>
  68. </div>
  69. <div class="btns">
  70. <!-- <div class="btn" :class="{'blue':wtype==1}" @tap="changeWindFx(1)">左右扫风</div> -->
  71. <div></div>
  72. <image :src="imgBase+'home/kongtiao_open1.png'" v-if="ktInfo.opStatus==1" @tap="control(1)"></image>
  73. <image :src="imgBase+'home/kongtiao_open2.png'" v-else-if="ktInfo.opStatus==0" @tap="control(0)"></image>
  74. <!-- <div class="btn" :class="{'blue':wtype==2}" @tap="changeWindFx(2)">上下扫风</div> -->
  75. <div></div>
  76. </div>
  77. </template>
  78. <template v-else>
  79. <div class="form">
  80. <div class="item">
  81. <div class="left">所属楼栋</div>
  82. <div class="right">
  83. <text>{{airInfo.buildingName}}</text>
  84. </div>
  85. </div>
  86. <div class="item">
  87. <div class="left">所属楼层</div>
  88. <div class="right">
  89. <text>{{airInfo.storeyName}}</text>
  90. </div>
  91. </div>
  92. <div class="item">
  93. <div class="left">房间号</div>
  94. <div class="right">
  95. <text>{{airInfo.roomNumbers}}</text>
  96. </div>
  97. </div>
  98. <div class="item">
  99. <div class="left">设备序列号</div>
  100. <div class="right">
  101. <text>{{airInfo.deviceId}}</text>
  102. </div>
  103. </div>
  104. <div class="item">
  105. <div class="left">空调名称</div>
  106. <div class="right">
  107. <text>{{airInfo.airConditionerName}}</text>
  108. </div>
  109. </div>
  110. <div class="item">
  111. <div class="left">空调编号</div>
  112. <div class="right">
  113. <text>{{airInfo.airConditionerNo}}</text>
  114. </div>
  115. </div>
  116. <div class="item">
  117. <div class="left">是否为公共区域</div>
  118. <div class="right">
  119. <u-switch v-model="airInfo.isPublic" size="40" disabled></u-switch>
  120. </div>
  121. </div>
  122. </div>
  123. <div class="confirm" @tap="confirmSet">返回</div>
  124. </template>
  125. </div>
  126. </u-popup>
  127. </view>
  128. </template>
  129. <script>
  130. import TemperatureControl from '@/pagesHome/components/TemperatureControl/index.vue'
  131. import pageEmpty from '@/components/pageEmpty/index.vue'
  132. export default {
  133. components:{
  134. TemperatureControl,
  135. pageEmpty
  136. },
  137. data(){
  138. return {
  139. ktNum:0,
  140. zcNum:0,
  141. lxNum:0,
  142. params:{
  143. page:1,
  144. limit:9999,
  145. controlCategory:'CommonLighting'
  146. },
  147. modeList:[],
  148. modeCfg:{},
  149. modeValue:'',
  150. speendList:[],
  151. speendCfg:{},
  152. speendValue:'',
  153. ktStatus:'',
  154. temperature:0,
  155. list:[],
  156. lIndex:'',
  157. show:false,
  158. setShow:false,
  159. ktInfo:{},
  160. wtype:1,
  161. canClick:true,
  162. airInfo:{}
  163. }
  164. },
  165. async onLoad() {
  166. await this.getModeList();
  167. await this.getSpeendList();
  168. this.getList();
  169. },
  170. onPullDownRefresh() {
  171. this.getList();
  172. },
  173. methods:{
  174. async getModeList(){
  175. let res = await this.$api.get('/sys/dict/data/getListByType/air_mode');
  176. if(res.data.code===0){
  177. this.modeList = res.data.data;
  178. res.data.data.map(d=>this.modeCfg[d.dictValue]=d);
  179. }else this.$showToast(res.data.msg)
  180. },
  181. async getSpeendList(){
  182. let res = await this.$api.get('/sys/dict/data/getListByType/air_fan');
  183. if(res.data.code===0){
  184. this.speendList = res.data.data;
  185. res.data.data.map(d=>this.speendCfg[d.dictValue]=d);
  186. }else this.$showToast(res.data.msg)
  187. },
  188. getList(){
  189. this.$api.get('/airconditioner/page',this.params).then(res=>{
  190. if(res.data.code===0){
  191. this.list = res.data.data.list;
  192. this.ktNum = res.data.data.total;
  193. this.zcNum = this.list.filter(l=>l.opStatus==1).length;
  194. this.lxNum = this.list.filter(l=>l.opStatus==0).length;
  195. }else this.$showToast(res.data.msg)
  196. })
  197. },
  198. showDetail(item,index){
  199. this.ktInfo = JSON.parse(JSON.stringify(item));
  200. this.ktStatus = item.opStatus;
  201. this.modeValue = this.ktInfo.attributeList[2].value;
  202. this.temperature = this.ktInfo.attributeList[5].value;
  203. this.speendValue = this.ktInfo.attributeList[0].value;
  204. this.lIndex = index;
  205. this.show = true;
  206. this.$refs.tcRef.status = this.ktStatus;
  207. this.$refs.tcRef.sjTemperature = this.temperature;
  208. this.$refs.tcRef.init();
  209. },
  210. changeType(type){
  211. if(this.ktInfo.opStatus==0) return
  212. if(this.modeValue == type) return
  213. this.modeValue = type;
  214. this.updateAirConditioner(type,this.ktInfo.attributeList[2].sensorAddress)
  215. },
  216. changeWindSpeend(type){
  217. if(this.ktInfo.opStatus==0) return
  218. let idx = this.speendList.findIndex(s=>s.dictValue==this.speendValue)
  219. if(idx>-1){
  220. if(type==1){
  221. if(idx==0) return
  222. this.speendValue = this.speendList[idx-1].dictValue;
  223. }else if(type==2){
  224. if(idx==this.speendList.length-1) return
  225. this.speendValue = this.speendList[idx+1].dictValue;
  226. }
  227. }
  228. this.updateAirConditioner(this.speendValue,this.ktInfo.attributeList[0].sensorAddress)
  229. },
  230. // changeWindFx(type){
  231. // if(this.ktInfo.opStatus==0) return
  232. // },
  233. control(status){
  234. this.openCloseAirConditioner(status,this.ktInfo.deviceId,this.lIndex,this.ktInfo.attributeList[3].sensorAddress);
  235. },
  236. ktClose(){
  237. this.ktInfo = {};
  238. this.setShow = false;
  239. this.show = false;
  240. },
  241. confirmSet(){
  242. this.setShow = false;
  243. },
  244. changeTemperature(temperature){
  245. this.updateAirConditioner(temperature,this.ktInfo.attributeList[5].sensorAddress)
  246. },
  247. switchOpenClose(status,deviceId,index,identifier){
  248. this.openCloseAirConditioner(status,deviceId,index,identifier);
  249. },
  250. openCloseAirConditioner(status,deviceId,index,identifier){
  251. let msg = status?'关闭':'开启';
  252. uni.showModal({
  253. title:'温馨提示',
  254. content:`是否确认【${msg}】此设备`,
  255. success: (res) => {
  256. if(res.confirm){
  257. this.$api.post('/airconditioner/command',{
  258. identifier,
  259. action: 0,
  260. value: status? 0 : 1,
  261. deviceId,
  262. }).then(resu=>{
  263. if(resu.data.code===0){
  264. this.show = false;
  265. this.$showToast('操作成功');
  266. setTimeout(()=>{
  267. this.getList();
  268. },3000)
  269. }else this.$showToast(resu.data.msg)
  270. })
  271. }
  272. }
  273. })
  274. },
  275. updateAirConditioner(value, identifier){
  276. if(!this.canClick) return
  277. this.canClick = false;
  278. this.$api.post('/airconditioner/command',{
  279. action: 0,
  280. identifier,
  281. value,
  282. deviceId:this.ktInfo.deviceId,
  283. }).then(resu=>{
  284. if(resu.data.code===0){
  285. this.show = false;
  286. this.$showToast('操作成功');
  287. setTimeout(()=>{
  288. this.getList();
  289. },3000)
  290. }else this.$showToast(resu.data.msg)
  291. this.canClick = true;
  292. }).catch(err=>{
  293. this.canClick = true;
  294. })
  295. },
  296. showInfo(){
  297. this.setShow = true;
  298. this.$api.get('/airconditioner/'+this.ktInfo.id).then(res=>{
  299. if(res.data.code===0){
  300. this.airInfo = {...this.airInfo,...res.data.data};
  301. this.airInfo.isPublic = this.airInfo.isPublic == 1 ? true : false;
  302. this.airInfo.roomNumbers = this.airInfo.roomNumbers.split(",");
  303. }else this.$showToast(res.data.msg)
  304. })
  305. }
  306. }
  307. }
  308. </script>
  309. <style scoped lang="less">
  310. .page{
  311. width: 100%;
  312. padding: 0 24rpx 20rpx;
  313. box-sizing: border-box;
  314. background: #F4F8FB;
  315. .bg{
  316. width: 100%;
  317. position: fixed;
  318. top: 0;
  319. left: 0;
  320. z-index: 0;
  321. }
  322. .nums{
  323. width: 100%;
  324. background: #FFFFFF;
  325. border-radius: 16rpx;
  326. padding: 37rpx 24rpx;
  327. box-sizing: border-box;
  328. display: flex;
  329. margin-top: 20rpx;
  330. position: relative;
  331. .pre{
  332. width: calc(100% / 3);
  333. font-family: PingFangSC, PingFang SC;
  334. font-weight: 400;
  335. font-size: 30rpx;
  336. color: #4E5969;
  337. line-height: 36rpx;
  338. text-align: left;
  339. span{
  340. font-family: PingFang-SC, PingFang-SC;
  341. font-weight: bold;
  342. font-size: 32rpx;
  343. line-height: 36rpx;
  344. text-align: left;
  345. &.mr{
  346. color: #1D2129;
  347. }
  348. &.zc{
  349. color: #14CC8C;
  350. }
  351. &.lx{
  352. color: #F95050;
  353. }
  354. }
  355. }
  356. }
  357. .boxs{
  358. position: relative;
  359. display: flex;
  360. flex-wrap: wrap;
  361. justify-content: space-between;
  362. margin-top: 4rpx;
  363. .box{
  364. width: calc(50% - 11rpx);
  365. box-shadow: 0rpx 4rpx 12rpx 0rpx rgba(35,130,255,0.1), inset 0rpx 3rpx 3rpx 0rpx #FFFFFF;
  366. border-radius: 16rpx;
  367. margin-top: 20rpx;
  368. padding: 32rpx 21rpx 42rpx 29rpx;
  369. box-sizing: border-box;
  370. position: relative;
  371. .type{
  372. width: 164rpx;
  373. height: 164rpx;
  374. position: absolute;
  375. top: 0;
  376. right: 0;
  377. z-index: 9;
  378. }
  379. .place{
  380. font-family: PingFang-SC, PingFang-SC;
  381. font-weight: bold;
  382. font-size: 30rpx;
  383. color: #1D2129;
  384. line-height: 42rpx;
  385. white-space: nowrap;
  386. overflow: hidden;
  387. text-overflow: ellipsis;
  388. }
  389. .position{
  390. font-family: PingFangSC, PingFang SC;
  391. font-weight: 400;
  392. font-size: 24rpx;
  393. color: #86909C;
  394. line-height: 33rpx;
  395. white-space: nowrap;
  396. overflow: hidden;
  397. text-overflow: ellipsis;
  398. margin-top: 16rpx;
  399. }
  400. .temperature{
  401. font-family: PingFang-SC, PingFang-SC;
  402. font-weight: bold;
  403. font-size: 54rpx;
  404. color: #198CFF;
  405. line-height: 64rpx;
  406. margin-top: 33rpx;
  407. &.off{
  408. color: #4E5969;
  409. }
  410. }
  411. .text{
  412. font-family: PingFangSC, PingFang SC;
  413. font-weight: 400;
  414. font-size: 24rpx;
  415. color: #86909C;
  416. line-height: 33rpx;
  417. margin-top: 9rpx;
  418. }
  419. .btn{
  420. width: 98rpx;
  421. height: 54rpx;
  422. background: #FFFFFF;
  423. box-shadow: 0rpx 2rpx 8rpx 0rpx rgba(0,0,0,0.06), inset 0rpx 2rpx 4rpx 0rpx #FFFFFF, inset 0rpx -1rpx 1rpx 0rpx #FFFFFF;
  424. border-radius: 27rpx;
  425. display: flex;
  426. align-items: center;
  427. justify-content: center;
  428. position: absolute;
  429. right: 21rpx;
  430. bottom: 40rpx;
  431. .circle{
  432. width: 24rpx;
  433. height: 24rpx;
  434. background: #6FDD93;
  435. border-radius: 50%;
  436. &.off{
  437. background: #CCCCCC;
  438. }
  439. }
  440. text{
  441. font-family: PingFang-SC, PingFang-SC;
  442. font-weight: bold;
  443. font-size: 24rpx;
  444. color: #1D2129;
  445. line-height: 33rpx;
  446. }
  447. }
  448. }
  449. }
  450. .kt_info{
  451. width: 100%;
  452. padding: 40rpx 30rpx 65rpx;
  453. box-sizing: border-box;
  454. background: #FFFFFF;
  455. position: relative;
  456. border-radius: 40rpx 40rpx 0 0;
  457. .top{
  458. display: flex;
  459. justify-content: space-between;
  460. .left{
  461. display: flex;
  462. image{
  463. width: 72rpx;
  464. height: 72rpx;
  465. }
  466. .addr{
  467. display: flex;
  468. flex-direction: column;
  469. margin-left: 20rpx;
  470. text{
  471. font-family: PingFang-SC, PingFang-SC;
  472. font-weight: bold;
  473. font-size: 30rpx;
  474. color: #1D2129;
  475. line-height: 42rpx;
  476. text-align: left;
  477. &.ts{
  478. font-weight: 400;
  479. font-size: 24rpx;
  480. color: #86909C;
  481. margin-top: 16rpx;
  482. }
  483. }
  484. }
  485. }
  486. }
  487. .setting{
  488. width: 48rpx;
  489. height: 48rpx;
  490. position: absolute;
  491. right: 30rpx;
  492. top: 165rpx;
  493. z-index: 9;
  494. }
  495. .wendu{
  496. width: 484rpx;
  497. height: 484rpx;
  498. margin: 69rpx auto 0;
  499. }
  500. .type{
  501. display: flex;
  502. justify-content: space-around;
  503. margin-top: 20rpx;
  504. .pre{
  505. margin: 0 10rpx;
  506. padding: 36rpx 0;
  507. display: flex;
  508. flex-direction: column;
  509. align-items: center;
  510. background: linear-gradient( 180deg, #ECF2F7 0%, #FFFFFF 100%);
  511. box-shadow: 0rpx 4rpx 16rpx 0rpx #EDF4FF, inset 0rpx 3rpx 3rpx 0rpx #FFFFFF;
  512. border-radius: 16rpx;
  513. border: 2rpx solid #FFFFFF;
  514. image{
  515. width: 48rpx;
  516. height: 48rpx;
  517. }
  518. text{
  519. font-family: PingFangSC, PingFang SC;
  520. font-weight: 400;
  521. font-size: 28rpx;
  522. color: #1D2129;
  523. line-height: 40rpx;
  524. text-align: center;
  525. margin-top: 16rpx;
  526. }
  527. &.active{
  528. background: #198CFF;
  529. box-shadow: 0rpx 4rpx 16rpx 4rpx #EDF4FF;
  530. text{
  531. font-weight: bold;
  532. color: #FFFFFF;
  533. }
  534. }
  535. }
  536. }
  537. .speend{
  538. width: 100%;
  539. padding-left: 20rpx;
  540. box-sizing: border-box;
  541. display: flex;
  542. align-items: center;
  543. margin-top: 80rpx;
  544. text{
  545. font-family: PingFangSC, PingFang SC;
  546. font-weight: 400;
  547. font-size: 28rpx;
  548. color: #1D2129;
  549. line-height: 40rpx;
  550. }
  551. image{
  552. width: 32rpx;
  553. height: 32rpx;
  554. margin: 0 20rpx;
  555. }
  556. .area{
  557. width: calc(100% - 200rpx);
  558. height: 20rpx;
  559. border-radius: 16rpx;
  560. display: flex;
  561. justify-content: space-between;
  562. .pre{
  563. height: 20rpx;
  564. background: #EDF4FF;
  565. position: relative;
  566. &.active{
  567. background: linear-gradient( 90deg, #3A8DFF 0%, #0BC6FF 100%);
  568. box-shadow: 0rpx 4rpx 16rpx 4rpx #EFEFEF;
  569. }
  570. .text{
  571. width: 100%;
  572. font-family: PingFangSC, PingFang SC;
  573. font-weight: 400;
  574. font-size: 24rpx;
  575. color: #86909C;
  576. line-height: 33rpx;
  577. text-align: center;
  578. position: absolute;
  579. top: -33rpx;
  580. }
  581. }
  582. }
  583. }
  584. .btns{
  585. display: flex;
  586. align-items: center;
  587. justify-content: space-between;
  588. margin-top: 28rpx;
  589. .btn{
  590. width: 210rpx;
  591. height: 88rpx;
  592. background: #FFFFFF;
  593. box-shadow: 0rpx 4rpx 12rpx 4rpx #EDF4FF;
  594. border-radius: 16rpx;
  595. font-family: PingFangSC, PingFang SC;
  596. font-weight: 400;
  597. font-size: 28rpx;
  598. color: #1D2129;
  599. line-height: 88rpx;
  600. text-align: center;
  601. &.blue{
  602. background: #198CFF;
  603. color: #FFFFFF;
  604. }
  605. }
  606. image{
  607. width: 170rpx;
  608. height: 170rpx;
  609. }
  610. }
  611. .form{
  612. margin-top: 72rpx;
  613. .item{
  614. width: 100%;
  615. padding: 28rpx 30rpx;
  616. box-sizing: border-box;
  617. box-shadow: inset 0rpx -1rpx 0rpx 0rpx #EDF4FF;
  618. display: flex;
  619. align-items: center;
  620. justify-content: space-between;
  621. .left{
  622. font-family: PingFangSC, PingFang SC;
  623. font-weight: 400;
  624. font-size: 30rpx;
  625. color: #1D2129;
  626. line-height: 42rpx;
  627. letter-spacing: 2rpx;
  628. }
  629. .right{
  630. text{
  631. font-family: PingFangSC, PingFang SC;
  632. font-weight: 400;
  633. font-size: 30rpx;
  634. color: #4E5969;
  635. line-height: 42rpx;
  636. text-align: right;
  637. }
  638. }
  639. }
  640. }
  641. .confirm{
  642. width: calc(100% - 48rpx);
  643. height: 88rpx;
  644. background: #198CFF;
  645. border-radius: 16rpx;
  646. margin: 234rpx 24rpx 0;
  647. font-family: PingFang-SC, PingFang-SC;
  648. font-weight: bold;
  649. font-size: 32rpx;
  650. color: #FFFFFF;
  651. line-height: 88rpx;
  652. text-align: center;
  653. letter-spacing: 2rpx;
  654. }
  655. }
  656. }
  657. </style>