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 { 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 ( {ActiveModeItem.openSourceData && ( )} {isMusicPlay ? ( ) : ( )} {!isShowNurse && ( 护理时间:10:00 WE200电量: {Electricity === 4 && ( )} {Electricity === 3 && ( )} {Electricity === 2 && ( )} {Electricity === 1 && ( )} {Electricity === 1 && ( )} {ModeList.length > 0 && ( )}