addAir.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544
  1. <template>
  2. <view class="container">
  3. <view class="line"></view>
  4. <view class="show-selected">
  5. <view class="title-selected">已选择:</view>
  6. <view class="air-selected-name">{{show_airs}}</view>
  7. </view>
  8. <view class="btn">
  9. <view class="btn-bg" @tap="confirm_selection">确认选择</view>
  10. </view>
  11. <view class="line"></view>
  12. <view class="title-tip">请选择</view>
  13. <view class="line"></view>
  14. <view class="tree-box">
  15. <scroll-view scroll-y="true" class="tree-scroll" :style="{height: screenHeight}">
  16. <view class="item-loudong" v-for="(item1, index1) in treeData" :key="index1">
  17. <view class="loudong" :id="item1.id" @tap="handle_toggle_items">
  18. <view class="title-loudong">
  19. <uni-icons type="plus-filled" size="22" color="#2979ff"
  20. :style="{display: item1.isShow ? 'none' : ''}"></uni-icons>
  21. <uni-icons type="minus-filled" size="22" color="#2979ff"
  22. :style="{display: item1.isShow ? '' : 'none'}"></uni-icons>
  23. <view class="txt-loudong">{{item1.label}}</view>
  24. </view>
  25. <uni-icons type="bottom" size="22" color="#2979ff"
  26. :style="{display: item1.isShow ? '' : 'none'}"></uni-icons>
  27. <uni-icons type="top" size="22" color="#2979ff" :style="{display: item1.isShow ? 'none' : ''}">
  28. </uni-icons>
  29. </view>
  30. <view class="item-loucheng" v-for="(item2, index2) in item1.children" :key="index2"
  31. :style="{display: item1.isShow ? '' : 'none'}">
  32. <view class="loucheng" :id="item2.id" @tap="handle_toggle_items">
  33. <view class="title-loucheng">
  34. <uni-icons type="plus-filled" size="22" color="#2979ff"
  35. :style="{display: item2.isShow ? 'none' : ''}"></uni-icons>
  36. <uni-icons type="minus-filled" size="22" color="#2979ff"
  37. :style="{display: item2.isShow ? '' : 'none'}"></uni-icons>
  38. <view class="txt-loucheng">{{item2.label}}</view>
  39. </view>
  40. <uni-icons type="bottom" size="22" color="#2979ff"
  41. :style="{display: item2.isShow ? '' : 'none'}"></uni-icons>
  42. <uni-icons type="top" size="22" color="#2979ff"
  43. :style="{display: item2.isShow ? 'none' : ''}"></uni-icons>
  44. </view>
  45. <view class="item-jiaoshi" v-for="(item3, index3) in item2.children" :key="index3"
  46. :style="{display: item2.isShow ? '' : 'none'}">
  47. <view class="jiaoshi" :id="item3.id" @tap="handle_toggle_items">
  48. <view class="title-jiaoshi">
  49. <uni-icons type="plus-filled" size="22" color="#2979ff"
  50. :style="{display: item3.isShow ? 'none' : ''}"></uni-icons>
  51. <uni-icons type="minus-filled" size="22" color="#2979ff"
  52. :style="{display: item3.isShow ? '' : 'none'}"></uni-icons>
  53. <view class="txt-jiaoshi">{{item3.label}}</view>
  54. </view>
  55. <uni-icons type="bottom" size="22" color="#2979ff"
  56. :style="{display: item3.isShow ? '' : 'none'}"></uni-icons>
  57. <uni-icons type="top" size="22" color="#2979ff"
  58. :style="{display: item3.isShow ? 'none' : ''}"></uni-icons>
  59. </view>
  60. <view v-for="(item4, index4) in item3.children" :key="index4"
  61. :style="{display: item3.isShow ? '' : 'none'}">
  62. <view class="item-kongtiao" v-if="item4.isUsering">
  63. <view :style="{color: item4.isUsering ? '#747578' : '#2979ff'}">
  64. {{item4.label}}(使用中)
  65. </view>
  66. <checkbox :id="item4.id" :checked="true" :disabled="true" />
  67. </view>
  68. <view class="item-kongtiao" v-else>
  69. <view :style="{color: item4.isUsering ? '#747578' : '#2979ff'}">
  70. {{item4.label}}
  71. </view>
  72. <checkbox :value="index4" :id="item4.id" :checked="item4.isChecked"
  73. @tap="handle_kongtiao" />
  74. </view>
  75. </view>
  76. </view>
  77. </view>
  78. </view>
  79. </scroll-view>
  80. </view>
  81. </view>
  82. </template>
  83. <script>
  84. export default {
  85. data() {
  86. return {
  87. // 用于返回到上一页面的结果变量
  88. airs_selected: '',
  89. show_airs: '', // 用于显示已经选择的空调
  90. screenHeight: '', // 屏幕的高度
  91. // tree
  92. treeData: [] // 树形选择器的数据
  93. };
  94. },
  95. onLoad() {
  96. uni.showLoading({
  97. title: '加载中'
  98. })
  99. // 模拟异步请求
  100. setTimeout(() => {
  101. this.treeData = [{
  102. id: 1,
  103. label: '科技楼',
  104. isShow: false,
  105. children: [{
  106. id: 11,
  107. label: '5F',
  108. isShow: false,
  109. children: [{
  110. id: 111,
  111. label: '501',
  112. isShow: false,
  113. children: [{
  114. id: 1111,
  115. label: '空调-01',
  116. isChecked: false,
  117. isUsering: false
  118. }, {
  119. id: 1112,
  120. label: '空调-02',
  121. isChecked: true,
  122. isUsering: true
  123. }]
  124. }, {
  125. id: 112,
  126. label: '502',
  127. isShow: false,
  128. children: [{
  129. id: 1121,
  130. label: '空调-01',
  131. isChecked: false,
  132. isUsering: false
  133. }]
  134. }]
  135. }]
  136. }, {
  137. id: 2,
  138. label: '志胜楼',
  139. isShow: false,
  140. children: [{
  141. id: 21,
  142. label: '1F',
  143. isShow: false,
  144. children: [{
  145. id: 211,
  146. label: '101',
  147. isShow: false,
  148. children: [{
  149. id: 2111,
  150. label: '空调-01',
  151. isChecked: false,
  152. isUsering: false
  153. }, {
  154. id: 2112,
  155. label: '空调-02',
  156. isChecked: false,
  157. isUsering: false
  158. }]
  159. }, {
  160. id: 212,
  161. label: '102',
  162. isShow: false,
  163. children: [{
  164. id: 2121,
  165. label: '空调-01',
  166. isChecked: false,
  167. isUsering: false
  168. }, {
  169. id: 2122,
  170. label: '空调-02',
  171. isChecked: false,
  172. isUsering: false
  173. }]
  174. }]
  175. }]
  176. }];
  177. setTimeout(() => {
  178. uni.hideLoading();
  179. }, 500);
  180. }, 500);
  181. },
  182. onShow() {
  183. // 从新计算高度
  184. this.calc_screen_height()
  185. },
  186. methods: {
  187. /**
  188. * 获取空调的全称,勾选返回空调全称,不勾返回-空调全称,递归调用
  189. * @param {Object} obj
  190. * @param {Object} id
  191. * @param {Object} parentName
  192. */
  193. get_airs_full_name(obj, id, parentName) {
  194. for (var i = 0; i < obj.length; i++) {
  195. if (obj[i].id == id) {
  196. if (parentName == '') {
  197. return obj[i].label
  198. }
  199. if (obj[i].isChecked) {
  200. obj[i].isChecked = false
  201. return '-' + parentName + ' ' + obj[i].label
  202. } else {
  203. obj[i].isChecked = true
  204. return parentName + ' ' + obj[i].label
  205. }
  206. }
  207. let selfName = ''
  208. if (typeof obj[i].children != 'undefined' && obj[i].children.length > 0) {
  209. if (parentName == '') {
  210. selfName = this.get_airs_full_name(obj[i].children, id, obj[i].label)
  211. } else {
  212. selfName = this.get_airs_full_name(obj[i].children, id, parentName + '-' + obj[i].label)
  213. }
  214. if (typeof selfName != 'undefined') {
  215. return selfName
  216. }
  217. }
  218. }
  219. },
  220. /**
  221. * 更新airs_selected中的数据
  222. * @param {Object} param
  223. */
  224. update_airs_selected(param) {
  225. let tmp_airs_selected = ''
  226. if (param.indexOf('-') == 0) { // 删除airs_selected中的数据
  227. // 把前面的'-'去除
  228. let del_val = param.substring(1)
  229. // 需要删除的值进行拆分成:【楼栋-楼层-房间,空调】
  230. let room = del_val.split(' ')
  231. if (this.airs_selected.trim() != '') {
  232. let arrAirs = this.airs_selected.trim().split(',')
  233. let airs = ''
  234. for (var i = 0; i < arrAirs.length; i++) {
  235. airs = arrAirs[i].trim() // 删除空格后,赋给临时变量
  236. // 如果找到指定的房间,则删除
  237. if (airs.indexOf(room[0]) == 0) {
  238. // 删除 楼栋-楼层-房间 中的空调
  239. airs = airs.replace(' ' + room[1], '')
  240. // 如果只剩下 楼栋-楼层-房间,没有了空调,则置为空
  241. if (airs == room[0]) {
  242. airs = ''
  243. }
  244. }
  245. if (airs != '') {
  246. // 保存到临时变量tmp_airs_selected中
  247. tmp_airs_selected += airs + ','
  248. }
  249. }
  250. }
  251. } else { // 添加、合并到airs_selected中
  252. // 如果为空,直接加入
  253. if (this.airs_selected.trim() == '') {
  254. tmp_airs_selected = param + ','
  255. } else {
  256. let arrAirs = this.airs_selected.trim().split(',')
  257. let num = 0
  258. // 需要添加的数据
  259. let room = param.split(' ')
  260. for (var i = 0; i < arrAirs.length; i++) {
  261. let airs = arrAirs[i].trim().split(' ')
  262. // 如果找到指定的房间,则合并
  263. if (airs[0] == room[0]) {
  264. // 临时数组, 为排序做准备
  265. let tmp_arr = []
  266. // 数组转字符串, 即拼接
  267. tmp_arr.push(room[1])
  268. for (var j = 1; j < airs.length; j++) {
  269. tmp_arr.push(airs[j])
  270. }
  271. // 数组排序
  272. tmp_arr.sort()
  273. // 生成字符串
  274. tmp_airs_selected += room[0]
  275. for (var k = 0; k < tmp_arr.length; k++) {
  276. tmp_airs_selected += ' ' + tmp_arr[k]
  277. }
  278. // 加入分隔符
  279. tmp_airs_selected += ','
  280. } else {
  281. num++ // 计数
  282. tmp_airs_selected += arrAirs[i] + ','
  283. }
  284. }
  285. // 如果没有找到同一房间的,则直接拼接要添加的数据
  286. if (num == arrAirs.length) {
  287. tmp_airs_selected += param + ','
  288. }
  289. }
  290. }
  291. // 更新变量airs_selected
  292. this.airs_selected = tmp_airs_selected.substring(0, tmp_airs_selected.length - 1)
  293. // 更新显示框的内容
  294. this.show_selected_airs()
  295. },
  296. /**
  297. * 选择空调
  298. * @param {Object} e
  299. */
  300. handle_kongtiao(e) {
  301. // console.log(e.currentTarget.id);
  302. // 获取id
  303. let id = e.currentTarget.id
  304. // 获取勾选的值
  305. let airsFullName = this.get_airs_full_name(this.treeData, id, '')
  306. if (typeof airsFullName != 'undefined') {
  307. // 更新airs_selected中的数据
  308. this.update_airs_selected(airsFullName)
  309. } else {
  310. uni.showToast({
  311. title: '选取无效!',
  312. duration: 1500
  313. })
  314. }
  315. },
  316. /**
  317. * 选项的展开与收起,进行切换,递归调用
  318. * @param {Object} obj
  319. * @param {Object} id
  320. */
  321. toggle_item(obj, id) {
  322. for (var i = 0; i < obj.length; i++) {
  323. if (obj[i].id == id) {
  324. if (obj[i].isShow) {
  325. obj[i].isShow = false
  326. } else {
  327. obj[i].isShow = true
  328. }
  329. return
  330. }
  331. if (typeof obj[i].children != 'undefined' && obj[i].children.length > 0) {
  332. this.toggle_item(obj[i].children, id)
  333. }
  334. }
  335. },
  336. /**
  337. * 选项的展开与收起,进行切换
  338. * @param {Object} e
  339. */
  340. handle_toggle_items(e) {
  341. // console.log(e.currentTarget.id);
  342. // 获取id
  343. let id = e.currentTarget.id
  344. this.toggle_item(this.treeData, id)
  345. },
  346. /**
  347. * 确认选择,将结果返回到前一页面显示
  348. */
  349. confirm_selection() {
  350. // 触发全局的自定义事件,附加参数都会传给监听器回调函数。
  351. if (this.airs_selected != '') {
  352. uni.$emit('selectAirs', {
  353. airs: this.airs_selected
  354. })
  355. }
  356. // 返回空调列表页面
  357. uni.navigateBack({
  358. delta: -1
  359. })
  360. },
  361. /**
  362. * 超出左边显示...
  363. */
  364. show_selected_airs() {
  365. // 显示到上方
  366. this.show_airs = this.airs_selected.split('').reverse().join('')
  367. },
  368. /**
  369. * 计算屏幕的高度
  370. */
  371. calc_screen_height() {
  372. uni.getSystemInfo({
  373. success: res => {
  374. let h = ((res.screenHeight * (750 / res.windowWidth)) - 480) //将px 转换rpx
  375. this.screenHeight = Math.floor(h) + 'rpx'
  376. }
  377. });
  378. }
  379. }
  380. }
  381. </script>
  382. <style lang="scss">
  383. .container {
  384. display: flex;
  385. flex-direction: column;
  386. font-size: 28rpx;
  387. font-family: "Microsoft YaHei-3970(82674968)";
  388. width: 730rpx;
  389. padding: 10rpx;
  390. .line {
  391. height: 20rpx;
  392. }
  393. .show-selected {
  394. display: flex;
  395. padding: 20rpx;
  396. border-radius: 10rpx;
  397. border: 1px solid #c7c9ce;
  398. font-size: 32rpx;
  399. .title-selected {
  400. color: #686b71;
  401. white-space: nowrap;
  402. }
  403. .air-selected-name {
  404. width: 600rpx;
  405. font-weight: bold;
  406. white-space: nowrap;
  407. text-overflow: ellipsis;
  408. direction: rtl;
  409. unicode-bidi: bidi-override;
  410. overflow: hidden;
  411. }
  412. }
  413. .btn {
  414. display: flex;
  415. justify-content: flex-end;
  416. .btn-bg {
  417. margin-top: 30rpx;
  418. padding: 20rpx 40rpx;
  419. border-radius: 10rpx;
  420. font-size: 32rpx;
  421. color: #ffffff;
  422. background-color: #2979ff;
  423. }
  424. }
  425. .title-tip {
  426. font-size: 36rpx;
  427. }
  428. .tree-box {
  429. border-radius: 10rpx;
  430. border: 1px solid #c7c9ce;
  431. color: #2979ff;
  432. .tree-scroll {
  433. border-radius: 10rpx;
  434. overflow: scroll;
  435. }
  436. .item-loudong {
  437. display: flex;
  438. flex-direction: column;
  439. padding: 10rpx 0 0 10rpx;
  440. .loudong {
  441. display: flex;
  442. align-items: center;
  443. justify-content: space-between;
  444. border: 1rpx solid #c7c9ce;
  445. padding: 10rpx;
  446. height: 60rpx;
  447. width: 636rpx;
  448. font-size: 30rpx;
  449. .title-loudong {
  450. display: flex;
  451. }
  452. .txt-loudong {
  453. padding-left: 5rpx;
  454. }
  455. }
  456. .item-loucheng {
  457. display: flex;
  458. flex-direction: column;
  459. margin-left: 60rpx;
  460. .loucheng {
  461. display: flex;
  462. align-items: center;
  463. justify-content: space-between;
  464. border: 1rpx solid #c7c9ce;
  465. padding: 10rpx;
  466. height: 60rpx;
  467. width: 578rpx;
  468. font-size: 30rpx;
  469. .title-loucheng {
  470. display: flex;
  471. }
  472. .txt-loucheng {
  473. padding-left: 5rpx;
  474. }
  475. }
  476. .item-jiaoshi {
  477. display: flex;
  478. flex-direction: column;
  479. margin-left: 60rpx;
  480. .jiaoshi {
  481. display: flex;
  482. align-items: center;
  483. justify-content: space-between;
  484. border: 1rpx solid #c7c9ce;
  485. padding: 10rpx;
  486. height: 60rpx;
  487. width: 520rpx;
  488. font-size: 30rpx;
  489. .title-jiaoshi {
  490. display: flex;
  491. }
  492. .txt-jiaoshi {
  493. padding-left: 5rpx;
  494. }
  495. }
  496. .item-kongtiao {
  497. display: flex;
  498. justify-content: space-between;
  499. align-items: center;
  500. border: 1rpx solid #c7c9ce;
  501. margin-left: 60rpx;
  502. padding: 10rpx 10rpx 10rpx 30rpx;
  503. height: 60rpx;
  504. width: 442rpx;
  505. font-size: 32rpx;
  506. }
  507. }
  508. }
  509. }
  510. }
  511. }
  512. </style>