From c4bccbc11c5fca2908a93746f982910a840250d0 Mon Sep 17 00:00:00 2001 From: blak-kong <546598185@qq.com> Date: Tue, 12 Mar 2024 20:18:57 +0800 Subject: [PATCH] =?UTF-8?q?iot=E6=8B=86=E5=88=86=E5=AD=90=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 41 +- src/app.config.ts | 11 +- src/moduleIOT/pages/iotCarePlan/FR200.less | 0 src/moduleIOT/pages/iotCarePlan/FR200.tsx | 0 .../iotCarePlan/components/Echart/index.less | 1634 ++++++++++++ .../iotCarePlan/components/Echart/index.tsx | 621 +++++ .../components/ElectricityView/index.tsx | 111 + .../iotCarePlan/components/Footer/index.less | 76 + .../iotCarePlan/components/Footer/index.tsx | 132 + .../components/ModeContent/index.less | 57 + .../components/ModeContent/index.tsx | 51 + .../components/ModeList/index.less | 157 ++ .../iotCarePlan/components/ModeList/index.tsx | 238 ++ .../pages/iotCarePlan/iotCarePlan.less | 148 ++ .../pages/iotCarePlan/iotCarePlan.tsx | 2211 +++++++++++++++++ src/pages/index/index.tsx | 4 +- src/pages/instrument/intro.tsx | 4 +- 17 files changed, 5469 insertions(+), 27 deletions(-) create mode 100644 src/moduleIOT/pages/iotCarePlan/FR200.less create mode 100644 src/moduleIOT/pages/iotCarePlan/FR200.tsx create mode 100644 src/moduleIOT/pages/iotCarePlan/components/Echart/index.less create mode 100644 src/moduleIOT/pages/iotCarePlan/components/Echart/index.tsx create mode 100644 src/moduleIOT/pages/iotCarePlan/components/ElectricityView/index.tsx create mode 100644 src/moduleIOT/pages/iotCarePlan/components/Footer/index.less create mode 100644 src/moduleIOT/pages/iotCarePlan/components/Footer/index.tsx create mode 100644 src/moduleIOT/pages/iotCarePlan/components/ModeContent/index.less create mode 100644 src/moduleIOT/pages/iotCarePlan/components/ModeContent/index.tsx create mode 100644 src/moduleIOT/pages/iotCarePlan/components/ModeList/index.less create mode 100644 src/moduleIOT/pages/iotCarePlan/components/ModeList/index.tsx create mode 100644 src/moduleIOT/pages/iotCarePlan/iotCarePlan.less create mode 100644 src/moduleIOT/pages/iotCarePlan/iotCarePlan.tsx diff --git a/package.json b/package.json index a6e080b..d08cd69 100644 --- a/package.json +++ b/package.json @@ -35,26 +35,25 @@ ], "author": "", "dependencies": { - "@antmjs/vantui": "^3.2.2", + "@antmjs/vantui": "^3.3.5", "@flossom-npm/iot-translater": "^1.0.8", "@flossom-npm/iot-translater-we100": "^1.1.1", "@reduxjs/toolkit": "^2.0.1", - "@taroify/core": "^0.1.1-alpha.8", - "@tarojs/components": "3.6.19", - "@tarojs/helper": "3.6.19", - "@tarojs/plugin-framework-react": "3.6.19", + "@tarojs/components": "~3.6.24", + "@tarojs/helper": "~3.6.24", + "@tarojs/plugin-framework-react": "~3.6.24", "@tarojs/plugin-html": "^3.6.20", - "@tarojs/plugin-platform-alipay": "3.6.19", - "@tarojs/plugin-platform-h5": "3.6.19", - "@tarojs/plugin-platform-jd": "3.6.19", - "@tarojs/plugin-platform-qq": "3.6.19", - "@tarojs/plugin-platform-swan": "3.6.19", - "@tarojs/plugin-platform-tt": "3.6.19", - "@tarojs/plugin-platform-weapp": "3.6.19", - "@tarojs/react": "3.6.19", - "@tarojs/runtime": "3.6.19", - "@tarojs/shared": "3.6.19", - "@tarojs/taro": "3.6.19", + "@tarojs/plugin-platform-alipay": "~3.6.24", + "@tarojs/plugin-platform-h5": "~3.6.24", + "@tarojs/plugin-platform-jd": "~3.6.24", + "@tarojs/plugin-platform-qq": "~3.6.24", + "@tarojs/plugin-platform-swan": "~3.6.24", + "@tarojs/plugin-platform-tt": "~3.6.24", + "@tarojs/plugin-platform-weapp": "~3.6.24", + "@tarojs/react": "~3.6.24", + "@tarojs/runtime": "~3.6.24", + "@tarojs/shared": "~3.6.24", + "@tarojs/taro": "~3.6.24", "dayjs": "^1.11.10", "echarts": "^5.5.0", "lodash": "^4.17.15", @@ -68,19 +67,19 @@ "@babel/core": "^7.8.0", "@babel/runtime": "^7.7.7", "@pmmmwh/react-refresh-webpack-plugin": "^0.5.5", - "@tarojs/cli": "3.6.19", - "@tarojs/taro-loader": "3.6.19", - "@tarojs/webpack5-runner": "3.6.19", + "@tarojs/cli": "~3.6.24", + "@tarojs/taro-loader": "~3.6.24", + "@tarojs/webpack5-runner": "~3.6.24", "@types/node": "^18.15.11", "@types/react": "^18.0.0", "@types/webpack-env": "^1.13.6", "@typescript-eslint/eslint-plugin": "^5.20.0", "@typescript-eslint/parser": "^5.20.0", "babel-plugin-import": "^1.13.8", - "babel-preset-taro": "3.6.19", + "babel-preset-taro": "3.6.24", "cache-loader": "^4.1.0", "eslint": "^8.12.0", - "eslint-config-taro": "3.6.19", + "eslint-config-taro": "~3.6.24", "eslint-plugin-import": "^2.12.0", "eslint-plugin-react": "^7.8.2", "eslint-plugin-react-hooks": "^4.2.0", diff --git a/src/app.config.ts b/src/app.config.ts index a3ad8a5..a4e9b69 100644 --- a/src/app.config.ts +++ b/src/app.config.ts @@ -17,7 +17,6 @@ export default defineAppConfig({ "pages/instrument_manage/index", "pages/instrument_detail/index", "pages/instrumentClickinUpload/index", - "pages/iotCarePlan/iotCarePlan", 'pages/privacyPolicy/privacyPolicy', 'pages/userPolicy/userPolicy', 'pages/about/about', @@ -82,5 +81,13 @@ export default defineAppConfig({ navigationBarTextStyle: 'black', // enablePullDownRefresh: true }, - requiredPrivateInfos: ["getLocation"] + requiredPrivateInfos: ["getLocation"], + subPackages: [ + { + root: 'moduleIOT', + pages: [ + "pages/iotCarePlan/iotCarePlan", + ] + } + ] }) diff --git a/src/moduleIOT/pages/iotCarePlan/FR200.less b/src/moduleIOT/pages/iotCarePlan/FR200.less new file mode 100644 index 0000000..e69de29 diff --git a/src/moduleIOT/pages/iotCarePlan/FR200.tsx b/src/moduleIOT/pages/iotCarePlan/FR200.tsx new file mode 100644 index 0000000..e69de29 diff --git a/src/moduleIOT/pages/iotCarePlan/components/Echart/index.less b/src/moduleIOT/pages/iotCarePlan/components/Echart/index.less new file mode 100644 index 0000000..3813c5a --- /dev/null +++ b/src/moduleIOT/pages/iotCarePlan/components/Echart/index.less @@ -0,0 +1,1634 @@ +.box { + width: 690rpx; + height: 320rpx; + margin: 28rpx auto; + background-color: #fff; + border-radius: 30rpx; + padding: 35rpx 25rpx 25rpx 35rpx; + box-sizing: border-box; + position: relative; + z-index: 0; +} +.box_background { + position: absolute; + top: 0; + left: 0; + width: 690rpx; + height: 320rpx; + border-radius: 30rpx; + background-color: #fff; + .power { + margin: 34rpx 0 28rpx 28rpx; + font-family: PingFang-SC; + font-weight: 500; + font-size: 18rpx; + color: #cccccc; + } + .full { + width: 24rpx; + height: 24rpx; + position: absolute; + top: 32rpx; + right: 26rpx; + } + .line { + margin: 0 0 6rpx 35rpx; + font-family: PingFang-SC; + font-size: 14rpx; + color: #cccccc; + display: flex; + position: relative; + height: 18rpx; + .bottom_line { + border-bottom: 1rpx #ccc dashed; + width: 550rpx; + margin-left: 20rpx; + position: absolute; + bottom: -6rpx; + right: 74rpx; + height: 4rpx; + color: #fff; + } + } + + .time { + position: absolute; + bottom: 22rpx; + right: 24rpx; + font-family: PingFang-SC; + font-size: 18rpx; + color: #cccccc; + } +} + +page { + background: #f8f8f8; + background: #f3f3f3; +} +.titlemain { + position: fixed; + z-index: 99; + width: 100%; + top: 0; + .logoicon { + width: 223rpx; + } + .title { + position: relative; + display: flex; + align-items: center; + justify-content: center; + } +} +.infobox1 { + background: #fff; + border-radius: 30rpx; + margin: 27rpx 30rpx 22rpx; + position: relative; + box-shadow: -2rpx 0 12rpx 0.5rpx rgba(129, 129, 129, 0.05); + .img { + width: 690rpx; + height: 690rpx; + box-shadow: -2rpx 0 12rpx 0.5rpx rgba(129, 129, 129, 0.05); + position: relative; + border-radius: 20rpx; + margin: auto; + .imgz { + border-radius: 20rpx; + width: 100%; + height: 100%; + overflow: hidden; + .video_tip { + position: absolute; + z-index: 99; + background: rgba(0, 0, 0, 0.5); + color: #fff; + font-size: 28rpx; + top: 50%; + left: 50%; + margin-top: -25rpx; + padding: 11rpx 34rpx; + font-weight: 500; + border-radius: 30rpx; + width: 500rpx; + transform: translateX(-50%); + text-align: center; + word-break: break-word; + box-sizing: border-box; + .icon { + width: 30rpx; + height: 30rpx; + margin-right: 17rpx; + } + } + .music { + width: 54rpx; + height: 54rpx; + background: rgba(255, 255, 255, 0.6); + border-radius: 50%; + position: absolute; + right: 20rpx; + top: 20rpx; + image { + width: 100%; + height: 100%; + } + } + } + .tipbox2 { + position: absolute; + z-index: 999999; + width: 500rpx; + bottom: -290rpx; + background: linear-gradient(#e2c6a3, #c7a274); + border-radius: 20rpx; + padding: 0 0 16rpx 0; + .jicon { + width: 26rpx; + position: absolute; + top: -20rpx; + left: 54rpx; + } + .tip1 { + color: #fefeff; + font-size: 36rpx; + padding: 34rpx 24rpx 0 24rpx; + } + .tip_btn { + background: #ffffff; + border-radius: 26rpx; + width: 154rpx; + height: 52rpx; + line-height: 52rpx; + text-align: center; + font-size: 30rpx; + font-weight: bold; + color: #c69962; + margin-top: 16rpx; + position: relative; + left: calc(500rpx - 36rpx - 154rpx); + } + } + .dottedLine { + border: 4rpx dashed #e2c6a3; + height: 100%; + position: absolute; + z-index: 999999; + border-radius: 20rpx; + right: 0; + left: 0; + } + .tipbox1 { + position: absolute; + z-index: 999999; + width: 480rpx; + bottom: -330rpx; + background: linear-gradient(#e2c6a3, #c7a274); + border-radius: 20rpx; + padding: 0 0 16rpx 0; + margin-left: 8rpx; + .jicon { + width: 26rpx; + position: absolute; + top: -20rpx; + left: 54rpx; + } + .tip1 { + color: #fefeff; + font-size: 36rpx; + padding: 34rpx 2rpx 0 24rpx; + } + .tip_btn { + background: #ffffff; + border-radius: 26rpx; + width: 154rpx; + height: 52rpx; + line-height: 52rpx; + text-align: center; + font-size: 30rpx; + font-weight: bold; + color: #c69962; + margin-top: 14rpx; + position: relative; + left: calc(460rpx - 22rpx - 154rpx); + } + } + } + .info1 { + height: 92rpx; + background: #fff; + border-radius: 20rpx; + position: relative; + .dottedLine { + border: 4rpx dashed #e2c6a3; + height: 100%; + position: absolute; + z-index: 999999; + border-radius: 20rpx; + right: 0; + left: 0; + } + .block { + width: 33%; + text-align: center; + .num { + font-size: 30rpx; + font-weight: 800; + color: #000000; + } + .color { + font-size: 30rpx; + font-weight: 800; + color: #000000; + } + .icon { + position: relative; + margin-left: 10rpx; + .num { + position: absolute; + color: #e8d3b0; + font-size: 22rpx; + font-weight: bold; + left: 50%; + margin-left: -8rpx; + top: 50%; + margin-top: -18rpx; + } + } + .dianliang1 { + background: linear-gradient(0deg, #efdcc2, #fff2df); + width: 10rpx; + height: 24rpx; + border-radius: 5rpx; + margin: 0 12rpx 0 0; + } + .dianliang2 { + background: #f8f8f8; + width: 10rpx; + height: 24rpx; + border-radius: 5rpx; + margin: 0 12rpx 0 0; + } + } + .border { + background: #dddddd; + width: 1rpx; + height: 50rpx; + } + } + .border_img { + position: absolute; + width: 700rpx; + z-index: 9999999; + bottom: -6rpx; + border: 6rpx dashed #e2c6a3; + border-radius: 20rpx; + padding: 4rpx; + left: -4rpx; + } + .tipbox4 { + position: absolute; + z-index: 999999; + width: 460rpx; + bottom: -260rpx; + background: linear-gradient(#e2c6a3, #c7a274); + border-radius: 20rpx; + padding: 0 0 16rpx 0; + .jicon { + width: 26rpx; + position: absolute; + top: -20rpx; + left: 54rpx; + } + .tip1 { + color: #fefeff; + font-size: 36rpx; + padding: 34rpx 0 0 24rpx; + } + .tip_btn { + background: #ffffff; + border-radius: 26rpx; + width: 154rpx; + height: 52rpx; + line-height: 52rpx; + text-align: center; + font-size: 30rpx; + font-weight: bold; + color: #c69962; + margin-top: 14rpx; + position: relative; + left: calc(460rpx - 22rpx - 154rpx); + } + } +} +.infobox1 .info1 .block .tip1, +.infobox1 .info1 .block .dang { + font-size: 26rpx; + font-weight: 500; + color: #000000; +} +.infobox2 { + position: relative; + border-radius: 20rpx; + height: 74rpx; + margin: 60rpx 20rpx 0; + .block { + width: 50%; + .icon { + width: 46rpx; + } + .name { + margin-left: 14rpx; + color: #202020; + font-size: 22rpx; + } + } + .border { + background: #696460; + width: 2rpx; + height: 16rpx; + } + .border_img4 { + height: 94rpx; + border: 6rpx dashed #e2c6a3; + position: absolute; + z-index: 99999; + left: -8rpx; + width: calc(100% + 8rpx); + border-radius: 20rpx; + } + .tipbox5 { + position: fixed; + z-index: 999999; + width: 460rpx; + background: linear-gradient(#e2c6a3, #c7a274); + border-radius: 20rpx; + padding: 0 0 24rpx 0; + left: 60rpx; + .jicon { + width: 26rpx; + position: absolute; + bottom: -20rpx; + left: 54rpx; + } + .tip1 { + color: #fefeff; + font-size: 36rpx; + padding: 26rpx 0 0 34rpx; + } + .tip_btn { + background: #ffffff; + border-radius: 26rpx; + width: 154rpx; + height: 52rpx; + line-height: 52rpx; + text-align: center; + font-size: 30rpx; + font-weight: bold; + color: #c69962; + margin-top: 14rpx; + position: relative; + left: calc(460rpx - 22rpx - 154rpx); + } + } +} +.action_box { + position: fixed; + bottom: 0; + width: 100%; + height: 138rpx; + background: #ffffff; + box-shadow: 0rpx -3rpx 7rpx 1rpx rgba(173, 191, 207, 0.21); + border-bottom: 15rpx solid #ffffff; + .line { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 2rpx; + height: 70rpx; + background: #dddddd; + } + .items { + flex: 1; + } + .start_img { + width: 36rpx; + height: 36rpx; + } + .disabled { + opacity: 0.5 !important; + } + .end_img { + width: 36rpx; + height: 36rpx; + } + .text { + font-size: 32rpx; + font-weight: bold; + color: #000000; + margin-left: 18rpx; + } + .start_test { + width: 100%; + padding: 0 30rpx; + .txt { + width: 100%; + height: 90rpx; + line-height: 90rpx; + background: #000000; + border-radius: 45rpx; + text-align: center; + font-size: 32rpx; + font-weight: bold; + color: #ffffff; + } + } +} +.infobox3 { + margin: 4rpx 0 0 0; + height: 162rpx; + position: relative; + border-radius: 20rpx; + .tipbox4 { + position: absolute; + z-index: 999999; + width: 460rpx; + bottom: -260rpx; + background: linear-gradient(#e2c6a3, #c7a274); + border-radius: 20rpx; + padding: 0 0 16rpx 0; + .jicon { + width: 26rpx; + position: absolute; + top: -20rpx; + left: 54rpx; + } + .tip1 { + color: #fefeff; + font-size: 36rpx; + padding: 34rpx 0 0 24rpx; + } + .tip_btn { + background: #ffffff; + border-radius: 26rpx; + width: 154rpx; + height: 52rpx; + line-height: 52rpx; + text-align: center; + font-size: 30rpx; + font-weight: bold; + color: #c69962; + margin-top: 14rpx; + position: relative; + left: calc(460rpx - 22rpx - 154rpx); + } + } + .dottedLine { + border: 4rpx dashed #e2c6a3; + height: 100%; + position: absolute; + z-index: 999999; + border-radius: 20rpx; + right: 0; + left: 0; + } + .left { + display: inline-block; + width: 134rpx; + background: #fff; + border-radius: 0 18rpx 18rpx 0; + margin: 0 22rpx 0 0; + overflow: hidden; + .img { + width: 78rpx; + height: 78rpx; + margin-top: 10rpx; + margin: 4rpx auto 0; + } + .tip { + color: #000; + font-size: 22rpx; + padding: 4rpx 0; + text-align: center; + } + .checked { + text-align: center; + } + } + .info1 { + display: inline-block; + white-space: nowrap; + background: #fff; + flex-direction: column; + height: 100%; + border-radius: 20rpx; + overflow: hidden; + box-shadow: -2rpx 0 12rpx 0.5rpx rgba(129, 129, 129, 0.05); + .block1 { + .block1_1 { + height: 100%; + padding: 0 20rpx; + flex-direction: column; + .tip1 { + font-size: 26rpx; + font-weight: bold; + color: #000000; + } + .tip2 { + font-size: 24rpx; + font-weight: 500; + color: #666666; + padding-top: 3rpx; + } + } + } + .block2 { + display: inline-block; + height: 100%; + width: 0; + transition: all 0.3s; + .block2_info { + width: 140rpx; + text-align: center; + box-shadow: -2rpx 0 12rpx 0.5rpx rgba(129, 129, 129, 0.05); + height: calc(140rpx - 10rpx); + border-radius: 20rpx; + align-items: flex-end; + padding: 0 0 10rpx 0; + display: inline-block; + position: relative; + overflow: hidden; + .block2_img { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + } + .block3_img { + -webkit-filter: grayscale(100%); + -moz-filter: grayscale(100%); + -ms-filter: grayscale(100%); + -o-filter: grayscale(100%); + filter: grayscale(100%); + filter: gray; + opacity: 0.5; + } + .block2_bg { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + opacity: 0.5; + } + .block2_info1 { + height: 100%; + position: relative; + z-index: 99; + background: transparent; + .block2_info1_tip1 { + color: #202020; + font-weight: bold; + font-size: 22rpx; + position: absolute; + bottom: 20rpx; + width: 100%; + text-align: center; + } + .block2_info1_tip2 { + color: #202020; + font-size: 16rpx; + position: absolute; + bottom: 0; + text-align: center; + width: 100%; + } + } + } + } + .icon { + width: 28rpx; + margin-top: 20rpx; + } + } + .info2 { + width: calc(100% - 130rpx - 20rpx); + background: #fff; + height: 162rpx; + border-radius: 20rpx; + box-shadow: -2rpx 0 12rpx 0.5rpx rgba(129, 129, 129, 0.05); + .block1 { + padding: 0 16rpx; + } + } + .border_img2 { + width: calc(100% + 8rpx); + position: absolute; + z-index: 999999; + left: -8rpx; + } + .tipbox3 { + position: absolute; + z-index: 999999; + width: 460rpx; + bottom: -290rpx; + background: linear-gradient(#e2c6a3, #c7a274); + border-radius: 20rpx; + padding: 0 0 16rpx 0; + margin-left: 8rpx; + .jicon { + width: 26rpx; + position: absolute; + top: -20rpx; + left: 54rpx; + } + .tip1 { + color: #fefeff; + font-size: 36rpx; + padding: 34rpx 0 0 24rpx; + } + .tip_btn { + background: #ffffff; + border-radius: 26rpx; + width: 154rpx; + height: 52rpx; + line-height: 52rpx; + text-align: center; + font-size: 30rpx; + font-weight: bold; + color: #c69962; + margin-top: 14rpx; + position: relative; + left: calc(460rpx - 22rpx - 154rpx); + } + } +} +.infobox3 .info1 .block1, +.infobox3 .info2 .block1 { + flex-direction: column; + display: inline-block; + height: 100%; + text-align: center; +} +.infobox3 .info1 .tip1, +.infobox3 .info2 .tip1 { + color: #202020; + font-size: 22rpx; + font-weight: bold; +} +.infobox3 .info1 .tip2, +.infobox3 .info2 .tip2 { + color: #202020; + font-size: 22rpx; +} +.infobox3 .info1 .quan1, +.infobox3 .info2 .quan1 { + border-radius: 50%; + width: 30rpx; + height: 30rpx; + position: relative; + margin: 18rpx auto 0; + background: #fff; + box-sizing: border-box; + border: 4rpx solid #f1f1f1; +} +.infobox3 .info1 .quan1 .quan2, +.infobox3 .info2 .quan1 .quan2 { + position: absolute; + border-radius: 50%; + background: #000000; + width: 14rpx; + height: 14rpx; +} +.tipbox { + position: absolute; + z-index: 999999; + width: 100%; + bottom: 50rpx; + .tip1 { + color: #fefeff; + font-size: 36rpx; + text-align: center; + } + .tip_btn { + background: #e2c6a3; + border-radius: 32rpx; + width: 212rpx; + height: 66rpx; + line-height: 66rpx; + text-align: center; + margin: auto; + font-size: 30rpx; + font-weight: bold; + color: #ffffff; + margin-top: 54rpx; + } +} +.infobox4 { + height: 300rpx; + border-radius: 20rpx; + box-shadow: -2rpx 0 12rpx 0.5rpx rgba(129, 129, 129, 0.05); + margin: 22rpx 20rpx; + background: #fff; + position: relative; + .dottedLine { + border: 4rpx dashed #e2c6a3; + height: 100%; + position: absolute; + z-index: 999999; + border-radius: 20rpx; + right: 0; + left: 0; + } + .border_img3 { + width: calc(100% + 16rpx); + position: absolute; + z-index: 999999; + top: -15rpx; + left: -8rpx; + } + .tipbox5 { + position: absolute; + z-index: 999999; + width: 460rpx; + top: -280rpx; + background: linear-gradient(#e2c6a3, #c7a274); + border-radius: 20rpx; + padding: 0 0 24rpx 0; + margin-left: 60rpx; + .jicon { + width: 26rpx; + position: absolute; + bottom: -20rpx; + left: 54rpx; + } + .tip1 { + color: #fefeff; + font-size: 36rpx; + padding: 26rpx 0 0 34rpx; + } + .tip_btn { + background: #ffffff; + border-radius: 26rpx; + width: 154rpx; + height: 52rpx; + line-height: 52rpx; + text-align: center; + font-size: 30rpx; + font-weight: bold; + color: #c69962; + margin-top: 14rpx; + position: relative; + left: calc(460rpx - 22rpx - 154rpx); + } + } +} +ec-canvas { + width: 100%; + height: 100%; +} +.popbox2 { + width: 670rpx; + height: 1102rpx; + background: #ffffff; + border-radius: 30rpx; + & > .title { + text-align: center; + padding: 49rpx 0 61rpx; + font-size: 36rpx; + font-weight: bold; + color: #030000; + line-height: 1; + } + & > .tipimg { + margin: 20rpx 28rpx 0; + } + & > .tipvideo { + margin: 0 auto; + width: 600rpx; + height: 600rpx; + } + & > .tiptext { + margin: 65rpx 0 63rpx; + padding: 0 48rpx 0 36rpx; + font-size: 28rpx; + font-weight: 500; + color: #000000; + min-height: 76rpx; + } + & > .popbox2btn { + & > .nextbtn { + text-align: center; + color: #fff; + width: 270rpx; + height: 90rpx; + line-height: 90rpx; + background: #000000; + border-radius: 45rpx; + font-size: 32rpx; + font-weight: bold; + margin: 0 auto; + box-sizing: border-box; + } + & > .prebtn { + text-align: center; + width: 270rpx; + height: 90rpx; + line-height: 90rpx; + border-radius: 45rpx; + font-weight: bold; + font-size: 32rpx; + color: #000000; + border: 2rpx solid #000000; + background: #ffffff; + margin: 0 auto; + box-sizing: border-box; + } + } + & > .icon { + position: absolute; + top: 0; + right: 0; + width: 90rpx; + height: 90rpx; + display: flex; + justify-content: center; + align-items: center; + & > image { + width: 24rpx; + height: 24rpx; + } + } +} +.popbox2btn { + display: flex; + align-items: center; + justify-content: space-between; + padding: 0 25rpx; +} +.quantityTipShow { + position: absolute; + top: -50rpx; + right: 0; + background: rgba(0, 0, 0, 0.3); + font-size: 22rpx; + color: #fff; + border-radius: 30rpx; + padding: 8rpx 0rpx; + width: 260rpx; + .sanjiao { + position: absolute; + left: 50%; + margin-left: -15rpx; + width: 30rpx; + height: 30rpx; + transform: rotate(45deg); + bottom: -15rpx; + background: rgba(0, 0, 0, 0.3); + } +} +.async_box { + padding: 0 50rpx; + .title { + font-weight: bold; + text-align: center; + font-size: 32rpx; + padding: 30rpx 0; + } + .jindubox { + background: #dddddd; + height: 30rpx; + border-radius: 30rpx; + overflow: hidden; + position: relative; + .jindu { + width: 80%; + background: #dfc3a2; + height: 100%; + border-radius: 30rpx; + } + .baifenbi { + position: absolute; + font-size: 22rpx; + right: 20rpx; + color: #999; + top: 0; + } + } + .tip1 { + font-size: 26rpx; + padding: 30rpx 0 40rpx; + } +} +.infobox5 { + margin: 24rpx 20rpx 0; + border-radius: 18rpx; + background: #fff; + height: 260rpx; + padding: 20rpx; + position: relative; + .icon { + position: absolute; + width: 24rpx; + height: 24rpx; + right: 26rpx; + top: 32rpx; + } + .title { + color: #ccc; + font-size: 18rpx; + height: 42rpx; + line-height: 42rpx; + } + .info1 { + font-size: 14rpx; + color: #ccc; + display: flex; + margin-top: 10rpx; + .left { + border-right: 1px solid #e3e3e3; + padding: 0 8rpx; + width: 16rpx; + height: 180rpx; + display: flex; + align-items: center; + flex-direction: column; + justify-content: center; + .numblock { + padding: 0rpx 0; + } + } + .right { + width: calc(100% - 20rpx - 100rpx); + height: 180rpx; + border-bottom: 1px solid #e3e3e3; + padding: 0 10rpx 4rpx 20rpx; + position: relative; + .block { + flex-direction: column; + justify-content: flex-end; + position: relative; + .num { + position: absolute; + bottom: -30rpx; + } + .block_b0 { + border-radius: 10rpx; + width: 38rpx; + height: 18rpx; + margin: 4rpx 0 0; + } + .block_b1 { + background: #ffcf55; + border-radius: 10rpx; + width: 38rpx; + height: 18rpx; + margin: 4rpx 0 0; + } + .block_b2 { + background: #febb22; + border-radius: 10rpx; + width: 38rpx; + height: 18rpx; + margin: 4rpx 0 0; + } + .block_b3 { + background: #ffad28; + border-radius: 10rpx; + width: 38rpx; + height: 18rpx; + margin: 4rpx 0 0; + } + .block_b4 { + background: #ff8510; + border-radius: 10rpx; + width: 38rpx; + height: 18rpx; + margin: 4rpx 0 0; + } + .block_b5 { + background: #f85803; + border-radius: 10rpx; + width: 38rpx; + height: 18rpx; + margin: 4rpx 0 0; + } + .block_b6 { + background: #e02e13; + border-radius: 10rpx; + width: 38rpx; + height: 18rpx; + margin: 4rpx 0 0; + } + .block_b7 { + background: #b40016; + border-radius: 10rpx; + width: 38rpx; + height: 18rpx; + margin: 4rpx 0 0; + } + .block_b8 { + background: #750010; + border-radius: 10rpx; + width: 38rpx; + height: 18rpx; + margin: 4rpx 0 0; + } + } + .timetip { + position: absolute; + right: -40rpx; + bottom: -25rpx; + } + } + } + .tipbox5 { + position: absolute; + z-index: 999999; + width: 460rpx; + top: -280rpx; + background: linear-gradient(#e2c6a3, #c7a274); + border-radius: 20rpx; + padding: 0 0 24rpx 0; + margin-left: 60rpx; + .jicon { + width: 26rpx; + position: absolute; + bottom: -20rpx; + left: 54rpx; + } + .tip1 { + color: #fefeff; + font-size: 36rpx; + padding: 26rpx 0 0 34rpx; + } + .tip_btn { + background: #ffffff; + border-radius: 26rpx; + width: 154rpx; + height: 52rpx; + line-height: 52rpx; + text-align: center; + font-size: 30rpx; + font-weight: bold; + color: #c69962; + margin-top: 14rpx; + position: relative; + left: calc(460rpx - 22rpx - 154rpx); + } + } +} +.water_test { + margin: 0 auto; + box-sizing: border-box; + padding: 42rpx 48rpx; + width: 690rpx; + height: 292rpx; + background: #ffffff; + border-radius: 30rpx; + .test_step { + .step_block { + flex-direction: column; + } + .step_top { + position: relative; + .line { + position: absolute; + top: 50%; + right: -117rpx; + width: 97rpx; + height: 0; + border-top: 2rpx dashed #f1f1f1; + } + .drop { + width: 10rpx; + height: 10rpx; + background: #999999; + border-radius: 50%; + } + .step_num { + font-size: 24rpx; + font-weight: 500; + color: #666666; + margin-left: 14rpx; + } + } + .step_name { + font-size: 26rpx; + font-weight: bold; + color: #000000; + margin-left: 14rpx; + padding-top: 12rpx; + letter-spacing: 2rpx; + } + } + .test_txt { + font-size: 24rpx; + font-weight: 500; + color: #999999; + padding-top: 48rpx; + line-height: 36rpx; + letter-spacing: 2rpx; + } +} +.testing { + .testing_header { + .items { + flex: 1; + border-radius: 30rpx 30rpx 0rpx 0rpx; + padding: 25rpx 0 21rpx; + justify-content: space-evenly; + .finish_img { + width: 24rpx; + height: 24rpx; + border-radius: 50%; + } + .value { + font-size: 24rpx; + font-weight: 500; + color: #666666; + line-height: 1; + } + .name { + font-size: 26rpx; + font-weight: bold; + color: #000000; + line-height: 1; + } + } + } + .testing_content { + width: 100%; + height: 228rpx; + background: #ffffff; + border-radius: 0rpx 0rpx 30rpx 30rpx; + padding: 51rpx 30rpx 0 36rpx; + box-sizing: border-box; + .progress_box { + width: 100%; + height: 36rpx; + line-height: 36rpx; + .title { + font-size: 28rpx; + font-weight: bold; + color: #000000; + min-width: 200rpx; + margin-right: 60rpx; + letter-spacing: 2rpx; + } + } + .tips { + font-size: 24rpx; + font-weight: 500; + color: #999999; + margin-top: 45rpx; + line-height: 36rpx; + letter-spacing: 2rpx; + } + .progress_block { + flex: 1; + } + .finish_img { + width: 36rpx; + height: 36rpx; + margin-left: 49rpx; + } + } +} +.isquanpingclass { + position: fixed; + width: calc(100% - 100rpx); + padding: 20rpx 50rpx; + margin: 0; + z-index: 999; + top: 0; + left: 0; + right: 0; + height: 100vh; +} +.canvas { + position: fixed; + top: -9999999px; +} +.popbox1 { + width: 600rpx; + height: 360rpx; + border-radius: 28rpx; + flex-direction: column; + .tip1 { + font-size: 40rpx; + color: #000000; + text-align: center; + font-weight: 400; + margin-top: 28rpx; + } + .tip2 { + font-size: 32rpx; + color: #000000; + text-align: center; + font-weight: 400; + margin-top: 36rpx; + height: 110rpx; + } + .btnbox { + .btn1 { + font-size: 30rpx; + color: #000000; + text-align: center; + font-weight: 400; + width: 240rpx; + height: 100rpx; + line-height: 100rpx; + border: 2rpx solid rgba(0, 0, 0, 0.3); + border-radius: 28rpx; + } + .btn2 { + font-size: 30rpx; + color: #000000; + text-align: center; + font-weight: 400; + width: 240rpx; + height: 100rpx; + line-height: 100rpx; + margin-left: 40rpx; + background: #e2c5a3; + border-radius: 28rpx; + } + } +} +.van-tabs__scroll--line { + background: transparent !important; +} +image { + width: 100%; + height: 100%; + display: flex; +} +/* .color{ + color: #F1AB15; + } */ +.ellipsis2 { + overflow: hidden; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; +} +.nodata { + color: #666666; + text-align: center; + margin-top: 50rpx; + font-size: 28rpx; +} +.MT30 { + margin-top: 30rpx; +} +.submitbtn { + position: absolute; + bottom: 100rpx; + width: 400rpx; + left: 50%; + margin-left: -200rpx; + .btn { + position: absolute; + top: 20rpx; + color: #fff; + font-weight: bold; + font-size: 32rpx; + text-align: center; + width: 100%; + bottom: 0; + } +} +.avatar-wrapper { + position: absolute; + bottom: 0; + width: 100%; + height: 100%; + left: 0; + right: 0; + top: 0; + z-index: 99; + opacity: 0; +} +.permeate_model_box { + position: relative; + display: flex; + flex-direction: column; + align-items: center; + width: 100%; + padding: 52rpx 30rpx 38rpx 30rpx; + box-sizing: border-box; + .my_moisture_box { + width: 600rpx; + height: 600rpx; + margin: 0 auto; + } + .permeate_title { + font-size: 36rpx; + font-weight: bold; + color: #030000; + line-height: 1; + padding-bottom: 54rpx; + box-sizing: border-box; + } + .permeate_tips { + font-size: 28rpx; + font-weight: 500; + color: #030000; + line-height: 60rpx; + padding: 37rpx 0; + box-sizing: border-box; + .txt { + font-size: 26rpx; + font-weight: 500; + color: #666666; + margin-left: 12rpx; + } + } + .permeate_btn { + height: 90rpx; + line-height: 90rpx; + background: #000000; + border-radius: 45rpx; + font-size: 32rpx; + font-weight: bold; + color: #ffffff; + padding: 0 72rpx; + } + .close_box { + position: absolute; + top: 34rpx; + right: 29rpx; + padding: 50rpx; + } + .close_img { + position: absolute; + top: 0; + right: 0; + width: 24rpx; + height: 24rpx; + } +} +.gear_adjust { + padding: 2rpx 10rpx 40rpx 18rpx; + .title { + font-size: 28rpx; + font-weight: bold; + color: #000000; + } + .gear_box { + margin-top: 14rpx; + .slider_class { + height: 12rpx; + box-sizing: border-box; + flex: 1; + border-radius: 6rpx; + } + .gear { + padding: 20rpx 0; + } + .pos { + font-size: 26rpx; + font-weight: 500; + color: #666666; + min-width: 76rpx; + margin-right: 32rpx; + } + } +} + +.gear_adjustment { + box-sizing: border-box; + width: 690rpx; + height: 300rpx; + background: #ffffff; + border-radius: 30rpx; + padding: 30rpx; + margin: 30rpx auto 200rpx; + .gear_box { + .gear { + margin-bottom: 30rpx; + .pos { + font-size: 26rpx; + font-weight: 500; + color: #666666; + min-width: 76rpx; + margin-right: 32rpx; + } + .gear_button { + width: 500rpx; + height: 60rpx; + background: #f8f8f8; + border-radius: 30rpx; + justify-content: space-between; + font-size: 20rpx; + + .button_minus { + width: 90rpx; + height: 60rpx; + background: #e5e5e5; + border-radius: 30rpx 0rpx 0rpx 30rpx; + display: flex; + justify-content: center; + align-items: center; + .image { + width: 28rpx; + height: 28rpx; + } + } + + .button_plus { + width: 90rpx; + height: 60rpx; + background: #e5e5e5; + border-radius: 0rpx 30rpx 30rpx 0rpx; + display: flex; + justify-content: center; + align-items: center; + .image { + width: 28rpx; + height: 28rpx; + } + } + + .button_value { + display: flex; + justify-content: center; + align-items: center; + font-size: 24rpx; + width: 320rpx; + height: 60rpx; + line-height: 60rpx; + color: #666; + .number { + font-family: PingFang SC; + font-weight: 800; + font-size: 30rpx; + color: #000000; + margin-right: 4rpx; + } + } + } + } + } +} + +.level_box { + padding-left: 109rpx; + .level_num { + font-size: 16rpx; + font-weight: 500; + color: #cccccc; + } +} +.custom-button { + position: relative; + width: 32rpx; + height: 32rpx; + background: linear-gradient(90deg, #ffe9c7, #eecda1); + border: 4rpx solid #ffffff; + border-radius: 50%; + box-sizing: border-box; + .circle { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 12rpx; + height: 12rpx; + background: #ffffff; + border-radius: 50%; + } + .level { + position: absolute; + top: -30rpx; + left: 0; + width: 44rpx; + font-size: 20rpx; + font-weight: 500; + color: #bf8e49; + height: 28rpx; + } +} +.current-button { + background: #cccc; + .level { + color: #cccc; + } +} +.success_popup { + width: calc(100% - 110rpx); + box-sizing: border-box; + .popup_content { + width: 100%; + padding: 52rpx 0 60rpx; + box-sizing: border-box; + display: flex; + flex-direction: column; + align-items: center; + color: #030000; + .title { + font-size: 36rpx; + font-weight: bold; + } + .success_icon { + width: 120rpx; + height: 120rpx; + margin: 52rpx 0; + } + .tips { + font-size: 30rpx; + } + } + & > .infobox1 { + padding: 0rpx 0 35rpx; + .tip { + font-size: 36rpx; + font-weight: bold; + color: #030000; + text-align: center; + } + .tip1 { + text-align: center; + margin-top: 71rpx; + font-size: 30rpx; + color: #030000; + } + .tip2 { + color: #202020; + font-size: 40rpx; + text-align: center; + } + .btnbox { + margin-top: 71rpx; + padding: 0 3rpx 10rpx 15rpx; + display: flex; + align-items: center; + justify-content: space-between; + .btn1 { + background: #fff; + width: 212rpx; + height: 66rpx; + line-height: 66rpx; + text-align: center; + font-size: 30rpx; + color: #e2c6a3; + border-radius: 32rpx; + border: 2rpx solid #e2c6a3; + font-style: normal; + width: 270rpx; + height: 90rpx; + line-height: 90rpx; + background: #ffffff; + text-align: center; + border: 2rpx solid #000000; + border-radius: 45rpx; + font-size: 32rpx; + font-weight: bold; + color: #000000; + } + .btn2 { + width: 270rpx; + height: 90rpx; + line-height: 90rpx; + text-align: center; + background: #000000; + border-radius: 45rpx; + font-size: 32rpx; + font-weight: bold; + color: #ffffff; + font-style: normal; + width: 270rpx; + height: 90rpx; + line-height: 90rpx; + background: #000000; + text-align: center; + border-radius: 45rpx; + font-size: 32rpx; + font-weight: bold; + color: #ffffff; + } + } + } +} +.flex { + display: flex; +} +.aitems { + align-items: center; +} +.jcenter { + justify-content: center; +} +.sb { + justify-content: space-between; +} +.sa { + justify-content: space-around; +} +.wrap { + flex-wrap: wrap; +} diff --git a/src/moduleIOT/pages/iotCarePlan/components/Echart/index.tsx b/src/moduleIOT/pages/iotCarePlan/components/Echart/index.tsx new file mode 100644 index 0000000..273c20d --- /dev/null +++ b/src/moduleIOT/pages/iotCarePlan/components/Echart/index.tsx @@ -0,0 +1,621 @@ +import Taro from "@tarojs/taro"; +import classnames from "classnames"; +import { Block, View, Image, Text, Input } from "@tarojs/components"; +import { Popup, Progress, Slider } from "@antmjs/vantui"; +import { useRef } from "react"; +import Echarts, { EChartOption, EchartsHandle } from "taro-react-echarts"; +import echarts from "@/utils/echarts.min.js"; + +import "./index.less"; + +interface Props { + Electricity: any; + matrixElectricity: any; + facialMaskConnectStatus: any; +} + +function Index() { + const stepIndex = 0; + const testIndex = 1; + + const stepList = [ + { + value: "Step1", + name: "额头", + finish: false, + }, + { + value: "Step2", + name: "左脸颊", + finish: false, + }, + { + value: "Step3", + name: "右脸颊", + finish: false, + }, + ]; + + const gearLevel = { + currentGear: null, + //现在工作的档位 + currentGearMode: "forehead", + //现在工作模式 + forehead: 5, + leftCheek: 5, + rightCheek: 5, + }; + const echartsRef = useRef(null); + const option: EChartOption = { + grid: { + // 让图表占满容器 + top: "28rpx", + left: "18rpx", + right: "28rpx", + bottom: "17rpx", + }, + legend: { + show: false, + zlevel: -1, + }, + xAxis: { + // name: '', + // nameGap: 5, + // nameTextStyle: { + // color: '#e4e4e4', + // fontSize:7 + // }, + type: "category", + axisLine: { + //坐标轴轴线相关设置。数学上的x轴 + show: true, + lineStyle: { + color: "#cccccc", + }, + }, + axisLabel: { + //坐标轴刻度标签的相关设置 + color: "#cccccc", + fontSize: 8, + }, + axisTick: { + show: false, + }, + data: [ + "00:01", + "00:02", + "00:03", + "00:04", + "00:05", + "00:06", + "00:07", + "00:08", + "00:09", + "00:10", + ], + }, + yAxis: { + type: "value", + min: 0, + max: 8, + splitNumber: 8, + splitLine: { + show: false, + lineStyle: { + color: "#cccccc", + type: [4, 2], + dashOffset: 4, + }, + }, + axisLine: { + show: false, + }, + axisLabel: { + show: false, + }, + axisTick: { + show: false, + }, + }, + visualMap: { + z: 1, + top: 0, + right: 0, + seriesIndex: 0, + show: false, + pieces: [ + { + gt: 0, + lte: 1, + color: "#fff8c9", + }, + { + gt: 1, + lte: 2, + color: "#fff0c6", + }, + { + gt: 2, + lte: 3, + color: "#ffe5c3", + }, + { + gt: 3, + lte: 4, + color: "#ffdbbf", + }, + { + gt: 4, + lte: 5, + color: "#ffcfbb", + }, + { + gt: 5, + lte: 6, + color: "#ffbab5", + }, + { + gt: 6, + lte: 7, + color: "#ffb4b3", + }, + { + gt: 7, + lte: 8, + color: "#ffb4b3", + }, + ], + outOfRange: { + color: "#ff8410", + }, + }, + series: [ + { + data: [2, 3, 5, 3, 5, 6, 8, 5, 6, 4], + type: "line", + smooth: true, + z: 1, + areaStyle: {}, + color: "red", + }, + { + data: [2, 3, 5, 3, 5, 6, 8, 5, 6, 4], + type: "line", + smooth: true, + symbolSize: 5, + lineStyle: { + color: "#ff8410", + width: 1, + }, + itemStyle: { + color: "#ff8410", + }, + }, + { + name: "a", + data: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + type: "bar", + barWidth: 12, + z: 2, + stack: "x", + visualMap: false, + itemStyle: { + color: "#ffcf56", + }, + }, + { + name: "b", + data: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + type: "bar", + z: 2, + stack: "x", + visualMap: false, + itemStyle: { + color: "#febb22", + }, + }, + { + name: "c", + data: [0, 1, 1, 1, 1, 1, 1, 1, 1, 1], + type: "bar", + z: 2, + stack: "x", + visualMap: false, + itemStyle: { + color: "#ffac28", + }, + }, + { + name: "d", + data: [0, 0, 1, 0, 1, 1, 1, 1, 1, 1], + type: "bar", + z: 2, + stack: "x", + visualMap: false, + itemStyle: { + color: "#ff8410", + }, + }, + { + name: "e", + data: [0, 0, 1, 0, 1, 1, 1, 1, 1, 0], + type: "bar", + z: 2, + stack: "x", + visualMap: false, + itemStyle: { + color: "#f85804", + }, + }, + { + name: "f", + data: [0, 0, 0, 0, 0, 1, 1, 0, 1, 0], + type: "bar", + z: 2, + stack: "x", + visualMap: false, + itemStyle: { + color: "#e02e14", + }, + }, + { + name: "h", + data: [0, 0, 0, 0, 0, 0, 1, 0, 0, 0], + type: "bar", + z: 2, + stack: "x", + visualMap: false, + itemStyle: { + color: "#b30016", + }, + }, + { + name: "i", + data: [0, 0, 0, 0, 0, 0, 1, 0, 0, 0], + type: "bar", + z: 2, + stack: "x", + visualMap: false, + itemStyle: { + color: "#750010", + }, + }, + ], + }; + + const level = [8, 7, 6, 5, 4, 3, 2]; + + return ( + + + + + + 实时能量 + {level.map((item) => ( + + {item} + 8 + + ))} + + 1 + + 时间 + + + + + + + + {stepList.map((item, index) => { + return ( + + + + {item.value} + {index != 2 && } + + {item.name} + + ); + })} + + + 通过小紫弹的水分测试功能,对脸部的额头、左脸颊、右脸颊三个区域进行水分检测,并定制适合您的促渗档位方案 + + + + + + {stepList.map((item, index) => { + return ( + + {stepIndex > index && ( + + )} + {item.value} + {item.name} + + ); + })} + + + + + {stepList[stepIndex].name + "水分测试"} + + {/* */} + + {stepList[stepIndex].finish && 80 >= 99 ? ( + + ) : ( + + )} + {/* */} + + {/* */} + {/* 请参考视频指引,将仪器紧贴额头区域 */} + {/* */} + + + 请参考视频指引,将仪器紧贴 + {(testIndex == 1 || testIndex == 2 || testIndex == 4) && ( + + {stepList[stepIndex].name + "区域"} + + )} + {testIndex == 1 && ( + ,并点击下方启动检测按钮进行测试 + )} + + + + + + + + + 档位调节 + + + 额头 + + + + + {gearLevel.forehead + "档"} + + + + } + > + + + 左脸颊 + + + + + {gearLevel.leftCheek + "档"} + + + + } + > + + + 右脸颊 + + + + + {gearLevel.rightCheek + "档"} + + + + } + > + + {/* + {(10).map((item, index) => { + return ( + + {item + 1} + + ) + })} + */} + + + + + + + + 额头 + + + + + + 1档 + + + + + + + + 左脸颊 + + + + + + 1档 + + + + + + + + 右脸颊 + + + + + + 1档 + + + + + + + + + + + ); +} + +export default Index; diff --git a/src/moduleIOT/pages/iotCarePlan/components/ElectricityView/index.tsx b/src/moduleIOT/pages/iotCarePlan/components/ElectricityView/index.tsx new file mode 100644 index 0000000..4141899 --- /dev/null +++ b/src/moduleIOT/pages/iotCarePlan/components/ElectricityView/index.tsx @@ -0,0 +1,111 @@ +import Taro from "@tarojs/taro"; +import classnames from "classnames"; +import { Block, View, Image, Text } from "@tarojs/components"; +import { useState, useEffect } from "react"; +// import "./index.less"; + +interface Props { + Electricity: any; + matrixElectricity: any; + facialMaskConnectStatus: any; +} +function Index({ + Electricity, + matrixElectricity, + facialMaskConnectStatus, +}: Props) { + return ( + + + {/* + WE200电量 : + + {matrixElectricity >= 4 && ( + + + + + + + )} + {matrixElectricity === 3 && ( + + + + + + + )} + {matrixElectricity === 2 && ( + + + + + + + )} + {matrixElectricity === 1 && ( + + + + + + + )} + {matrixElectricity === 0 && ( + + + + + + + )} + + */} + {facialMaskConnectStatus === 1 && ( + + + 面罩电量 : + + {Electricity >= 4 && ( + + + + + + + )} + {Electricity === 3 && ( + + + + + + + )} + {Electricity === 2 && ( + + + + + + + )} + {Electricity <= 1 && ( + + + + + + + )} + + + + )} + + + ); +} + +export default Index; diff --git a/src/moduleIOT/pages/iotCarePlan/components/Footer/index.less b/src/moduleIOT/pages/iotCarePlan/components/Footer/index.less new file mode 100644 index 0000000..f62877e --- /dev/null +++ b/src/moduleIOT/pages/iotCarePlan/components/Footer/index.less @@ -0,0 +1,76 @@ +.iot-footer { + position: fixed; + bottom: 0; + z-index: 99; + display: flex; + align-items: baseline; + width: 100%; + height: 153rpx; + background: #ffffff; + box-shadow: 0rpx -3rpx 7rpx 1rpx rgba(173, 191, 207, 0.21); + padding-bottom: env(safe-area-inset-bottom); + box-sizing: border-box; + .btn { + width: 690rpx; + height: 90rpx; + background: #000; + border-radius: 45rpx; + color: #fff; + line-height: 90rpx; + text-align: center; + margin: 21rpx 49rpx 42rpx 30rpx; + font-size: 32rpx; + } + + .text { + display: flex; + align-items: center; + font-size: 32rpx; + font-weight: bold; + color: #000; + } + + .btn-disable { + background-color: #ccc !important; /* 设置按钮背景颜色为灰色 */ + color: #fff !important; /* 设置按钮文字颜色为白色 */ + border-color: #ccc !important; /* 设置按钮边框颜色为灰色 */ + } + + .switch-btn-box { + width: 100vw; + display: flex; + align-items: center; + margin-top: 34rpx; + .btn-item { + height: 70rpx; + display: flex; + flex: 1; + align-items: center; + justify-content: center; + .btn-icon { + width: 36rpx; + height: 36rpx; + margin-right: 18rpx; + } + .btn-text { + font-size: 32rpx; + font-family: PingFang SC; + font-weight: bold; + color: #000000; + } + } + .border-right { + border-right: 1px solid #ddd; + } + .btn-disable { + color: #fff !important; /* 设置按钮文字颜色为白色 */ + border-color: #ccc !important; /* 设置按钮边框颜色为灰色 */ + background-color: #fff !important; /* 设置按钮背景颜色为灰色 */ + .btn-text { + color: #ccc !important; /* 设置按钮文字颜色为白色 */ + border-color: #ccc !important; /* 设置按钮边框颜色为灰色 */ + background-color: #fff !important; /* 设置按钮背景颜色为灰色 */ + } + } + } +} diff --git a/src/moduleIOT/pages/iotCarePlan/components/Footer/index.tsx b/src/moduleIOT/pages/iotCarePlan/components/Footer/index.tsx new file mode 100644 index 0000000..3f63092 --- /dev/null +++ b/src/moduleIOT/pages/iotCarePlan/components/Footer/index.tsx @@ -0,0 +1,132 @@ +import Taro from "@tarojs/taro"; +import classnames from "classnames"; +import { Block, View, Image, Text } from "@tarojs/components"; +import { useState, useEffect } from "react"; +import "./index.less"; + +interface Props { + isShowNurse: boolean; + isStopNurse: boolean; + isDisabled: boolean; // 是否禁用开始暂停按钮:模式与连接设备是否一致 + onEmitStartNurse: Function; // 每次点击item,回调事件和数据给父组件 + onEmitSwitchChange: Function; + onEmitEndPlan: Function; + onEmitErrorTips: Function; // 不可点击,提示错误 +} +function Index({ + isShowNurse, + isStopNurse, + isDisabled, + onEmitStartNurse, + onEmitSwitchChange, + onEmitEndPlan, + onEmitErrorTips, +}: Props) { + const onStartNurse = () => { + onEmitStartNurse(); + }; + + const onSwitchChange = () => { + if (!isDisabled) { + onEmitSwitchChange(); + } + }; + + const onEndPlan = () => { + onEmitEndPlan(); + }; + + const onErrorTips = () => { + onEmitErrorTips(); + }; + + return ( + + + {!isShowNurse && ( + + {isDisabled ? ( + + 开始护理 + + ) : ( + + 开始护理 + + )} + + )} + {isShowNurse && ( + + {!isDisabled && ( + + {isStopNurse ? ( + + + 启动光照 + + ) : ( + + + 暂停光照 + + )} + + )} + {isDisabled && ( + + {isStopNurse ? ( + + + + 启动光照 + + + ) : ( + + + + 暂停光照 + + + )} + + )} + + + + 结束护理 + + + )} + + + ); +} + +export default Index; diff --git a/src/moduleIOT/pages/iotCarePlan/components/ModeContent/index.less b/src/moduleIOT/pages/iotCarePlan/components/ModeContent/index.less new file mode 100644 index 0000000..a991d6f --- /dev/null +++ b/src/moduleIOT/pages/iotCarePlan/components/ModeContent/index.less @@ -0,0 +1,57 @@ +.modelInfo-box { + width: 690rpx; + margin: 26rpx auto 0; + padding: 37rpx 35rpx; + background-color: #fff; + box-sizing: border-box; + border-radius: 30rpx; + overflow: visible; + margin-bottom: 150rpx; + .modelInfo-line { + margin-bottom: 50rpx; + &:last-child { + margin-bottom: 0; + .modelInfo-title { + margin-bottom: 6rpx; + } + } + .modelInfo-title { + margin-bottom: 24rpx; + font-size: 28rpx; + font-weight: bold; + line-height: 1; + color: #000; + } + + .modelInfo-effect { + font-size: 26rpx; + line-height: 1; + color: #000; + } + + .modelInfo-light-box { + display: flex; + flex-wrap: wrap; + .modelInfo-light-item { + display: flex; + align-items: center; + margin-right: 40rpx; + margin-top: 20rpx; + /*margin-bottom: 20rpx;*/ + } + + .modelInfo-light-color { + width: 12rpx; + height: 12rpx; + margin-right: 10rpx; + background-color: #f2c95b; + border-radius: 50%; + } + + .modelInfo-light-colorname { + font-size: 26rpx; + line-height: 1; + } + } + } +} diff --git a/src/moduleIOT/pages/iotCarePlan/components/ModeContent/index.tsx b/src/moduleIOT/pages/iotCarePlan/components/ModeContent/index.tsx new file mode 100644 index 0000000..e34cf02 --- /dev/null +++ b/src/moduleIOT/pages/iotCarePlan/components/ModeContent/index.tsx @@ -0,0 +1,51 @@ +import Taro from "@tarojs/taro"; +import classnames from "classnames"; +import { Block, View, ScrollView, Image } from "@tarojs/components"; +import { useState, useEffect } from "react"; +import "./index.less"; + +interface Props { + isShowNurse: boolean; + ActiveModeItem: any; +} +function Index({ isShowNurse, ActiveModeItem }: Props) { + const ModeColor = { + "590nm": "#CF231D", + "630nm": "#CF231D", + "830nm": "#9C1D17", + }; + return ( + + {isShowNurse && ( + + + 模式功效 + {ActiveModeItem.modeDesc} + + + 当前输出技术 + + {ActiveModeItem.combineData.map((item) => { + return ( + + + + {item.effectContent}({item.technologyInfo}) + + + ); + })} + + + + )} + + ); +} + +export default Index; diff --git a/src/moduleIOT/pages/iotCarePlan/components/ModeList/index.less b/src/moduleIOT/pages/iotCarePlan/components/ModeList/index.less new file mode 100644 index 0000000..a0ade45 --- /dev/null +++ b/src/moduleIOT/pages/iotCarePlan/components/ModeList/index.less @@ -0,0 +1,157 @@ +.mode-list-main { + position: relative; + font-family: PingFang SC; + .change-all-mode-btn { + position: absolute; + top: 10rpx; + right: -30rpx; + width: 140rpx; + height: 160rpx; + background-color: #fff; + border-radius: 30rpx 0rpx 0rpx 30rpx; + box-shadow: 1rpx 2rpx 16rpx 2rpx rgba(97, 97, 97, 0.1); + text-align: center; + // align-items: center; + z-index: 20; + box-sizing: border-box; + .title { + font-size: 26rpx; + text-align: center; + font-weight: bold; + text-align: center; + margin-top: 33rpx; + } + .icon { + display: block; + width: 36rpx; + height: 36rpx; + margin: 0 auto; + margin-top: 26rpx; + } + } +} +.mode-list-box { + width: 100%; + height: 180rpx; + padding: 10rpx 26rpx; + margin-top: 20rpx; + background-color: #f2f2f2; + border-radius: 30rpx; + box-sizing: border-box; + &:last-child { + margin-bottom: 0; + } + .mode-list { + display: flex; + align-items: center; + + .mode-item-title { + display: flex; + align-items: center; + justify-content: center; + width: 110rpx; + min-width: 110rpx; + font-size: 26rpx; + font-family: PingFang SC; + font-weight: bold; + color: #000000; + margin-right: 20rpx; + } + .mode-item { + position: relative; + display: flex; + min-width: 140rpx; + height: 160rpx; + align-items: center; + margin-bottom: 20rpx; + background-color: #fff; + border-radius: 20rpx; + /*padding: 17rpx 18rpx;*/ + box-sizing: border-box; + transition: all 0.3s; + flex-shrink: 0; + overflow: hidden; + .new { + display: none; + position: absolute; + left: 0; + top: 0; + width: 48rpx; + height: 24rpx; + font-size: 16rpx; + font-family: PingFang SC; + font-weight: bold; + color: #ffffff; + text-align: center; + background-color: #eb5858; + border-radius: 15rpx 10rpx 12rpx 0rpx; + z-index: 20; + } + .is-new { + display: block; + } + .mode-info { + min-width: 140rpx; + padding-left: 10rpx; + padding-right: 10rpx; + .mode-info-title { + margin-bottom: 4rpx; + font-size: 26rpx; + text-align: center; + font-weight: bold; + } + .mode-info-time { + margin-bottom: 4rpx; + text-align: center; + color: #666666; + font-size: 24rpx; + } + .mode-info-select { + display: flex; + align-items: center; + justify-content: center; + width: 30rpx; + height: 30rpx; + margin: 10rpx auto 0; + border: 3rpx solid #f1f1f1; + border-radius: 50%; + box-sizing: border-box; + &.is-select { + background-color: #fff; + border: none; + } + } + + .mode-info-select-point { + width: 14rpx; + height: 14rpx; + background-color: #000000; + border-radius: 50%; + } + } + } + .mode-item + .mode-item { + margin-left: 20rpx; + } + .mode-item-active { + // min-width: 300rpx; + padding-right: 11rpx; + background: linear-gradient(90deg, #efdcc2 0%, #fff2df 100%); + } + + .mode-pic { + width: 140rpx; + height: 140rpx; + /*margin-left: 20rpx;*/ + background-color: #f1f1f1; + border-radius: 20rpx; + overflow: hidden; + } + + .mode-pic image { + width: 100%; + height: 100%; + vertical-align: middle; + } + } +} diff --git a/src/moduleIOT/pages/iotCarePlan/components/ModeList/index.tsx b/src/moduleIOT/pages/iotCarePlan/components/ModeList/index.tsx new file mode 100644 index 0000000..395d26e --- /dev/null +++ b/src/moduleIOT/pages/iotCarePlan/components/ModeList/index.tsx @@ -0,0 +1,238 @@ +import Taro from "@tarojs/taro"; +import classnames from "classnames"; +import { Block, View, ScrollView, Image } from "@tarojs/components"; +import { useState, useEffect } from "react"; +import "./index.less"; + +interface Props { + ModeID: any; + activeModeID: any; + ModeList: any; + ModeType: string; // all visor cabin yimeish + isShowNurse: boolean; // 是否已进入护理详情页 + isPop: boolean; // 是否弹窗 + onEmit: Function; // 每次点击item,回调事件和数据给父组件 + onEmitShowAll: Function; // 打开弹窗按钮 +} +function Index({ + isShowNurse, + isPop, + ModeList, + ModeType, + ModeID, + activeModeID, + onEmit, + onEmitShowAll, +}: Props) { + let VisorList = ModeList.filter((item) => item.modeClass === 1); // 面罩模式 + let CabinList = ModeList.filter((item) => item.modeClass === 2); // 舱体模式 + let YimeishList = ModeList.filter((item) => item.modeClass === 3); // 医美术后 + + console.log("ModeType", ModeType); + const yimeishClick = (item) => { + onEmit(item); + }; + + const cabinClick = (item) => { + onEmit(item); + }; + + const visorClick = (item) => { + onEmit(item); + }; + + const showAll = () => { + onEmitShowAll(); + }; + + return ( + + + {!isPop && ModeList.length > 0 && isShowNurse && ( + + 全部模式 + + + )} + {VisorList.length > 0 && + (ModeType === "all" || ModeType === "visor" || isPop) && ( + + + 面罩模式 + {VisorList.map((item: any, index: any) => { + return ( + + + NEW + + + {item.modeName} + + {item.modeTimeStr} + + + {activeModeID === item.id && ( + + )} + + + + {activeModeID === item.id && ( + + + + )} + + ); + })} + + + + )} + {CabinList.length > 0 && + (ModeType === "all" || ModeType === "cabin" || isPop) && ( + + + 舱体模式 + {CabinList.map((item: any, index: any) => { + return ( + + + NEW + + + {item.modeName} + + {item.modeTimeStr} + + + {activeModeID === item.id && ( + + )} + + + + {activeModeID === item.id && ( + + + + )} + + ); + })} + + + )} + + {YimeishList.length > 0 && + (ModeType === "all" || ModeType === "yimeish" || isPop) && ( + + + 医美术后 + {YimeishList.map((item: any, index: any) => { + return ( + + + NEW + + + {item.modeName} + + {item.modeTimeStr} + + + {activeModeID === item.id && ( + + )} + + + + {activeModeID === item.id && ( + + + + )} + + ); + })} + + + )} + + + ); +} + +export default Index; diff --git a/src/moduleIOT/pages/iotCarePlan/iotCarePlan.less b/src/moduleIOT/pages/iotCarePlan/iotCarePlan.less new file mode 100644 index 0000000..c17455d --- /dev/null +++ b/src/moduleIOT/pages/iotCarePlan/iotCarePlan.less @@ -0,0 +1,148 @@ +.iot-main { + padding: 20rpx 30rpx; + background: #f8f8f8; + box-sizing: border-box; + min-height: calc(100vh - 180rpx); + .banner-box { + position: relative; + display: block; + width: 690rpx; + height: 790rpx; + background-color: #fff; + border-radius: 30rpx; + .music-btn { + position: absolute; + top: 17rpx; + right: 17rpx; + width: 54rpx; + height: 54rpx; + background: #f8f8f8; + border-radius: 50%; + z-index: 10; + display: flex; + justify-content: center; + align-items: center; + .music-btn_icon { + width: 54rpx; + height: 54rpx; + } + } + .video-or-image { + display: block; + width: 690rpx; + height: 640rpx; + border-radius: 30rpx; + animation-iteration-count: 1; // gif只播放一次 + } + .iot-device { + width: 690rpx; + height: 150rpx; + display: flex; + align-items: center; + justify-content: center; + .device-time { + font-size: 26rpx; + color: #000; + font-weight: 400; + .time { + font-size: 30rpx; + font-weight: 800; + } + } + .line { + width: 1rpx; + height: 50rpx; + background: #dddddd; + margin-left: 69rpx; + margin-right: 60rpx; + } + .electricity-box { + display: flex; + flex-direction: column; + .item { + display: flex; + align-items: center; + justify-content: left; + height: 50rpx; + .label { + width: 154rpx; + font-size: 26rpx; + color: #000; + margin-right: 14rpx; + } + } + } + } + .msg-tips { + position: absolute; + top: 40%; + left: 0; + right: 0; + transform: translateY(-40%); + display: flex; + align-items: center; + max-width: 635rpx; + margin: auto; + padding: 15rpx 34rpx; + background-color: rgba(0, 0, 0, 0.5); + box-sizing: border-box; + border-radius: 30rpx; + z-index: 10100 !important; // 提升层级,防止被其他元素遮挡 + .msg-tips-img { + width: 30rpx; + height: 30rpx; + margin-right: 17rpx; + } + .msg-tips-content { + flex: 1; + max-width: 530rpx; + font-size: 28rpx; + color: #fff; + word-break: break-word; + } + } + } + .mode-box { + // background-color: #fff; + } +} + +.iot-btn-start { + width: 690rpx; + height: 90rpx; + line-height: 90rpx; + text-align: center; + color: #fff; + font-size: 32rpx; + background-color: #ccc; + border-radius: 45rpx; + &.is-connect { + background-color: #000; + } +} + +.battery_icon { + width: 8rpx; + height: 20rpx; + border-radius: 5rpx; + & + .battery_icon { + margin-left: 8rpx; + } +} + +.v1 { + background: linear-gradient(0deg, #efdcc2 0%, #fff2df 100%); +} + +.v2 { + background: #f8f8f8; +} + +.v3 { + background: linear-gradient(0deg, #ff4646, #ff6b6b, #f86f6f, #ff9494); +} + +#chart { + width: 690rpx; + height: 320rpx; +} diff --git a/src/moduleIOT/pages/iotCarePlan/iotCarePlan.tsx b/src/moduleIOT/pages/iotCarePlan/iotCarePlan.tsx new file mode 100644 index 0000000..f3459e0 --- /dev/null +++ b/src/moduleIOT/pages/iotCarePlan/iotCarePlan.tsx @@ -0,0 +1,2211 @@ +import Taro from "@tarojs/taro"; +import dayjs from "dayjs"; +import classnames from "classnames"; +import { debounce } from "lodash"; +// eslint-disable-next-line import/no-named-as-default +import React, { + Component, + PropsWithChildren, + useEffect, + useState, +} from "react"; + +// import Echarts from "./components/Echart/index"; +import { + Block, + View, + Text, + Image, + Video, + Input, + Button, +} from "@tarojs/components"; + +/*** redux ***/ +import { connect } from "react-redux"; +/*** redux end ***/ + +/* 公共组件 */ +import Navbar from "@/components/navbar/navbar"; +import PopupCountdown from "@/components/popup/popup-countdown"; +import PopupStepTips from "@/components/popup/popup-step-tips"; +import PopupConfirm from "@/components/popup/popup-confirm"; +import PopupAlert from "@/components/popup/popup-alert"; +import PopupStatus from "@/components/popup/popup-status"; +import PopupInstrumentUploadTips from "@/components/popup/popup-instrument-upload-tips"; +import ConnectionBluetoot from "@/components/bluetoot/connection"; +/* 公共组件 END */ + +/* 本页组件 */ +import ElectricityView from "./components/ElectricityView/index"; +import ModeListView from "./components/ModeList/index"; +import ModeContent from "./components/ModeContent/index"; +import Footer from "./components/Footer"; +/* 本页组件 END */ + +import { go, getStorageSync, setStorageSync, msg } from "@/utils/traoAPI"; +import { InstrumentInfo } from "@/utils/Interface"; +import "./iotCarePlan.less"; + +import { + notifyBLECharacteristicValueChange, + sendCommand, +} from "@/utils/bluetoothWXAPI"; +import { + deviceCommandSamples, + bleCommandSamples, +} from "@/components/bluetoot/connection/wl200"; + +import { minSecToS, s_to_ms, s_to_hms, sleep } from "@/utils/util"; +import { DeviceToolKit as DeviceToolKitWE100 } from "@flossom-npm/iot-translater-we100"; +import commandMap from "@/utils/commandMap"; + +const deviceToolKitInstanceWL200 = new DeviceToolKitWE100("WL200", "WL200"); + +let currentTimeTimer: any = null; // 当前项目时间定时器 +let CountdownTimer: any = null; +let timer: any = null; +let showTipsTimer: any = null; +let loadingTipsTimer: any = null; // 蓝牙连接提示 +let switchModeStatus = "free"; // 用于标记是否在切换模式中, free: 空闲, switching: 切换中 +// 设备运行时间校准频率,每多少秒校准一次 +const TIME_CALIBRATION_FREQUENCY = 5; + +// 组合模式:分别对应的是哪几个模式类型 +// 黄光590nm +// 红光630nm +// 近红外光830nm + +// 模式类型中文名 +const WORK_MODE_Chinese_NAME = { + 强效舒缓: "powerfulSoothing", + 维稳修复: "Stability", // 黄光?近红外光? + 均色提亮: "Brighten", // 黄光?近红外光? + 紧致淡纹: "FirmSkin", // 黄光?近红外光? + 自定义: "MaskCustom", + 均色提亮Pro: "BrightenStand", + 紧致淡纹Pro: "FirmSkinStand", + 痘肌舒缓Pro: "SmallpoxSoothingPro", + 痘肌舒缓: "SmallpoxSoothing", + 混合Pro: "MixNursePro", + 混合: "MixNurse", + 头皮护理: "ScalpCare", +}; + +const MODE_WORKING_ENUM = { + STANDBY: "standby", // 待命 + WORKING: "working", // 工作 + PAUSE: "pause", + END: "end", +}; + +// 不同模式启动前的倒计时时间 +let CountDownTime = { + powerfulSoothing: 6, + Stability: 3, + Brighten: 3, + FirmSkin: 3, + MaskCustom: 6, + BrightenStand: 6, + FirmSkinStand: 6, + SmallpoxSoothingPro: 6, + SmallpoxSoothing: 4, + MixNursePro: 6, + MixNurse: 4, + ScalpCare: 6, +}; + +let DeviceSyncData = { + totalWorkingMinutes: 0, + totalWorkingSeconds: 0, +}; +let deviceToolKitInstance = deviceToolKitInstanceWL200; + +class IotCarePlan extends Component { + constructor(props) { + super(props); + this.state = { + name: "iotCarePlan", + title: "美容仪名字", // 页面标题 + // 当前设备 + currentDevice: { + name: "", + model: "", + }, + + /** 连接设备 */ + hasVersion: false, // 是否已查询到版本号 + basicModeList: [], //模式列表 + modelActiveIndex: 0, //模式下标 + sliderProgress: 22, + facialMaskConnectStatus: 1, // 面罩连接状态 0未连接 1已连接 + Electricity: 4, // WL200电量 + matrixElectricity: 4, // WE200发箍电量 + + workMode: "", //当前模式 + + gear: { gear: 1 }, + currentShowDialog: "", + step: 1, // 1:选择模式并播放视频, 2:护理中 + showVideoPlayBtn: true, // 视频播放按钮 + duration: 0, // 视频总时长 + hadShowBreakTips: false, // 是否展示过支架断开提示 + + isConnectShow: false, // 是否弹出连蓝牙弹窗:在蓝牙断开时弹出 + /** 连接设备 End */ + + /** 护理过程 */ + isStandStatus: false, // 当前模式是否舱体/支架模式 + isShowStepTips: false, // 是否显示介绍步骤弹窗 + isConnectionBlutoot: true, // 是否已连接蓝牙 + isShowNurse: false, // 是否开始并显示护理 + isStopNurse: false, // 是否暂停护理 + isEndNurse: false, // 是否结束护理 + errorTips: "", // 错误提示 + /** 护理过程 END*/ + + // 模式列表 + isSwitchActiveMode: false, // 是否显示弹窗切换模式 + ModeList: [], + ModeType: "all", // all visor面罩 cabin舱体 yimeish医美 + modeClass: "", // 1面罩 2舱体 3医美 + ActiveModeItem: {}, // 当前选中模式 + SwitchActiveModeItem: {}, // 切换选中模式 + ModeID: "mode_", // 模式KEY + activeModeID: "", // 当前选中模式ID:用于高亮 + ModeStepIndex: 0, // 当前护理功效步骤:每个步骤时间不定,所以时间另外计算,根据步骤显示 + ModeStepTimeArray: [], // 护理功效时间步骤,用于切换显示GIF + currentServiceData: { + // 当前展示的开启暂停GIF: 因为时间判断不方便,所以单独领出来 + startSource: "", + stopSource: "", + }, + + // 模式组合 + isCombineSuccess: false, // 组合模式是否设置成功 + // 倒计时 + isShowCountdown: false, // 倒计时弹窗 + countdown: 3, + // 是否结束护理 + isEndCarePlan: false, + currentTime: "01:00", + + // 护理时间不够 + isNotEnoughTime: false, + // 通用错误提示 + isShowErrorTipsText: false, // 护理模式切换错误弹窗 + errorTipsText: "", // 护理模式切换错误提示 + + isShowNursingSuccess: false, // 护理成功弹窗 + isShowTipsSave: false, // 切换模式时,提示是否保存部分护理记录 + + // 初次护理弹窗 + isFirstTipShow: false, + nurseInfo: [], + + // 上一次护理记录未生成,是否继续连接设备 + isShowReReadRecordConnect: false, + + // 按钮是否不可运行 + isFooterBtnDisabled: true, + isFirstEntryMode: false, // 模式首次打开 + }; + } + + // 不涉及渲染的页面变量 + isRuning: any = false; // 设备是否运行中 + jsonStatus: any = {}; // 同步设备返回数据,用于结束 + tempModeCurrent: any = {}; // 临时保存的当前模式 + elapsedTime: any = 0; // 设备已运行时间 + workStatus: any = ""; // 工作状态 + WL200NursingHistory: any = null; // 护理缓存历史 + hadCheckReport = false; // 是否已检查仪器护理记录 + hadGotInstrumentHistoryData = false; // 是否已缓存仪器历史数据 + hadLoadedPage = false; // 判断是否首次进入页面 + + async onLoad() { + // 保持屏幕常亮 + Taro.setKeepScreenOn({ + keepScreenOn: true, + }); + this.getWL200NursingHistory(); + this.initData(); + } + componentDidMount() {} + + componentWillUnmount() {} + + componentDidShow() { + console.log("页面显示了"); + + if (!this.hadLoadedPage) { + this.hadLoadedPage = true; // 二次进入页面(非首次进入) + return; + } + + this.getWL200NursingHistory(); + // 重置初始值,每次进入页面重新检查面罩护理记录 + this.hadCheckReport = false; + this.hadGotInstrumentHistoryData = false; + } + + componentDidHide() { + console.log("Hide"); + // 页面隐藏后,下次显示需要重新检查记录 + this.hadCheckReport = false; + } + + async initData() { + let obj = getStorageSync("instrument_detail"); + if (obj) { + this.setState({ + currentDevice: obj, + }); + + await this.GetModeList(obj.id); + + // 如果不存在设备模式值,则判断为首次进入,弹窗提示 + let isFirstTipShow = getStorageSync("first_instrument_" + obj.id); + if (!isFirstTipShow) { + this.firstNurseInfo(); + } + } + + // 开发者工具 + const platform = Taro.getSystemInfoSync().platform; + if (platform !== "devtools") { + // 仅手机端初始化蓝牙 + this.init(); + } + + // 初始化蓝牙 + // this.init(); + } + + getOption() { + const option = { + grid: { top: 8, right: 8, bottom: 24, left: 36 }, + xAxis: { + type: "category", + data: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], + }, + yAxis: { + type: "value", + }, + series: [ + { + data: [820, 932, 901, 934, 1290, 1330, 1320], + type: "line", + smooth: true, + }, + ], + tooltip: { + trigger: "axis", + }, + // title: { + // text: 'ECharts 示例' + // }, + // tooltip: {}, + // xAxis: { + // data: ['A', 'B', 'C', 'D', 'E'] + // }, + // yAxis: {}, + // series: [{ + // name: '数量', + // type: 'bar', + // data: [5, 20, 36, 10, 10] + // }] + }; + return option; + } + + async init() { + // 查询自定义设备指令 + const queryInstructionParams = { + commandType: "InfoQuery", + infoQueryType: "customModeInfo", + }; + let commandBuffer = deviceToolKitInstance.toBleCommand( + queryInstructionParams as any + ); + sendCommand({ value: commandBuffer }).then((res) => { + console.log( + "查询自定义组合模式指令发送成功 参数为=>", + queryInstructionParams + ); + }); + + // 监听蓝牙连接状态改变 + Taro.onBLEConnectionStateChange(this.listener); + await this.notifyBLECharacteristicValueChange(); + + // this.handleWorkStatus(false, MODE_WORKING_ENUM.STANDBY); + } + listener = (res) => { + console.log("listener res", res); + if (res?.connected) return; + // 蓝牙未连接才执行下面逻辑 + Taro.offBLECharacteristicValueChange((res) => { + console.log("offBLECharacteristicValueChange", res); + }); + clearTimeout(loadingTipsTimer); + console.log(commandMap.WL200Command, "监听到蓝牙断开, 打开断开提示"); + + this.workStatus = ""; + // 显示蓝牙断开弹窗 + this.setState({ + isConnectShow: true, // 打开蓝牙链接弹窗 + isConnectionBlutoot: false, // 断开蓝牙 + isShowCountdown: false, // 关闭倒计时,防止倒计时还在运行 + }); + this.footerIsDisabled(); + }; + + GetModeList = async (id) => { + let params = { + instrumentId: id, + }; + let res = await InstrumentInfo.modeInfoList(params); + if (res.data.code === 200) { + if (res.data.data.length > 0) { + this.setState({ + ActiveModeItem: res.data.data[0], + ModeList: res.data.data, + }); + + setTimeout(() => { + this.modeCurrentFun(res.data.data[0]); + }, 100); + } else { + this.setState({ ModeList: res.data.data }); + } + } + }; + + /** + * 倒计时弹窗 + * param 重置倒计时 + * callback 回调函数 + */ + showCountdownFun(count = 3, callback: any = null) { + this.setState({ + countdown: count, + }); + setTimeout(() => { + clearInterval(CountdownTimer); + this.setState({ + isShowCountdown: true, + }); + CountdownTimer = setInterval(() => { + if (this.state.countdown === 0) { + clearInterval(CountdownTimer); + this.setState({ + isShowCountdown: false, + }); + if (callback) callback(); + } else { + this.setState({ + countdown: this.state.countdown - 1, + }); + } + }, 1000); + }, 0); + } + + /** 选中护理模式 */ + modeCurrentFun = async (data, isNotCheck = false) => { + // 仅在未开始护理前,切换模式的时候提示模式弹窗 + if (!this.state.isShowNurse) { + this.openStepTips(); + } + + // 护理检查改变模式,是否提示切换护理模式 + // isNotCheck为真时,不进行校验,直接切换 + this.tempModeCurrent = data; + let { isShowNurse } = this.state; + let currentServiceData = { + startSource: "", + stopSource: "", + }; + if (data.serviceData.length) { + currentServiceData = data.serviceData[0]; + } + + let currentTime = data.modeTimeStr; + this.setState({ + ActiveModeItem: data, + activeModeID: data.id, + ModeID: "mode_" + data.id, + currentServiceData, + ModeStepIndex: 0, + currentTime, + }); + + // 如果按钮不可点击则报错,内部自带检查底部按钮函数 + this.onEmitErrorTips(); + if (!isNotCheck) { + let isReturn = this.modeRuningChange(); + if (isReturn) return; + } + + setTimeout(() => { + // 设置时间组合 + if (data.serviceData.length > 0) { + this.setServiceTimeData(); + } + // 存在组合模式时,设置组合模式 + if (data.combineData.length > 0) { + this.setCustomMaskData(); + } + }); + + // 如果是正在运行中切换,则直接准备运行 + if (isShowNurse) { + if (!this.footerIsDisabled()) { + this.stepNext(); // 如果切换模式,则不执行开始逻辑 + return; + } + setTimeout(() => { + this.onNursingTap("switch"); + }, 800); + } + }; + /** 设备运行中切换模式 */ + modeRuningChange() { + // 运行中切换模式逻辑 + if ( + this.workStatus === MODE_WORKING_ENUM.PAUSE || + this.workStatus === MODE_WORKING_ENUM.WORKING + ) { + const { totalWorkingMinutes, totalWorkingSeconds } = DeviceSyncData; + const totalTime = totalWorkingMinutes * 60 + totalWorkingSeconds; // 设备时间 + let { ActiveModeItem } = this.state; + if (!ActiveModeItem || totalTime === 0) { + return false; + } + + if (this.state.step == 2 && this.state.facialMaskConnectStatus == 1) { + // 提示切换护理模式 + if (this.isCheckNurseTime()) { + // 满足时间条件,提示是否保存部分护理记录 + this.judgementWorkStatus( + MODE_WORKING_ENUM.PAUSE, + this.state.ActiveModeItem?.modeType + ); + this.setState({ + isShowTipsSave: true, + }); + } + return true; + } + } + return false; + } + + /** 切换护理模式 */ + switchModeCurrentFun = async (data) => { + this.setState({ + SwitchActiveModeItem: data, + activeModeID: data.id, + ModeID: "mode_" + data.id, + }); + }; + // 打开模式切换弹窗 + openModeSwitch = () => { + console.log("openModeSwitch"); + this.setState({ + isSwitchActiveMode: true, + }); + }; + // 取消并关闭切换护理模式弹窗 + cancelModeSwitchBtn = () => { + this.setState({ + isSwitchActiveMode: false, + }); + }; + // 弹窗确定切换护理模式 + confirmModeSwitchBtn = () => { + let { SwitchActiveModeItem } = this.state; + this.cancelModeSwitchBtn(); + this.modeCurrentFun(SwitchActiveModeItem); + + let modeArray = ["all", "visor", "cabin", "yimeish"]; + this.setState({ + ModeType: modeArray[SwitchActiveModeItem.modeClass], + }); + setTimeout(() => { + console.log("ModeType", this.state.ModeType); + }, 100); + }; + + stepNext = () => { + // //0未定义(全部) 1面罩模式 2舱体模式 3医美术后 + let modeArray = ["all", "visor", "cabin", "yimeish"]; + let modeClass = this.state.ActiveModeItem.modeClass; + this.workStatus = "pause"; + this.setState({ + ModeType: modeArray[modeClass], + isShowNurse: true, + isStopNurse: true, + step: 2, + }); + + setTimeout(() => { + this.handleWorkStatus(false, MODE_WORKING_ENUM.STANDBY); + }); + }; + /** 开始护理按钮:点击开始,页面进行到下一步 */ + onStartNurse = async () => { + // 如果检查通过,可运行,则执行下一步 + if (!this.footerIsDisabled()) { + this.stepNext(); + + setTimeout(() => { + this.onNursingTap(); + // 倒计时弹窗: 倒计时完成后,自动开始,并判断弹窗 + let downNum = CountDownTime[this.state.ActiveModeItem.modeType] || 3; + this.showCountdownFun(downNum, () => {}); + }, 500); + + return; + } + // 如果检查失败,则报错 + this.onEmitErrorTips(); + }; + + /** + * @name 不可切换光照提示 + * @description isCabinMode是否舱体模式。 0.检测面罩与舱体是否仍在连接中,需要分离 1.检测是否连接失败,需要重新连接 + */ + onEmitErrorTips = async () => { + setTimeout(() => { + let { ActiveModeItem } = this.state; + + // 按钮不可点击时,提示报错 + let isDisabled = this.footerIsDisabled(); + if (isDisabled) { + if (ActiveModeItem.isCabinMode === 0) { + this.showTips("检测到面罩与舱体仍在连接中,该模式需要分离面罩和舱体"); + } else { + this.showTips( + "检测到面罩与舱体未连接成功,请确认面罩是否和舱体连接并接通舱体电源" + ); + } + } + }); + }; + + // 绘制能量图 + drawProwerPicture() {} + + /** 切换光照 */ + onSwitchChange = async () => { + // todo + let { isStopNurse } = this.state; + if (isStopNurse) { + // 开始光照逻辑 + this.onNursingTap(); + } else { + // 暂停光照逻辑 + this.handleWorkStatus(false, MODE_WORKING_ENUM.PAUSE); + } + this.setState({ + isStopNurse: !isStopNurse, + }); + }; + + /** + * @name 每次进入设备运行页,打开首个模式的介绍弹窗 + */ + openStepTips = () => { + let isFirstEntryModeNot = getStorageSync( + "isFirstEntryMode_" + this.state.currentDevice.id + ); + // 1.如果没有持久化不再提示,每次进入都会弹窗提示 + if (!isFirstEntryModeNot) { + // 2.必须要有数据才弹窗 + if (this.state.ActiveModeItem.openSourceData.length > 0) { + this.setState({ isShowStepTips: true }); + } + } + }; + closeStepTips = (data) => { + if (data.isLocal) { + setStorageSync("isFirstEntryMode_" + this.state.currentDevice.id, true); // 关闭首次进入弹窗 + } + this.setState({ isShowStepTips: false }); + }; + + /** 蓝牙相关 */ + switchBLEMatch = (jsonStatus: any) => { + console.log("蓝牙相关", jsonStatus); + let { ActiveModeItem } = this.state; + switch (jsonStatus.bleCommandType) { + // 如果设备配对链接发送配对码的时候,设备应答小程序配对码是否正确。 + case "SendMatchCode": + if (jsonStatus.matchedSuccess) { + console.log("设备配对成功"); + this.setState({ + facialMaskConnectStatus: 1, + }); + } + break; + + // 设备状态主动上报,这种指令是主机主动上报某个附属设备断开或者连上了 + case "BleStatusSync": + console.log("BleStatusSync 附属设备状态主动上报", jsonStatus); + switch (jsonStatus.connectMessage?.deviceName) { + case "WL200": + if (jsonStatus.connectMessage?.connectType == "CONNECTED") { + } else { + this.setState({ + facialMaskConnectStatus: 0, // 蓝牙断开 + isFooterBtnDisabled: false, // 蓝牙断开所以不可点击 + }); + // 断开连接直接暂停:会自动暂停定时器 + this.judgementWorkStatus( + MODE_WORKING_ENUM.PAUSE, + ActiveModeItem?.modeType + ); + // 设备断开时,给定一个断开时间 + ActiveModeItem.breakTimeStr = this.state.currentTime; + } + break; + // 附属设备是否连接支架 + case "Stand": + if (jsonStatus.connectMessage?.connectType == "CONNECTED") { + console.log("舱体支架连接"); + this.setState({ + isStandStatus: true, + }); + if (!this.state.isStandStatus && this.isRuning) { + // 断开连接直接暂停 + this.judgementWorkStatus( + MODE_WORKING_ENUM.PAUSE, + ActiveModeItem?.modeType + ); + } + } else { + console.log("舱体支架断开连接"); + + if (this.state.isStandStatus && this.isRuning) { + // 断开连接直接暂停 + this.judgementWorkStatus( + MODE_WORKING_ENUM.PAUSE, + ActiveModeItem?.modeType + ); + } + + // 设备断开时,给定一个断开时间 + ActiveModeItem.breakTimeStr = this.state.currentTime; + + this.setState({ + isStandStatus: false, + isStopNurse: true, + ActiveModeItem, + }); + + setTimeout(() => { + this.onEmitErrorTips(); + }, 500); + } + setTimeout(() => { + this.footerIsDisabled(); + }, 100); + break; + default: + console.log("监听到到设备连接状态改变 this.footerIsDisabled()"); + this.footerIsDisabled(); // 判断底部运行按钮是否可点击 + break; + } + break; + + //小程序主动问主机,现在链接了哪些附属设备,这时候主机给小程序的回复消息 + case "QueryMatchStatus": + console.log("QueryMatchStatus 设备回复小程序", jsonStatus); + + const isStandDevice = jsonStatus?.subDeviceList?.includes("Stand"); + deviceToolKitInstance = deviceToolKitInstanceWL200; + console.log("支架是否链接", isStandDevice); + this.setState({ + isStandStatus: isStandDevice, + }); + setTimeout(() => { + this.footerIsDisabled(); + }); + + // 连上面罩后, 获取仪器记录, 与缓存信息对比 + if (!this.hadGotInstrumentHistoryData) { + // 查询护理记录 + this.getInstrumentHistoryData(); + + // 查询仪器状态 + const queryDeviceArrayBuffer = deviceToolKitInstance.toBleCommand( + bleCommandSamples.queryDeviceStatus as any + ); + console.log("发送查询设备指令 获取仪器状态"); + sendCommand({ + value: queryDeviceArrayBuffer, + }); + } + } + }; + + // 蓝牙特征更改 + notifyBLECharacteristicValueChange = () => { + console.log("notifyBLECharacteristicValueChange deviceInfo 参数为=>"); + const bluetoothInfo = this.props.bluetoothInfo; + notifyBLECharacteristicValueChange({ + deviceId: bluetoothInfo.deviceId, + servicesuuid: bluetoothInfo.servicesuuid, + characteristicsuuid1: bluetoothInfo.characteristicsuuid1, + characteristicsuuid0: bluetoothInfo.characteristicsuuid0, + }).then((res) => { + Taro.onBLECharacteristicValueChange((value) => { + const jsonStatus: any = deviceToolKitInstance.toJsonStatus(value.value); + console.log( + "onBLECharacteristicValueChange jsonStatus => ", + jsonStatus + ); + if (!jsonStatus || jsonStatus == null) { + return; + } + this.workStatus = jsonStatus.workStatus; // 记录工作状态 + // end 和 endWork 都是护理结束, endWork不关机, end 关机, 对小程序而言处理流程都一样 + if (jsonStatus.workStatus && jsonStatus.workStatus == "endWork") { + jsonStatus.workStatus = "end"; + console.log(jsonStatus.workStatus, "护理结束"); + } + + // 指令类型判断 + switch (jsonStatus?.commandType) { + case "BleMatch": + // 蓝牙相关指令 + this.switchBLEMatch(jsonStatus); + break; + + case "DeviceControl": + console.log("打印小程序控制设备,给设备发送的指令", jsonStatus); + // setTimeout(() => { + // console.log("currentTime", this.state.currentTime); + // }); + break; + //设备主动上报给小程序的指令 一般是工作状态改变 + case "DeviceStatusSync": + console.log( + "设备主动上报给小程序的指令 一般是工作状态改变", + jsonStatus + ); + + // 判断设备主动上报的关机事件 + if (jsonStatus.workStatus === MODE_WORKING_ENUM.END) { + // 判断id是否一致, 一致的话则生成护理报表, 并提示 + if (jsonStatus.id == this.WL200NursingHistory.id) { + debounce( + this.checkInstrumentRecord.bind(this, jsonStatus), + 500 + ); + } + + return; + } + + this.workStatus = jsonStatus.workStatus; + this.setState({ + Electricity: jsonStatus.battery, + // fr200Electricity: jsonStatus.battery, + matrixElectricity: jsonStatus.matrixBattery, + }); + + if (jsonStatus?.workMode === this.state.ActiveModeItem.modeType) { + this.setState({ + workMode: jsonStatus?.workMode, // 仅当设备上报模式与小程序一致时,才允许改变小程序变量缓存 + }); + + // 判断是否在step == 2(护理中) + // 仅当设备模式与小程序是否一致,才允许更改设备运行时间 + if ( + this.state.facialMaskConnectStatus === 1 && + this.state.step == 2 && + jsonStatus.workStatus !== MODE_WORKING_ENUM.END + ) { + this.updateDeviceSyncData( + { + totalWorkingMinutes: jsonStatus.totalWorkingMinutes, + totalWorkingSeconds: jsonStatus.totalWorkingSeconds, + }, + jsonStatus + ); + } + } + + if ( + jsonStatus.workMode === MODE_WORKING_ENUM.WORKING && + this.state.step == 2 + ) { + const { ActiveModeItem } = this.state; + const item = ActiveModeItem; + if (jsonStatus.workMode !== item.modeType) { + clearTimeout(loadingTipsTimer); + this.setState({ + isShowCountdown: false, + }); + } + } + break; + //设备信息查询返回 + case "InfoQuery": + switch (jsonStatus.infoQueryType) { + // 自定义模式设置 + case "customModeSet": + console.log(">>>>>>>>>>>>>>>设置自定义模式>>>>>>>>>>>>>>>"); + console.log( + "InfoQuery customModeSet responseStatus=====>", + jsonStatus + ); + + if (jsonStatus.responseStatus == "OK") { + console.log("设置成功自定义模式"); + this.setState({ + isCombineSuccess: true, + }); + } + break; + // 自定义模式信息 + case "customModeInfo": + console.log(">>>>>>>>>>>>>>>查询自定义模式信息>>>>>>>>>>>>>>>"); + console.log( + "InfoQuery customModeInfo responseStatus=====>", + jsonStatus + ); + break; + case "versionInfo": + break; + // 当前报告 + case "currentMaskReportInfo": + // 每次切换模式并开始运行后,生成一个新的自增ID + // commandType: "InfoQuery" + // createDate: "" + // gear: 0 + // id: 73 + // infoQueryType: "currentMaskReportInfo" + // neededTotalSeconds: 900 + // totalSeconds: 0 + // workMode: "BrightenStand" + console.log("当前面罩报告 currentMaskReportInfo", jsonStatus); + + if (!this.hadCheckReport) { + this.hadCheckReport = true; + this.checkInstrumentRecord(jsonStatus); + } else { + this.setWL200NursingHistory(jsonStatus); + } + + break; + default: + break; + } + break; + // default: + // break; + } + }); + + /** + * 延迟600毫秒获取附属设备状态 + */ + const querySubDeviceArrayBuffer = deviceToolKitInstance.toBleCommand({ + ...bleCommandSamples.querySubDevice, + queryType: "WL200", + } as any); + setTimeout(() => { + console.log("发送查询附属设备指令 querySubDeviceArrayBuffer"); + sendCommand({ + value: querySubDeviceArrayBuffer, + }); + }, 600); + + /** + * 延迟500毫秒获取设备电量 + */ + const queryDeviceArrayBuffer = deviceToolKitInstance.toBleCommand( + bleCommandSamples.queryDeviceStatus as any + ); + setTimeout(() => { + console.log("发送查询设备电量指令"); + sendCommand({ + value: queryDeviceArrayBuffer, + }); + }, 500); + }); + }; + + /**监听关机事件*/ + onEndDevice = () => { + this.rmWL200NursingHistory(this.WL200NursingHistory, true); + // 判断护理时间,如果不足,则提示不足 + if (!this.isCheckNurseTime()) { + this.setState({ isNotEnoughTime: true }); + } else { + this.endNurseFun(); + } + }; + + /** 同步设备运行信息:运行时间 */ + updateDeviceSyncData = (newData, jsonStatus) => { + DeviceSyncData = { + ...DeviceSyncData, + ...newData, + }; + if (newData.hasOwnProperty("totalWorkingSeconds")) { + this.renderDeviceStatus.renderWorkTime(jsonStatus); + } + }; + + // 页面同步护理剩余时间 + renderDeviceStatus = { + renderWorkTime: (jsonStatus) => { + const { totalWorkingMinutes, totalWorkingSeconds } = DeviceSyncData; + let { ActiveModeItem, currentTime } = this.state; + const totalTime = totalWorkingMinutes * 60 + totalWorkingSeconds; + console.log("仪器上报的已经运行的总秒数", totalTime); + console.log("时间校准频率,默认5秒一次", TIME_CALIBRATION_FREQUENCY); + //对比仪器上报运行的总秒数 和小程序页面运行的已经运行的总秒数,如果不一致就进行校准 + const currentScene = ActiveModeItem; // 获取当前的场景 + let sceneTime = ActiveModeItem?.breakTimeStr + ? minSecToS(ActiveModeItem.breakTimeStr) + : minSecToS(currentScene.modeTimeStr); // 场景时间 + + console.log("场景时间 sceneTime", sceneTime); + console.log("当前显示时间 currentTime", currentTime); + console.log("设备运行时间 totalTime", totalTime); + + // 更新界面倒计时 + this.resetTimer(); + + if ( + sceneTime > totalTime && + this.state.step == 2 && + this.state.facialMaskConnectStatus == 1 + ) { + // 界面倒计时同步设备时间 + const t = sceneTime - totalTime; // 场景时间 - 已运行时间 = 剩余时间 + this.setState({ + currentTime: s_to_ms(t), + }); + } else { + this.setState({ + currentTime: "00:00", + }); + this.judgementWorkStatus(MODE_WORKING_ENUM.END, jsonStatus.workMode); + } + + // 每次同步后,更新历史缓存 + setTimeout(() => { + this.updateWL200NursingHistory(); + }, 100); + }, + }; + + // 仪器开始倒计时 + setLoadingTips(time) { + this.setState({ + countdown: time, + }); + if (time >= 0) { + loadingTipsTimer = setTimeout(() => { + this.setLoadingTips(--time); + }, 1000); + } else { + // 停止倒计时 + // that.data.startSettingCountDown = false; + this.setState({ + isShowCountdown: false, + }); + } + } + + /** + * 设备上报不同状态 + * params 工作状态 工作模式 响应状态 + */ + judgementWorkStatus(nWorkStatus, nWorkMode) { + const { step, workMode, ActiveModeItem, ModeList } = this.state; + const opts: any = {}; + // ActiveModeItem + let nowModeItem; + if (nWorkMode) { + nowModeItem = ModeList.find((item) => { + return item.modeType === nWorkMode; + }); + } + opts.workStatus = nWorkStatus; + + let nowCurrentTime = ActiveModeItem.modeTimeStr; + // 完成重连同步则删除重连时间字段 + if (ActiveModeItem?.breakTimeStr) { + nowCurrentTime = ActiveModeItem?.breakTimeStr; + } + + const statusF = { + sleep: () => { + this.setState({ + isShowCountdown: false, + }); + }, + standby: () => { + this.setState({ + isShowCountdown: false, + }); + if (nowModeItem?.isCabinMode && step == 2) { + opts.currentTime = nowCurrentTime; + } else if (!nowModeItem?.isCabinMode && step == 2) { + // fix: 启动非支架模式倒计时时,连上支架,仪器的状态变为standby + opts.step = 1; + } + }, + setting: () => { + // that.data.hadShowBreakTips = false; + this.setState({ + hadShowBreakTips: false, + }); + if (step != 2 && !ActiveModeItem.isCabinMode) { + opts.step = 2; + this.setState({ + title: "正在护理", + isStopNurse: false, + }); + } else if (step != 2 && ActiveModeItem.isCabinMode) { + opts.step = 2; + // this.setState({ + // title: "正在护理", + // }); + this.setState({ + title: "正在护理", + isStopNurse: false, + }); + } + if (nowModeItem) { + opts.currentTime = nowCurrentTime; + } + // startSettingCountDown 用于标记打开了倒计时loading + if (!this.state.isShowCountdown) { + this.setState({ + isShowCountdown: true, + }); + this.setLoadingTips(CountDownTime[workMode] || 6); + } + }, + working: () => { + if (this.state.facialMaskConnectStatus != 1) { + opts.workStatus = MODE_WORKING_ENUM.STANDBY; + opts.step = 1; + } else if (step != 2) { + opts.step = 2; + this.setState({ + title: "正在护理", + isStopNurse: false, + }); + } + + this.setState({ + isShowCountdown: false, + hadShowBreakTips: false, + }); + }, + pause: () => { + clearInterval(currentTimeTimer); + this.setState({ + isShowCountdown: false, + }); + if (ActiveModeItem.isCabinMode) { + this.setState({ + title: "暂停护理", + isStopNurse: true, + }); + } + }, + end: () => { + // 已进入了报告阶段, 防止重复进入, 主要防止在手动点击结束护理接收到仪器消息 + console.log("END 护理结束"); + clearInterval(currentTimeTimer); + + this.endnursing(true); + }, + }; + statusF[nWorkStatus] && statusF[nWorkStatus](); + if (Object.keys(opts).length) { + this.setState(opts); + } + } + + /** + * 保存护理报告 + * 1.是否跳转 2.数据 + * */ + saveNurseReport = async (isJump = true, from) => { + this.endNurseFun(); + }; + + /** + * 结束护理 + * param isAuto 是否仪器自动结束 + */ + endnursing = (isAuto) => { + if (isAuto == true) { + // 仪器自动上报完成, 直接上报并跳转报告页 + clearInterval(currentTimeTimer); + const isEnough = this.isCheckNurseTime(); + if (isEnough) { + this.saveNurseReport(true, "endnursing"); + } + } else { + // 手动点击结束, 弹出弹窗, 看看是否需要结束 + this.onEndPlan(); + } + }; + + // 重置并同步计时器 + resetTimer = () => { + // 切换模式后, 需要重新设置计时器, 以防进行中的计时器 + currentTimeTimer && clearInterval(currentTimeTimer); + currentTimeTimer = setInterval(() => { + let { + step, + facialMaskConnectStatus, + currentTime, + ModeStepTimeArray, + ModeStepIndex, + ActiveModeItem, + } = this.state; + if ( + this.workStatus == MODE_WORKING_ENUM.WORKING && + step == 2 && + facialMaskConnectStatus == 1 + ) { + let totalSeconds = ActiveModeItem?.breakTimeStr + ? minSecToS(ActiveModeItem.breakTimeStr) + : minSecToS(ActiveModeItem.modeTimeStr); + // 现在的倒计时剩余时间:同步时检查是否断开重连,如果是,则使用断开的剩余时长,进行倒计时计算 + let currentSeconds = minSecToS(currentTime); + let checkTime = totalSeconds - currentSeconds; + + // 缓存经过的时间:用于接口提交 + this.elapsedTime = checkTime; + // 如果存在中断时间,则要加上间隔的时间 + if (ActiveModeItem?.breakTimeStr) { + let intervalTime = + minSecToS(ActiveModeItem.modeTimeStr) - + minSecToS(ActiveModeItem.breakTimeStr); + this.elapsedTime += intervalTime; + } + + // 判断剩余时间是否大于1 + if (currentSeconds >= 1) { + // 小程序显示倒计时 + this.setState({ + currentTime: s_to_ms(--currentSeconds), + }); + + let length = ModeStepTimeArray.length; + if (length) { + // 模式多个步骤节点切换 + // 已运行时间达到下一节点时,切换 + if (checkTime > ModeStepTimeArray[ModeStepIndex]) { + // 已运行时间达到下一节点,且存在下一节点,步骤切换时更新 + if (ModeStepIndex < length - 1) { + let index = ModeStepIndex + 1; // 提前步骤+1 + let currentServiceData = { + startSource: "", + stopSource: "", + }; + let serviceLength = ActiveModeItem.serviceData.length; + if (serviceLength > index) { + currentServiceData = ActiveModeItem.serviceData[index]; + } + + console.log("********************"); + console.log("********************"); + console.log( + "仅在时间达到下一步,步骤切换时更新currentServiceData", + currentServiceData + ); + this.setState({ + ModeStepIndex: index, + currentServiceData, + }); + } + } + } + } else { + clearInterval(currentTimeTimer); + this.setState({ + currentTime: "00:00", + ModeStepIndex: 0, + }); + this.saveNurseReport(true, "setTimer"); // 保存护理计划,并且结束 + } + } + }, 1000); + }; + + // 检测并控制工作状态 + handleWorkStatus = (isBtnClick: boolean, workStatus) => { + const { facialMaskConnectStatus, isStandStatus, ActiveModeItem } = + this.state; + let newWorkStatus = + workStatus || + (this.workStatus == MODE_WORKING_ENUM.WORKING ? "pause" : "working"); + if (isBtnClick && newWorkStatus == "working") { + // 舱体模式 + if (ActiveModeItem.isCabinMode === 1 && !isStandStatus) { + this.showTips( + `检测到舱体未连接成功,请确认面罩开机后与舱体连接,并接通舱体电源` + ); + return; + } + // 非舱体模式 + if (!ActiveModeItem.isCabinMode && facialMaskConnectStatus != 1) { + console.log("facialMaskConnectStatus", facialMaskConnectStatus); + this.showTips("检测到面罩未连接成功,请确认面罩开机并佩戴"); + return; + } + } + + const sendParams = { + ...deviceCommandSamples.pause, + workMode: ActiveModeItem.modeType, // 使用模式 + workStatus: newWorkStatus, + }; + console.log("准备发送自定义或工作指令", ActiveModeItem, sendParams); + const pauseArrayBuffer = deviceToolKitInstance.toBleCommand( + sendParams as any + ); + sendCommand({ + value: pauseArrayBuffer, + }).then(() => { + this.workStatus = newWorkStatus; + this.resetTimer(); + console.info( + `handleWorkStatus 发送${newWorkStatus}指令成功 参数为 =>`, + sendParams + ); + }); + }; + + /** + * @name 点击开始护理 + * @params type 传值 switch 则用于区分是否切换模式的启动 + */ + onNursingTap(type = "") { + // 如果已禁止运行,则停止执行后续逻辑 + if (this.state.isFooterBtnDisabled) return; + // 防止多次点击 + if (this.state.hadClickStart) return; + this.setState({ + hadClickStart: true, + }); + setTimeout(() => { + this.setState({ + hadClickStart: false, + }); + }, 500); + + const { ActiveModeItem, isStandStatus, facialMaskConnectStatus } = + this.state; + + if (isStandStatus === 1 && ActiveModeItem.isCabinMode === 0) { + console.log("已连接舱体,只可选择舱体模式"); + return; + } + if (isStandStatus === 0 && ActiveModeItem.isCabinMode === 1) { + console.log("未连接舱体!"); + return; + } + + console.info( + commandMap.WL200Command, + "点击开始护理按钮", + `当前模式: ${ActiveModeItem.modeType}`, + `当前面罩状态:${facialMaskConnectStatus}`, + `当前仪器模式:${this.workStatus}` + ); + console.log(ActiveModeItem); + console.log("isStandStatus:" + isStandStatus); + + if (facialMaskConnectStatus != 1) { + console.log("facialMaskConnectStatus 开始处", facialMaskConnectStatus); + this.showTips("检测到面罩未连接成功,请确认面罩开机并佩戴"); + return; + } + // 如果是强效舒缓,需要判断是否连接支架 + if (ActiveModeItem.isCabinMode && !isStandStatus) { + this.showTips( + `检测到舱体未连接成功,请确认面罩开机后与舱体连接,并接通舱体电源` + ); + return; + } else if (!ActiveModeItem.isCabinMode && isStandStatus) { + this.showTips(`检测到面罩仍和舱体连接中,请分离后切换`); + return; + } + if ( + ActiveModeItem.modeType === "MaskCustom" && + !this.state.isCombineSuccess + ) { + this.showTips(`${ActiveModeItem.modeName}模式设置失败,请联系小助手`); + return; + } + + // 仅在切换模式的时候,弹窗倒计时. + if (type === "switch") { + let downNum = CountDownTime[ActiveModeItem.modeType] || 3; + this.showCountdownFun(downNum, () => {}); // 倒计时弹窗 + } + + // 开始执行护理 + this.workStatus = MODE_WORKING_ENUM.WORKING; // 不管当前什么状态,直接设为工作状态 + this.handleWorkStatus(true, MODE_WORKING_ENUM.WORKING); + this.setState({ + isStopNurse: false, + }); + } + + // 结束护理 + endNurseFun() { + this.handleWorkStatus(false, "end"); + if (this.isCheckNurseTime()) { + this.PostNursingLogClock(); + } else { + // 时间不满足,回到主页 + this.handleWorkStatus(false, "end"); + this.setState({ + isEndCarePlan: false, + isNotEnoughTime: true, + }); + } + } + + /** 检查时间是否达标仪器最低护理时间 */ + isCheckNurseTime() { + const { currentDevice, ActiveModeItem } = this.state; + const currentScene = ActiveModeItem; + let sceneTime = minSecToS(currentScene.modeTimeStr); + const timeRemaining = sceneTime - minSecToS(this.state.currentTime); // 当前模式已运行时间 + + let nursingTimeStr = currentDevice?.nursingTimeStr; + let nursingTime = nursingTimeStr ? minSecToS(nursingTimeStr) : 60; // 设备生成护理记录至少需要运行时间 + + console.log("检查已运行时间", timeRemaining, nursingTime); + if (timeRemaining >= nursingTime) { + return true; + } else { + return false; + } + } + /*** 护理记录 START ***/ + /** 小程序查询护理记录 */ + getInstrumentHistoryData() { + this.hadGotInstrumentHistoryData = true; + console.log("发送指令currentMaskReportInfo 获取设备护理记录"); + setTimeout(() => { + const queryCurrentMaskReportInfoBuffer = + deviceToolKitInstance.toBleCommand({ + ...(bleCommandSamples.queryCurrentMaskReportInfo as any), + }); + sendCommand({ + value: queryCurrentMaskReportInfoBuffer, + }); + }, 3000); + } + /** + * @title 检查护理记录 + * @description + * 1.判断是否存在工作状态:如果不存在,则等待两秒用于连接设备与赋值,再执行后面的代码 + * + * 2.判断是否已存在缓存的护理记录:如果没有历史,则缓存 + * + * 3.判断是否当天(如果不是当天,则删除记录) + * + * 4.判断设备状态-未运行/已完成/待机 + * 4-1.已有缓存护理记录,判断ID一致,同步时间。若主动结束,需判断时间是否满足仪器最低护理时间,满足直接跳转护理报告页;不满足需提示不满足,回到首页 + * 4-2.已有缓存护理记录,判断ID不一致(同步异常)。直接提交,固定设置为一分钟。 + * + * 5.判断设备状态-运行中 + * 正常执行逻辑 + * + * */ + checkInstrumentRecord = async (jsonStatus: any) => { + console.log("检查护理记录"); + let { currentDevice, ActiveModeItem, ModeList } = this.state; + if (jsonStatus) { + } + // 1.判断是否存在工作状态:如果不存在,则等待两秒用于连接设备与赋值,再执行后面的代码 + if (!this.workStatus) { + await sleep(2); + } + + // 2.判断是否已存在缓存的护理记录:如果没有历史,则缓存 + let workStatus = this.workStatus; + let WL200NursingHistory = this.WL200NursingHistory; + if (!this.WL200NursingHistory) { + console.log("小程序缓存没有数据, 忽略"); + if ( + workStatus == MODE_WORKING_ENUM.WORKING || + workStatus == MODE_WORKING_ENUM.PAUSE + ) { + // 缓存没有数据, 要存缓存 + this.setWL200NursingHistory(jsonStatus); + } + return; + } + + // 3.判断是否当天(如果不是当天,则删除记录) + if (!dayjs().isSame(WL200NursingHistory?.createDate, "day")) { + console.log("小程序缓存有数据,但是不是当天数据,忽略"); + this.rmWL200NursingHistory(WL200NursingHistory); + return; + } + + // 仪器缓存模式,判断是否存在于现有模式中 + let recordModeItem = ModeList.find((item) => { + return item.id == WL200NursingHistory.id; + }); + if (!WL200NursingHistory || !recordModeItem) { + console.log("仪器有数据, 但是缓存没有数据, 忽略"); + return; + } + + // 4.判断设备状态-未运行/已完成/待机 + if ( + workStatus == MODE_WORKING_ENUM.STANDBY || + workStatus == MODE_WORKING_ENUM.END || + !workStatus + ) { + // 判断id是否一致, 一致的话则生成护理报表 + if (jsonStatus.id == WL200NursingHistory.id) { + console.log("id一致, 设备没有运行/已完成/待机"); + let totalSeconds = jsonStatus.totalSeconds; // 从仪器上获取的使用时间 + let neededTotalSeconds = jsonStatus.neededTotalSeconds; // 从仪器上获取的使用时间 + console.log( + "从仪器上获取的使用时间 totalSeconds: %d neededTotalSeconds: %d", + totalSeconds, + neededTotalSeconds + ); + let nursingTimeStr = currentDevice?.nursingTimeStr; + let nursingTime = nursingTimeStr ? minSecToS(nursingTimeStr) : 60; // 设备生成护理记录至少需要运行时间 + + if (totalSeconds < nursingTime) { + // 护理时间不足 + this.setState({ isNotEnoughTime: true }); + this.rmWL200NursingHistory(WL200NursingHistory); + return; + } + + // 小程序时间和设备时间,谁大用谁 + let timeValue = + totalSeconds > this.elapsedTime + ? s_to_hms(totalSeconds) + : s_to_hms(this.elapsedTime); + + let params = { + instrumentId: currentDevice.id, + instrumentName: currentDevice.name, + modeId: ActiveModeItem.id, + modeName: ActiveModeItem.modeName, + nursingTime: timeValue, + }; + let res: any = await this.PostNursingLogClock(params); + console.log("res", res); + this.rmWL200NursingHistory(WL200NursingHistory); + } else { + // ID不一致,同步异常,统一提交一分钟 + let params = { + instrumentId: currentDevice.id, + instrumentName: currentDevice.name, + modeId: ActiveModeItem.id, + modeName: ActiveModeItem.modeName, + nursingTime: "00:01:00", + }; + let res: any = await this.PostNursingLogClock(params); + console.log("res", res); + this.rmWL200NursingHistory(WL200NursingHistory); + } + } else { + // 5.判断设备状态-运行中 正常逻辑,这里不做处理,如果用户操作,则按正常流程判断 + console.log("同步异常,但设备运行中"); + console.log("同步异常,但设备运行中"); + console.log("同步异常,但设备运行中"); + } + }; + + /** 获取小程序本地缓存的历史记录 */ + getWL200NursingHistory() { + this.WL200NursingHistory = Taro.getStorageSync("WL200NursingHistory"); + } + /** 设置WL200护理历史 */ + setWL200NursingHistory = (jsonStatus: any) => { + let { currentDevice, ActiveModeItem, ModeList } = this.state; + const params = { + createDate: dayjs().format("YYYY-MM-DD"), + workMode: jsonStatus.workMode, + instrumentId: currentDevice.id, + instrumentName: currentDevice.name, + modeId: ActiveModeItem.id, + modeName: ActiveModeItem.modeName, + id: jsonStatus.id, + neededTotalSeconds: jsonStatus.neededTotalSeconds, + jsonStatus, + }; + this.WL200NursingHistory = JSON.parse(JSON.stringify(params)); + Taro.setStorageSync("WL200NursingHistory", params); + console.log("保存setWL200NursingHistory"); + }; + /** 更新WL200护理历史运行时间 */ + updateWL200NursingHistory = (data: any = null) => { + this.WL200NursingHistory = Taro.getStorageSync("WL200NursingHistory"); + + if (this.WL200NursingHistory) { + let params: any = this.WL200NursingHistory; + + // 设置当前时间 + params.currentTime = this.state.currentTime; + + // 设置正确封面 + if (data) { + params.currentServiceData = data; + } else { + let currentServiceData = { + startSource: "", + stopSource: "", + }; + let serviceLength = this.state.ActiveModeItem.serviceData.length; + if (serviceLength > 0) { + currentServiceData = this.state.ActiveModeItem.serviceData[0]; + } + params.currentServiceData = currentServiceData; + } + Taro.setStorageSync("WL200NursingHistory", params); + console.log("更新updateWL200NursingHistory"); + } + }; + /** + * @name 删除WL200护理历史 + * @description 参数1 护理历史 参数2 强制删除 + * 如果传入护理历史ID与现有ID相等,则删除。 + * 如果参数二为真,则强制删除 + */ + rmWL200NursingHistory = (WL200NursingHistory, hard = false) => { + const nowWL200NursingHistory = Taro.getStorageSync("WL200NursingHistory"); + if (nowWL200NursingHistory.id == WL200NursingHistory.id) { + Taro.removeStorageSync("WL200NursingHistory"); + this.WL200NursingHistory.id = ""; + } else if (hard) { + Taro.removeStorageSync("WL200NursingHistory"); + this.WL200NursingHistory.id = ""; + } + }; + + /** 提交护理记录 */ + PostNursingLogClock = async (data: any = null, isJump = true) => { + let { currentDevice, ActiveModeItem } = this.state; + + let params = {}; + if (data) { + params = data; + } else { + params = { + instrumentId: currentDevice.id, + instrumentName: currentDevice.name, + modeId: ActiveModeItem.id, + modeName: ActiveModeItem.modeName, + nursingTime: s_to_hms(this.elapsedTime), + }; + } + + let res: any = await InstrumentInfo.apiNursingLog.addLog(params); + console.log("PostNursingLogClock", res); + + if (res.data.code === 200) { + this.rmWL200NursingHistory(this.WL200NursingHistory); // 护理完成,删除记录 + if (isJump) { + this.setState({ + isShowNursingSuccess: true, + }); + setTimeout(() => { + this.setState({ + isShowNursingSuccess: false, + }); + this.goFaceReport(); + }, 2000); + } + } + }; + /*** 护理记录 END ***/ + + //蓝牙断开连接处理 + bluetoothDisconnectProcessing() { + clearInterval(timer); + Taro.offBLEConnectionStateChange(this.listener); // 需传入与监听时同一个的函数对象 + Taro.offBLECharacteristicValueChange((res) => { + console.log("offBLECharacteristicValueChange", res); + }); + if (!this.state.isToOTA) { + Taro.closeBluetoothAdapter(); + } + } + + /** 获取护理时间组合 */ + getServiceTimeData() { + const { ActiveModeItem } = this.state; + let serviceData = ActiveModeItem.serviceData.map((item) => { + let totalWorkingMinutes = parseInt( + item.serviceStartTimeStr.split(":")[0] + ); // 仅分钟数 + let totalWorkingSeconds = parseInt(item.serviceEndTimeStr.split(":")[1]); // 仅秒数 + // let totalWorkingMinutes = 1; // 仅分钟数 + // let totalWorkingSeconds = 0; // 仅秒数 + return { + totalWorkingMinutes, + totalWorkingSeconds, + }; + }); + return serviceData; + } + /** 设置护理时间组合 */ + setServiceTimeData() { + let ServiceTimeData = this.getServiceTimeData(); + + // 组合时间 + let ModeStepTimeArray: any = []; + ServiceTimeData.reduce((old, cur) => { + let curTime = cur.totalWorkingMinutes * 60 + cur.totalWorkingSeconds; + let newTotalWorkingMinutes = cur.totalWorkingMinutes; + let newTotalWorkingSeconds = cur.totalWorkingSeconds; + if (old) { + newTotalWorkingMinutes += old.totalWorkingMinutes; + newTotalWorkingSeconds += old.totalWorkingSeconds; + + let oldTime = old.totalWorkingMinutes * 60 + old.totalWorkingSeconds; + let value = oldTime + curTime; + ModeStepTimeArray.push(value); + return { + totalWorkingMinutes: newTotalWorkingMinutes, + totalWorkingSeconds: newTotalWorkingSeconds, + }; + } + ModeStepTimeArray.push(curTime); + return { + totalWorkingMinutes: newTotalWorkingMinutes, + totalWorkingSeconds: newTotalWorkingSeconds, + }; + }, null); + this.setState({ + ModeStepTimeArray: ModeStepTimeArray, + ModeStepIndex: 0, // 每次切换组合模式,重置组合步骤 + }); + console.log("组合时间ModeStepTimeArray", ModeStepTimeArray); + } + + /* 组合模式 */ + /** 获取自定义组合模式数组 */ + getCustomModesArray = () => { + const { ModeList, ActiveModeItem } = this.state; + const combineIds = ActiveModeItem.combineData.map( + (item) => item.combineModeId + ); + let modesArray = ModeList.filter((item) => + combineIds.includes(item.id) + ).map((item) => { + let totalWorkingMinutes = parseInt(item.modeTimeStr.split(":")[0]); // 仅分钟数 + let totalWorkingSeconds = parseInt(item.modeTimeStr.split(":")[1]); // 仅秒数 + return { + workMode: item.modeType, + totalWorkingMinutes, + totalWorkingSeconds, + }; + }); + return modesArray; + }; + setCustomMaskData() { + console.log("================"); + console.log("setCustomMaskData"); + console.log("================"); + + // modesArray 发送组合模式数组指令到设备存储 + let modesArray = this.getCustomModesArray(); + console.log("组合模式modesArray", modesArray); + + let customModeSetCommand = { + commandType: "InfoQuery", + infoQueryType: "customModeSet", + modesArray, + }; + let commandBuffer = deviceToolKitInstance.toBleCommand( + customModeSetCommand as any + ); + sendCommand({ + value: commandBuffer, + }).then((res) => { + console.info("发送切换组合模式指令成功", res); + }); + } + // 发送启动组合模式指令 + startCombinationMode() { + const jsonCommand = { + commandType: "DeviceControl", + workStatus: "working", + workMode: "MaskCustom", + }; + let commandBuffer = deviceToolKitInstance.toBleCommand(jsonCommand as any); + sendCommand({ + value: commandBuffer, + }).then(() => { + console.info("发送启动组合模式指令成功 参数为 =>", jsonCommand); + }); + } + + // 护理的错误提示 + showTips(ctx) { + if (!ctx) return; + if (showTipsTimer) clearTimeout(showTipsTimer); + this.setState({ + errorTips: ctx, + }); + showTipsTimer = setTimeout(() => { + this.setState({ + errorTips: "", + }); + }, 2000); + } + + /** 结束护理弹窗 */ + onEndPlan = async () => { + this.setState({ + isEndCarePlan: true, + }); + }; + confirmEndBtn = () => { + console.log("confirmEndBtn", this.isCheckNurseTime()); + if (this.isCheckNurseTime()) { + this.endNurseFun(); + this.cancelEndBtn(); + } else { + this.handleWorkStatus(false, "end"); + this.setState({ + isEndCarePlan: false, + isNotEnoughTime: true, + }); + } + }; + cancelEndBtn = () => { + this.setState({ + isEndCarePlan: false, + }); + }; + /** 弹窗 END*/ + + // 打开通用错误弹窗 + openErrorTipsText = (str) => { + this.setState({ + isShowErrorTipsText: true, + errorTipsText: str, + }); + }; + // 关闭通用错误弹窗 + closeErrorTipsText = () => { + this.setState({ + isShowErrorTipsText: false, + }); + }; + + closeNotEnoughTime = () => { + this.setState({ + isNotEnoughTime: false, + }); + Taro.reLaunch({ + url: "/pages/index/index", + }); + }; + + /** 完成护理提交:跳转护理报告页 */ + goFaceReport = () => { + // 跳转前置空定时器,防止重复提交 + if (currentTimeTimer) clearInterval(currentTimeTimer); + go("/pages/face_report/face_report?id=" + this.state.currentDevice.id); + }; + + // 完成配对 + pairingChange = () => { + this.setState({ + isConnectShow: false, + }); + this.onNursingTap("switch"); + }; + connectionClose = () => { + this.setState({ + isConnectShow: false, + }); + Taro.reLaunch({ url: "/pages/index/index" }); + }; + + // 手动护理模式切换:提示是否保存护理 + /**仅关闭*/ + closeTipsSave = () => { + this.setState({ + isShowTipsSave: false, + }); + }; + /**关闭+切换*/ + cancelTipsSave = () => { + this.setState({ + isShowTipsSave: false, + }); + this.modeCurrentFun(this.tempModeCurrent, true); // 不提交护理记录,也不进行校验 + }; + /**关闭+提交+切换*/ + confirmTipsSave = async () => { + this.setState({ + isShowTipsSave: false, + }); + this.PostNursingLogClock(null, false); // 先提交护理记录 + this.modeCurrentFun(this.tempModeCurrent, true); // 不进行校验 + }; + + /** 初次护理信息弹窗 */ + firstNurseInfo = async () => { + let { currentDevice } = this.state; + let res = await InstrumentInfo.firstNurseInfo({ + instrumentId: currentDevice.id, + }); + if (res.data.code === 200) { + let isFirstTipShow = getStorageSync( + "first_instrument_" + currentDevice.id + ); + if (!isFirstTipShow) { + // 首次进入页面:自动打开打卡介绍弹窗 + this.setState({ nurseInfo: res.data.data, isFirstTipShow: true }); + setStorageSync("first_instrument_" + currentDevice.id, true); + } else { + this.setState({ nurseInfo: res.data.data }); + } + } + }; + onTipShowOpen = async () => { + this.setState({ isFirstTipShow: true }); + }; + onTipShowClose = async () => { + setStorageSync("first_instrument_" + this.state.currentDevice.id, true); + this.setState({ isFirstTipShow: false }); + }; + /** 初次护理信息弹窗 END */ + + /** + * @name 设备运行开关按钮是否禁用 + * @description 判断所选模式与设备连接状态是否一致 + * @returns 返回true则禁用 + */ + footerIsDisabled = () => { + let { isStandStatus } = this.state; + let isCanClick = isStandStatus + ? this.tempModeCurrent?.isCabinMode === 1 + : this.tempModeCurrent?.isCabinMode === 0; + // 如果舱体状态和模式类型不相等,则禁用 + let isFooterBtnDisabled = false; + + if (!isCanClick) { + isFooterBtnDisabled = true; + } + console.log("isCanClick", isCanClick); + console.log("isFooterBtnDisabled", isFooterBtnDisabled); + // 仅在值变化时更新state + // if (isFooterBtnDisabled !== this.state.isFooterBtnDisabled) { + this.setState({ + isFooterBtnDisabled: isFooterBtnDisabled, + }); + // } + + return isFooterBtnDisabled; // 数据更新有延迟,返回用于判断 + }; + + customBack = () => { + Taro.reLaunch({ url: "/pages/index/index" }); + }; + + render() { + let { + title, + isConnectShow, + isShowStepTips, + isShowNurse, + isStopNurse, + ModeList, + ModeType, + currentServiceData, + ActiveModeItem, + SwitchActiveModeItem, + isSwitchActiveMode, + ModeID, + activeModeID, + isShowCountdown, + countdown, + Electricity, + matrixElectricity, + errorTips, + isEndCarePlan, + currentTime, + facialMaskConnectStatus, + isShowErrorTipsText, + errorTipsText, + isNotEnoughTime, + isShowNursingSuccess, + currentDevice, + isConnectionBlutoot, + isShowTipsSave, + isFirstTipShow, + nurseInfo, + isShowReReadRecordSave, + isFooterBtnDisabled, + isFirstEntryMode, + } = this.state; + + return ( + + + + + + + + + + + } + textAlgin="center" + cancelButtonText="取消" + confirmButtonText="确定" + close={this.cancelModeSwitchBtn} + confirm={this.confirmModeSwitchBtn} + /> + + {ActiveModeItem.openSourceData && ( + + )} + + + + + + + 当前模式已护理部分时间 + 是否保存护理记录 + + } + cancelButtonText="取消" + confirmButtonText="确认" + textAlgin="center" + close={this.closeTipsSave} + cancel={this.cancelTipsSave} + confirm={this.confirmTipsSave} + /> + + { + /*不需要做处理*/ + }} + /> + + {isConnectShow && ( + {}} + pairingChange={this.pairingChange} + upgradeFun={() => {}} + /> + )} + + + + + + + {!isShowNurse && ( + + + + + + 护理时间: + {currentTime} + + + + + + + + {ModeList.length > 0 && ( + + )} + + + + {/* */} + + +