You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1627 lines
52 KiB
TypeScript

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import Taro from "@tarojs/taro";
import dayjs from "dayjs";
import classnames from "classnames";
import { Component, PropsWithChildren, useEffect, useState } from "react";
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";
/* 公共组件 END */
/* 本页组件 */
import ModeListView from "./components/ModeList/index";
import ModeContent from "./components/ModeContent/index";
import Footer from "./components/Footer";
/* 本页组件 END */
import { getStorageSync, setStorageSync } from "@/utils/traoAPI";
import { InstrumentInfo } from "@/utils/Interface";
import "./iotCarePlan.less";
// import log from "@/utils/log";
// log.info("123456info", 123456, { sdfasdf: 123 });
import {
notifyBLECharacteristicValueChange,
sendCommand,
} from "@/utils/bluetoothWXAPI";
import {
deviceCommandSamples,
bleCommandSamples,
} from "@/components/bluetoot/connection/test";
import {
minSecToS,
s_to_h,
s_to_hs,
s_to_s,
isNeedToUpdate,
} from "@/utils/util";
import { DeviceToolKit as DeviceToolKitWE100 } from "@flossom-npm/iot-translater-we100";
import commandMap from "@/utils/commandMap";
const deviceToolKitInstanceWE100 = new DeviceToolKitWE100("WE100", "M01");
const deviceToolKitInstanceWL200 = new DeviceToolKitWE100("WE100", "WL200");
let timer: any = null;
let checkVersionTimeout: any = null;
let showTipsTimer: any = null;
let loadingTipsTimer: any = null; // 蓝牙连接提示
let switchModeStatus = "free"; // 用于标记是否在切换模式中, free: 空闲, switching: 切换中
//时间校准频率,每多少秒校准一次
const TIME_CALIBRATION_FREQUENCY = 5;
// 模式类型
const WORK_MODE_NAME_ENUM = {
POWERFULSOOTHING: "powerfulSoothing",
STABILITY: "Stability",
BRIGHTEN: "Brighten",
FIRMSKIN: "FirmSkin",
MaskCustom: "MaskCustom",
BrightenStand: "BrightenStand",
FirmSkinStand: "FirmSkinStand",
SmallpoxSoothingPro: "SmallpoxSoothingPro",
SmallpoxSoothing: "SmallpoxSoothing",
MixNursePro: "MixNursePro",
MixNurse: "MixNurse",
ScalpCare: "ScalpCare",
};
// 模式类型:英文名
const WORK_MODE_ENGLISH_NAME = {
6: "powerfulSoothing",
7: "Stability",
8: "Brighten",
9: "FirmSkin",
MaskCustom: "MaskCustom",
21: "BrightenStand",
22: "FirmSkinStand",
23: "SmallpoxSoothingPro",
24: "SmallpoxSoothing",
25: "MixNursePro",
26: "MixNurse",
27: "ScalpCare",
};
// 模式类型中文名
const WORK_MODE_Chinese_NAME = {
: "powerfulSoothing",
: "Stability",
: "Brighten",
: "FirmSkin",
: "MaskCustom",
Pro: "BrightenStand",
Pro: "FirmSkinStand",
Pro: "SmallpoxSoothingPro",
: "SmallpoxSoothing",
Pro: "MixNursePro",
: "MixNurse",
: "ScalpCare",
};
const WORK_MODE_TYPE = {
powerfulSoothing: 6,
Stability: 7,
Brighten: 8,
FirmSkin: 9,
MaskCustom: "MaskCustom",
BrightenStand: 21,
FirmSkinStand: 22,
SmallpoxSoothingPro: 23,
SmallpoxSoothing: 24,
MixNursePro: 25,
MixNurse: 26,
ScalpCare: 27,
};
const MODE_WORKING_ENUM = {
STANDBY: "standby",
WORKING: "working",
PAUSE: "pause",
END: "end",
};
// 倒计时时间
let CountDownTime = {
powerfulSoothing: 6,
Stability: 4,
Brighten: 4,
FirmSkin: 4,
MaskCustom: 6,
BrightenStand: 6,
FirmSkinStand: 6,
SmallpoxSoothingPro: 6,
SmallpoxSoothing: 4,
MixNursePro: 6,
MixNurse: 4,
ScalpCare: 6,
};
let KeepCheckingLink = true;
let DeviceSyncData = {
totalWorkingMinutes: 0,
totalWorkingSeconds: 0,
};
let deviceToolKitInstance = deviceToolKitInstanceWE100; // we100
class IotCarePlan extends Component<any, any> {
constructor(props) {
super(props);
this.state = {
name: "iotCarePlan",
title: "美容仪名字",
instrument: "WE200",
/** 连接设备 */
hasVersion: false, // 是否已查询到版本号
curDeviceInfo: {}, // 当前设备信息
basicModeList: [], //模式列表
modelActiveIndex: 0, //模式下标
sliderProgress: 22,
isStandStatus: false, //支架开启状态(支架就是舱体)
workStatus: "", //工作状态
Electricity: 0, //fr200电量
matrixElectricity: 0, //matrix电量
workMode: "", //当前模式
showCombinationModeDialog: false, // 组合模式弹窗
combinationModeList: [], // 可选的组合模式列表
combinationList: [], // 选择的组合模式列表
combinationModeInfo: {}, // 组合模式缓存的信息
originCombinationList: [], // 原始组合模式列表
originCombinationModeInfo: {}, // 原始组合模式缓存的信息
isCurrentModeCombination: false, // 当前模式是否是组合模式
isSendModeCombination: false, // 当前是否在发送组合模式
gear: { gear: 1 },
currentShowDialog: "",
// countdown: 3, // 倒计时
step: 1, // 1:选择模式并播放视频, 2:护理中
facialMaskConnectStatus: 0, // 面膜连接状态
checkedMaskVersion: false, //是否检查过固件版本了
askedOta: false, //询问过用户是否需要OTA
showVideoPlayBtn: true, // 视频播放按钮
duration: 0, // 视频总时长
hadShowBreakTips: false, // 是否展示过支架断开提示
popupType: "", // enoughTimePopup: 时间达标提示, endPopup: 结束弹窗
safeAreaBottom: 0,
video_guide: "", // 指导视频
wl200CustomMode: [], // wl200所有的自定义模式
joinModeId: 0,
todayMode: 0, // 今日场景id
customModeData: {
hadCustom: false,
hadSetCustom: false, // 是否设置过 -- 代码逻辑使用
setCustomSuc: false, // 是否设置成功 -- 页面需要用于判断
}, // 自定义模式判断
/** 连接设备 End */
// isMuted: false, // 视频是否静音
isMusicPlay: false, // 声音播放状态
isShowStepTips: false, // 是否显示介绍步骤弹窗
isConnectionBlutoot: false, // 是否已连接蓝牙
isShowNurse: false, // 是否开始并显示护理
isStopNurse: false, // 是否暂停护理
isEndNurse: false, // 是否结束护理
errorTips: "", // 错误提示
// 模式列表
ModeList: [],
ModeType: "all", // all visor面罩 cabin舱体 yimeish医美
modeClass: "", // 1面罩 2舱体 3医美
ActiveModeItem: {}, // 当前选中模式
ModeStepIndex: 0, // 当前护理功效步骤:每个步骤时间不定,所以时间另外计算,根据步骤显示
// 倒计时
isShowCountdown: false, // 倒计时弹窗
countdown: 6,
// startSettingCountDown: false, // 是否开始倒计时
// 音乐
// innerAudioContext: null,
// 最后执行步骤位置
endPlace: "",
};
}
async onLoad() {
// 保持屏幕常亮
Taro.setKeepScreenOn({
keepScreenOn: true,
});
}
componentDidMount() {
this.setState({
videoContext: Taro.createVideoContext("myVideo"),
standVideoContext: null,
});
}
componentWillUnmount() {}
componentDidShow() {
this.initData();
}
componentDidHide() {}
async initData() {
let objStr = getStorageSync("instrument_detail");
if (objStr) {
let info = JSON.parse(objStr);
this.GetModeList(info.id);
console.log("info");
// 如果不存在设备模式值,则判断为首次进入,弹窗提示
let isFirstEntry = getStorageSync("isFirstEntry_" + info.model);
if (!isFirstEntry) {
// this.setState({ isShowStepTips: true });
}
}
// 初始化蓝牙
this.init();
}
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(null, MODE_WORKING_ENUM.STANDBY);
}
listener = (res) => {
console.log("listener res", res);
if (res?.connected) return;
Taro.offBLECharacteristicValueChange((res) => {
console.log("offBLECharacteristicValueChange", res);
});
clearTimeout(loadingTipsTimer);
// 断开蓝牙关闭倒计时
this.setState({
isShowCountdown: false,
});
console.log(commandMap.WL200Command, "监听到蓝牙断开, 打开断开提示");
// 显示蓝牙断开弹窗
// this.setState({
// workStatus: "",
// currentShowDialog: "connection_break",
// });
};
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(() => {
console.log("ActiveModeItem", this.state.ActiveModeItem);
});
} else {
this.setState({ ModeList: res.data.data });
}
}
};
changeMusicStatus = () => {
let { isMusicPlay } = this.state;
this.setState({ isMusicPlay: !isMusicPlay });
};
/** 开始护理按钮:点击开始,页面进行到下一步 */
onStartNurse = async () => {
this.stepNext();
return;
let { isConnectionBlutoot } = this.state;
if (isConnectionBlutoot) {
this.stepNext();
} else {
// todo 提示未连接蓝牙
}
};
/** 切换光照 */
onSwitchChange = async () => {
// todo
let { isStopNurse } = this.state;
let switchStatus = !isStopNurse;
if (switchStatus) {
// 开始光照逻辑
} else {
// 暂停光照逻辑
}
this.setState({ isStopNurse: switchStatus });
};
onEndPlan = async () => {
// todo
};
modeCurrentFun = async (data) => {
console.log("modeCurrentFun", data);
this.setState({ ActiveModeItem: data });
};
stepNext = () => {
// //0未定义全部 1面罩模式 2舱体模式 3医美术后
let modeArray = ["all", "visor", "cabin", "yimeish"];
let modeClass = this.state.ActiveModeItem.modeClass;
this.setState({ ModeType: modeArray[modeClass] });
this.setState({ isShowNurse: true });
};
closeStepTips = (data) => {
if (data.isLocal) {
setStorageSync("isFirstEntry_" + this.state.ActiveModeItem.model, true); // 关闭首次进入弹窗
}
this.setState({ isShowStepTips: false });
};
/** 蓝牙相关 */
switchBLEMatch = (jsonStatus: any) => {
switch (jsonStatus.bleCommandType) {
// 如果设备配对链接发送配对码的时候,设备应答小程序配对码是否正确。
case "SendMatchCode":
if (jsonStatus.matchedSuccess) {
// msg('配对成功')
console.log("配对成功");
// log.info(commandMap.WL200Command, "配对成功");
}
break;
//附属设备状态主动上报,这种指令是主机主动上报某个附属设备断开或者连上了
case "BleStatusSync":
switch (jsonStatus.connectMessage?.deviceName) {
case "WL200":
if (jsonStatus.connectMessage?.connectType == "CONNECTED") {
// 已连接WL200
this.setState({ isConnectionBlutoot: true });
if (
!this.state.customModeData.setCustomSuc &&
!this.state.customModeData.hadSetCustom
) {
// this.setCustomMaskData();
}
// that.setData({
// facialMaskConnectStatus: 1,
// });
// this.deviceToolKitInstance = deviceToolKitInstanceWL200;
// console.log(
// "checkedMaskVersion",
// this.data.checkedMaskVersion
// );
// if (!this.data.checkedMaskVersion) {
// this.checkVersion();
// }
} else {
// deviceToolKitInstance = deviceToolKitInstanceWE100;
// // TODO 护理中(step==2)时, 如果断开, 可能需要暂停
// that.setData({
// facialMaskConnectStatus: 0,
// });
}
break;
case "Stand":
// that.setData({
// isStandStatus:
// jsonStatus.connectMessage?.connectType == "CONNECTED",
// });
break;
default:
break;
}
break;
//小程序主动问主机,现在链接了哪些附属设备,这时候主机给小程序的回复消息
case "QueryMatchStatus":
const isStandDevice =
jsonStatus?.subDeviceList?.includes("Stand") || false;
const isConnectedMask =
jsonStatus?.subDeviceList?.includes("WL200") || false;
deviceToolKitInstance = isConnectedMask
? deviceToolKitInstanceWL200
: deviceToolKitInstanceWE100;
console.log(isConnectedMask, "更改成功deviceToolKitInstance");
if (!this.state.checkedMaskVersion && isConnectedMask) {
this.checkVersion();
}
console.log("支架是否链接", isStandDevice);
console.log("面罩是否链接", isConnectedMask);
//这里bug 先注释掉 bug是拔掉支架之后启动面罩工作就会一直弹
// let { basicModeList, modelActiveIndex } = that.data;
// if (
// that.data.step == 2 &&
// !isStandDevice &&
// basicModeList[modelActiveIndex].isStandMode &&
// !that.data.hadShowBreakTips
// ) {
// that.data.hadShowBreakTips = true;
// that.onPauseTap();
// that.standVideoContext.seek(0);
// // that.showTips('检测到支架未连接成功,请确认面罩开机后与支架连接,并接通支架电源');
// that.showTips(
// `检测到${that.data.deviceChineseName.WL200Stand}未连接成功,请确认面罩开机后与${that.data.deviceChineseName.WL200Stand}连接,并接通${that.data.deviceChineseName.WL200Stand}电源`
// );
// 连上面罩后, 设置自定义模式 -- 不在这里设置自定义模式
if (
this.state.ActiveModeItem &&
isConnectedMask &&
!this.state.customModeData.setCustomSuc &&
!this.state.customModeData.hadSetCustom &&
this.state.ActiveModeItem.isCustomMode
) {
this.setCustomMaskData();
}
// 连上面罩后, 获取仪器记录, 与缓存信息对比,
// if (
// isConnectedMask &&
// !this.state.hadGotInstrumentHistoryData
// ) {
// // 如果不延时, 无法获取到仪器状态
// const queryDeviceArrayBuffer =
// deviceToolKitInstance.toBleCommand(
// bleCommandSamples.queryDeviceStatus as any
// );
// console.log("发送查询设备指令");
// sendCommand({
// value: queryDeviceArrayBuffer,
// });
// // 打开ota页面需要关闭
// // that.data.getInstrumentHistoryDataTimer = setTimeout(() => {
// // that.getInstrumentHistoryData();
// // }, 3000);
// }
// this.setData({
// isStandStatus: isStandDevice,
// facialMaskConnectStatus: `${isConnectedMask ? 1 : 0}`,
// // currentTime: this.data.standInfo.currentTime
// });
}
};
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
);
// log.info(commandMap.WL200Command, 'onBLECharacteristicValueChange jsonStatus =>', jsonStatus);
if (!jsonStatus || jsonStatus == null) {
return;
}
// 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);
if (
jsonStatus.responseStatus == "OK" &&
this.state.isSendModeCombination
) {
// 发送启动指令
this.startCombinationMode();
const totalTime = this.state.combinationList.reduce(
(total, item) => {
return total + minSecToS(item.time);
},
0
);
// 设备启动后小程序操作
this.setState({
showCombinationModeDialog: false,
combinationModeInfo: {
time: s_to_hs(totalTime),
seconds: totalTime,
},
modelActiveIndex: -1,
currentTime: s_to_hs(totalTime),
isCurrentModeCombination: true,
isSendModeCombination: false,
});
setTimeout(() => {
console.log("currentTime", this.state.currentTime);
});
}
break;
//设备主动上报给小程序的指令 一般是工作状态改变
case "DeviceStatusSync":
console.log(
"设备主动上报给小程序的指令 一般是工作状态改变",
jsonStatus
);
this.setState({
Electricity: jsonStatus.battery,
matrixElectricity: jsonStatus.matrixBattery,
workStatus: jsonStatus.workStatus,
workMode: jsonStatus?.workMode,
});
this.setState({
fr200Electricity: jsonStatus.battery,
matrixElectricity: jsonStatus.matrixBattery,
workStatus: jsonStatus.workStatus,
workMode: jsonStatus?.workMode,
});
// 判断是否在step == 2(护理中)
if (
this.state.step == 2 &&
jsonStatus.workStatus !== MODE_WORKING_ENUM.END
) {
this.updateDeviceSyncData({
totalWorkingMinutes: jsonStatus.totalWorkingMinutes,
totalWorkingSeconds: jsonStatus.totalWorkingSeconds,
});
}
if (jsonStatus.workMode && this.state.step == 2) {
const { ActiveModeItem } = this.state;
const item = ActiveModeItem;
if (
jsonStatus.workMode !== WORK_MODE_ENGLISH_NAME[item.model_type]
) {
clearTimeout(loadingTipsTimer);
this.setState({
isShowCountdown: false,
});
}
}
// // 我忘记了为啥要这样传参... 埋坑了...
this.judgementWorkStatus(
jsonStatus.workStatus,
jsonStatus.workMode,
jsonStatus
);
if (jsonStatus.workMode && this.state.step == 2) {
// this.judgementModel(jsonStatus.workMode);
// that.data.startSettingCountDown = false;
}
break;
//设备信息查询返回
case "InfoQuery":
switch (jsonStatus.infoQueryType) {
// 自定义模式设置
case "customModeSet":
console.log(
"InfoQuery customModeSet responseStatus=====>",
jsonStatus
);
let { customModeData } = this.state;
if (jsonStatus.responseStatus == "OK") {
customModeData.setCustomSuc = true;
this.setState({
customModeData,
});
console.log("设置成功自定义模式");
} else {
customModeData.hadSetCustom = false;
customModeData.setCustomSuc = false;
this.setState({
customModeData,
});
}
break;
// 自定义模式信息
case "customModeInfo":
console.log(
"InfoQuery customModeInfo responseStatus=====>",
jsonStatus
);
break;
case "versionInfo":
console.log(
"InfoQuery versionInfo responseStatus=====>",
jsonStatus
);
if (jsonStatus.versionNo) {
// 清理计时器
if (checkVersionTimeout) clearTimeout(checkVersionTimeout);
if (this.state.hasVersion) return;
this.setState({
hasVersion: true,
});
this.checkOta(jsonStatus.versionNo);
}
break;
// 当前报告
case "currentMaskReportInfo":
console.log("currentMaskReportInfo", jsonStatus);
// if (!this.state.hadCheckReport) {
// this.state.hadCheckReport = true;
// that.checkInstrumentRecord(jsonStatus);
// } else {
// that.setWL200NursingHistory(jsonStatus);
// }
break;
default:
break;
}
break;
// default:
// break;
}
});
/**
* 延迟500毫秒获取附属设备状态
*/
const querySubDeviceArrayBuffer = deviceToolKitInstance.toBleCommand({
...bleCommandSamples.querySubDevice,
queryType: "WL200",
} as any);
setTimeout(() => {
console.log("发送查询指令");
sendCommand({
value: querySubDeviceArrayBuffer,
});
}, 500);
/**
* 延迟500毫秒获取设备电量
*/
const queryDeviceArrayBuffer = deviceToolKitInstance.toBleCommand(
bleCommandSamples.queryDeviceStatus as any
);
setTimeout(() => {
console.log("发送查询设备指令");
sendCommand({
value: queryDeviceArrayBuffer,
});
}, 500);
});
};
// 检查版本
checkVersion = () => {
this.sendCheckVersion();
this.setState({
checkedMaskVersion: true,
});
if (checkVersionTimeout) clearTimeout(checkVersionTimeout);
checkVersionTimeout = setTimeout(() => {
if (this.state.hasVersion) {
if (checkVersionTimeout) clearTimeout(checkVersionTimeout);
} else {
this.sendCheckVersion();
}
}, 600);
};
// 检查版本指令
sendCheckVersion = () => {
deviceToolKitInstance.setDebug(true);
// 加定时器查询版本
const queryVersion = deviceToolKitInstance.toBleCommand({
commandType: "InfoQuery",
infoQueryType: "versionInfo",
otaDeviceType: "WL200",
});
sendCommand({
value: queryVersion,
});
};
checkOta = async (versionNo) => {
const { iot_versions } = this.state.curDeviceInfo;
let isNeedToUpdateBl = isNeedToUpdate(versionNo, iot_versions);
console.log(
`设备版本号: ${versionNo}`,
`后台版本号: ${iot_versions}`,
`是否需要升级: ${isNeedToUpdateBl}`
);
if (isNeedToUpdateBl) {
this.setState({
askedOta: true,
// currentShowDialog: 'offlineDialog',
});
// this.confirmOta();
}
};
// 发送启动组合模式指令
startCombinationMode() {
const jsonCommand = {
commandType: "DeviceControl",
workStatus: "working",
workMode: "MaskCustom",
};
let commandBuffer = deviceToolKitInstance.toBleCommand(jsonCommand as any);
sendCommand({
value: commandBuffer,
}).then(() => {
console.info("发送启动组合模式指令成功 参数为 =>", jsonCommand);
});
}
//待完善,以后同步设备数据到小程序的事件,在这个事件里判断是否需要更新页面(是否需要触发setData)
updateDeviceSyncData = (newData) => {
DeviceSyncData = {
...DeviceSyncData,
...newData,
};
if (newData.hasOwnProperty("totalWorkingSeconds")) {
this.renderDeviceStatus.renderWorkTime();
}
};
// 待完善以后更新页面状态的方法在这里执行setData
renderDeviceStatus = {
renderWorkTime() {
// const that = this;
const { totalWorkingMinutes, totalWorkingSeconds } = DeviceSyncData;
const { ActiveModeItem, currentTime } = this.state;
const totalTime = totalWorkingMinutes * 60 + totalWorkingSeconds;
console.log("仪器上报的已经运行的总秒数", totalTime);
// console.log('时间校准频率默认5秒一次',TIME_CALIBRATION_FREQUENCY)
//对比仪器上报运行的总秒数 和小程序页面运行的已经运行的总秒数,如果不一致就进行校准
const currentScene = ActiveModeItem; // 获取当前的场景
let sceneTime = minSecToS(currentScene.time); // 场景时间
const timeRemaining = sceneTime - minSecToS(currentTime); // 小程序上已运行的总秒数
if (
Math.abs(timeRemaining - totalTime) >= 2 &&
this.state.step == 2 &&
this.state.facialMaskConnectStatus == 1
) {
this.setTimer();
const t = sceneTime - totalTime; // 场景时间 - 已运行时间 = 剩余时间
let { ActiveModeItem } = this.state;
ActiveModeItem.seconds = t; //修复时间跳变的问题
this.setState({
currentTime: s_to_hs(t),
ActiveModeItem,
});
}
},
};
// 仪器开始倒计时
setLoadingTips(time) {
this.setState({
countdown: time,
});
if (time >= 0) {
loadingTipsTimer = setTimeout(() => {
this.setLoadingTips(--time);
}, 1000);
} else {
// 停止倒计时
// that.data.startSettingCountDown = false;
this.setState({
isShowCountdown: false,
});
}
}
// 设备上报不同状态
judgementWorkStatus(nWorkStatus, nWorkMode, jsonStatus) {
const {
workStatus,
step,
isStandStatus,
workMode,
ActiveModeItem,
ModeList,
} = this.state;
const opts: any = {};
// ActiveModeItem
const modeItem = ActiveModeItem;
let nowModeItem;
if (nWorkMode) {
const nowModeType = WORK_MODE_TYPE[nWorkMode];
nowModeItem = ModeList.find((item) => {
return item.model_type == nowModeType;
});
}
opts.workStatus = nWorkStatus;
const statusF = {
sleep: () => {
this.setState({
isShowCountdown: false,
});
},
standby: () => {
this.setState({
isShowCountdown: false,
});
if (nowModeItem?.isStandMode && step == 2) {
opts.currentTime = nowModeItem.time;
} else if (!nowModeItem?.isStandMode && step == 2) {
// fix: 启动非支架模式倒计时时连上支架仪器的状态变为standby
opts.step = 1;
}
if (loadingTipsTimer) {
clearTimeout(loadingTipsTimer);
}
// 本来用于更新时间的,但是产生了 ID1000367 bug先移除
// if (nowModeItem) {
// opts.currentTime = nowModeItem.time;
// }
},
setting: () => {
// that.data.hadShowBreakTips = false;
this.setState({
hadShowBreakTips: false,
});
if (step != 2 && !modeItem.isStandMode) {
opts.step = 2;
this.setState({
title: "正在护理",
isStopNurse: false,
});
// Taro.setNavigationBarTitle({
// title: "正在护理",
// });
// 处理音乐
this.musicStatusChange();
} else if (step != 2 && modeItem.isStandMode) {
opts.step = 2;
// this.setState({
// title: "正在护理",
// });
this.setState({
title: "正在护理",
isStopNurse: false,
});
}
if (nowModeItem) {
opts.currentTime = nowModeItem.time;
}
// 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.musicStatusChange();
}
// else if (modeItem?.isStandMode) {
// 支架模式也使用gif图, 不需要播放视频了, 所以注释
// that.onPlayTap();
// }
this.setState({
isShowCountdown: false,
hadShowBreakTips: false,
});
},
pause: () => {
this.setState({
isShowCountdown: false,
});
if (modeItem.isStandMode) {
// this.onPauseTap();
this.setState({
title: "暂停护理",
isStopNurse: true,
});
}
},
end: () => {
// 仪器返回护理结束, 支架模式不需要了
// if (modeItem.isStandMode) {
// that.onPauseTap();
// }
// 已进入了报告阶段, 防止重复进入, 主要防止在手动点击结束护理接收到仪器消息
if (this.state.endPlace) return;
// 获取仪器运行时间,更新currentTime, 判断仪器返回时间正常的情况下
const { totalWorkingSeconds, totalWorkingMinutes } = jsonStatus;
if (totalWorkingSeconds != 0 || totalWorkingMinutes != 0) {
const sceneTime = minSecToS(modeItem.currentTime); // 模式的总时长
const runTime = totalWorkingMinutes * 60 + totalWorkingSeconds; //仪器运行时长
const timeRemaining = sceneTime - runTime; // 剩余未运行时间
this.setState({
currentTime: s_to_hs(timeRemaining),
});
}
this.endnursing(null, true);
this.rmWL200NursingHistory(this.state.WL200NursingHistory);
},
};
statusF[nWorkStatus] && statusF[nWorkStatus]();
if (Object.keys(opts).length) {
this.setState(opts);
}
}
/**
* 保存护理报告
* 1.是否跳转 2.数据
* */
saveNurseReport = async (isJump = true, from) => {
const { isStandStatus, standInfo, ActiveModeItem, options } = this.state;
const currentScene = ActiveModeItem;
let sceneTime = minSecToS(currentScene.time);
const timeRemaining = sceneTime - minSecToS(this.state.currentTime);
const form = {
second: timeRemaining,
screne_id: currentScene.screne_id,
screne_name: currentScene.screne_name,
instrument_id: options?.devId,
report: JSON.stringify({
positionRatio: Math.floor((timeRemaining / sceneTime) * 100),
}),
};
// log.info(commandMap.WL200Command, '保存护理报告saveNurseReport', '来自方法from:' + from, '护理时间timeRemaining:'+timeRemaining);
console.log("timeRemaining=>", timeRemaining);
console.log("currentScene=>", currentScene);
console.log("form=>", form);
// const { data } = await UserNursingLogAdd(form)
// // 清除缓存
// that.rmWL200NursingHistory(that.data.WL200NursingHistory, true);
// if (data.code == 200 && isJump) {
// that.setData({
// showNurseSuccess: true
// });
// setTimeout(()=>{
// wx.redirectTo({ url: `/pages/MatrixWL200/pages/nursingRecord/nursingRecord?instrument_id=${options?.devId}&id=${data.data}` })
// }, 2000);
// }
};
/**
* 结束护理
* param isAuto 是否仪器自动结束
*/
endnursing(e, isAuto) {
if (isAuto == true) {
// 仪器自动上报完成, 直接上报并跳转报告页
clearInterval(timer);
const isEnough = this.checkTime();
if (isEnough && !this.state.endPlace) {
this.setState({
endPlace: "report",
});
this.saveNurseReport(true, "endnursing");
}
// this.handleTimeCheck(that.endNurseFun)
} else {
// 手动点击结束, 弹出弹窗, 看看是否需要结束
this.setState({
popupType: "endPopup",
});
/*showModal({
t2: "是否结束护理?",
}).then(async () => {
this.handleTimeCheck(that.endNurseFun)
});*/
}
}
setCustomModeData() {
const { basicModeList, modelActiveIndex, currentTime } = that.data;
const modeItem = basicModeList[modelActiveIndex];
const group = modeItem.group;
if (group.length == 1) return; // 只有1项不用管
let inTimeScopeIndex = -1; // 选择的index
group.forEach((item, index) => {
let startMinute = item.scope[0];
let endMinute = item.scope[1];
let targetMinute = currentTime.split(":")[0];
let targetSecond = currentTime.split(":")[1];
const isInTime = this.isInTimeScope(
startMinute,
endMinute,
targetMinute,
targetSecond
);
if (isInTime) inTimeScopeIndex = index;
});
if (modeItem.timeScopeIndex !== inTimeScopeIndex) {
// this.setState({
// [`basicModeList[${modelActiveIndex}].timeScopeIndex`]: inTimeScopeIndex,
// [`basicModeList[${modelActiveIndex}].desc`]: group[inTimeScopeIndex].desc,
// [`basicModeList[${modelActiveIndex}].technique`]: group[inTimeScopeIndex].technique,
// [`basicModeList[${modelActiveIndex}].pause_img`]: group[inTimeScopeIndex].pause_img,
// [`basicModeList[${modelActiveIndex}].running_img`]: group[inTimeScopeIndex].running_img,
// })
}
}
isInTimeScope(start, end, targetMinute, targetSecond) {
const startTime = dayjs().set("minute", start).set("second", 0);
const endTime = dayjs().set("minute", end).set("second", 0);
const targetTime = dayjs()
.set("minute", targetMinute)
.set("second", targetSecond); // 要判断的时间,这里使用当前时间作为示例
let inTime = false;
if (
(targetTime.isAfter(startTime) && targetTime.isBefore(endTime)) ||
targetTime.isSame(startTime) ||
targetTime.isSame(endTime)
) {
inTime = true;
}
return inTime;
}
setTimer() {
// 切换模式后, 需要重新设置计时器, 以防进行中的计时器
timer && clearInterval(timer);
timer = setInterval(() => {
if (
this.state.workStatus == MODE_WORKING_ENUM.WORKING &&
this.state.step == 2 &&
this.state.facialMaskConnectStatus == 1
) {
/*if(that.data.workMode !== WORK_MODE_NAME_ENUM.POWERFULSOOTHING){*/
let currentSeconds;
if (this.state.isCurrentModeCombination) {
// 组合模式逻辑
// that.data.combinationModeInfo.seconds -= 1;
// that.setData({
// currentTime: s_to_hs(that.data.combinationModeInfo.seconds)
// })
// currentSeconds = that.data.combinationModeInfo.seconds
} else {
const { ActiveModeItem, currentTime } = this.state;
currentSeconds = minSecToS(currentTime);
this.setState({
currentTime: s_to_hs(--currentSeconds),
});
console.log(ActiveModeItem.isCustomMode);
if (ActiveModeItem.isCustomMode) {
this.setCustomModeData();
}
}
if (currentSeconds <= 0) {
clearInterval(timer);
// 统一接收仪器结束指令
// that.data.endPlace = 'report';
// that.saveNurseReport(true, 'setTimer');
}
/*} else {
that.data.standInfo.seconds -= 1;
that.setData({ currentTime: s_to_hs(that.data.standInfo.seconds) })
if(that.data.standInfo.seconds <= 0){
clearInterval(timer);
this.showNurseSuccessDialog()
}
}*/
}
}, 1000);
}
// 工作状态
handleWorkStatus = (_, workStatus) => {
const { facialMaskConnectStatus, isStandStatus, ActiveModeItem } =
this.state;
const modeItem = ActiveModeItem;
let newWorkStatus =
workStatus ||
(this.state.workStatus == MODE_WORKING_ENUM.WORKING
? "pause"
: "working");
if (_ && newWorkStatus == "working") {
if (modeItem.modeClass === 2 && !isStandStatus) {
this.showTips(
`检测到${this.state.deviceChineseName.WL200Stand}未连接成功,请确认面罩开机后与${this.state.deviceChineseName.WL200Stand}连接,并接通${this.state.deviceChineseName.WL200Stand}电源`
);
return;
}
if (!modeItem.isStandMode && facialMaskConnectStatus != 1) {
this.showTips("检测到面罩未连接成功,请确认面罩开机并佩戴");
return;
}
}
const curModeData = ActiveModeItem;
const sendParams = {
...deviceCommandSamples.pause,
workMode: WORK_MODE_ENGLISH_NAME[curModeData.model_type],
workStatus: newWorkStatus,
};
const pauseArrayBuffer = deviceToolKitInstance.toBleCommand(
sendParams as any
);
sendCommand({
value: pauseArrayBuffer,
}).then(() => {
this.setState({
workStatus: newWorkStatus,
});
this.setTimer();
// 支架模式, 暂停, 需暂停视频播放
if (newWorkStatus == MODE_WORKING_ENUM.PAUSE && modeItem.isStandMode) {
this.onPauseTap();
}
// 支架模式, 开始播放, 需播放视频
if (newWorkStatus == MODE_WORKING_ENUM.WORKING && modeItem.isStandMode) {
this.onPlayTap();
}
console.info(
`handleWorkStatus 发送${newWorkStatus}指令成功 参数为 =>`,
sendParams
);
});
};
/**
* 点击开始护理
*/
onNursingTap() {
// 防止多次点击
if (this.state.hadClickStart) return;
this.setState({
hadClickStart: true,
});
setTimeout(() => {
this.setState({
hadClickStart: false,
});
}, 500);
const {
ActiveModeItem,
workStatus,
isStandStatus,
facialMaskConnectStatus,
customModeData,
} = this.state;
const modelActiveItem = ActiveModeItem;
// log.info(
// commandMap.WL200Command,
// "点击开始护理按钮",
// `当前模式: ${modelActiveIndex}`,
// `当前面罩状态:${facialMaskConnectStatus}`,
// `当前仪器模式:${workStatus}`
// );
console.info(
commandMap.WL200Command,
"点击开始护理按钮",
`当前模式: ${ActiveModeItem}`,
`当前面罩状态:${facialMaskConnectStatus}`,
`当前仪器模式:${workStatus}`
);
console.log(modelActiveItem);
console.log("isStandStatus:" + isStandStatus);
console.log(
workStatus !== MODE_WORKING_ENUM.WORKING &&
workStatus !== MODE_WORKING_ENUM.STANDBY &&
workStatus !== MODE_WORKING_ENUM.PAUSE
);
if (facialMaskConnectStatus != 1) {
this.showTips("检测到面罩未连接成功,请确认面罩开机并佩戴");
return;
}
if (
workStatus !== MODE_WORKING_ENUM.WORKING &&
workStatus !== MODE_WORKING_ENUM.STANDBY &&
workStatus !== MODE_WORKING_ENUM.PAUSE
) {
this.showTips("检测到面罩未连接成功,请确认面罩开机并佩戴");
return;
}
// 如果是强效舒缓,需要判断是否连接支架
if (modelActiveItem.isStandMode && !isStandStatus) {
this.showTips(
`检测到${this.state.deviceChineseName.WL200Stand}未连接成功,请确认面罩开机后与${this.state.deviceChineseName.WL200Stand}连接,并接通${this.state.deviceChineseName.WL200Stand}电源`
);
// that.showTips('检测到支架未连接成功,请确认面罩开机后与支架连接,并接通支架电源');
return;
} else if (!modelActiveItem.isStandMode && isStandStatus) {
this.showTips(
`检测到面罩仍和${this.state.deviceChineseName.WL200Stand}连接中,请分离后切换`
);
return;
}
if (modelActiveItem.isCustomMode && !customModeData.setCustomSuc) {
this.showTips(
`${modelActiveItem.nursing_name}模式设置失败,请联系小助手`
);
return;
}
// 开始执行护理
this.handleWorkStatus(null, MODE_WORKING_ENUM.WORKING);
}
// 结束护理?
endNurseFun() {
// this.handleWorkStatus(null, "end");
setTimeout(() => {
//TODO IOS关闭蓝牙太快导致关机指令没发出去暂时这么解决
const isEnough = this.checkTime();
if (!isEnough) {
Taro.showModal({
title: "提示",
content: "护理时间不足,请重新连接护理",
showCancel: false,
success: (res) => {
if (!this.state.endPlace || this.state.endPlace !== "report") {
// back();
console.log("back");
}
// this.state.innerAudioContext.destroy();
Taro.closeBluetoothAdapter();
},
});
} else {
if (!this.state.endPlace || this.state.endPlace !== "report") {
// back();
console.log("back");
}
// this.state.innerAudioContext.destroy();
Taro.closeBluetoothAdapter();
}
}, 500);
}
/**
* 音乐暂停播放时间
*/
musicStatusChange() {
const { step, ActiveModeItem } = this.state;
const modeItem = ActiveModeItem;
this.setState({
musicStatus: !this.state.musicStatus,
});
// if (step == 2 && !modeItem.isStandMode) {
// if (this.state.musicStatus) {
// this.state.innerAudioContext?.play(); // 播放
// } else {
// this.state.innerAudioContext?.pause(); //暂停
// }
// }
}
// 检查时间是否达标
checkTime() {
const { curDeviceInfo, workStatus, ActiveModeItem } = this.state;
const currentScene = ActiveModeItem;
let sceneTime = minSecToS(currentScene.time);
const timeRemaining = sceneTime - minSecToS(this.state.currentTime);
if (timeRemaining >= Number(curDeviceInfo?.times) * 60) {
return true;
} else {
return false;
}
}
// 开始护理?
onPlayTap() {
const { ActiveModeItem, step } = this.state;
const modeItem = ActiveModeItem;
if (step == 1) {
this.state.videoContext.play();
this.setState({
showVideoPlayBtn: false,
});
} else if (modeItem.isStandMode && step == 2) {
this.setState({
standVideoContext: Taro.createVideoContext("standVideo"),
});
setTimeout(() => {
this.state.standVideoContext.play();
}, 100);
}
}
// 暂停护理?
onPauseTap() {
const { ActiveModeItem, step } = this.state;
const modeItem = ActiveModeItem;
if (step == 1) {
} else if (modeItem.isStandMode && step == 2) {
this.setState({
standVideoContext: Taro.createVideoContext("standVideo"),
});
setTimeout(() => {
this.state.standVideoContext.play();
}, 100);
}
}
// 删除WL200护理历史
rmWL200NursingHistory(WL200NursingHistory, hard = false) {
const nowWL200NursingHistory = Taro.getStorageSync("WL200NursingHistory");
if (nowWL200NursingHistory.id == WL200NursingHistory.id) {
Taro.removeStorageSync("WL200NursingHistory");
} else if (hard) {
Taro.removeStorageSync("WL200NursingHistory");
}
}
//蓝牙断开连接处理
bluetoothDisconnectProcessing() {
clearInterval(timer);
Taro.offBLEConnectionStateChange(this.listener); // 需传入与监听时同一个的函数对象
// this.state.innerAudioContext.destroy();
Taro.offBLECharacteristicValueChange((res) => {
console.log("offBLECharacteristicValueChange", res);
});
if (!this.state.isToOTA) {
Taro.closeBluetoothAdapter();
}
}
/* 组合模式 */
setCustomMaskData() {
console.log("================");
console.log("setCustomMaskData");
console.log("================");
const { customModeData, ActiveModeItem } = this.state;
const customItem = ActiveModeItem;
if (!customItem.isCustomMode) {
let { customModeData } = this.state;
customModeData.hadSetCustom = false;
customModeData.setCustomSuc = false;
this.setState({
customModeData,
});
return;
}
if (
!customModeData.setCustomSuc &&
customItem &&
!customModeData.hadSetCustom
) {
this.state.customModeData.hadSetCustom = true;
// 设置组
let customModeSetCommand = customItem.customModeSetCommand;
console.log("自定义模式:", customModeSetCommand);
// log.info('自定义模式:', customModeSetCommand);
let commandBuffer =
deviceToolKitInstanceWL200.toBleCommand(customModeSetCommand);
sendCommand({
value: commandBuffer,
}).then((res) => {
console.info("发送切换组合模式指令成功", res);
});
}
}
showTips(ctx) {
if (!ctx) return;
if (showTipsTimer) clearTimeout(showTipsTimer);
this.setState({
errorTips: ctx,
});
showTipsTimer = setTimeout(() => {
this.setState({
errorTips: "",
});
}, 2000);
}
render() {
let {
name,
title,
isMusicPlay,
isShowStepTips,
ModeList,
ModeType,
isConnectionBlutoot,
isShowNurse,
isStopNurse,
ActiveModeItem,
isShowCountdown,
countdown,
ModeStepIndex,
Electricity,
errorTips,
} = this.state;
return (
<Block>
<Navbar titleSlot={title} isBack={true} />
<PopupCountdown isShow={isShowCountdown} countdown={countdown} />
{ActiveModeItem.openSourceData && (
<PopupStepTips
isShow={isShowStepTips}
isLarge={true}
title={"" + "准备中"}
confirmButtonText="开始护理"
data={ActiveModeItem.openSourceData}
close={this.closeStepTips}
/>
)}
<View>
<View className="iot-main">
<View className="banner-box">
<View className="music-btn" onClick={this.changeMusicStatus}>
{isMusicPlay ? (
<Image
className="music-btn_icon"
src={require("../../img/iot/volume_icon.png")}
mode="aspectFill"
/>
) : (
<Image
className="music-btn_icon"
src={require("../../img/iot/mute_icon.png")}
mode="aspectFill"
/>
)}
</View>
<View>
{!isShowNurse && (
<Video
className="video-or-image"
src={ActiveModeItem.modeVideo}
muted={isMusicPlay}
/>
)}
{isShowNurse && (
<Block>
{isStopNurse ? (
<Image
className="video-or-image"
src={
ActiveModeItem.serviceData[ModeStepIndex].stopSource
}
/>
) : (
<Image
className="video-or-image"
src={
ActiveModeItem.serviceData[ModeStepIndex].startSource
}
/>
)}
</Block>
)}
{errorTips && (
<Block>
<View className="msg-tips">
<Image
className="msg-tips-img"
src={require("../../img/tips.png")}
/>
<View className="msg-tips-content">{{ errorTips }}</View>
</View>
</Block>
)}
</View>
<View className="iot-device">
<View className="item border-right">
<Text>10:00</Text>
</View>
<View className="item">
<Text>WE200</Text>
<View className="value flex aitems">
{Electricity === 4 && (
<Block>
<View className="v1 battery_icon"></View>
<View className="v1 battery_icon"></View>
<View className="v1 battery_icon"></View>
<View className="v1 battery_icon"></View>
</Block>
)}
{Electricity === 3 && (
<Block>
<View className="v1 battery_icon"></View>
<View className="v1 battery_icon"></View>
<View className="v1 battery_icon"></View>
<View className="v2 battery_icon"></View>
</Block>
)}
{Electricity === 2 && (
<Block>
<View className="v1 battery_icon"></View>
<View className="v1 battery_icon"></View>
<View className="v2 battery_icon"></View>
<View className="v2 battery_icon"></View>
</Block>
)}
{Electricity === 1 && (
<Block>
<View className="v1 battery_icon"></View>
<View className="v2 battery_icon"></View>
<View className="v2 battery_icon"></View>
<View className="v2 battery_icon"></View>
</Block>
)}
{Electricity === 1 && (
<Block>
<View className="v3 battery_icon"></View>
<View className="v2 battery_icon"></View>
<View className="v2 battery_icon"></View>
<View className="v2 battery_icon"></View>
</Block>
)}
</View>
</View>
</View>
</View>
{ModeList.length > 0 && (
<ModeListView
ModeList={ModeList}
ModeType={ModeType}
isShowNurse={isShowNurse}
ActiveModeItem={ActiveModeItem}
onEmit={this.modeCurrentFun}
/>
)}
<ModeContent
isShowNurse={isShowNurse}
ActiveModeItem={ActiveModeItem}
/>
</View>
<Footer
isConnectionBlutoot={isConnectionBlutoot}
isShowNurse={isShowNurse}
isStopNurse={isStopNurse}
onEmitStartNurse={this.onStartNurse}
onEmitSwitchChange={this.onSwitchChange}
onEmitEndPlan={this.onEndPlan}
/>
</View>
</Block>
);
}
}
const mapStateToProps = (state) => ({
bluetoothInfo: state.deviceInfo.bluetoothInfo,
});
const mapDispatchToProps = (dispatch) => ({
// userRefresh(data) {
// dispatch(userRefresh(data));
// },
});
export default connect(mapStateToProps, mapDispatchToProps)(IotCarePlan);