index.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  1. <template>
  2. <view>
  3. <uni-nav-bar fixed :border="false" left-icon="left" title="我的家人" :statusBar="true" @clickLeft="$navBack()" @clickRight="handleAdd">
  4. <!-- #ifndef MP-WEIXIN -->
  5. <template v-slot:right>
  6. <view class="add">
  7. <image src="@/static/images/pages_watch/icons/nav_add_icon.png"></image>
  8. 新增
  9. </view>
  10. </template>
  11. <!-- #endif -->
  12. </uni-nav-bar>
  13. <view class="container">
  14. <view class="family-card" v-for="(item,index) in list" :key="index">
  15. <view class="card-header border-line">
  16. <view class="card-title">{{item.name}}</view>
  17. <view class="card-header-right" v-if="item.name !== '自己'" @tap="handleEdit(index-1)">
  18. 编辑
  19. <image src="@/static/images/pages_watch/icons/edit_right_arrow_right_icon.png"></image>
  20. </view>
  21. </view>
  22. <view class="card-body">
  23. <scroll-view v-if="item.child && item.child.length > 0 &&item.child[0].ble" scroll-x="true" class="device-list">
  24. <view class="device-item x-f" v-for="i in item.child">
  25. <image src="@/static/images/pages_watch/images/watch_icon.png" mode="aspectFill"></image>
  26. <view style="flex: 1;overflow: hidden;">
  27. <view>{{i.ble}}</view>
  28. <view class="device-item-desc x-f">
  29. <view :class="i.status == 1 ? 'device-status green x-f':'device-status red x-f'">
  30. {{i.status == 1 ? '在线' : '离线'}}
  31. </view>
  32. </view>
  33. </view>
  34. </view>
  35. </scroll-view>
  36. <!-- h5平台不扫码 -->
  37. <!-- #ifdef APP-PLUS || MP-WEIXIN -->
  38. <button class="bind_btn" @tap="handleBind(index)" :disabled="btnLoading" :loading="editIndex == index && btnLoading">
  39. <template v-if="editIndex == index &&btnLoading">
  40. 绑定中...
  41. </template>
  42. <template v-else>
  43. <image src="@/static/images/pages_watch/icons/edit_add_icon.png"></image>
  44. 绑定预警手表
  45. </template>
  46. </button>
  47. <!-- #endif -->
  48. </view>
  49. </view>
  50. <!-- #ifndef APP-PLUS || H5 -->
  51. <view class="footer-add" @click="handleAdd">新增</view>
  52. <!-- #endif -->
  53. </view>
  54. </view>
  55. </template>
  56. <script>
  57. import {getUser} from '@/utils/common.js'
  58. import permision from "@/utils/permission.js";
  59. import { getWatchUserInfo,getStatus,editUser,editMyfamily,editDevice,getFamWatchInfo } from "@/api/pages_watch/user.js";
  60. export default {
  61. data() {
  62. return {
  63. editIndex: 0,
  64. // 扫描出来的deviceId
  65. deviceId: "",
  66. // // 选择绑定的人index
  67. // index: 0,
  68. btnLoading: false,
  69. list: [],
  70. // 不包含自己
  71. userList: [],
  72. status: 1
  73. }
  74. },
  75. onLoad() {
  76. uni.$on('getScanCodeInfoFamily',(data)=>{
  77. this.deviceId = data.imei || ""
  78. this.verifyDeviceId(this.editIndex,data)
  79. })
  80. },
  81. onUnload() {
  82. uni.$off("getScanCodeInfoFamily")
  83. },
  84. onShow() {
  85. if(this.$isLogin()){
  86. this.getList()
  87. }
  88. },
  89. methods: {
  90. back() {
  91. uni.navigateBack({
  92. delta: 1
  93. })
  94. },
  95. // 新增
  96. handleAdd() {
  97. uni.navigateTo({
  98. url: "/pages_watch/index/myfamily/changeTitle?type=add",
  99. })
  100. },
  101. // 编辑
  102. handleEdit(index) {
  103. uni.navigateTo({
  104. url: '/pages_watch/index/myfamily/changeTitle?type=edit&index='+ index
  105. })
  106. },
  107. getList() {
  108. getFamWatchInfo().then(res=>{
  109. if(res.code == 200 && res.data && res.data.length > 0) {
  110. // 使用reduce方法根据name和relationship字段进行分组
  111. const groupedByNameAndRelationship = res.data.reduce((acc, cur) => {
  112. // 如果acc中没有这个name的键,就创建一个
  113. if (!acc.find(item => item.name === cur.name)) {
  114. acc.push({ name: cur.name, child: [] });
  115. }
  116. // 将当前对象添加到对应的name下的child数组中
  117. const index = acc.findIndex(item => item.name === cur.name);
  118. if (index !== -1) {
  119. acc[index].child.push(cur);
  120. }
  121. return acc;
  122. }, []);
  123. let arry = groupedByNameAndRelationship.filter(el=>el.name!='自己')
  124. let my = groupedByNameAndRelationship.filter(el=>el.name=='自己')
  125. this.list = my.concat(arry)
  126. this.userList = groupedByNameAndRelationship.filter(el=>el.name!='自己').map(item=>({
  127. name: item.name,
  128. deviceId: item.child.map(device =>
  129. device.deviceId ? device.deviceId.split(',') : []
  130. ).reduce((acc, ids) => acc.concat(ids), []),
  131. relationship: item.child[0].relationship
  132. }))
  133. } else {
  134. this.list = []
  135. }
  136. })
  137. },
  138. // getUser(){
  139. // getWatchUserInfo({isFamily: false}).then(res=>{
  140. // let otherDevice = res.user.otherDevice ? JSON.parse(res.user.otherDevice) : []
  141. // this.userList = otherDevice.map(item=>({
  142. // ...item,
  143. // deviceId: item.deviceId ? item.deviceId.split(',') : []
  144. // }))
  145. // const arry = [{
  146. // name: "自己",
  147. // deviceId: res.user.deviceId,
  148. // relationship: ""
  149. // }]
  150. // this.list = arry.concat(this.userList)
  151. // })
  152. // },
  153. // 绑定预警手表
  154. async handleBind(index) {
  155. this.editIndex = index
  156. // #ifdef APP-PLUS
  157. let status = await this.checkAppCamera(index)
  158. if(status == 1) {
  159. // this.scanQRCode(index)
  160. uni.navigateTo({
  161. url: '/pages_watch/healthMonitoring/scanCode?typeFun=getScanCodeInfoFamily'
  162. })
  163. }
  164. // #endif
  165. // #ifdef MP-WEIXIN
  166. this.checkWXCamera(index)
  167. // #endif
  168. },
  169. scanQRCode(index) {
  170. const that = this
  171. uni.scanCode({
  172. success(res) {
  173. if (res.result) {
  174. // 扫描成功,处理二维码内容
  175. console.log('扫描结果:', res.result);
  176. const scanInfo = JSON.parse(res.result)
  177. that.deviceId = scanInfo.dev_info.imei || ""
  178. that.verifyDeviceId(index,scanInfo.dev_info)
  179. } else {
  180. // 扫描失败
  181. uni.showToast({
  182. title: '扫描失败',
  183. icon: 'none'
  184. });
  185. }
  186. },
  187. fail() {}
  188. });
  189. },
  190. // 验证设备
  191. verifyDeviceId(index,data) {
  192. // index,0表示自己,如果是自己绑定直接调用修改用户信息接口
  193. this.btnLoading = true
  194. if(index == 0) {
  195. editDevice(data).then(res=>{
  196. this.btnLoading = false
  197. if(res.code == 200) {
  198. uni.showToast({
  199. title: res.msg,
  200. icon: "none",
  201. position: 'top',
  202. duration: 2000
  203. })
  204. // this.getUser()
  205. this.getList()
  206. } else {
  207. uni.showToast({
  208. title: res.msg,
  209. icon: "none",
  210. position: 'top',
  211. duration: 2000
  212. })
  213. }
  214. }).catch(err=>{
  215. this.btnLoading = false
  216. })
  217. } else {
  218. this.bindDeviceId(index)
  219. // getStatus({deviceId: this.deviceId}).then(res=>{
  220. // if(res.code == 200) {
  221. // if(res.data === 0 || res.data === 1 || res.data === 2 || res.data === 3) {
  222. // this.bindDeviceId(index)
  223. // } else {
  224. // this.btnLoading = false
  225. // uni.showToast({
  226. // title: '绑定失败',
  227. // icon: "none",
  228. // position: 'top',
  229. // duration: 2000
  230. // })
  231. // }
  232. // }else {
  233. // this.btnLoading = false
  234. // uni.showToast({
  235. // title: res.msg,
  236. // icon: "none",
  237. // position: 'top',
  238. // duration: 2000
  239. // })
  240. // }
  241. // }).catch(err=>{
  242. // this.btnLoading = false
  243. // })
  244. }
  245. },
  246. // 绑定设备
  247. bindDeviceId(index) {
  248. const param = this.userList.map((item,idx)=>({
  249. ...item,
  250. deviceId: idx == index-1 && !item.deviceId.includes(this.deviceId) ? item.deviceId.concat([this.deviceId]).join(',') : item.deviceId.join(',')
  251. }))
  252. console.log("this.userList=====",this.userList)
  253. editMyfamily({otherDevice: JSON.stringify(param)}).then(res=>{
  254. this.btnLoading = false
  255. if(res.code == 200) {
  256. uni.showToast({
  257. title: "绑定成功",
  258. icon: "none",
  259. position: 'top',
  260. duration: 2000
  261. })
  262. // this.getUser()
  263. this.getList()
  264. } else {
  265. uni.showToast({
  266. title: res.msg,
  267. icon: "none",
  268. position: 'top',
  269. duration: 2000
  270. })
  271. }
  272. }).catch(err => {
  273. this.btnLoading = false
  274. console.log('err', err);
  275. })
  276. },
  277. async checkAppCamera() {
  278. let status = permision.isIOS ? await permision.requestIOS("camera") : await permision.requestAndroid("android.permission.CAMERA")
  279. if(status === null || status == 1) {
  280. status == 1
  281. } else if(status == 2) {
  282. uni.showModal({
  283. content: "相机权限已关闭",
  284. showCancel: false,
  285. success: () => {}
  286. })
  287. } else if(status.code) {
  288. uni.showModal({
  289. content: status.message
  290. })
  291. } else {
  292. uni.showModal({
  293. content: "为了使用相机功能,请点击设置开启相机权限",
  294. confirmText: "设置",
  295. success: (res) => {
  296. if(res.confirm) {
  297. permision.gotoAppSetting()
  298. }
  299. }
  300. })
  301. }
  302. return status
  303. },
  304. checkWXCamera(index) {
  305. const that = this
  306. uni.getSetting({
  307. success(res) {
  308. // 判断是否拥有此权限进行拉起授权 和 重新授权功能
  309. if (!res.authSetting['scope.camera']) {
  310. // 未授权此项权限 拉起授界面
  311. uni.authorize({
  312. scope: 'scope.camera',
  313. success() {
  314. // 授权成功后 就可以执行 需要权限的 操作函数了
  315. // 使用已授权的功能
  316. that.scanQRCode(index);
  317. },
  318. fail(err) {
  319. /*
  320. 第一次拒绝授权后必须在 uni.authorize的fail中使用
  321. uni.openSetting 才能进入设置界面打开授权按钮
  322. */
  323. uni.showToast({
  324. title: '您拒绝了授权',
  325. icon: 'none'
  326. });
  327. // 这里必须经过一个confirm 不然也会出现问题(啥问题我也不知道)
  328. uni.showModal({
  329. title: '是否重新授权相机功能',
  330. success(res) {
  331. if (res.confirm) {
  332. uni.openSetting({
  333. success() {
  334. console.log('开启权限成功');
  335. },
  336. fail() {
  337. console.log('开启权限失败');
  338. }
  339. });
  340. } else if (res.cancel) {
  341. console.log('拒绝开启开启权限');
  342. }
  343. }
  344. });
  345. }
  346. });
  347. } else {
  348. that.scanQRCode(index)
  349. }
  350. }
  351. });
  352. }
  353. }
  354. }
  355. </script>
  356. <style lang="scss" scoped>
  357. @mixin u-flex($flexD, $alignI, $justifyC) {
  358. display: flex;
  359. flex-direction: $flexD;
  360. align-items: $alignI;
  361. justify-content: $justifyC;
  362. }
  363. .device-list {
  364. white-space: nowrap;
  365. padding-top: 24rpx;
  366. }
  367. .device-item {
  368. display: inline-flex;
  369. border-radius: 16rpx;
  370. padding: 16rpx;
  371. margin-right: 20rpx;
  372. box-sizing: border-box;
  373. font-family: PingFang SC, PingFang SC;
  374. font-weight: 500;
  375. font-size: 32rpx;
  376. color: #333333;
  377. border: 2rpx solid #f5f5f5;
  378. &:last-of-type {
  379. margin-bottom: 0;
  380. }
  381. image {
  382. width: 78rpx;
  383. height: 78rpx;
  384. border-radius: 50%;
  385. padding: 10rpx;
  386. margin-right: 28rpx;
  387. }
  388. .green {
  389. &::after {
  390. background-color: #52D087;
  391. }
  392. }
  393. .red {
  394. &::after {
  395. background-color: #FF5558;
  396. }
  397. }
  398. .device-status {
  399. padding-left: 30rpx;
  400. position: relative;
  401. &::after {
  402. content: "";
  403. width: 16rpx;
  404. height: 16rpx;
  405. border-radius: 50%;
  406. position: absolute;
  407. left: 0;
  408. top: 50%;
  409. transform: translateY(-50%);
  410. }
  411. }
  412. .device-item-desc {
  413. margin-top: 6rpx;
  414. font-family: PingFang SC, PingFang SC;
  415. font-weight: 400;
  416. font-size: 28rpx;
  417. color: #757575;
  418. .watch {
  419. flex-shrink: 0;
  420. width: 40rpx;
  421. height: 40rpx;
  422. margin-left: -16rpx;
  423. margin-right: -6rpx;
  424. }
  425. .electricity {
  426. flex-shrink: 0;
  427. width: 36rpx;
  428. height: 32rpx;
  429. margin: 0 10rpx 0 64rpx;
  430. }
  431. }
  432. }
  433. .footer-add {
  434. width: 702rpx;
  435. height: 98rpx;
  436. background: #FFFFFF;
  437. border-radius: 16rpx;
  438. font-family: PingFang SC, PingFang SC;
  439. font-weight: 500;
  440. font-size: 32rpx;
  441. color: #FF7700;
  442. line-height: 98rpx;
  443. text-align: center;
  444. margin-top: 24rpx 0;
  445. }
  446. .add {
  447. font-family: PingFang SC, PingFang SC;
  448. font-weight: 400;
  449. font-size: 24rpx;
  450. color: #FF7700;
  451. @include u-flex(row, center, flex-end);
  452. image {
  453. flex-shrink: 0;
  454. width: 48rpx;
  455. height: 48rpx;
  456. margin-right: 6rpx;
  457. }
  458. }
  459. .container {
  460. padding: 24rpx;
  461. .family-card {
  462. width: 100%;
  463. min-height: 298rpx;
  464. margin-bottom: 20rpx;
  465. padding: 24rpx;
  466. box-sizing: border-box;
  467. background: #FFFFFF;
  468. border-radius: 16rpx 16rpx 16rpx 16rpx;
  469. }
  470. }
  471. .card{
  472. &-header {
  473. height: 64rpx;
  474. padding-bottom: 18rpx;
  475. width: 100%;
  476. line-height: 64rpx;
  477. @include u-flex(row, center, space-between);
  478. font-family: PingFang SC, PingFang SC;
  479. font-weight: 400;
  480. font-size: 24rpx;
  481. color: #999999;
  482. position: relative;
  483. image {
  484. height: 48rpx;
  485. width: 48rpx;
  486. }
  487. &-right {
  488. flex-shrink: 0;
  489. @include u-flex(row, center, flex-start);
  490. }
  491. }
  492. &-title {
  493. font-weight: 500;
  494. font-size: 32rpx;
  495. color: #333333;
  496. }
  497. &-body {
  498. .bind_btn {
  499. width: 308rpx;
  500. height: 72rpx;
  501. background-color: #fff;
  502. border-radius: 36rpx 36rpx 36rpx 36rpx;
  503. border: 2rpx solid #ECECEC;
  504. font-family: PingFang SC, PingFang SC;
  505. font-weight: 400;
  506. font-size: 24rpx;
  507. color: #333333;
  508. @include u-flex(row, center, center);
  509. margin: auto;
  510. margin-top: 60rpx;
  511. &::after {
  512. border: none;
  513. }
  514. image {
  515. width: 24rpx;
  516. height: 24rpx;
  517. margin-right: 12rpx;
  518. }
  519. }
  520. }
  521. }
  522. </style>