diff --git a/.gitignore b/.gitignore index e0287e8..85e062f 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ node_modules/ .DS_Store .swc .idea +package-lock.json \ No newline at end of file diff --git a/config/index.ts b/config/index.ts index fe57964..e1fd645 100644 --- a/config/index.ts +++ b/config/index.ts @@ -17,6 +17,7 @@ const config = { defineConstants: { }, alias: { + '@/img': path.resolve(__dirname, '..', 'src/img'), '@/components': path.resolve(__dirname, '..', 'src/components'), '@/utils': path.resolve(__dirname, '..', 'src/utils'), '@/store': path.resolve(__dirname, '..', 'src/store'), diff --git a/package.json b/package.json index 458ee37..1c4804b 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,8 @@ "author": "", "dependencies": { "@antmjs/vantui": "^3.2.2", - "@babel/runtime": "^7.7.7", + "@flossom-npm/iot-translater": "^1.0.14", + "@flossom-npm/iot-translater-we100": "^1.0.74", "@reduxjs/toolkit": "^2.0.1", "@taroify/core": "^0.1.1-alpha.8", "@tarojs/components": "3.6.19", @@ -60,10 +61,7 @@ "react": "^18.0.0", "react-dom": "^18.0.0", "react-redux": "^9.0.3", - "taro-ui": "^3.2.0", - "terser-webpack-plugin": "^5.3.9", - "@flossom-npm/iot-translater": "^1.0.8", - "@flossom-npm/iot-translater-we100": "^1.0.66" + "taro-ui": "^3.2.0" }, "devDependencies": { "@babel/core": "^7.8.0", @@ -91,6 +89,8 @@ "thread-loader": "^4.0.2", "ts-node": "^10.9.1", "typescript": "^4.1.0", - "webpack": "^5.78.0" + "webpack": "^5.78.0", + "terser-webpack-plugin": "^5.3.9", + "@babel/runtime": "^7.7.7" } } diff --git a/src/app.config.ts b/src/app.config.ts index 02e72dc..1387ae3 100644 --- a/src/app.config.ts +++ b/src/app.config.ts @@ -16,7 +16,7 @@ export default defineAppConfig({ "pages/instrument/intro", "pages/instrument_manage/index", "pages/instrument_detail/index", - "pages/instrument_clickin_upload/index", + "pages/instrumentClickinUpload/index", 'pages/privacyPolicy/privacyPolicy', 'pages/userPolicy/userPolicy', 'pages/about/about', @@ -27,6 +27,7 @@ export default defineAppConfig({ "pages/webViewPage/webViewPage", 'pages/template/template', 'pages/face_report/face_report', + "pages/connection_help/connection_help", ], "tabBar": { "custom": true, @@ -78,5 +79,6 @@ export default defineAppConfig({ navigationBarTitleText: 'WeChat', navigationBarTextStyle: 'black', // enablePullDownRefresh: true - } + }, + requiredPrivateInfos: ["getLocation"] }) diff --git a/src/components/bluetoot/InstrumentTypeEnum.js b/src/components/bluetoot/InstrumentTypeEnum.js new file mode 100644 index 0000000..48bd86a --- /dev/null +++ b/src/components/bluetoot/InstrumentTypeEnum.js @@ -0,0 +1,10 @@ +const InstrumentTypeEnum = { + //仪器类型 + FR200: 1, + MATRIX: 2, + WL200: 3, + FR380: 4, + FR390: 5, + M01: 6, +}; +export default InstrumentTypeEnum; diff --git a/src/components/bluetoot/OtaDeviceTypeEnum.js b/src/components/bluetoot/OtaDeviceTypeEnum.js new file mode 100644 index 0000000..03f3dcd --- /dev/null +++ b/src/components/bluetoot/OtaDeviceTypeEnum.js @@ -0,0 +1,7 @@ +const OtaDeviceTypeEnum = { + WL200: "WL200", + WE100: "WE100", + FACIALMASK: "FacialMask", + STAND: "Stand", +}; +export default OtaDeviceTypeEnum; diff --git a/src/components/bluetoot/connection/index.less b/src/components/bluetoot/connection/index.less new file mode 100644 index 0000000..e69de29 diff --git a/src/components/bluetoot/connection/index.tsx b/src/components/bluetoot/connection/index.tsx new file mode 100644 index 0000000..4b1eb5d --- /dev/null +++ b/src/components/bluetoot/connection/index.tsx @@ -0,0 +1,1139 @@ +import Taro from "@tarojs/taro"; +import classnames from "classnames"; + +import { Component, PropsWithChildren, useEffect, useState } from "react"; +import { Block, View, Text, Image, Input, Button } from "@tarojs/components"; + +import DeviceConnectPopup from "../device-connection-popup/device-connection-popup"; + +/*** redux ***/ +import { connect } from "react-redux"; +import { setBluetoothInfo } from "../../../store/features/deviceInfo"; +/*** redux end ***/ + +import { + getSystemInfo, + openBluetoothAdapter, + startBluetoothDevicesDiscovery, + createBLEConnection, + closeBLEConnection, + getBLEDeviceServices, + notifyBLECharacteristicValueChange, + writeBLECharacteristicValue, + sendCommand, +} from "@/utils/bluetoothWXAPI"; +import { + ab2hex, + ccrc8, + filterBleData, + getofflineData, + hex2int, + getTimeCode, +} from "@/utils/util"; +const log = require("@/utils/log"); +import commandMap from "@/utils/commandMap"; +import { bleCommandSamples } from "./test"; + +import { DeviceToolKit as DeviceToolKitWE100 } from "@flossom-npm/iot-translater-we100"; +const deviceToolKitInstanceWL200 = new DeviceToolKitWE100("WE100", "WL200"); +deviceToolKitInstanceWL200.setDebug(true); + +const deviceToolKitInstanceM01 = new DeviceToolKitWE100("WE100", "M01"); +deviceToolKitInstanceM01.setDebug(true); + +const deviceToolKitInstanceFR200 = new DeviceToolKitFR200("FR200"); + +import { DeviceToolKit as DeviceToolKitFR200 } from "@flossom-npm/iot-translater"; +import { showModal, msg } from "@/utils/traoAPI"; + +// const { InstrumentTypeEnum, OtaDeviceTypeEnum } = app.globalData; +import InstrumentTypeEnum from "../instrumentTypeEnum"; +import OtaDeviceTypeEnum from "../OtaDeviceTypeEnum"; + +let isGetVersionTimer: any = null; +let isGetSubDeviceTimer: any = null; +let isGetSyncRecordingTimer: any = null; + +let overTimer: any = null; + +let isGetSubDeviceTimerNum = 0; + +let sendgetversionTimer: any = null; +let sendGetVersionTimerNum = 0; + +let searchBluetootTimers: any = null; // 搜索蓝牙定时器 +let searchBluetootTimersNum = 0; // 搜索蓝牙秒数 + +let connectionTimer: any = null; // 连接蓝牙定时器 +let connectionTimerNum = 0; + +let sendPairingTimer: any = null; + +import "./index.less"; + +class ConnectionBluetoot extends Component { + constructor(props) { + super(props); + this.state = { + name: "ConnectionBluetoot", + stepList: [], //指引 + stepListIndex: 0, + + platform: "", //客户端平台 + connectionSuccess: false, //配对成功 + + isConnection: false, //是否处理连接中 + error: false, //是否连接失败 + errorText: "", //失败文字 + searchError: false, //是否没有搜索到设备 + connectionStatus: false, //是否连接成功状态 + hasVersionInfo: false, // 是否已获得版本信息 + hasSyncRecord: false, + subDeviceConnectedStatus: false, //子设备是否连接成功状态 + synchronousStatus: false, // 设备同步记录状态 + islian: false, //是否获取离线记录状态 + offlineData: [], //离线协议返送数据 + offlineDataindex: 0, //离线记录发送下标index + versionInfo: {}, //版本号 + offlineDataList: [], //离线数据 + }; + } + + async onLoad() {} + componentDidMount() { + this.connection(); + } + + componentWillUnmount() {} + + componentDidShow() {} + + componentDidHide() {} + + async initData() {} + + close() { + clearInterval(sendPairingTimer); + clearInterval(sendgetversionTimer); + clearTimeout(isGetVersionTimer); + clearTimeout(isGetSyncRecordingTimer); + if (overTimer) clearTimeout(overTimer); + this.again(); + // this.triggerEvent("close", "connection_guide"); + console.log("this.close"); + this.onClose(); + Taro.closeBluetoothAdapter(); + } + + /** 关闭连接前:重置数据 */ + again() { + this.setState({ + stepListIndex: 0, + isConnection: false, + error: false, + errorText: "", + connectionStatus: false, + islian: false, + offlineDataindex: 0, + versionInfo: {}, + offlineDataList: [], + }); + } + + /** 开始连接 */ + connection() { + this.setState({ + isConnection: true, + }); + //初始化 蓝牙连接 + this.bluetoothInit(); + } + + /** 重新连接 */ + // againConnection() { + // this.setState({ + // connectionStatus: false, + // islian: false, + // error: false, + // }); + // Taro.closeBluetoothAdapter({ + // complete: () => { + // this.bluetoothInit(); + // }, + // }); + // } + + // skip() { + // this.setState({ + // stepListIndex: this.state.stepList.length - 1, + // isConnection: true, + // }); + // //初始化 蓝牙连接 + // this.bluetoothInit(); + // } + + /**1.蓝牙初始化*/ + bluetoothInit() { + searchBluetootTimersNum = 0; + getSystemInfo().then((res) => { + console.log(res); + // bluetoothEnabled 蓝牙开关 + // locationEnabled 地理位置的系统开关 + // locationAuthorized 允许微信使用定位的开关 + let { locationEnabled, locationAuthorized, bluetoothEnabled } = res; + const softwareProblem = [ + locationEnabled, + locationAuthorized, + bluetoothEnabled, + ].every((item) => !item); + if (softwareProblem) { + let errorText = !bluetoothEnabled + ? "检测到手机设置当中,微信的蓝牙访问授权未打开,请前往开启蓝牙授权" + : "检测到手机设置当中,微信的定位访问授权未打开,请前往开启定位授权"; + //手机定位或者微信定位的开关没开启 + this.setState({ + error: true, + searchError: false, + errorText, + }); + } else { + Taro.closeBluetoothAdapter({ + complete: () => { + this.openBluetoothAdapter(); + }, + }); + } + }); + } + + /**2.打开蓝牙适配器*/ + openBluetoothAdapter() { + openBluetoothAdapter() + .then((res) => { + console.info("openBluetoothAdapter res value =>", res); + let { errno, errMsg } = res; + if (errno == 0) { + this.startBluetoothDevicesDiscovery(); + } else { + this.errorCode(errno, errMsg); + } + }) + .catch((err) => { + let { errno, errMsg } = err; + if (errMsg == "openBluetoothAdapter:fail auth deny") { + showModal({ + t2: "您的微信小程序设置中,蓝牙授权未开启", + btn2text: "前往授权", + }) + .then((res) => { + this.close(); + Taro.openSetting(); + }) + .catch(() => { + this.close(); + }); + } else { + console.info("openBluetoothAdapter err value => ", err); + this.failErrorCode(errno, errMsg); + } + }); + } + + /** 3.开始蓝牙设备搜索 */ + startBluetoothDevicesDiscovery() { + startBluetoothDevicesDiscovery() + .then((res) => { + let { errno, errMsg } = res; + console.log("startBluetoothDevicesDiscovery res value=>", res); + if (errno == 0) { + /** + * 开始搜索蓝牙 + * 设定8秒搜索时间,15秒后表示搜索不到 弹出 + */ + this.onBluetoothDeviceFound(); + searchBluetootTimers = setInterval(() => { + searchBluetootTimersNum += 1; + console.log( + "searchBluetootTimersNum value => ", + searchBluetootTimersNum + ); + if (searchBluetootTimersNum === 8) { + clearInterval(searchBluetootTimers); + this.setState({ + error: true, + searchError: true, + }); + } + }, 1000); + } else { + this.errorCode(errno, errMsg); + } + }) + .catch((err) => { + let { errno, errMsg } = err; + console.log("startBluetoothDevicesDiscovery error =>", err); + this.failErrorCode(errno, errMsg); + }); + } + /** 4.蓝牙查找 */ + onBluetoothDeviceFound() { + Taro.onBluetoothDeviceFound((item: any) => { + console.log("蓝牙查找item", item, item.devices[0].name); + /* + * 这里增加判断,类型不同识别的设备名称不一样 + * type1 FR200 + * type2 WM100 + * type3 we100 + * type4 FR380 + * */ + // const tranType = { + // 1: "FR200", + // 3: "WE200", // WL200 + // 4: "FR380", + // 5: "FR390", + // 6: "WE200", // M01 + // }; + // let type = this.props.yiqiInfo.model || "FR200"; + let type = "WE200"; + // console.info('搜索到到蓝牙设备 value => ', item.devices[0]?.name) + for (let i = 0; i < item.devices.length; i++) { + if ( + item.devices[i].connectable && + (item.devices[i].localName + ? item.devices[i].localName + : item.devices[i].name + ).indexOf(`${type}`) !== -1 + ) { + console.info("连接的设备信息", item.devices[i], type); + + clearInterval(searchBluetootTimers); + Taro.stopBluetoothDevicesDiscovery(); //停止搜索蓝牙 + // app.globalData.deviceInfo.deviceId = item.devices[i].deviceId; + this.createBLEConnection(); + break; + } + } + }); + } + + /** 5.新建蓝牙连接 */ + async createBLEConnection() { + console.log("========新建蓝牙连接========"); + try { + await closeBLEConnection(this.props.bluetoothInfo.deviceId); + } catch (e) {} + clearTimeout(connectionTimer); + const { yiqiInfo: deviceInfo } = this.props; + /*********开始主动连接*******/ + createBLEConnection(this.props.bluetoothInfo.deviceId) + .then((res) => { + let { errno, errMsg } = res; + if (errno == 0) { + if ( + deviceInfo.type == InstrumentTypeEnum.FR200 || + deviceInfo.type == InstrumentTypeEnum.FR380 || + deviceInfo.type == InstrumentTypeEnum.FR390 + ) { + this.setState({ + connectionStatus: true, + }); + connectionTimer = setTimeout(() => { + if (!this.state.islian) { + if (overTimer) clearTimeout(overTimer); + this.failErrorCode(-1, "连接蓝牙失败,请重新开机后重试"); + } + }, 10000); + } + this.getBLEDeviceServices(); //获取特征 + } else { + this.errorCode(errno, errMsg); + } + }) + .catch((err) => { + let { errno, errMsg } = err; + console.log("createBLEConnection error =>", err); + this.failErrorCode(errno, errMsg); + }); + } + + /** 6.获取蓝牙特征值 */ + getBLEDeviceServices() { + getBLEDeviceServices(this.props.bluetoothInfo.deviceId) + .then((res) => { + let bluetoothInfo = this.props.bluetoothInfo; + bluetoothInfo.servicesuuid = res.servicesuuid; + bluetoothInfo.characteristicsuuid1 = res.characteristicsuuid1; + bluetoothInfo.characteristicsuuid0 = res.characteristicsuuid0; + this.props.setBluetoothInfo(bluetoothInfo); + this.notifyBLECharacteristicValueChange(); + }) + .catch((err) => { + let { errno, errMsg } = err; + console.info("getBLEDeviceServices error =>", err); + this.failErrorCode(errno, errMsg); + }); + } + + /** 7.通知BLE特征值更改 */ + notifyBLECharacteristicValueChange() { + const { yiqiInfo: deviceInfo } = this.props; + const bluetoothInfo = this.props.bluetoothInfo; + notifyBLECharacteristicValueChange({ + deviceId: bluetoothInfo.deviceId, + servicesuuid: bluetoothInfo.servicesuuid, + characteristicsuuid1: bluetoothInfo.characteristicsuuid1, + characteristicsuuid0: bluetoothInfo.characteristicsuuid0, + }) + .then((ress) => { + let { errno, errMsg } = ress; + if (errno == 0) { + Taro.onBLECharacteristicValueChange((value) => { + console.info("onBLECharacteristicValueChange value => ", value); + let str = ab2hex(value.value); //转为16进制字符串 + let connectionStatus = [ + InstrumentTypeEnum.FR200, + InstrumentTypeEnum.WL200, + InstrumentTypeEnum.FR380, + InstrumentTypeEnum.FR390, + InstrumentTypeEnum.M01, + ].includes(Number(deviceInfo.type)); + const isFRDevice = [ + InstrumentTypeEnum.FR200, + InstrumentTypeEnum.FR380, + InstrumentTypeEnum.FR390, + ].includes(Number(deviceInfo.type)); + if (isFRDevice) { + this.setState({ + connectionStatus, + }); + log.info( + commandMap.reciviedBLECommand, + `仪器类型: ${deviceInfo.type}`, + value + ); + filterBleData(str).forEach((item) => { + console.log("设备响应数据===》", item); + if (item.indexOf(`dbf0a8010155`) !== -1) { + //配对成功 + log.info("蓝牙配对成功"); + clearInterval(sendPairingTimer); + this.setState({ islian: true }); + + console.log("获取设备版本号"); + this.sendGetVersion(); + sendgetversionTimer = setInterval(() => { + this.sendGetVersion(); + }, 1000); + } + + if (item.indexOf("dbf0a0030b") !== -1) { + // 版本号获取成功 + clearInterval(sendgetversionTimer); + let v1 = String(hex2int(str.substring(10, 12))).padStart( + 2, + "0" + ); + let v2 = String(hex2int(str.substring(12, 14))).padStart( + 2, + "0" + ); + let v3 = String(hex2int(str.substring(14, 16))).padStart( + 2, + "0" + ); + let versionInfo = { + v1, + v2, + v3, + version: `${v1}${v2}${v3}`, + }; + this.setState({ versionInfo }); + console.log("版本号:" + versionInfo.version); + log.info( + commandMap.versionInfoCG, + `connection_guide, ${deviceInfo.type}:${versionInfo.version}` + ); + if ( + deviceInfo.type == InstrumentTypeEnum.FR380 || + deviceInfo.type == InstrumentTypeEnum.FR390 + ) { + console.log("跳转护理页"); + // this.triggerEvent("offlineChange", this.state); + this.offlineChange(this.state); + } else { + if (this.state.isgetoffline) { + // 获取离线记录 + console.log("获取离线记录(总)"); + this.sendofflistSummary(); + } else { + console.log("跳转护理页"); + // that.triggerEvent("offlineChange", this.state); + this.offlineChange(this.state); + } + } + } + + if (item.indexOf("dbf0a0020b") !== -1) { + //离线护理记录(总)获取成功 + // 先获取记录总条数,再获取详细 + console.log("获取离线记录总条数====>", item); + log.info( + commandMap.finishOfflineData, + `接收到总的离线记录=》${item}` + ); + // this.state.offlineDataindex = + // 7 || Number(item.substring(24, 2)); + let offlineDataindex = 7 || Number(item.substring(24, 2)); + this.setState({ offlineDataindex }); + if (this.state.offlineDataindex > 0) { + this.sendofflist(); + } else { + // this.triggerEvent("offlineChange", that.data); + this.offlineChange(this.state); + } + } + if (item.indexOf("dbf0a00211") !== -1) { + //设备响应离线护理记录(细) + log.info( + commandMap.finishOfflineData, + "接收到详细离线记录, 准备进入sendofflist" + ); + this.sendOfflistPost(str); + this.sendofflist(); + } + + if (item.indexOf("dbf0a001006dde") !== -1) { + // 同步时间 + // that.sendAsyncTime() + } + }); + } else { + let jsonStatus: any = null; + let querySubDeviceArrayBuffer; + if (deviceInfo.type == InstrumentTypeEnum.WL200) { + // querySubDeviceArrayBuffer = deviceToolKitInstanceWL200.toBleCommand(bleCommandSamples.querySubDevice); + // jsonStatus = deviceToolKitInstanceWL200.toJsonStatus(value.value); + jsonStatus = deviceToolKitInstanceM01.toJsonStatus(value.value); + querySubDeviceArrayBuffer = + deviceToolKitInstanceM01.toBleCommand( + bleCommandSamples.querySubDevice as any + ); // todo + } else if (deviceInfo.type == InstrumentTypeEnum.M01) { + jsonStatus = deviceToolKitInstanceM01.toJsonStatus(value.value); + querySubDeviceArrayBuffer = + deviceToolKitInstanceM01.toBleCommand( + bleCommandSamples.querySubDevice as any + ); + } + log.info( + commandMap.reciviedBLECommand, + `仪器类型: ${deviceInfo.type}`, + jsonStatus + ); + if (jsonStatus?.commandType === "BleMatch") { + switch (jsonStatus?.bleCommandType) { + case "SendMatchCode": + if (jsonStatus.matchedSuccess) { + console.log("蓝牙配对成功"); + clearInterval(sendPairingTimer); + if (overTimer) clearTimeout(overTimer); + if (this.state.connectionSuccess) return; + this.setState({ + connectionSuccess: true, + connectionStatus, + }); + // 暂时不需要查询是否连接子设备, 直接进入查询版本信息 + this.detectVersionUpdate(); + /*if(deviceInfo.type == instrumentTypeEnum.M01) { + this.detectVersionUpdate() + } else { + this.sendQuerySubDevice(querySubDeviceArrayBuffer) + }*/ + } + break; + case "BleStatusSync": + if (jsonStatus.connectMessage?.connectType == "CONNECTED") { + switch (jsonStatus.connectMessage?.deviceName) { + case OtaDeviceTypeEnum.WE100: + case OtaDeviceTypeEnum.FACIALMASK: + console.log("面膜连上了 value => ", jsonStatus); + this.detectVersionUpdate(); + break; + case OtaDeviceTypeEnum.WL200: + console.log("面罩连上了 value => ", jsonStatus); + this.detectVersionUpdate(); + break; + default: + break; + } + } + console.info("BleStatusSync value => ", jsonStatus); + break; + case "QueryMatchStatus": + console.info("QueryMatchStatus value => ", jsonStatus); + break; + default: + break; + } + } else if (jsonStatus?.commandType === "InfoQuery") { + switch (jsonStatus.infoQueryType) { + case "versionInfo": + if (this.state.hasVersionInfo) return; + clearTimeout(isGetVersionTimer); + this.setState({ + hasVersionInfo: true, // 已返回版本信息 + connectionStatus: true, + subDeviceConnectedStatus: true, + synchronousStatus: true, + }); + const deviceVersionNo = jsonStatus.versionNo; + const latestVersionNo = deviceInfo.iot_versions; + // const isNeedToUpdateBl = isNeedToUpdate(deviceVersionNo, latestVersionNo) + // 判断是否需要升级 + // M01和WL200 不需要在这里进行蓝牙更新 + // if (isNeedToUpdateBl) { + // const pages = getCurrentPages(); + // const matchPageList = [{ + // route: 'pages/MatrixWL200/pages/index/index' + // },{ + // route: 'pages/MatrixM01/pages/index/index' + // }]; + // const hadOpen = checkSameKey(pages, matchPageList, 'route'); + // if (!hadOpen) { + // this.triggerEvent("pairingChange", { deviceVersionNo }); + this.pairingChange({ deviceVersionNo }); + // } + // } else { + // this.sendSyncRecording() + // } + break; + case "offlineClockSummary": + clearTimeout(isGetSyncRecordingTimer); + if (this.state.hasSyncRecord) return; + this.setState({ + hasSyncRecord: true, + synchronousStatus: true, + }); + console.info("offlineClockSummary value =>", jsonStatus); + // this.triggerEvent("pairingChange", this.state); + this.pairingChange(this.state); + // TODO 查询离线记录结果 + default: + break; + } + } + } + }); + /** + * 是否需要获取离线记录和版本获取 + * 这里增加判断,类型不同识别的设备名称不一样 + * type1 FR200 + * type2 WM100 + * type3 we100 + * type4 FR380 + */ + console.log("发送配对码"); + if (deviceInfo.type == InstrumentTypeEnum.FR200) { + if (sendPairingTimer) clearInterval(sendPairingTimer); + sendPairingTimer = setInterval(() => { + this.sendPairingSignal(); + }, 1000); + } else if ( + deviceInfo.type == InstrumentTypeEnum.WL200 || + deviceInfo.type == InstrumentTypeEnum.M01 + ) { + if (sendPairingTimer) clearInterval(sendPairingTimer); + sendPairingTimer = setInterval(() => { + this.sendPairingSignal(); + }, 1000); + } else if ( + deviceInfo.type == InstrumentTypeEnum.FR380 || + deviceInfo.type == InstrumentTypeEnum.FR390 + ) { + if (sendPairingTimer) clearInterval(sendPairingTimer); + sendPairingTimer = setInterval(() => { + this.sendPairingSignal(); + }, 1000); + } + if (overTimer) clearTimeout(overTimer); + overTimer = setTimeout(() => { + if (this.state.islian) { + console.log("超时跳转护理页"); + log.info("超时跳转护理页"); + // 已配对成功,其它操作导致超时未跳转则直接跳转 + // this.triggerEvent("offlineChange", this.state); + this.offlineChange(this.state); + return; + } + if (sendPairingTimer) clearInterval(sendPairingTimer); + this.failErrorCode(1509005, "配对超时"); + }, 1000 * 15); + } else { + this.errorCode(errno, errMsg); + } + }) + .catch((err) => { + console.log("notifyBLECharacteristicValueChange error =>", err); + let { errno, errMsg } = err; + this.failErrorCode(errno, errMsg); + }); + } + + // 8.发送指令:获取仪器版本号 + sendGetVersion() { + const { yiqiInfo: deviceInfo } = this.props; + const isFRDevice = [ + InstrumentTypeEnum.FR200, + InstrumentTypeEnum.FR380, + InstrumentTypeEnum.FR390, + ].includes(Number(deviceInfo.type)); + log.info(commandMap.sendVersionCommand, `仪器:${deviceInfo.type}`); + if (isFRDevice) { + writeBLECharacteristicValue({ + //发送获取仪器版本号 + deviceId: this.props.bluetoothInfo.deviceId, + servicesuuid: this.props.bluetoothInfo.servicesuuid, + characteristicsuuid1: this.props.bluetoothInfo.characteristicsuuid1, + characteristicsuuid0: this.props.bluetoothInfo.characteristicsuuid0, + value: `dbf0a00300${ccrc8("dbf0a00300")}de`, + }); + } else { + // const otaDeviceType = deviceInfo.type == instrumentTypeEnum.WL200 ? OtaDeviceTypeEnum.WL200 : OtaDeviceTypeEnum.WE100; + // 通过发箍连 都用we100 + const otaDeviceType = + deviceInfo.type == InstrumentTypeEnum.WL200 + ? OtaDeviceTypeEnum.WE100 + : OtaDeviceTypeEnum.WE100; + const versionCommand = { + commandType: "InfoQuery", + infoQueryType: "versionInfo", + otaDeviceType, + }; + const value = + deviceInfo.type == InstrumentTypeEnum.WL200 + ? deviceToolKitInstanceM01.toBleCommand(versionCommand as any) + : deviceToolKitInstanceM01.toBleCommand(versionCommand as any); + // const value = deviceInfo.type == instrumentTypeEnum.WL200 ? deviceToolKitInstanceWL200.toBleCommand(versionCommand) : deviceToolKitInstanceM01.toBleCommand(versionCommand); + sendCommand({ value }); + } + } + + /** 获取离线记录 */ + sendofflist() { + // log.info() + if (this.state.offlineDataindex == this.state.offlineDataList.length) { + console.log("离线记录获取完成"); + log.info(commandMap.finishOfflineData, this.state.offlineDataList); + /**** + * 发送同步时间 + * ****/ + this.sendAsyncTime(); + console.log(this.state.offlineDataList); + console.log("版本号:" + this.state.versionInfo.version); + this.setState({ islian: true }); + clearTimeout(connectionTimer); + // this.triggerEvent("offlineChange", this.state); + console.log("this.triggerEvent", this.state); + this.offlineChange(this.state); + return false; + } + console.log("发送获取离线记录(细)指令"); + log.info(commandMap.finishOfflineData, "发送获取离线记录(细)指令"); + writeBLECharacteristicValue({ + //发送获取离线记录 + deviceId: this.props.bluetoothInfo.deviceId, + servicesuuid: this.props.bluetoothInfo.servicesuuid, + characteristicsuuid1: this.props.bluetoothInfo.characteristicsuuid1, + characteristicsuuid0: this.props.bluetoothInfo.characteristicsuuid0, + value: this.state.offlineData[this.state.offlineDataList.length], + }); + } + /** 获取离线记录(汇总) */ + sendofflistSummary() { + let str = "DBF0A00200"; + console.log("发送离线记录汇总指令 ==》", str); + this.setState({ offlineDataList: [] }); // 置空重查离线记录 + log.info(commandMap.finishOfflineData, `发送获取离线记录(总)指令`); + writeBLECharacteristicValue({ + //发送获取离线记录 + deviceId: this.props.bluetoothInfo.deviceId, + servicesuuid: this.props.bluetoothInfo.servicesuuid, + characteristicsuuid1: this.props.bluetoothInfo.characteristicsuuid1, + characteristicsuuid0: this.props.bluetoothInfo.characteristicsuuid0, + value: `${str}${ccrc8(str)}DE`, + }); + } + + sendPairingSignal() { + const { yiqiInfo: deviceInfo } = this.props; + log.info(commandMap.sendMatchCode, `仪器:${deviceInfo.type}发送匹配码`); + let matchArrayBuffer: any = null; + switch (deviceInfo.type) { + case InstrumentTypeEnum.FR200: + matchArrayBuffer = deviceToolKitInstanceFR200.toBleCommand( + bleCommandSamples.match as any + ); + break; + case InstrumentTypeEnum.WL200: + matchArrayBuffer = deviceToolKitInstanceWL200.toBleCommand( + bleCommandSamples.match as any + ); + break; + case InstrumentTypeEnum.FR380: + writeBLECharacteristicValue({ + deviceId: this.props.bluetoothInfo.deviceId, + servicesuuid: this.props.bluetoothInfo.servicesuuid, + characteristicsuuid1: this.props.bluetoothInfo.characteristicsuuid1, + characteristicsuuid0: this.props.bluetoothInfo.characteristicsuuid0, + value: `DBF0A8010C464C534D204D465233383000E8DE`, + }); + break; + case InstrumentTypeEnum.FR390: + writeBLECharacteristicValue({ + deviceId: this.props.bluetoothInfo.deviceId, + servicesuuid: this.props.bluetoothInfo.servicesuuid, + characteristicsuuid1: this.props.bluetoothInfo.characteristicsuuid1, + characteristicsuuid0: this.props.bluetoothInfo.characteristicsuuid0, + value: `DBF0A8010C464C534D204D46523339300043DE`, + }); + break; + case InstrumentTypeEnum.M01: + matchArrayBuffer = deviceToolKitInstanceM01.toBleCommand( + bleCommandSamples.match as any + ); + break; + default: + break; + } + if (matchArrayBuffer) + sendCommand({ value: matchArrayBuffer }) + .then(() => {}) + .catch((e) => { + // 下发配对指令失败,走重连操作 + clearInterval(sendPairingTimer); + // wx.closeBLEConnection(); + this.createBLEConnection(); + }); + } + + /** 发送记录 */ + sendOfflistPost(str) { + let facehour = hex2int(str.substring(12, 14)); //脸部小时 + let faceminutes = hex2int(str.substring(14, 16)); //脸部分钟 + let faceseconds = hex2int(str.substring(16, 18)); //脸部秒 + let faceposition1 = hex2int(str.substring(18, 20)); //当前档位 + let facenum = hex2int(str.substring(20, 22)); //次数 + let faceyear = hex2int(str.substring(22, 24)); //年份 + let facemonth = hex2int(str.substring(24, 26)); //月份 + let faceday = hex2int(str.substring(26, 28)); //日期 + + let eyehour = hex2int(str.substring(28, 30)); //眼部小时 + let eyeminutes = hex2int(str.substring(30, 32)); //眼部分钟 + let eyeseconds = hex2int(str.substring(32, 34)); //眼部秒 + let eyeposition1 = hex2int(str.substring(34, 36)); //当前档位 + let eyenum = hex2int(str.substring(36, 38)); //次数 + let eyeyear = hex2int(str.substring(38, 40)); //年份 + let eyemonth = hex2int(str.substring(40, 42)); //月份 + let eyeday = hex2int(str.substring(42, 44)); //日期 + // console.log('脸部小时:' + facehour) + // console.log('脸部分钟:' + faceminutes) + // console.log('脸部秒:' + faceseconds) + // console.log('当前档位:' + faceposition1) + // console.log('脸部次数:' + facenum) + // console.log('年:' + faceyear) + // console.log('月:' + facemonth) + // console.log('日:' + faceday) + // console.log('-------------------') + // console.log('眼部小时:' + eyehour) + // console.log('眼部分钟:' + eyeminutes) + // console.log('眼部秒:' + eyeseconds) + // console.log('当前档位:' + eyeposition1) + // console.log('眼部次数:' + eyenum) + // console.log('年:' + eyeyear) + // console.log('月:' + eyemonth) + // console.log('日:' + eyeday) + let { offlineDataList } = this.state; + offlineDataList.push({ + facehour, + faceminutes, + faceseconds, + faceposition1, + facenum, + faceyear, + facemonth, + faceday, + eyehour, + eyeminutes, + eyeseconds, + eyeposition1, + eyenum, + eyeyear, + eyemonth, + eyeday, + }); + this.setState({ offlineDataList }); + } + + /** 同步时间 */ + sendAsyncTime() { + console.log("同步时间"); + writeBLECharacteristicValue({ + //发送同步时间 + deviceId: this.props.bluetoothInfo.deviceId, + servicesuuid: this.props.bluetoothInfo.servicesuuid, + characteristicsuuid1: this.props.bluetoothInfo.characteristicsuuid1, + characteristicsuuid0: this.props.bluetoothInfo.characteristicsuuid0, + value: getTimeCode(), + }); + } + + /** 错误代码处理 */ + errorCode(errno, errMsg) { + clearInterval(searchBluetootTimers); + clearInterval(sendgetversionTimer); + console.info("errorCode err => ", errno, errMsg); + if (errno == 10001 || errno == 10009) { + let t2 = + errno == 10001 + ? "您的手机蓝牙适配器不可用,请联系微信顾问" + : "你的Android 系统版本低于4.3不支持蓝牙连接"; + this.close(); + setTimeout(() => { + showModal({ + t2, + showCancel: false, + btn2text: "知道了", + }).then(() => { + this.close(); + }); + }, 500); + return; + } + let errorText = ""; + switch (errno) { + case -1: + errorText = "已连接"; + break; + case 10000: + errorText = "未初始化蓝牙适配器"; + break; + case 10000: + errorText = "未初始化蓝牙适配器"; + break; + case 10001: + errorText = "当前蓝牙适配器不可用"; + break; + case 10002: + errorText = "没有找到指定设备"; + break; + case 10003: + errorText = "连接失败"; + break; + case 10004: + errorText = "没有找到指定服务"; + break; + case 10005: + errorText = "没有找到指定特征"; + break; + case 10006: + errorText = "当前连接已断开"; + break; + case 10007: + errorText = "当前特征不支持此操作"; + break; + case 10008: + errorText = "其余所有系统上报的异常"; + break; + case 10009: + errorText = "其余所有系统上报的异常"; + break; + case 10012: + errorText = "连接超时"; + break; + case 10013: + errorText = "连接 deviceId 为空或者是格式不正确"; + break; + default: + errorText = errMsg; + break; + } + this.setState({ + error: true, + searchError: false, + errorText, + }); + } + + failErrorCode(errno, errMsg) { + console.info("failErrorCode err => ", errno, errMsg); + clearInterval(searchBluetootTimers); + clearInterval(sendgetversionTimer); + log.info("连接仪器失败", errno, errMsg); + let errorText = ""; + switch (errno) { + case 1500101: + errorText = "未初始化蓝牙适配器"; + break; + case 1500102: + errorText = "微信无法使用蓝牙,请到系统设置中启用"; + break; + case 1500103: + errorText = "当前蓝牙设备获取不到Service/获取不到对应UUID的Service"; + break; + case 1500104: + errorText = "调用系统蓝牙能力失败, 详细错误见errMsg"; + break; + case 1500105: + errorText = "系统不支持BLE"; + break; + case 1510101: + errorText = "配对当前蓝牙设备需要pin码"; + break; + case 1510102: + errorText = "支持蓝牙后台通信的设备数目已经达到上限"; + break; + case 1509001: + errorText = "连接蓝牙设备失败"; + break; + case 1509003: + errorText = "未连接上该蓝牙设备"; + break; + case 1509005: + errorText = "蓝牙操作超时"; + break; + case 1509007: + errorText = "当前蓝牙设备已经连接上"; + break; + case 1509008: + errorText = "Android6.0以上, 蓝牙扫描需授权地理位置"; + break; + default: + errorText = errMsg; + } + this.setState({ + error: true, + searchError: false, + errorText, + }); + } + sendQuerySubDevice(value) { + isGetSubDeviceTimer = setInterval(() => { + sendCommand({ value }); + isGetSubDeviceTimerNum += 1; + if (isGetSubDeviceTimerNum == 8) { + this.closeQuerySubDevice(); + this.setState({ + error: true, + searchError: true, + }); + } + }, 1000); + } + closeQuerySubDevice() { + clearInterval(isGetSubDeviceTimer); + isGetSubDeviceTimerNum = 0; + } + // 获取版本信息 + detectVersionUpdate() { + this.closeQuerySubDevice(); + this.sendGetVersion(); + sendGetVersionTimerNum = 0; + // 600毫秒查询一次版本号是否返回,若返回则跳转护理页 + if (isGetVersionTimer) clearTimeout(isGetVersionTimer); + isGetVersionTimer = setInterval(() => { + if (this.state.hasVersionInfo) { + if (isGetVersionTimer) clearTimeout(isGetVersionTimer); + // that.sendSyncRecording() + } else { + sendGetVersionTimerNum += 1; + if (sendGetVersionTimerNum >= 10) { + // 超时未返回版本号 + if (isGetVersionTimer) clearTimeout(isGetVersionTimer); + this.setState({ + connectionStatus: true, + }); + // this.triggerEvent("pairingChange", this.state); + console.log("this.pairingChange", this.state); + this.pairingChange(this.state); + } else { + this.sendGetVersion(); + } + } + }, 600); + + // 5秒后没有收到版本返回,直接跳去护理页 + // if (isGetVersionTimer) clearTimeout(isGetVersionTimer); + // isGetVersionTimer = setTimeout(() => { + // that.setData({ + // connectionStatus: true, + // // subDeviceConnectedStatus: true, // 子设备连接状态 + // }) + // this.sendSyncRecording() + // }, 5000); + } + sendSyncRecording() { + const { yiqiInfo: deviceInfo } = this.props; + const versionCommand = { + commandType: "InfoQuery", + infoQueryType: "offlineClockSummary", + }; + const value = + deviceInfo.type == InstrumentTypeEnum.WL200 + ? deviceToolKitInstanceWL200.toBleCommand(versionCommand as any) + : deviceToolKitInstanceM01.toBleCommand(versionCommand as any); + sendCommand({ value }).then(); + if (isGetSyncRecordingTimer) clearTimeout(isGetSyncRecordingTimer); + isGetSyncRecordingTimer = setTimeout(() => { + if (this.state.hasSyncRecord) { + if (isGetSyncRecordingTimer) clearTimeout(isGetSyncRecordingTimer); + } else { + this.sendSyncRecording(); + } + }, 1000); + } + + onClose = () => { + this.props.close(); + }; + + onConfirm = () => { + this.props.confirm("confirm"); + }; + + pairingChange = (data) => { + this.props.pairingChange(data); + }; + + offlineChange = (data) => { + this.props.offlineChange(data); + }; + + render() { + let { name, isConnection, connectionStatus } = this.state; + let { yiqiInfo } = this.props; + return ( + + + {name} + + ); + } +} + +const mapStateToProps = (state) => ({ + bluetoothInfo: state.deviceInfo.bluetoothInfo, +}); +const mapDispatchToProps = (dispatch) => ({ + setBluetoothInfo(data) { + dispatch(setBluetoothInfo(data)); + }, +}); +export default connect(mapStateToProps, mapDispatchToProps)(ConnectionBluetoot); diff --git a/src/components/bluetoot/connection/test.js b/src/components/bluetoot/connection/test.js new file mode 100644 index 0000000..6e2df78 --- /dev/null +++ b/src/components/bluetoot/connection/test.js @@ -0,0 +1,66 @@ +/**蓝牙命令合集*/ +export const bleCommandSamples = { + /**发送配对码*/ + match: { + commandType: "BleMatch", + bleCommandType: "SendMatchCode", + }, + /**查询附属设备的配对状态*/ + querySubDevice: { + commandType: "BleMatch", + bleCommandType: "QueryMatchStatus", + }, + /**查询设备状态指令*/ + queryDeviceStatus: { + commandType: "DeviceStatusSync", + deviceSyncCommandType: 'queryDeviceStatus' + }, + /**查询版本指令*/ + queryDeviceVersionStatus: { + commandType: "InfoQuery", + infoQueryType: 'versionInfo', + otaDeviceType: '' + }, + /**查询当前记录*/ + queryCurrentMaskReportInfo: { + commandType: "InfoQuery", + infoQueryType: 'currentMaskReportInfo' + } +}; + +/**控制设备命令合集*/ +export const deviceCommandSamples = { + /**控制设备暂停 pause暂停 working启动 end关闭*/ + pause:{ + commandType: "DeviceControl", + workStatus: "pause", + }, + standby:{ + commandType: "DeviceControl", + workStatus: "standby", + }, + end:{ + commandType: "DeviceControl", + workStatus: "end", + }, + /* + * powerfulSoothing 强效舒缓 01 + * Stability 维稳维护 02 + * Brighten 均色提亮 03 + * FirmSkin 紧致淡纹 04 + * Custom 自定义模式 05 + * WaterLightEssence 水光精华模式 11 + * ShapeBeautyEssence 塑颜精华模式 12 + * DiyFacial DIY面膜模式 13 + * FacialMaskCustom 面膜定制模式 1A + */ + work:{ + commandType: "DeviceControl", + workStatus: "working", + workMode: "", + }, + gear:{ + commandType: "DeviceControl", + partitionStatus: [{gear: 1},{gear: 1},{gear: 1},{gear: 1},] + } +}; diff --git a/src/components/bluetoot/device-connection-popup/device-connection-popup.less b/src/components/bluetoot/device-connection-popup/device-connection-popup.less new file mode 100644 index 0000000..a30d7f1 --- /dev/null +++ b/src/components/bluetoot/device-connection-popup/device-connection-popup.less @@ -0,0 +1,64 @@ +.site-popup-content-box { + margin: 0; +} +// .van-popup { +// background-color: transparent; +// } +.site-close { + position: absolute; + right: 36rpx; + top: 36rpx; + color: #fff; + font-size: 36rpx; + z-index: 100009; + background-color: #ababab; + border-radius: 50%; + padding: 8rpx; + box-sizing: border-box; +} + +.site-popup-btn { + position: absolute; + bottom: 100rpx; + left: calc(50% - 120rpx); + width: 240rpx; + height: 70rpx; + line-height: 70rpx; + font-size: 28rpx; + text-align: center; + border: 1rpx solid #000; + border-radius: 40rpx; + background-color: #000; + color: #fff; + box-sizing: border-box; +} + +.upload-tips-common-box { + padding: 50rpx 20rpx 44rpx 20rpx; + .tips-message { + margin-top: 30rpx; + text-align: center; + font-size: 28rpx; + line-height: 45rpx; + color: #666; + } +} + +.popup-btn-one { + display: flex; + margin-top: 60rpx; + justify-content: center; + .popup-btn { + width: 270rpx; + height: 90rpx; + line-height: 90rpx; + font-size: 32rpx; + font-weight: 500; + text-align: center; + border: 1rpx solid #000; + border-radius: 45rpx; + color: #fff; + background-color: #000; + font-family: PingFang SC; + } +} diff --git a/src/components/bluetoot/device-connection-popup/device-connection-popup.tsx b/src/components/bluetoot/device-connection-popup/device-connection-popup.tsx new file mode 100644 index 0000000..953791c --- /dev/null +++ b/src/components/bluetoot/device-connection-popup/device-connection-popup.tsx @@ -0,0 +1,157 @@ +import classnames from "classnames"; +import Taro from "@tarojs/taro"; +import { Component } from "react"; + +import { + Block, + View, + Image, + Text, + Button, + PageMeta, + Video, +} from "@tarojs/components"; + +import { Popup } from "@antmjs/vantui"; + +import "../../popup/popup.less"; +import "./device-connection-popup.less"; + +import { go } from "@/utils/traoAPI"; + +/*** props + * isLarge 是否大尺寸 + * isShow 是否显示 + * data 数据 + * @confirm 关闭回调 + * ***/ +export default class DeviceConnectPopup extends Component { + constructor(props) { + super(props); + this.state = { + name: "蓝牙提示弹窗", + current: 0, + toRight: false, + isClick: false, + }; + } + + async onLoad() {} + componentDidMount() {} + + componentWillUnmount() {} + + componentDidShow() {} + + componentDidHide() {} + + initData = () => { + if (this.props.siteData) { + let arr = JSON.parse(JSON.stringify(this.props.siteData)); + this.setState({ siteList: arr }); + } + }; + + onClose = () => { + this.props.close(); + }; + + onConfirm = () => { + this.props.confirm(); + }; + + onClickStop = (e) => { + e.stopPropagation(); + }; + + render() { + let { isShow, data, isLarge, title, connectionStatus, isConnection } = + this.props; + let { current } = this.state; + + return ( + + + + + + + {data.bluetoothConnectingTitle} + + + + + + + + + + {/* + {data.length === 1 && ( + + + + )} + {data.length > 1 && current === 0 && ( + + + + )} + {data.length > 1 && ( + + + + + )} + */} + + + + ); + } +} diff --git a/src/components/navbar/navbar.less b/src/components/navbar/navbar.less index 5145ccd..235f55e 100644 --- a/src/components/navbar/navbar.less +++ b/src/components/navbar/navbar.less @@ -38,6 +38,10 @@ font-weight: bold; color: #000000; } + .logo-title { + width: 320rpx; + text-align: center; + } .back { width: 100rpx; text-align: center; diff --git a/src/components/navbar/navbar.tsx b/src/components/navbar/navbar.tsx index d71892b..5109789 100644 --- a/src/components/navbar/navbar.tsx +++ b/src/components/navbar/navbar.tsx @@ -1,4 +1,5 @@ import { Component } from "react"; +import classnames from "classnames"; import Taro from "@tarojs/taro"; import { Block, View, Image } from "@tarojs/components"; @@ -92,7 +93,11 @@ export default class Navbar extends Component { )} {leftSlot} - + {titleSlot ? ( titleSlot ) : isWhite ? ( @@ -109,7 +114,7 @@ export default class Navbar extends Component { /> )} - + { constructor(props) { super(props); diff --git a/src/components/popup/popup-instrument-upload-tips.less b/src/components/popup/popup-instrument-upload-tips.less new file mode 100644 index 0000000..a30d7f1 --- /dev/null +++ b/src/components/popup/popup-instrument-upload-tips.less @@ -0,0 +1,64 @@ +.site-popup-content-box { + margin: 0; +} +// .van-popup { +// background-color: transparent; +// } +.site-close { + position: absolute; + right: 36rpx; + top: 36rpx; + color: #fff; + font-size: 36rpx; + z-index: 100009; + background-color: #ababab; + border-radius: 50%; + padding: 8rpx; + box-sizing: border-box; +} + +.site-popup-btn { + position: absolute; + bottom: 100rpx; + left: calc(50% - 120rpx); + width: 240rpx; + height: 70rpx; + line-height: 70rpx; + font-size: 28rpx; + text-align: center; + border: 1rpx solid #000; + border-radius: 40rpx; + background-color: #000; + color: #fff; + box-sizing: border-box; +} + +.upload-tips-common-box { + padding: 50rpx 20rpx 44rpx 20rpx; + .tips-message { + margin-top: 30rpx; + text-align: center; + font-size: 28rpx; + line-height: 45rpx; + color: #666; + } +} + +.popup-btn-one { + display: flex; + margin-top: 60rpx; + justify-content: center; + .popup-btn { + width: 270rpx; + height: 90rpx; + line-height: 90rpx; + font-size: 32rpx; + font-weight: 500; + text-align: center; + border: 1rpx solid #000; + border-radius: 45rpx; + color: #fff; + background-color: #000; + font-family: PingFang SC; + } +} diff --git a/src/components/popup/popup-instrument-upload-tips.tsx b/src/components/popup/popup-instrument-upload-tips.tsx new file mode 100644 index 0000000..f29a017 --- /dev/null +++ b/src/components/popup/popup-instrument-upload-tips.tsx @@ -0,0 +1,200 @@ +import classnames from "classnames"; +import Taro from "@tarojs/taro"; +import { Component } from "react"; + +import { + Block, + View, + Image, + Text, + Button, + PageMeta, + Swiper, + SwiperItem, +} from "@tarojs/components"; + +import { Popup } from "@antmjs/vantui"; + +import "./popup.less"; +import "./popup-instrument-upload-tips.less"; +import "./fade.css"; + +import { go, goJump } from "../../utils/traoAPI"; + +/*** props + * isLarge 是否大尺寸 + * isShow 是否显示 + * data 数据 + * @confirm 关闭回调 + * ***/ +export default class PopupInstrumentUploadTips extends Component { + constructor(props) { + super(props); + this.state = { + name: "打卡介绍弹窗", + current: 0, + toRight: false, + isClick: false, + }; + } + + async onLoad() {} + componentDidMount() {} + + componentWillUnmount() {} + + componentDidShow() {} + + componentDidHide() {} + + initData = () => { + if (this.props.siteData) { + let arr = JSON.parse(JSON.stringify(this.props.siteData)); + this.setState({ siteList: arr }); + } + }; + + onClose = () => { + this.props.close(); + }; + + onClickStop = (e) => { + e.stopPropagation(); + }; + + onChange(event) { + const current = event.detail.current; + const { current: curCurrent } = this.state; + const { siteData } = this.props; + if (curCurrent + 2 === siteData.length && current + 1 === siteData.length) { + this.setState({ toRight: true }); + } + this.setState({ current }); + } + onClickSwiperItem(item) { + goJump(item); + } + onFinish(event) { + const { current } = event.detail; + const { toRight, isClick } = this.state; + const { siteData } = this.props; + if (current === siteData.length - 1) { + if (toRight || isClick) { + this.setState({ toRight: false, isClick: false }); + } else { + // this.toHomePage(); + } + } + } + + onPrev = async () => { + let { current } = this.state; + this.setState({ current: current - 1 }); + }; + onNext = async () => { + let { current } = this.state; + + if (current === this.props.data.length) { + this.onClose(); + } else { + this.setState({ current: current + 1 }); + } + }; + + render() { + let { isShow, data, isLarge, title } = this.props; + let { current } = this.state; + + return ( + + + + + + + + {data.map((item, index) => { + return ( + + + + + + {item.message} + {item.message} + {item.message} + {item.message} + + + ); + })} + + + + + {data.length === 1 && ( + + + + )} + {data.length > 1 && current === 0 && ( + + + + )} + {data.length > 1 && ( + + + + + )} + + + + + ); + } +} diff --git a/src/pages/connection_help/connection_help.less b/src/pages/connection_help/connection_help.less new file mode 100644 index 0000000..22976ab --- /dev/null +++ b/src/pages/connection_help/connection_help.less @@ -0,0 +1,12 @@ +.nodes { + padding: 30rpx; + word-break: break-all; + box-sizing: border-box; + table { + border-collapse: collapse; /* 边框合并 */ + } + td { + text-align: center; /* 字体居中 */ + border: 1px solid #ccc; /* 边框样式 */ + } +} diff --git a/src/pages/connection_help/connection_help.tsx b/src/pages/connection_help/connection_help.tsx new file mode 100644 index 0000000..f1dbc33 --- /dev/null +++ b/src/pages/connection_help/connection_help.tsx @@ -0,0 +1,105 @@ +import { Component, PropsWithChildren, useEffect, useState } from "react"; +import Taro from "@tarojs/taro"; +import { Block, View, RichText } from "@tarojs/components"; + +import Navbar from "../../components/navbar/navbar"; + +import "./connection_help.less"; + +import { + GetBluetoothGuidance, + GetLocationGuidance, +} from "../../utils/Interface"; + +export default class ConnectionHelp extends Component { + constructor(props) { + super(props); + this.state = { + name: "蓝牙连接帮助", + nodes: "", + type: "bluetoot", // bluetoot location + title: "蓝牙权限开启指引", // 定位授权开启指引 + }; + } + + $instance = Taro.getCurrentInstance(); + + async onLoad() { + this.getType(); + } + componentDidMount() {} + + componentWillUnmount() {} + + componentDidShow() {} + + componentDidHide() {} + + async getType() { + let type = this.$instance.router?.params?.type; + if (type) { + let title = type === "bluetoot" ? "蓝牙权限开启指引" : "定位授权开启指引"; + this.setState({ type, title }); + + setTimeout(() => { + this.initData(); + }, 0); + } + } + + initData = async () => { + let { type } = this.state; + if (type === "bluetoot") { + this.GetBluetoothGuidance(); + } else { + this.GetLocationGuidance(); + } + }; + + GetBluetoothGuidance = async () => { + let res = await GetBluetoothGuidance(); + if (res.data.code === 200) { + let nodes = decodeURIComponent(res.data.data.value || ""); + nodes = nodes.replace(/\ { + let res = await GetLocationGuidance(); + if (res.data.code === 200) { + let nodes = decodeURIComponent(res.data.data.value || ""); + nodes = nodes.replace(/\ + + + + + + + ); + } +} diff --git a/src/pages/index/index.tsx b/src/pages/index/index.tsx index ebc0e6b..d9dcbab 100644 --- a/src/pages/index/index.tsx +++ b/src/pages/index/index.tsx @@ -13,20 +13,22 @@ import { /*** redux ***/ import { connect } from "react-redux"; -import { userRefresh, tokenRefresh } from "../../store/features/userInfo"; -import { setIndexFlag } from "../../store/features/globalStore"; +import { userRefresh, tokenRefresh } from "@/store/features/userInfo"; +import { setIndexFlag } from "@/store/features/globalStore"; /*** redux end ***/ /** 自定义组件 **/ -import AtCalendar from "../../components/calendar"; -import PopupPrivacy from "../../components/popup/popup-privacy"; -import PopupBinding from "../../components/popup/popup-binding"; +import AtCalendar from "@/components/calendar"; +import PopupPrivacy from "@/components/popup/popup-privacy"; +import PopupBinding from "@/components/popup/popup-binding"; // import PopupPrivacyTest from "../../components/popup/popup-privacy-test"; -import PopupSiteSwiper from "../../components/popup/popup-site-swiper"; -import PopupAlert from "../../components/popup/popup-alert"; -import type CustomTabBar from "../../custom-tab-bar"; -import Navbar from "../../components/navbar/navbar"; +import PopupSiteSwiper from "@/components/popup/popup-site-swiper"; +import PopupAlert from "@/components/popup/popup-alert"; +import type CustomTabBar from "@/custom-tab-bar"; +import Navbar from "@/components/navbar/navbar"; + +import ConnectionBluetoot from "@/components/bluetoot/connection"; /** 自定义组件 **/ import { @@ -48,8 +50,15 @@ import { msg, getStorageSync, setStorageSync, + showModal, } from "@/utils/traoAPI"; +const log = require("@/utils/log"); +import commandMap from "@/utils/commandMap"; + +import InstrumentTypeEnum from "@/components/bluetoot/instrumentTypeEnum"; +import OtaDeviceTypeEnum from "@/components/bluetoot/OtaDeviceTypeEnum"; + class Index extends Component { // pageCtx = Taro.getCurrentInstance().page; $instance = Taro.getCurrentInstance(); @@ -63,12 +72,10 @@ class Index extends Component { isNotRegister: false, // 是否未注册 isDev: false, // 正在开发提示 sitePopupList: [], // 站点管理列表 - // imgUrl: this.app.globalData.imgUrl, userinfo: { - mobile: this.props.mobile, + mobile: Taro.getStorageSync("mobile"), }, - connectInstrument: {}, - yiqiinfo: {}, + list: [], params: "", messageCount: Taro.getStorageSync("messageCount") || 0, @@ -95,7 +102,6 @@ class Index extends Component { isVisibleBinding: false, // 绑定弹窗 isBindingError: false, // 绑定失败 isBeforeBinding: false, // 已绑定弹窗 - typeBinding: 0, instrumentList: [], // 仪器列表 instrumentInfo: { // 扫码获得的序列号仪器 @@ -118,6 +124,16 @@ class Index extends Component { validStatus: 1, // 1有效,0无效 }, /** 绑定仪器 End */ + + /** 已绑定仪器 */ + instrument_detail: {}, + /* 已绑定仪器 END */ + + /** 蓝牙相关 */ + isConnectShow: false, + connectInstrument: {}, + yiqiinfo: {}, + /* END */ }; } @@ -556,12 +572,455 @@ class Index extends Component { // 跳转仪器介绍页 goNursing = (item) => { console.log("goNursing", item); - setStorageSync("instrument_item", JSON.stringify(item)); - go("/pages/instrument_clickin_upload/index?id=" + item.id); + setStorageSync("instrument_detail", JSON.stringify(item)); + // setStorageSync("connectInstrument", JSON.stringify(item)); + + // this.setState({ instrument_detail: item }); + // this.setState({ connectInstrument: item }); + // setTimeout(() => this.bindBlockLeft()); + // isConnectShow + setTimeout(() => { + go("/pages/instrumentClickinUpload/index?id=" + item.id); + }, 10); // go("/pages/instrument/intro?id=" + item.id); }; /* 扫码进入逻辑 */ + /** 蓝牙逻辑 */ + bindBlockLeft() { + console.log("this.state.userinfo", this.state.userinfo); + if (!this.state.userinfo.mobile) { + //未注册授权 + this.alertRegister(); + return false; + } + if (this.state.connectInstrument.type === 1) { + //非IOT + } else { + Taro.getSystemInfo({ + success: (res) => { + console.log("getSystemInfo", res); + this.setState({ isConnectShow: true }); + return; + let { locationEnabled, locationAuthorized, bluetoothEnabled } = res; + if (!locationEnabled || !locationAuthorized) { + showModal({ + t2: "您的手机定位授权未开启,请前往手机设置,打开定位访问授权", + btn2text: "查看指引", + }).then(() => { + go("/pages/connection_help/connection_help?type=location"); + }); + } else if (!bluetoothEnabled) { + showModal({ + t2: "您的手机蓝牙授权未开启,请前往手机设置,打开蓝牙访问授权", + btn2text: "查看指引", + }).then(() => { + go("/pages/connection_help/connection_help?type=bluetoot"); + }); + } else { + // 打开连接弹窗 + this.setState({ isConnectShow: true }); + } + }, + }); + } + } + + /** + * WE100,WL200配对完成回调 + */ + async pairingChange(e) { + console.log("epairingChange", e); + return; + const { connectInstrument } = this.state; + let latestVersionNo, isNeedToUpdateBl; + //当前版本号 + const deviceVersionNo = e.detail.deviceVersionNo; + console.info("配对完成回调", e, deviceVersionNo); + //最新版本号 + latestVersionNo = connectInstrument.iot_versions; + //TODO 这些信息需要放在WL200的接口里,现在没有。 暂时的方案,如果是WL200 需要查WE200的相关信息 + if (connectInstrument.type == instrumentTypeEnum.WL200) { + this.pureData.mianmo_id = app.globalData.bindinfo.mianmo_id; + const { data: resData } = await InstrumentInfo({ + id: this.pureData.mianmo_id, + }); + // if (resData) {} + // const mianmo_item = this.data.instruments.find(item=>{ + // return this.pureData.mianmo_id == item.id; + // }) + // if (mianmo_item) { + // const {iot_versions,type} = mianmo_item + // this.pureData.mianmo_iot_versions = iot_versions; + // this.pureData.mianmo_type = type; + // latestVersionNo = iot_versions + // } + // const {data: resData} = await UserInstrumentInfo({id: this.pureData.mianmo_id}); + if (resData.code == 200) { + const { data } = resData; + const { iot_versions, type } = data.info; + this.pureData.mianmo_iot_versions = iot_versions; + this.pureData.mianmo_type = type; + latestVersionNo = iot_versions; + } + isNeedToUpdateBl = isNeedToUpdate(deviceVersionNo, latestVersionNo); + console.log( + `设备版本号: ${deviceVersionNo}`, + `后台版本号: ${latestVersionNo}`, + `是否需要升级: ${isNeedToUpdateBl}` + ); + // 2023.11.29 18:00 经与黄工讨论, 后续版本暂时都需要进行强更 + // this.gotoOta(); + // return + if (isNeedToUpdateBl) { + this.gotoOta(); + return; + this.setData({ + params: "offlineDialog", + offlineDialogType: 2, + otaDeviceName: "skinpilot", + }); + return; + } + go(`/pages/MatrixWL200/pages/index/index?devId=${connectInstrument.id}`); + this.setData({ + params: "", + }); + } else if (connectInstrument.type == instrumentTypeEnum.M01) { + isNeedToUpdateBl = isNeedToUpdate(deviceVersionNo, latestVersionNo); + console.log( + `设备版本号: ${deviceVersionNo}`, + `后台版本号: ${latestVersionNo}`, + `是否需要升级: ${isNeedToUpdateBl}` + ); + if (isNeedToUpdateBl) { + // 2023.11.17 22:00 经与黄工讨论, 后续版本暂时都需要进行强更 + this.gotoOta(); + return; + this.setData({ + params: "offlineDialog", + offlineDialogType: 2, + otaDeviceName: "skinpilot", + offlineDialogForce: 1, + }); + return; + } + go( + `/pages/MatrixM01/pages/index/index?devId=${this.data.connectInstrument.id}` + ); + // this.setData({ + // params: "", + // }); + } + } + + //连接完成时数据的回调 + offlineChange = async (e) => { + const that = this; + log.info( + commandMap.versionInfoHome, + `offlineChange::e::${JSON.stringify(e)}` + ); + //offlineDataList 离线数据 + //versioninfo 版本号 + let { offlineDataList, versionInfo } = e.detail; + this.setState({ + versionInfo, + }); + let offlinelist: any = []; + offlineDataList.map((item, index) => { + let obj: any = { + clock_day: "", + status: 3, + second: 120, + screne_id: "", + screne_name: "离线打卡", + model_face_ward: 0, + model_face_use: 0, + model_face_type: "", + model_eye_ward: 0, + model_eye_use: 0, + model_eye_type: "", + instrument_id: this.state.connectInstrument.id, + }; + + //判断日期是否正常,如果不正常不处理 --- 脸部 + if ( + item.faceyear > 0 && + item.faceyear <= 99 && + item.facemonth >= 1 && + item.facemonth <= 12 && + item.faceday >= 1 && + item.faceday <= 31 + ) { + if ( + item.facehour > 0 || + (item.faceminutes > 0 && item.faceminutes < 60) || + (item.faceseconds > 0 && item.faceseconds < 60) + ) { + //脸部离线记录有值 + obj.model_face_use = + Number(item.facehour) * 60 * 60 + + Number(item.faceminutes) * 60 + + Number(item.faceseconds); + obj.model_face_ward = item.faceposition1; + obj.clock_day = `20${String(item.faceyear).padStart(2, "0")}-${String( + item.facemonth + ).padStart(2, "0")}-${String(item.faceday).padStart(2, "0")}`; + } + } + //判断日期是否正常,如果不正常不处理 --- 眼部 + if ( + item.eyeyear > 0 && + item.eyeyear <= 99 && + item.eyemonth >= 1 && + item.eyemonth <= 12 && + item.eyeday >= 1 && + item.eyeday <= 31 + ) { + if ( + item.eyehour > 0 || + (item.eyeminutes > 0 && item.eyeminutes < 60) || + (item.eyeseconds > 0 && item.eyeseconds < 60) + ) { + //眼部离线记录有值 + obj.model_eye_use = + Number(item.eyehour) * 60 * 60 + + Number(item.eyeminutes) * 60 + + Number(item.eyeseconds); + obj.model_eye_ward = item.eyeposition1; + obj.clock_day = `20${String(item.eyeyear).padStart(2, "0")}-${String( + item.eyemonth + ).padStart(2, "0")}-${String(item.eyeday).padStart(2, "0")}`; + } + } + + obj.second = obj.model_face_use + obj.model_eye_use; + + if ( + item.faceyear > 0 && + item.faceyear <= 99 && + (item.facemonth == 1 || item.facemonth <= 12) && + (item.faceday == 1 || item.faceday <= 31) + ) { + let dayTime = new Date(`${obj.clock_day.replace(/-/g, "/")}`).getTime(); //离线记录的日期 + let now = new Date( + `${new Date().getFullYear()}/${String( + new Date().getMonth() + 1 + ).padStart(2, "0")}/${String(new Date().getDate()).padStart(2, "0")}` + ).getTime(); //当前日期 + /** + * 过滤7天前的离线记录 + * + */ + if (dayTime <= now && dayTime >= now - 24 * 60 * 60 * 1000 * 6) { + offlinelist.push(obj); + } + } + }); + console.log(offlinelist); + let nowyear = new Date().getFullYear(); + let nowmonth = String(new Date().getMonth() + 1).padStart(2, "0"); + let nowday = String(new Date().getDate()).padStart(2, "0"); + // await IOTHistorySynchronization({ + // //把离线数据同步到后台 + // instrument_id: app.globalData.bindid, + // clock_times: offlinelist, + // }); + // offlinelist.map((item, index) => { + // // console.log(new Date(item.clock_day.replace(/-/g,'/')).getTime()) + // if (item.clock_day == `${nowyear}-${nowmonth}-${nowday}`) { + // //今日有离线护理 弹出 检测到您今天已进行护理,是否跳过护理直接前往打卡,或选择继续进行护理 + // if (item.second >= this.data.connectInstrument.times * 60) { + // console.log("今日有离线护理"); + // let screneList2 = { + // lianbuobj: { + // fen: String(s_to_h(item.model_face_use)).padStart("2", 0), + // miao: String(s_to_s(item.model_face_use)).padStart("2", 0), + // total: item.model_face_use, + // }, + // yanbuobj: { + // fen: String(s_to_h(item.model_eye_use)).padStart("2", 0), + // miao: String(s_to_s(item.model_eye_use)).padStart("2", 0), + // total: item.model_eye_use, + // }, + // ledobj: { + // fen: 0, + // miao: 0, + // total: 0, + // }, + // }; + // this.setData({ + // screneList2, + // }); + + // let screneList3 = { + // second: item.second, //总秒 + // screne_id: "", //场景id + // screne_name: "离线记录", //场景名称 + // model_face_ward: item.model_face_ward, //脸部场景档位 + // model_face_use: item.model_face_use, //脸部场景使用时长 + // model_face_type: "", //脸部模式类型 + // model_eye_ward: item.model_eye_ward, //眼部场景档位 + // model_eye_use: item.model_eye_use, //眼部场景使用时长 + // model_eye_type: "", //眼部模式类型 + // }; + + // /** + // * 如果今天有打过卡,需要累加 + // */ + // // if (this.data?.todayclockin?.id) { + // // screneList3.second += this.data.todayclockin.clock_info[0].second + // // screneList3.model_face_use += this.data.todayclockin.clock_info[0].model_face_use + // // screneList3.model_eye_use += this.data.todayclockin.clock_info[0].model_eye_use + // // } + // // + // // console.log(this.data.todayclockin) + // this.setData({ + // screneList3, + // }); + // console.log(this.data.screneList3, "2222222222222222222"); + + // this.setData({ + // params: "offlineDialog", + // offlineDialogType: 1, + // todayofflineData: item, + // }); + // } + // } + // }); + + // if (this.data.params == "connection_guide") { + // // this.setData({ + // // params: 'offlineDialog', + // // offlineDialogType:2 + // // }) + // console.log("设备版本号" + versioninfo.version); + // console.log("后台版本号" + this.data.connectInstrument.iot_versions); + // log.info( + // commandMap.versionInfoHome, + // `设备版本号: ${versioninfo.version}` + // ); + // log.info( + // commandMap.versionInfoHome, + // `后台版本号: ${that.data.connectInstrument.iot_versions}` + // ); + // console.log( + // "后台版本号H" + + // Number(this.data.connectInstrument.iot_versions.substring(0, 2)) + + // "版本号H" + + // Number(String(versioninfo.v1).padStart("2", 0)) + // ); + // log.info( + // commandMap.versionInfoHome, + // `后台版本号H: ${Number( + // that.data.connectInstrument.iot_versions.substring(0, 2) + // )} ,版本号H: ${Number(String(versioninfo.v1).padStart("2", 0))}` + // ); + // console.log( + // "后台版本号M" + + // Number(this.data.connectInstrument.iot_versions.substring(2, 4)) + + // "版本号M" + + // Number(String(versioninfo.v2).padStart("2", 0)) + // ); + // log.info( + // commandMap.versionInfoHome, + // "后台版本号M" + + // Number(this.data.connectInstrument.iot_versions.substring(2, 4)) + + // "版本号M" + + // Number(String(versioninfo.v2).padStart("2", 0)) + // ); + // console.log( + // "后台版本号L" + + // Number(this.data.connectInstrument.iot_versions.substring(4, 6)) + + // "版本号L" + + // Number(String(versioninfo.v3).padStart("2", 0)) + // ); + // log.info( + // commandMap.versionInfoHome, + // "后台版本号L" + + // Number(this.data.connectInstrument.iot_versions.substring(4, 6)) + + // "版本号L" + + // Number(String(versioninfo.v3).padStart("2", 0)) + // ); + // //这是有问题的固件,强制升级 + // if ( + // versioninfo.v1 == "01" && + // versioninfo.v2 == "02" && + // versioninfo.v3 == "00" + // ) { + // this.gotoOta(); + // return; + // } + // if ( + // this.data.connectInstrument.iot_versions.substring(0, 2) == + // versioninfo.v1 + // ) { + // if ( + // Number(this.data.connectInstrument.iot_versions.substring(2, 4)) > + // Number(versioninfo.v2) + // ) { + // this.setData({ + // params: "offlineDialog", + // offlineDialogType: 2, + // otaDeviceName: "设备", + // }); + // } else if ( + // Number(this.data.connectInstrument.iot_versions.substring(2, 4)) == + // Number(versioninfo.v2) + // ) { + // if ( + // Number(this.data.connectInstrument.iot_versions.substring(4, 6)) > + // Number(versioninfo.v3) + // ) { + // this.setData({ + // params: "offlineDialog", + // offlineDialogType: 2, + // otaDeviceName: "设备", + // }); + // } else { + // this.setData({ + // params: "", + // }); + // go( + // "/pages/nursing/nursing?id=&iid=" + + // app.globalData.bindid + + // `&type=fr200&version=${versioninfo?.version}` + // ); + // } + // } else { + // this.setData({ + // params: "", + // }); + // go( + // "/pages/nursing/nursing?id=&iid=" + + // app.globalData.bindid + + // `&type=fr200&version=${versioninfo?.version}` + // ); + // } + // } else { + // this.setData({ + // params: "", + // }); + // go( + // "/pages/nursing/nursing?id=&iid=" + + // app.globalData.bindid + + // `&type=fr200&version=${versioninfo?.version}` + // ); + // } + // } + }; + + connectionClose = async (data) => { + console.log("connectionClose", data); + this.setState({ isConnectShow: false }); + }; + connectionConfirm = async (data) => { + console.log("connectionConfirm", data); + this.setState({ isConnectShow: false }); + }; + + /*蓝牙 END*/ render() { let { calendarComplete, @@ -582,9 +1041,12 @@ class Index extends Component { isBeforeBinding, isRegisterBoolean, isExchangeBinding, - typeBinding, instrumentInfo, instrumentList, + + // 蓝牙连接 + isConnectShow, + connectInstrument, } = this.state; return ( @@ -663,6 +1125,16 @@ class Index extends Component { close={this.closeSiteSwiper} confirm={this.closeSiteSwiper} /> + + {isConnectShow && ( + + )} + {/* */} + diff --git a/src/pages/instrument/intro.tsx b/src/pages/instrument/intro.tsx index bf711de..7f345a2 100644 --- a/src/pages/instrument/intro.tsx +++ b/src/pages/instrument/intro.tsx @@ -16,11 +16,6 @@ import Navbar from "../../components/navbar/navbar"; // import PopupAlert from "../../components/popup/popup-alert"; /* 组件 */ -/*** redux ***/ -import { connect } from "react-redux"; -import { setInstrument } from "../../store/features/instrument"; -/*** redux end ***/ - import { InstrumentInfo } from "../../utils/Interface"; import { setStorageSync, getStorageSync, go } from "../../utils/traoAPI"; @@ -166,12 +161,4 @@ class Intro extends Component { } } -const mapStateToProps = (state) => ({ - instrument: state.instrument, -}); -const mapDispatchToProps = (dispatch) => ({ - setInstrument(data) { - dispatch(setInstrument(data)); - }, -}); -export default connect(mapStateToProps, mapDispatchToProps)(Intro); +export default Intro; diff --git a/src/pages/instrument_clickin_upload/index.less b/src/pages/instrumentClickinUpload/index.less similarity index 94% rename from src/pages/instrument_clickin_upload/index.less rename to src/pages/instrumentClickinUpload/index.less index b6b709c..71efa07 100644 --- a/src/pages/instrument_clickin_upload/index.less +++ b/src/pages/instrumentClickinUpload/index.less @@ -139,27 +139,20 @@ page { /*box-shadow: -2rpx 0 12rpx .5rpx rgba(129, 129, 129, 0.1);*/ border: 2rpx solid #dddddd; position: relative; -} -.infobox2 .info4 .content .textarea { - width: 100%; - height: 100%; - color: #000; - font-size: 28rpx; -} -.infobox2 .info4 .content .contenttip { - color: #e1e1e1; - font-size: 20rpx; - position: absolute; - right: 24rpx; - bottom: 18rpx; -} - -.infobox2 .info4 .content textarea { - width: 100%; - height: 100%; - font-size: 28rpx; - color: #000; - border-radius: 3rpx; + textarea { + width: 100%; + height: 100%; + font-size: 28rpx; + color: #000; + border-radius: 3rpx; + } + .tips-num { + color: #999; + font-size: 20rpx; + position: absolute; + right: 24rpx; + bottom: 18rpx; + } } .placeholder { font-size: 28rpx; diff --git a/src/pages/instrument_clickin_upload/index.tsx b/src/pages/instrumentClickinUpload/index.tsx similarity index 59% rename from src/pages/instrument_clickin_upload/index.tsx rename to src/pages/instrumentClickinUpload/index.tsx index 74d3ff4..72d2777 100644 --- a/src/pages/instrument_clickin_upload/index.tsx +++ b/src/pages/instrumentClickinUpload/index.tsx @@ -16,12 +16,14 @@ import { } from "@tarojs/components"; import Navbar from "@/components/navbar/navbar"; +import PopupInstrumentUploadTips from "@/components/popup/popup-instrument-upload-tips"; import { InstrumentInfo } from "@/utils/Interface"; import "./index.less"; import { contraction, getImgInfo } from "@/utils/compressImage"; import PopupAlert from "@/components/popup/popup-alert"; +import { setStorageSync, getStorageSync, msg } from "@/utils/traoAPI"; export default class InstrumentClickInUpload extends Component { constructor(props) { @@ -40,17 +42,27 @@ export default class InstrumentClickInUpload extends Component { showVideoPlayBtn: true, duration: 0, + videoContext: {}, // 视频播放器 + isTipShow: false, + clockContent: "", // 默认展示 + instrumentDetail: {}, punchInInfo: { - imageList: [], - content: "", + clockImageList: [], + clockContent: "", instrumentId: "84", + firstClockImg: null, + secondClockImg: null, + thirdClockImg: null, }, // 现在选中的数据 currentInfo: { modeVideo: "", }, modeInfo: [], + nurseInfo: [], // 首次进入介绍弹窗 isModeLock: false, + + isSubmit: false, // 已提交则禁用提交按钮 }; } @@ -61,27 +73,58 @@ export default class InstrumentClickInUpload extends Component { componentWillUnmount() {} - componentDidShow() {} + componentDidShow() { + let videoContext = Taro.createVideoContext("myVideo"); + this.setState({ videoContext }); + } componentDidHide() {} async initData() { - this.firstNurseInfo(); - this.modeInfoList(); + let objStr = getStorageSync("instrument_detail"); + if (objStr) { + let instrumentDetail = JSON.parse(objStr); + this.setState({ instrumentDetail }); + } + + setTimeout(() => { + this.firstNurseInfo(); + this.getLatestClockRecord(); + this.modeInfoList(); + }, 10); } + // 打卡介绍 firstNurseInfo = async () => { + let { instrumentDetail } = this.state; let res = await InstrumentInfo.firstNurseInfo({ - instrumentId: "84", + instrumentId: instrumentDetail.id, }); - console.log("firstNurseInfo", res); + if (res.data.code === 200) { + let isTipShow = getStorageSync("first_instrument_" + instrumentDetail.id); + if (!isTipShow) { + // 首次进入页面:自动打开打卡介绍弹窗 + this.setState({ nurseInfo: res.data.data, isTipShow: true }); + } else { + this.setState({ nurseInfo: res.data.data }); + } + } }; - + // 获取最新一条打卡记录 + getLatestClockRecord = async () => { + let { punchInInfo } = this.state; + let res = await InstrumentInfo.apiClock.getLatestClockRecord(); + if (res.data.code === 200) { + punchInInfo.clockContent = res.data.data.clockContent; + punchInInfo.clockImageList = res.data.data.clockImg; + } + this.setState({ punchInInfo }); + }; + // 获取仪器模式列表 modeInfoList = async () => { let res = await InstrumentInfo.modeInfoList({ instrumentId: "84", }); - console.log("modeInfo", res); if (res.data.code === 200) { if (res.data.data.length) { this.setState({ @@ -95,6 +138,10 @@ export default class InstrumentClickInUpload extends Component { bindMoshi = async (index) => { let { currentInfo, modeInfo, punchInInfo } = this.state; currentInfo = modeInfo[index]; + if (currentInfo.lock) { + this.onModeLockOpen(); // 点击了锁定模式 + return; + } this.setState({ zkmoshiindex: index, currentInfo }); }; @@ -113,15 +160,98 @@ export default class InstrumentClickInUpload extends Component { let compressImage = await contraction(img, "compressImage"); // 压缩后文件地址 let compressTempFilePath = compressImage.tempFilePath; - punchInInfo.imageList.push(compressTempFilePath); + punchInInfo.clockImageList.push(compressTempFilePath); + this.setState({ punchInInfo }); }, }); }; + // 删除打卡图片 handleDeleteImage = async (index) => { let { punchInInfo } = this.state; - punchInInfo.imageList.splice(index, 1); + punchInInfo.clockImageList.splice(index, 1); + + this.setState({ punchInInfo }); + }; + + // 提交打卡 + handleSubmit = async () => { + let { punchInInfo } = this.state; + let obj = punchInInfo; + if (obj.clockImageList.length === 0) { + msg("至少上传一张图片"); + return; + } + + let promiseTasks: any = []; + let imgList: any[] = []; + obj.clockImageList.map((imgUrl: string) => { + let isTmpFile = imgUrl.indexOf("//tmp") > -1; + let isWXFile = imgUrl.indexOf("wxfile://") > -1; + if (isTmpFile || isWXFile) { + let params = { + clockImg: imgUrl, + }; + promiseTasks.push(InstrumentInfo.apiClock.clockFileUpload(params)); + imgList.push("null"); + } else { + imgList.push(imgUrl); + } + }); + + if (promiseTasks.length) { + let res = await Promise.all(promiseTasks); + //具体处理写在如下 + if (res.length) { + res.map((item) => { + if (item.code === 200) { + let index = imgList.findIndex((url) => url === "null"); + if (index > -1) { + imgList[index] = item.data.url; + } + } + }); + } + } + + let clockParmas = { + clockImageList: imgList, + clockContent: obj.clockContent, + }; + let res = await InstrumentInfo.apiClock.postInsertClockLog(clockParmas); + if (res.data.code === 200) { + msg("打卡成功"); + setTimeout(() => { + Taro.switchTab({ + url: "/pages/index/index", + }); + }, 2000); + } + }; + + onPlayTap = async () => { + let { videoContext } = this.state; + videoContext.play(); + this.setState({ + showVideoPlayBtn: false, + }); + }; + + videoBindTimeUpdate = async () => {}; + + videoEnded = async () => {}; + + videoPause = async () => {}; + + videoPlay = async () => {}; + + videoLoadedMetaData = async () => {}; + + handleTextareaInput = async (e) => { + let { punchInInfo } = this.state; + punchInInfo.clockContent = e.detail.value; + this.setState({ punchInInfo }); }; @@ -132,9 +262,16 @@ export default class InstrumentClickInUpload extends Component { this.setState({ isModeLock: false }); }; - onTipShow = async () => {}; - - handleSubmit = async () => {}; + onTipShowOpen = async () => { + this.setState({ isTipShow: true }); + }; + onTipShowClose = async () => { + setStorageSync( + "first_instrument_" + this.state.instrumentDetail.id, + "true" + ); + this.setState({ isTipShow: false }); + }; render() { let { @@ -144,10 +281,12 @@ export default class InstrumentClickInUpload extends Component { scrollleft, zkmoshiindex, punchInInfo, - tipshow, + isTipShow, currentInfo, modeInfo, + nurseInfo, isModeLock, + isSubmit, } = this.state; return ( @@ -167,7 +306,15 @@ export default class InstrumentClickInUpload extends Component { isClose={false} close={this.onModeLockClose} confirm={this.onModeLockClose} - > + /> + + )} @@ -262,7 +411,7 @@ export default class InstrumentClickInUpload extends Component { 打卡上传 - + { - {punchInInfo.imageList.length > 0 && - punchInInfo.imageList.map((item, index) => { + {punchInInfo.clockImageList.length > 0 && + punchInInfo.clockImageList.map((item, index) => { return ( @@ -289,7 +438,7 @@ export default class InstrumentClickInUpload extends Component { ); })} - {punchInInfo.imageList.length < 3 && ( + {punchInInfo.clockImageList.length < 3 && ( { )} - {!tipshow && ( - - )} - - {tipshow && ( + + {/* {tipshow && ( - {punchInInfo.content - ? punchInInfo.content + {punchInInfo.clockContent + ? punchInInfo.clockContent : "请记录一下今天打卡的心得吧~"} - )} + )} */} + + {punchInInfo.clockContent.length}/100 + - - 提交打卡 - + + + {!isSubmit && ( + + 提交打卡 + + )} + {isSubmit && ( + + 提交打卡 + + )} ); } diff --git a/src/pages/integral_list/integral_list.tsx b/src/pages/integral_list/integral_list.tsx index 4f2cc01..ef482f6 100644 --- a/src/pages/integral_list/integral_list.tsx +++ b/src/pages/integral_list/integral_list.tsx @@ -31,6 +31,7 @@ import { GetIsAttentionOfficialAccount, GetOfficialAccount, GetCloseOfficialAccount, + RefreshWxUserInfo, } from "../../utils/Interface"; import { msg } from "../../utils/traoAPI"; @@ -75,10 +76,20 @@ class IntegralList extends Component { componentDidHide() {} async initData() { + this.RefreshWxUserInfo(); this.GetObtainUserIntegral(); this.GetIsAttentionOfficialAccount(); } + // 刷新用户信息 + RefreshWxUserInfo = async () => { + let res = await RefreshWxUserInfo(); + if (res.data.code === 200) { + this.props.userRefresh(res.data.data); + this.setState({ userInfo: res.data.data }); + } + }; + openShop = () => { let { otherSetting } = this.state; if (otherSetting.skipAppid) { @@ -368,7 +379,8 @@ class IntegralList extends Component { title="过期积分提醒" type="3" content={ - + // // 删除测试阶段标签后,需改回700rpx + { 长按图片关注公众号,可以接收积分过期提醒 - + (测试阶段公众号为:广州云强信息科技有限公司) diff --git a/src/pages/privacyPolicy/privacyPolicy.tsx b/src/pages/privacyPolicy/privacyPolicy.tsx index bfa2489..ca60149 100644 --- a/src/pages/privacyPolicy/privacyPolicy.tsx +++ b/src/pages/privacyPolicy/privacyPolicy.tsx @@ -52,14 +52,7 @@ export default class PrivacyPolicy extends Component { - " + - // nodes + - // "" - } - /> + ); diff --git a/src/pages/user/user.tsx b/src/pages/user/user.tsx index e59dee7..edbcc00 100644 --- a/src/pages/user/user.tsx +++ b/src/pages/user/user.tsx @@ -47,14 +47,13 @@ class User extends Component { }; } - async onLoad() { - this.initData(); - } + async onLoad() {} componentDidMount() {} componentWillUnmount() {} componentDidShow() { + this.initData(); this.setState({ userInfo: this.props.userInfo }); let messagecount = Taro.getStorageSync("messageCount"); @@ -83,7 +82,6 @@ class User extends Component { // 刷新用户信息 RefreshWxUserInfo = async () => { let res = await RefreshWxUserInfo(); - console.log("res", res); if (res.data.code === 200) { this.props.userRefresh(res.data.data); this.setState({ userInfo: res.data.data }); diff --git a/src/pages/userInfo/userInfo.tsx b/src/pages/userInfo/userInfo.tsx index 2ac95e5..7eb84b7 100644 --- a/src/pages/userInfo/userInfo.tsx +++ b/src/pages/userInfo/userInfo.tsx @@ -515,7 +515,9 @@ class UserInfo extends Component { 确认提交 ) : ( - 确认提交 + + 确认提交 + )} diff --git a/src/pages/userInfoDetail/userInfoDetail.tsx b/src/pages/userInfoDetail/userInfoDetail.tsx index 86eb30d..b0d333b 100644 --- a/src/pages/userInfoDetail/userInfoDetail.tsx +++ b/src/pages/userInfoDetail/userInfoDetail.tsx @@ -513,7 +513,9 @@ class UserInfoDetail extends Component { 保存 ) : ( - 保存 + + 保存 + )} diff --git a/src/store/features/deviceInfo.js b/src/store/features/deviceInfo.js new file mode 100644 index 0000000..a87398a --- /dev/null +++ b/src/store/features/deviceInfo.js @@ -0,0 +1,27 @@ +import Taro from "@tarojs/taro"; +import { createSlice } from "@reduxjs/toolkit"; + +// 设备连接蓝牙 +const deviceInfoReducer = createSlice({ + name: "deviceinfo", // store的名字 + initialState: { + bluetoothInfo: { + deviceId: "5FF5FD4F-9EF9-3CB6-AD89-F915B55E5DE9", // 先测试一下 + servicesuuid: "", + characteristicsuuid0: "", + characteristicsuuid1: "", + characteristicId: "", + }, + }, + reducers: { + setDeviceInfo(state, { payload }) { + state = JSON.parse(JSON.stringify(payload)); + }, + setBluetoothInfo(state, { payload }) { + state.bluetoothInfo = JSON.parse(JSON.stringify(payload)); + }, + }, +}); + +export const { setBluetoothInfo } = deviceInfoReducer.actions; +export default deviceInfoReducer.reducer; diff --git a/src/store/index.js b/src/store/index.js index 06a694a..75e90f5 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -5,7 +5,7 @@ import navigationReducer from "./features/navigation"; import userInfoReducer from "./features/userInfo"; import globalStoreReducer from "./features/globalStore"; import otherSettingReducer from "./features/otherSetting"; -import instrumentReducer from "./features/instrument"; +import deviceInfoReducer from "./features/deviceInfo"; const store = configureStore({ reducer: { @@ -15,7 +15,7 @@ const store = configureStore({ userInfo: userInfoReducer, globalStore: globalStoreReducer, otherSetting: otherSettingReducer, - instrument: instrumentReducer, + deviceInfo: deviceInfoReducer, }, }); diff --git a/src/utils/Interface.js b/src/utils/Interface.js index f08baec..caf707d 100644 --- a/src/utils/Interface.js +++ b/src/utils/Interface.js @@ -34,7 +34,6 @@ export const GetAboutUs = (data) => { //获取用户信息接口 return Ajax({ url: "/setting/getAboutUs", - data, method: "get", }); }; @@ -61,7 +60,6 @@ export const RefreshWxUserInfo = (data) => { // 刷新用户信息 return Ajax({ url: "/user/refreshWxUserInfo", - data, method: "get", }); }; @@ -69,7 +67,6 @@ export const GetProvince = (data) => { // 获取全部省份 return Ajax({ url: "/region/getProvince", - data, method: "get", }); }; @@ -77,7 +74,6 @@ export const GetAreaListByPid = (data) => { // 获取全部省份 ?pid=xxx return Ajax({ url: "/region/getAreaListByPid" + paramsToUrlQueryString(data), - data, method: "get", }); }; @@ -105,7 +101,6 @@ export const getPrivacyAgreement = (data) => { //用户隐私协议获取 return Ajax({ url: "/setting/getPrivacyAgreement", - data, method: "get", }); }; @@ -113,7 +108,6 @@ export const GetOtherSetting = (data) => { // 获取其他设置 return Ajax({ url: "/setting/getOtherSetting", - data, method: "get", }); }; @@ -121,7 +115,6 @@ export const getContactWorker = (data) => { // 联系客服 return Ajax({ url: "/setting/getContactWorker", - data, method: "get", }); }; @@ -139,7 +132,6 @@ export const GetNoReadMessageNum = (data) => { // 查询是否有消息未读 return Ajax({ url: "/userScriptLog/getNoReadMessageNum", - data, method: "get", }); }; @@ -148,7 +140,6 @@ export const GetHasBeenRead = (data) => { // 将消息设置为已读 return Ajax({ url: "/userScriptLog/hasBeenRead", - data, method: "get", }); }; @@ -157,79 +148,86 @@ export const GetMessageList = (data) => { // 分页获取消息 return Ajax({ url: "/userScriptLog/list" + paramsToUrlQueryString(data), - data, method: "get", }); }; // 积分页面 +/**分页获取用户积分列表*/ export const GetObtainUserIntegral = (data) => { - // 分页获取用户积分列表 return Ajax({ url: "/integralLog/obtainUserIntegral" + paramsToUrlQueryString(data), - data, method: "get", }); }; +/**获取积分规则*/ export const GetIntegralRule = (data) => { - // 获取积分规则 return Ajax({ url: "/setting/getIntegralRule", - data, method: "get", }); }; +/**查询用户是否关注公众号*/ export const GetIsAttentionOfficialAccount = (data) => { - // 查询用户是否关注公众号 return Ajax({ url: "/noRemind/isAttentionOfficialAccount", - data, method: "get", }); }; +/**查询用户是否关闭提醒关注公众号*/ export const GetOfficialAccount = (data) => { - // 查询用户是否关闭提醒关注公众号 return Ajax({ url: "/noRemind/getOfficialAccount", - data, method: "get", }); }; + +/**查询关闭提醒关注公众号*/ export const GetCloseOfficialAccount = (data) => { - // 查询关闭提醒关注公众号 return Ajax({ url: "/noRemind/closeOfficialAccount", - data, method: "get", }); }; +/**站点管理-弹窗列表 1-首页 2-发现模块 3-活动模块*/ export const GetSitePopupList = (data) => { - // 站点管理-弹窗列表 1-首页 2-发现模块 3-活动模块 return Ajax({ url: "/siteInfo/popup/" + data, - data, method: "get", }); }; +/**站点管理-轮播图*/ export const GetSiteCarousel = (data) => { - // 站点管理-轮播图 return Ajax({ url: "/siteInfo/carousel", - data, method: "get", }); }; +/**站点管理-轮播图-添加标签 传值是id*/ export const GetSiteAddTag = (data) => { - // 站点管理-轮播图-添加标签 传值是id return Ajax({ url: "/siteInfo/addTag/" + data, - data, method: "get", }); }; -// 仪器管理 +/**获取蓝牙指引权限引导*/ +export const GetBluetoothGuidance = () => { + return Ajax({ + url: "/setting/getBluetoothGuidance", + method: "get", + }); +}; +/**获取蓝牙定位权限引导*/ +export const GetLocationGuidance = () => { + return Ajax({ + url: "/setting/getLocationGuidance", + method: "get", + }); +}; + +/**仪器管理*/ export const InstrumentInfo = { /**根据序列号获取仪器信息 serial 序列号*/ getInstrumentInfoBySerial: (data) => { @@ -261,7 +259,6 @@ export const InstrumentInfo = { exchangeBinding: (data) => { return Ajax({ url: "/instrument/exchangeBinding" + paramsToUrlQueryString(data), - data, method: "get", }); }, @@ -269,7 +266,6 @@ export const InstrumentInfo = { bindingInstrumentList: () => { return Ajax({ url: "/instrument/bindingInstrumentList", - data, method: "get", }); }, @@ -278,7 +274,6 @@ export const InstrumentInfo = { unbindingInstrumentInfoList: () => { return Ajax({ url: "/instrument/unbindingInstrumentInfoList", - data, method: "get", }); }, @@ -346,12 +341,22 @@ export const InstrumentInfo = { }, /**打卡相关*/ - clock: { + apiClock: { + /**单文件上传*/ + clockFileUpload: (formData) => { + return AjaxUploadFile( + { + url: "/clock/upload", + filePath: formData.clockImg, + name: "clockImg", + }, + formData + ); + }, /**添加用户使用仪器记录 instrumentId*/ addClockInstrument: (data) => { return Ajax({ url: "/clock/addClockInstrument" + paramsToUrlQueryString(data), - data, method: "get", }); }, @@ -367,7 +372,6 @@ export const InstrumentInfo = { getLatestClockRecord: (data) => { return Ajax({ url: "/clock/latestClockRecord", - data, method: "get", }); }, @@ -375,7 +379,6 @@ export const InstrumentInfo = { getList: (data) => { return Ajax({ url: "/clock/list" + paramsToUrlQueryString(data), - data, method: "get", }); }, @@ -383,13 +386,12 @@ export const InstrumentInfo = { getClockStatistics: (data) => { return Ajax({ url: "/clock/clockStatistics", - data, method: "get", }); }, }, /**护理相关*/ - nursingLog: { + apiNursingLog: { /**新增用户护理日志*/ addLog: (data) => { return Ajax({ @@ -402,7 +404,6 @@ export const InstrumentInfo = { getRecord: (data) => { return Ajax({ url: "/nursingLog/record" + paramsToUrlQueryString(data), - data, method: "get", }); }, @@ -410,7 +411,6 @@ export const InstrumentInfo = { getStatistics: (data) => { return Ajax({ url: "/nursingLog/statistics" + paramsToUrlQueryString(data), - data, method: "get", }); }, diff --git a/src/utils/bluetoothWXAPI.js b/src/utils/bluetoothWXAPI.js index f116f95..a882f1f 100644 --- a/src/utils/bluetoothWXAPI.js +++ b/src/utils/bluetoothWXAPI.js @@ -1,12 +1,16 @@ +import Taro from "@tarojs/taro"; +import store from "../store"; +const deviceInfo = store.getState().deviceInfo; + import { msg, back, showModal, go, loading } from "./traoAPI"; -const app = getApp(); +// const app = getApp(); import { keywordTofilter } from "./util"; const log = require("./log"); import commandMap from "./commandMap"; export const getSystemInfo = () => { return new Promise((reslove, reject) => { - wx.getSystemInfo({ + Taro.getSystemInfo({ success(res) { reslove(res); }, @@ -16,7 +20,7 @@ export const getSystemInfo = () => { export const openBluetoothAdapter = () => { return new Promise((reslove, reject) => { - wx.openBluetoothAdapter({ + Taro.openBluetoothAdapter({ success(res) { reslove(res); }, @@ -29,7 +33,7 @@ export const openBluetoothAdapter = () => { export const startBluetoothDevicesDiscovery = () => { return new Promise((reslove, reject) => { - wx.startBluetoothDevicesDiscovery({ + Taro.startBluetoothDevicesDiscovery({ //开始搜索蓝牙 allowDuplicatesKey: false, success(res) { @@ -44,7 +48,7 @@ export const startBluetoothDevicesDiscovery = () => { export const createBLEConnection = (deviceId) => { return new Promise((reslove, reject) => { - wx.createBLEConnection({ + Taro.createBLEConnection({ deviceId, success(res) { reslove(res); @@ -58,7 +62,7 @@ export const createBLEConnection = (deviceId) => { export const closeBLEConnection = (deviceId) => { return new Promise((reslove, reject) => { - wx.closeBLEConnection({ + Taro.closeBLEConnection({ deviceId, success(res) { reslove(res); @@ -74,14 +78,14 @@ export const closeBLEConnection = (deviceId) => { //数组下标1读取 0写入 export const getBLEDeviceServices = (deviceId) => { return new Promise((reslove, reject) => { - wx.getBLEDeviceServices({ + Taro.getBLEDeviceServices({ //获取服务以及服务的uuid deviceId, success(res) { console.log("主要服务"); console.log(res); let servicesuuid = res.services[0].uuid; //主要服务 - wx.getBLEDeviceCharacteristics({ + Taro.getBLEDeviceCharacteristics({ //获取蓝牙低功耗设备某个服务中所有特征 (characteristic)。 deviceId, serviceId: servicesuuid, @@ -109,7 +113,7 @@ export const getBLEDeviceServices = (deviceId) => { export const notifyBLECharacteristicValueChange = (info) => { return new Promise((reslove, reject) => { - wx.notifyBLECharacteristicValueChange({ + Taro.notifyBLECharacteristicValueChange({ state: true, // 启用 notify 功能 deviceId: info.deviceId, serviceId: info.servicesuuid, @@ -126,7 +130,7 @@ export const notifyBLECharacteristicValueChange = (info) => { export const writeBLECharacteristicValue = (info, completeCallback) => { return new Promise((reslove, reject) => { - wx.writeBLECharacteristicValue({ + Taro.writeBLECharacteristicValue({ deviceId: info.deviceId, serviceId: info.servicesuuid, characteristicId: info.characteristicsuuid0, @@ -152,10 +156,10 @@ export const writeBLECharacteristicValue = (info, completeCallback) => { export const sendCommand = (info) => { return new Promise((reslove, reject) => { - wx.writeBLECharacteristicValue({ - deviceId: app.globalData.deviceInfo.deviceId, - serviceId: app.globalData.deviceInfo.servicesuuid, - characteristicId: app.globalData.deviceInfo.characteristicsuuid0, + Taro.writeBLECharacteristicValue({ + deviceId: deviceInfo.bluetoothInfo.deviceId, + serviceId: deviceInfo.bluetoothInfo.servicesuuid, + characteristicId: deviceInfo.bluetoothInfo.characteristicsuuid0, value: info.value, success(res) { console.log(info.value);