diff --git a/project.config.json b/project.config.json
index aab17ff..e796931 100644
--- a/project.config.json
+++ b/project.config.json
@@ -30,7 +30,8 @@
"outputPath": ""
},
"disableUseStrict": false,
- "useCompilerPlugins": false
+ "useCompilerPlugins": false,
+ "minifyWXML": true
},
"compileType": "miniprogram",
"libVersion": "2.24.5",
diff --git a/src/api/mine.ts b/src/api/mine.ts
index aa0ae5a..bb53baf 100644
--- a/src/api/mine.ts
+++ b/src/api/mine.ts
@@ -10,3 +10,17 @@ export const userassets = () => {
method: "get",
})
}
+//取色对比
+export const productabsorbcontrast = () => {
+ return useRequest({
+ url: `/v1/mall/product/color/absorb/contrast`,
+ method: "get",
+ })
+}
+//订单统计
+export const userorderStatistics = () => {
+ return useRequest({
+ url: `/v1/mall/user/orderStatistics`,
+ method: "get",
+ })
+}
\ No newline at end of file
diff --git a/src/app.config.ts b/src/app.config.ts
index e735150..0d19c18 100644
--- a/src/app.config.ts
+++ b/src/app.config.ts
@@ -177,6 +177,13 @@ export default {
pages: [
"index",
]
- }
+ },
+ {
+ root: "pages/sampleComparison",
+ pages: [
+ "index",
+ ]
+ },
+
]
}
diff --git a/src/common/constant.js b/src/common/constant.js
index 8e37364..1e472c2 100644
--- a/src/common/constant.js
+++ b/src/common/constant.js
@@ -5,7 +5,7 @@
// export const BASE_URL = `http://192.168.0.89:40001/lymarket`
// export const BASE_URL = `http://192.168.1.165:40001/lymarket` // 王霞
// export const BASE_URL = `https://test.zzfzyc.com/lymarket` // 测试环境
-// export const BASE_URL = `http://192.168.1.9:40001/lymarket` // 发
+// export const BASE_URL = `http://192.168.1.30:40001/lymarket` // 发
// export const BASE_URL = `http://192.168.1.30:50001/lymarket` // 发
// export const BASE_URL = `https://dev.zzfzyc.com/lymarket` // 开发环境
// export const BASE_URL = `https://www.zzfzyc.com/lymarket` // 正式环境
diff --git a/src/pages/order/components/offlinePay/index.tsx b/src/pages/order/components/offlinePay/index.tsx
index 4022374..35bb7ff 100644
--- a/src/pages/order/components/offlinePay/index.tsx
+++ b/src/pages/order/components/offlinePay/index.tsx
@@ -17,7 +17,7 @@ export default memo(({show = true, onClose}:Param) => {
//复制功能
const clipboardData = () => {
Taro.setClipboardData({
- data: '开户名称:佛山市浩川盛世科技有限公司; 开户银行:招商银行汾江支行; 转账汇款账号:62062342120001221231212',
+ data: '开户名称:佛山市浩川盛世科技有限公司;\n\r 开户银行:招商银行汾江支行;\n\r 转账汇款账号:62062342120001221231212;',
success: function (res) {
Taro.showToast({
icon: 'none',
diff --git a/src/pages/sampleComparison/compoents/bluetooth/LinkBlueTooth.tsx b/src/pages/sampleComparison/compoents/bluetooth/LinkBlueTooth.tsx
new file mode 100644
index 0000000..3d36166
--- /dev/null
+++ b/src/pages/sampleComparison/compoents/bluetooth/LinkBlueTooth.tsx
@@ -0,0 +1,90 @@
+import { View } from "@tarojs/components";
+import { memo, useEffect, useMemo, useState } from "react";
+import Taro from "@tarojs/taro";
+import { useBluetooth } from "@/use/contextBlueTooth"
+import SearchInput from "@/components/searchInput";
+import Popup from "./Popup"
+import classnames from "classnames";
+import styles from "../../css/linkBlueTooth.module.scss"
+
+export default memo(() => {
+ const { state, init, startScan, connect, disconnect } = useBluetooth()
+
+ useEffect(() => {
+ init()
+ }, [])
+
+ const [linkStatus, setLinkStatus] = useState(1)
+ useEffect(() => {
+ if (!state.available) {
+ setLinkStatus(1)
+ } else if (state.available && state.connected?.name) {
+ setLinkStatus(3)
+ } else {
+ setLinkStatus(2)
+ }
+ console.log('aaa:::', state.connected)
+ }, [state.available, state.connected])
+
+ const linkName = useMemo(() => {
+ return state.connected?.localName || ''
+ }, [state.connected])
+
+ //链接设备
+ const onLinkListen = (item) => {
+ if (!state.connected && !state.connecting)
+ connect(item)
+ }
+
+ const [popupShow, setPopupShow] = useState(false)
+ //显示设备列表
+ const onFindDevice = () => {
+ if (linkStatus == 1) {
+ Taro.showToast({
+ title: '请打开蓝牙',
+ icon: 'none'
+ })
+ } else {
+ setPopupShow(true)
+ onFindEven()
+ }
+
+ }
+ const onFindEven = () => {
+ if (!state.discovering && !state.connected && !state.connecting)
+ startScan()
+ }
+
+ //断开链接
+ const onDisconnect = () => {
+ disconnect()
+ setPopupShow(false)
+ }
+
+ return (
+ <>
+
+
+
+
+ {
+ linkStatus == 1 && 请开启蓝牙 ||
+ linkStatus == 2 && 未连接设备 ||
+ linkStatus == 3 && {linkName}
+ }
+
+
+ setPopupShow(false)}
+ onLink={item => onLinkListen(item)}
+ onOff={onDisconnect}
+ onFind={onFindEven}
+ />
+
+ >
+
+ );
+
+})
diff --git a/src/pages/sampleComparison/compoents/bluetooth/Popup.tsx b/src/pages/sampleComparison/compoents/bluetooth/Popup.tsx
new file mode 100644
index 0000000..d8a9464
--- /dev/null
+++ b/src/pages/sampleComparison/compoents/bluetooth/Popup.tsx
@@ -0,0 +1,73 @@
+import { ScrollView, View } from "@tarojs/components"
+import { memo, useEffect, useState } from "react"
+import Loading from "@/components/loading"
+import style from "../../css/popup.module.scss"
+
+interface params {
+ state: any,
+ show: Boolean,
+ onClose: (Boolean) => void,
+ onLink: (any) => void,
+ children?: React.ReactNode
+ onOff: () => void,
+ onFind: () => void,
+}
+
+export default memo(({state, show=false, onClose, onLink, onOff, onFind}:params) => {
+ const [popupShow, setPopupShow] = useState(show)
+ useEffect(() => {
+ setPopupShow(show)
+ }, [show])
+ const onCloseListener = () => {
+ onClose(false)
+ }
+
+ return (
+ <>
+ {
+ popupShow&&
+
+ 搜索设备
+
+
+ {
+ (state.devices&&state.devices.length > 0)&&state?.devices.map(item => {
+ return (
+ onLink(item)}>
+ {item.name}
+ {
+ (!state.connecting&&!state.connected)&&链接||
+ (state.connecting&&item.deviceId == state.connecting.deviceId)&&正在链接...||
+ (state.connected&&item.deviceId == state.connected.deviceId)&&链接成功
+ }
+
+ )
+ })||
+
+ {
+ (!state.discovering)&& <>
+ 暂无设备,请按以下条件检查
+ 1.请确保取色仪处于激活状态
+ 2.请确保取色仪没有链接其他设备
+ 3.请打开手机定位
+ >||
+ 设备搜索中
+ }
+
+
+
+ }
+
+
+ {
+ state.connected&&断开链接||
+ (!state.connected&&state.discovering)&&搜索中||
+ 重新搜索
+ }
+
+
+
+ }
+ >
+ )
+})
\ No newline at end of file
diff --git a/src/pages/sampleComparison/css/linkBlueTooth.module.scss b/src/pages/sampleComparison/css/linkBlueTooth.module.scss
new file mode 100644
index 0000000..0714b46
--- /dev/null
+++ b/src/pages/sampleComparison/css/linkBlueTooth.module.scss
@@ -0,0 +1,42 @@
+.main {
+ width: 690px;
+ height: 86px;
+ background: #ffffff;
+ border-radius: 10px;
+ margin-top: 24px;
+ margin-left: 30px;
+
+ .bluetooth_link {
+ display: flex;
+ align-items: center;
+
+ .link_status {
+ width: 12px;
+ height: 12px;
+ background: #f02409;
+ border-radius: 50%;
+ }
+
+ .link_statused {
+ background: #07C160;
+ }
+
+ .link_statused_no {
+ background: #f0ec09;
+ }
+
+ .link_name {
+ font-size: $font_size;
+ margin-left: 20px;
+
+ }
+
+ .link_name_no {
+ color: #f02409;
+ }
+
+ .link_name_no_link {
+ color: #f0ec09;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/pages/sampleComparison/css/popup.module.scss b/src/pages/sampleComparison/css/popup.module.scss
new file mode 100644
index 0000000..d6c273f
--- /dev/null
+++ b/src/pages/sampleComparison/css/popup.module.scss
@@ -0,0 +1,90 @@
+.popup{
+ width: 100vw;
+ height: 100vh;
+ position: absolute;
+ top: 0;
+ left: 0;
+ .mask{
+ width: 100%;
+ height: 100%;
+ background-color: rgba(0,0,0,0.5);
+ position: fixed;
+ top:0;
+ left:0;
+ z-index: 9;
+ }
+ .content{
+ z-index: 99;
+ background-color: #fff;
+ width: 75vw;
+ height: 600px;
+ position: fixed;
+ top: 50%;
+ left: 50%;
+ border-radius: 20px;
+ transform: translateX(-50%) translateY(-50%);
+ display: flex;
+ flex-direction: column;
+ font-size: 28px;
+ .title{
+ text-align: center;
+ margin: 20px;
+ }
+ .list{
+ height: 480px;
+ padding: 0 20px;
+ .scroll{
+ height: 100%;
+ }
+ .item{
+ margin-bottom: 20px;
+ display: flex;
+ justify-content: space-between;
+ border-bottom: 1px dashed #ccc;
+ padding: 15px 0;
+ color: #3b3b3b;
+ @mixin link{
+ font-size: 25px;
+ }
+ .link_success{
+ @include link;
+ color: green;
+ }
+ .link_ing {
+ color: orange;
+ }
+ }
+ .noDevice{
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ color: #a8a8a8;
+ .n_item{
+ width: 100%;
+ text-align: left;
+ margin-top: 20px;
+ padding: 0 30px;
+ box-sizing: border-box;
+ }
+ }
+
+ }
+ .footer{
+ text-align: center;
+ padding: 20px 0;
+ background-color: #f1f1f1;
+ border-radius: 0 0 10px 10px;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ }
+ .finding{
+ color: orange;
+ }
+ .footer_off{
+ color: red;
+ }
+ }
+}
diff --git a/src/pages/sampleComparison/index.module.scss b/src/pages/sampleComparison/index.module.scss
index 210c3fa..e46e9fe 100644
--- a/src/pages/sampleComparison/index.module.scss
+++ b/src/pages/sampleComparison/index.module.scss
@@ -94,7 +94,21 @@ page {
font-family: Microsoft YaHei, Microsoft YaHei-Regular;
font-weight: 400;
color: #707070;
+
}
+
+ }
+
+ .color_bock {
+ width: 290px;
+ height: 290px;
+ border-radius: 50%;
+ }
+
+ .color_bocktwo {
+ width: 290px;
+ height: 290px;
+ border-radius: 50%;
}
.nameColor {
@@ -195,4 +209,45 @@ page {
margin-right: 37px;
}
}
+
+ .bottomBox {
+ position: fixed;
+ bottom: 0;
+ width: 750px;
+ height: 182px;
+ background: #f3f3f3;
+ box-shadow: 0px 0px 12px 0px rgba(0, 0, 0, 0.16);
+ overflow: hidden;
+ display: flex;
+
+ .leftBtn {
+ width: 264px;
+ height: 82px;
+ background: #ffffff;
+ border-radius: 42px;
+ font-size: 32px;
+ font-family: Microsoft YaHei, Microsoft YaHei-Regular;
+ font-weight: 400;
+ text-align: center;
+ color: #007aff;
+ line-height: 82px;
+ margin-top: 34px;
+ margin-left: 67px;
+ }
+
+ .rightBtn {
+ width: 264px;
+ height: 82px;
+ background: #007aff;
+ border-radius: 42px;
+ font-size: 32px;
+ font-family: Microsoft YaHei, Microsoft YaHei-Regular;
+ font-weight: 400;
+ text-align: center;
+ color: #ffffff;
+ line-height: 82px;
+ margin-top: 34px;
+ margin-left: 88px;
+ }
+ }
}
\ No newline at end of file
diff --git a/src/pages/sampleComparison/index.tsx b/src/pages/sampleComparison/index.tsx
index a71d7ab..6639e3a 100644
--- a/src/pages/sampleComparison/index.tsx
+++ b/src/pages/sampleComparison/index.tsx
@@ -1,14 +1,38 @@
import { Image, Text, Textarea, View } from "@tarojs/components"
import Taro, { useDidShow, usePullDownRefresh, useRouter } from "@tarojs/taro";
-import { useBluetooth } from "@/use/contextBlueTooth"
+import { useCallback, useEffect, useMemo, useRef, useState } from "react";
+import { useBluetooth } from "../../use/contextBlueTooth"
import classnames from "classnames";
+import LinkBlueTooth from "./compoents/bluetooth/LinkBlueTooth";
+import { toRgb } from '../../common/bluetooth/color/colorSpace'
import styles from './index.module.scss'
+import { productabsorbcontrast } from "@/api/mine"
export default () => {
+ //搜索参数
+ const [searchField, setSearchField] = useState({
+ l1: '',
+ a1: '',
+ b1: '',
+ l2: '',
+ a2: '',
+ b2: '',
+ })
+
+ const [colorList, setColorList] = useState({
+ one: null,
+ two: null
+ })
const { state: colorState, measureAndGetLab } = useBluetooth()
- const getLab = () => {
+
+ const getLab = async (val) => {
if (colorState.connected) {
- measureAndGetLab()
+ let res = await measureAndGetLab()
+ if (val === 1) {
+ setColorList({ ...colorList, one: res })
+ } else {
+ setColorList({ ...colorList, two: res })
+ }
} else {
Taro.showToast({
title: '请链接设备',
@@ -16,9 +40,84 @@ export default () => {
})
}
}
+ const getNowTime = () => {
+ const yy = new Date().getFullYear()
+ const MM = (new Date().getMonth() + 1) < 10 ? '0' + (new Date().getMonth() + 1) : (new Date().getMonth() + 1)
+ const dd = new Date().getDate() < 10 ? '0' + new Date().getDate() : new Date().getDate()
+ const HH = new Date().getHours() < 10 ? '0' + new Date().getHours() : new Date().getHours()
+ const mm = new Date().getMinutes() < 10 ? '0' + new Date().getMinutes() : new Date().getMinutes()
+ const ss = new Date().getSeconds() < 10 ? '0' + new Date().getSeconds() : new Date().getSeconds()
+ return yy + '-' + MM + '-' + dd + ' ' + HH + ':' + mm + ':' + ss
+ }
+ //监听lab数据变化
+ const [blueToothColor, setBlueToothColor] = useState('')
+ const [blueToothColorTwo, setBlueToothColorTwo] = useState('')
+ const [time, setTime] = useState('')
+ const [timeTwo, setTimeTwo] = useState('')
+ useEffect(() => {
+ if (colorState.deviceLab) {
+
+ if (colorList.one?.constructor === Object) {
+ const rgb = toRgb([colorList.one.L, colorList.one.a, colorList.one.b])
+ setBlueToothColor(`rgb(${rgb[0]}, ${rgb[1]}, ${rgb[2]})`)
+ setTime(getNowTime())
+ setSearchField({ ...searchField, l1: rgb[0], a1: rgb[1], b1: rgb[2] })
+ }
+ if (colorList.two?.constructor === Object) {
+ const rgb = toRgb([colorList.two.L, colorList.two.a, colorList.two.b])
+ setBlueToothColorTwo(`rgb(${rgb[0]}, ${rgb[1]}, ${rgb[2]})`)
+ setTimeTwo(getNowTime())
+ setSearchField({ ...searchField, l2: rgb[0], a2: rgb[1], b2: rgb[2] })
+ }
+ }
+ }, [colorList])
+ const reset = () => {
+ setBlueToothColor('')
+ setBlueToothColorTwo('')
+ setTime('')
+ setTime('')
+ setData('')
+ setResult('')
+ }
+ const [data, setData] = useState('')
+ const [result, setResult] = useState('')
+ const { fetchData } = productabsorbcontrast()
+ const handTake = async () => {
+ if (searchField.l1 === '') {
+ Taro.showToast({
+ title: '请填充基础样品',
+ icon: 'none'
+ })
+ return
+ }
+ if (searchField.l2 === '') {
+ Taro.showToast({
+ title: '请填充对比样品',
+ icon: 'none'
+ })
+ return
+ }
+ const query = {
+ ...searchField
+ }
+ const res = await fetchData(query)
+ if (res.data) {
+ setData(res.data)
+ let diffarray = [
+ res.data.reddish && "偏红",
+ res.data.yellowish && "偏黄",
+ res.data.greenish && "偏绿",
+ res.data.bluish && "偏蓝",
+ res.data.whitish && "偏亮",
+ res.data.darker && "偏暗",
+ ];
+ let resCont = diffarray.filter(item => item).join(",");
+ setResult(resCont)
+ }
+ }
return (
-
+ {/*
蓝牙设备
@@ -26,35 +125,82 @@ export default () => {
-
+ */}
+
- 对比样品
-
- 点击取色
-
- --
+ 基础样品
+ {
+ blueToothColor === '' &&
+ getLab(1)}>
+ 点击取色
+
+ }
+ {blueToothColor && getLab(1)} style={{ background: blueToothColor }}>
+
+ }
+ {
+ time === '' && --
+ }
+ {
+ time && {time}
+ }
对比样品
-
- 点击取色
-
- --
+ {
+ blueToothColorTwo === '' &&
+ getLab(2)}>
+ 点击取色
+
+ }
+ {blueToothColorTwo && getLab(2)} style={{ background: blueToothColorTwo }}>
+
+ }
+ {
+ timeTwo === '' && --
+ }
+ {
+ timeTwo && {timeTwo}
+ }
测量结果
- {/* 不合格 */}
- 合格
-
- {/* 暂无数据 */}
-
- 色差值: 0.2
- 无明显色差
+ {
+ (data as any).ciede_2000 >= 1 &&
+ 不合格
+ }
+ {
+ (data as any).ciede_2000 <= 1 &&
+ 合格
+ }
+
+ {
+ data === '' &&
+ 暂无数据
+ }
+ {
+ data &&
+
+ 色差值: {(data as any).ciede_2000}
+ {
+ !(data as any).reddish && !(data as any).yellowish && !(data as any).greenish && !(data as any).bluish && !(data as any).whitish && !(data as any).darker &&
+ 无明显色差
+ }
+ {
+ result &&
+ {result}
+ }
+
+ }
-
+
+ reset()}>重置
+ handTake()}>提交
+
+
)
}
\ No newline at end of file
diff --git a/src/pages/user/index.tsx b/src/pages/user/index.tsx
index 7c748b5..be206a9 100644
--- a/src/pages/user/index.tsx
+++ b/src/pages/user/index.tsx
@@ -7,8 +7,9 @@ import { alert, goLink } from "@/common/common";
import useLogin from '@/use/useLogin'
import { BASE_URL } from '@/common/constant'
import Taro from "@tarojs/taro";
-import { userassets } from "@/api/mine"
+import { userassets, userorderStatistics } from "@/api/mine"
import { formatPriceDiv } from "@/common/fotmat"
+import { useDidShow, } from '@tarojs/taro'
export default () => {
// 用户信息
const { getSelfUserInfo } = useLogin();
@@ -23,10 +24,14 @@ export default () => {
alert.none("授权失败,请授权后再使用");
});
}
- const { fetchData, state } = userassets()
+ const { fetchData: Apiassets, state } = userassets()
+ const { fetchData: ApigetTotal, state: stateData } = userorderStatistics()
useEffect(() => {
- fetchData();
+ Apiassets();
}, [])
+ useDidShow(() => {
+ ApigetTotal()
+ })
const checkGo = () => {
if (adminUserInfo?.authentication_status === 0 || adminUserInfo?.authentication_status === 1 || adminUserInfo?.authentication_status === 2 || adminUserInfo?.authentication_status === 3) {
Taro.showModal({
@@ -50,7 +55,7 @@ export default () => {
}
return (
-
+
checkGo()} />
{/* {(adminUserInfo as any)?.authentication_status==1&&} */}
@@ -91,6 +96,7 @@ const Modal = memo((props: any) => {
// 头部 | 订单
const Header = memo((props: any) => {
const { data } = props;
+ console.log(props, 'propsprops')
let menu = [{ text: "待配布", icon: "icon-daipeibu", url: "/pages/orderList/index" }, { text: "待付款", icon: "icon-daifukuan", url: "/pages/orderList/index" },
{ text: "待发货", icon: "icon-daifahuo", url: "/pages/orderList/index" }, { text: "已发货", icon: "icon-yifahuo", url: "/pages/orderList/index" },
{ text: "退款/售后", icon: "icon-a-tuikuanshouhou", url: "/pages/salesAfterList/index" }];
@@ -224,7 +230,37 @@ const Header = memo((props: any) => {
{item.text}
- {index == 2 ? "99+" : 10}
+ {
+ index == 0 && props.MenuData.data.wait_match !== 0 &&
+
+ {props.MenuData.data.wait_match > 99 ? '99+' : props.MenuData.data.wait_match}
+
+ }
+ {
+ index == 1 && props.MenuData.data.wait_pay !== 0 &&
+
+ {props.MenuData.data.wait_pay > 99 ? '99+' : props.MenuData.data.wait_pay}
+
+ }
+ {
+ index == 2 && props.MenuData.data.wait_shipped !== 0 &&
+
+ {props.MenuData.data.wait_shipped > 99 ? '99+' : props.MenuData.data.wait_shipped}
+
+ }
+ {
+ index == 3 && props.MenuData.data.already_shipped !== 0 &&
+
+ {props.MenuData.data.already_shipped > 99 ? '99+' : props.MenuData.data.already_shipped}
+
+ }
+ {
+ index == 4 && props.MenuData.data.after_return !== 0 &&
+
+ {props.MenuData.data.after_return > 99 ? '99+' : props.MenuData.data.after_return}
+
+ }
+
)
})
@@ -271,7 +307,7 @@ const Assets = (props: any) => {
// 功能
const Main = memo(() => {
- let menu = [{ text: "地址管理", icon: "icon-shoucang", url: "/pages/addressManager/index" }, { text: "码单管理", icon: "icon-shoucang", url: "/pages/weightList/index" },
+ let menu = [{ text: "地址管理", icon: "icon-daohang", url: "/pages/addressManager/index" }, { text: "码单管理", icon: "icon-a-yuanmadanmadanguanli", url: "/pages/weightList/index" },
{ text: "我的收藏", icon: "icon-shoucang" }, { text: "颜色对比", icon: "icon-yanseduibi", url: "/pages/sampleComparison/index" },
{ text: "分享推广", icon: "icon-fenxiang" }, { text: "团队邀请", icon: "icon-yaoqingtuandui" }]
return (
diff --git a/src/use/BlueToothCopy.tsx b/src/use/BlueToothCopy.tsx
new file mode 100644
index 0000000..0d07766
--- /dev/null
+++ b/src/use/BlueToothCopy.tsx
@@ -0,0 +1,477 @@
+import React, {useRef, useState } from "react"
+import Taro from "@tarojs/taro";
+import { Command } from "@/common/bluetooth/command";
+import { uint8ArrayToFloat32, uint8ArrayToHex, waitFor } from "@/common/bluetooth/utils";
+
+
+interface params {
+ init: () => void
+ state: Object,
+ startScan: () => void,
+ measureAndGetLab: () => any,
+ getAdapterState: () => void,
+ connect: (any) => void,
+ disconnect: () => void
+}
+const Context = React.createContext(null)
+
+interface stateStype {
+ listeners: any,
+ discovering: boolean,
+ available: boolean,
+ connected: any,
+ connecting: any,
+ serviceRule: any,
+ serviceId: any,
+ characteristicRule: any,
+ characteristicId: any,
+
+ /** 正在执行的命令 */
+ command: any,
+ responseResolve: any,
+ responseReject: any,
+ responseTimer: any,
+
+ /** 是否显示蓝牙调试信息 */
+ debug: any,
+ //搜索到的设备
+ devices: any,
+ //取色仪主动返回的数据
+ deviceLab: any
+}
+
+let stateObj: stateStype = {
+ /** 事件监听器 */
+ listeners: new Set(),
+ /** 正在扫描设备 */
+ discovering: false,
+ /** 蓝牙是否可用 */
+ available: true,
+ /** 当前连接的设备 */
+ connected: null,
+ /** 正在连接的设备 */
+ connecting: null,
+
+ serviceRule: /^0000FFE0/,
+ serviceId: null,
+ characteristicRule: /^0000FFE1/,
+ characteristicId: null,
+
+ /** 正在执行的命令 */
+ command: null,
+ responseResolve: null,
+ responseReject: null,
+ responseTimer: null,
+
+ /** 是否显示蓝牙调试信息 */
+ debug: true,
+ //搜索到的设备
+ devices: [],
+ //取色仪主动返回的数据
+ deviceLab: null
+}
+
+export default (props) => {
+ let refStatus = useRef(stateObj)
+ let [state, setState] = useState(refStatus.current)
+
+ const changeStatus = (obj:Object): void => {
+ refStatus.current = {...refStatus.current, ...obj}
+ setState({...refStatus.current})
+ }
+
+ const init = async () => {
+ try{
+ await openAdapter();
+ }catch(e) {
+ changeStatus({available:false})
+ }
+
+ // 绑定事件通知
+ Taro.onBluetoothAdapterStateChange(res => {
+ emit({ type: 'stateUpdate', detail: res });
+ });
+ Taro.onBLEConnectionStateChange(res => {
+ emit({ type: res.connected ? 'connected' : 'disconnect', detail: res });
+ });
+ Taro.onBLECharacteristicValueChange(({ value }) => notifySubscriber(value));
+ subscribe(async ev => {
+ if (ev.type === 'stateUpdate') {
+ // 蓝牙状态发生的变化
+ changeStatus({discovering:ev.detail.discovering, available:ev.detail.available})
+ } else if (ev.type === 'disconnect' && refStatus.current.connected && refStatus.current.connected.deviceId === ev.detail.deviceId) {
+ // 断开连接
+ changeStatus({
+ connected:null,
+ serviceId:null,
+ characteristicId:null,
+ deviceLab:null,
+ devices:[]
+ })
+ Taro.showToast({ icon: 'none', title: '蓝牙连接已断开' });
+ } else if (ev.type === 'connected' && refStatus.current.connecting) {
+ // 连接成功
+ changeStatus({connected: refStatus.current.connecting, connecting: null})
+ Taro.showToast({ title: '蓝牙已连接' });
+ } else if (ev.type === 'measure') {
+ //监听取色仪主动推送lab
+ await measureAndGetLab()
+ }
+
+ });
+ }
+
+ /** 打开蓝牙适配器 */
+ const openAdapter = () => {
+ return new Promise((resolve, reject) => {
+ Taro.openBluetoothAdapter({
+ success: resolve,
+ fail: reject
+ });
+ });
+ }
+
+ /**
+ * 推送事件
+ * @param {{type: string; data: any}} event
+ */
+ const emit = (event) => {
+ refStatus.current.listeners.forEach(cb => {
+ cb && cb(event);
+ });
+ }
+
+ const subscribe = (cb) => {
+ if (cb) {
+ changeStatus({
+ listeners: refStatus.current.listeners.add(cb)
+ })
+ }
+ }
+
+ /**
+ * 获取蓝牙适配器状态
+ * @returns {Promise<{discovering: boolean; available: boolean}>}
+ */
+ const getAdapterState = () => {
+ return new Promise((resolve, reject) => {
+ Taro.getBluetoothAdapterState({
+ success: resolve,
+ fail: reject
+ })
+ })
+ }
+
+ /**
+ * 启动设备扫描
+ * @param {(res: { devices: { name: string, deviceId: string, RSSI: number }[] }) => void} cb
+ * @param {number} duration
+ */
+ const startScan = (duration = 30000) => {
+ console.log('开始寻找')
+ changeStatus({devices:[]})
+ Taro.onBluetoothDeviceFound(getDevices);
+ return new Promise((resolve, reject) => {
+ Taro.startBluetoothDevicesDiscovery({
+ allowDuplicatesKey: true,
+ success: resolve,
+ fail: reject
+ });
+
+ if (duration > 0) {
+ setTimeout(() => {
+ Taro.offBluetoothDeviceFound(getDevices);
+ Taro.stopBluetoothDevicesDiscovery();
+ console.log("停止搜索")
+ }, duration);
+ }
+ });
+ }
+
+ //获取搜索到的设备
+ const getDevices = (res) => {
+ res.devices.forEach(device => {
+ // 排除掉已搜索到的设备和名称不合法的设备, 将新发现的设备添加到列表中
+ if (/^CM/.test(device.name) && !refStatus.current.devices.find(i => i.deviceId === device.deviceId)) {
+ changeStatus({devices: [ ...refStatus.current.devices, device ]})
+ }
+ });
+ }
+
+ /**
+ * 连接设备
+ * @param {{ name: string, deviceId: string, RSSI: number }} device
+ */
+ const connect = async (device) => {
+ try {
+ changeStatus({connecting: device})
+ console.log('connecting::', device)
+ await createConnection(device.deviceId);
+ await discoverService(device.deviceId);
+ await discoverCharacteristic(device.deviceId);
+ await notifyCharacteristicValueChange(device.deviceId);
+ } catch (e) {
+ changeStatus({connecting: null})
+ Taro.showToast({ icon: 'none', title: '蓝牙连接失败' });
+ throw e;
+ }
+ }
+
+ /** 断开当前连接的设备 */
+ const disconnect = async () => {
+ if (!refStatus.current.connected && !refStatus.current.connecting) return;
+ if (refStatus.current.connected) {
+ await closeConnection(refStatus.current.connected.deviceId);
+ resetCommand();
+ changeStatus({
+ connected: null,
+ serviceId: null,
+ characteristicId: null,
+ devices: [],
+ deviceLab: null
+ })
+ }
+
+ if (refStatus.current.connecting) {
+ await closeConnection(refStatus.current.connecting.deviceId);
+ changeStatus({connecting:null})
+ }
+ }
+
+ /** 创建 BLE 连接 */
+ function createConnection(deviceId) {
+ return new Promise((resolve, reject) => {
+ Taro.createBLEConnection({
+ deviceId,
+ timeout: 2000,
+ success: resolve,
+ fail: reject
+ });
+ });
+ }
+
+ /** 关闭 BLE 连接 */
+ function closeConnection(deviceId) {
+ return new Promise((resolve, reject) => {
+ Taro.closeBLEConnection({
+ deviceId,
+ success: resolve,
+ fail: reject
+ });
+ });
+ }
+
+ /** 搜索服务 */
+ function discoverService(deviceId) {
+ return new Promise((resolve, reject) => {
+ Taro.getBLEDeviceServices({
+ deviceId,
+ success: ({ services }) => {
+ const service = services.find(i => refStatus.current.serviceRule.test(i.uuid));
+ if (!service) {
+ reject(new Error('服务不可用'));
+ } else {
+ changeStatus({serviceId: service.uuid})
+ resolve(service);
+ }
+ },
+ fail: reject
+ });
+ });
+ }
+
+ /** 搜索特征 */
+ function discoverCharacteristic(deviceId) {
+ return new Promise((resolve, reject) => {
+ Taro.getBLEDeviceCharacteristics({
+ deviceId,
+ serviceId: refStatus.current.serviceId,
+ success: ({ characteristics }) => {
+ const characteristic = characteristics.find(i => refStatus.current.characteristicRule.test(i.uuid));
+ if (!characteristic) {
+ reject(new Error('特征不可用'));
+ } else {
+ changeStatus({characteristicId: characteristic.uuid})
+ resolve(characteristic);
+ }
+ },
+ fail: reject
+ })
+ });
+ }
+
+ /** 启动特征通知 */
+ function notifyCharacteristicValueChange(deviceId, stateParm = true) {
+ return new Promise((resolve, reject) => {
+ Taro.notifyBLECharacteristicValueChange({
+ deviceId,
+ serviceId: refStatus.current.serviceId,
+ characteristicId: refStatus.current.characteristicId,
+ state:stateParm,
+ success: resolve,
+ fail: reject
+ });
+ });
+ }
+
+ /**
+ * 通知订阅器
+ * @param {ArrayBuffer} buffer
+ */
+ function notifySubscriber(buffer) {
+ if (refStatus.current.command) {
+ if (refStatus.current.debug) {
+ console.log(`[BLE RESP] ${uint8ArrayToHex(new Uint8Array(buffer))}`);
+ }
+ refStatus.current.command.fillResponse(buffer);
+ if (refStatus.current.command.isComplete) {
+ if (refStatus.current.command.isValid && refStatus.current.responseResolve) {
+ refStatus.current.responseResolve(refStatus.current.command.response);
+ } else if (!refStatus.current.command.isValid) {
+ refStatus.current.responseReject(new Error('无效数据'));
+ }
+ resetCommand();
+ }
+ } else {
+ const uint8Array = new Uint8Array(buffer);
+ if (uint8Array[0] === 0xbb && uint8Array[1] === 1 && uint8Array[3] === 0) {
+ const ev = { type: 'measure', detail: { mode: uint8Array[2] } };
+ emit(ev);
+ }
+ }
+ }
+
+ /**
+ * 发送命令
+ * @param {Command}} command
+ * @returns {Promise}
+ */
+ function exec(command) {
+ return new Promise(async (resolve, reject) => {
+ if (refStatus.current.command) {
+ reject(new Error('正在执行其他命令'));
+ } else {
+ try {
+ refStatus.current.command = command;
+ const data = command.data;
+ for (let i = 0; i < data.length; i++) {
+ await sendData(data[i]);
+ }
+
+ if (command.responseSize <= 0) {
+ resolve(true);
+ resetCommand();
+ } else {
+ refStatus.current.responseReject = reject;
+ refStatus.current.responseResolve = resolve;
+ refStatus.current.responseTimer = setTimeout(() => {
+ reject(new Error('命令响应超时'));
+ resetCommand();
+ }, command.timeout);
+ }
+ } catch (e) {
+ reject(e);
+ }
+ }
+
+ });
+ }
+
+ /**
+ * 发送命令
+ * @param {ArrayBuffer} buffer
+ */
+ function sendData(buffer) {
+ if (refStatus.current.debug) {
+ console.log(`[BLE SEND] ${uint8ArrayToHex(new Uint8Array(buffer))}`);
+ }
+ return new Promise((resolve, reject) => {
+ console.log('current:::',refStatus.current)
+ Taro.writeBLECharacteristicValue({
+ deviceId: refStatus.current.connected.deviceId,
+ serviceId: refStatus.current.serviceId,
+ characteristicId: refStatus.current.characteristicId,
+ value: buffer,
+ success: resolve,
+ fail: reject
+ })
+ });
+ }
+
+ function resetCommand() {
+ if (refStatus.current.responseTimer) {
+ clearTimeout(refStatus.current.responseTimer);
+ }
+ changeStatus({
+ command: null,
+ responseResolve: null,
+ responseReject: null,
+ responseTimer: null
+ })
+ }
+
+ /**
+ * 测量
+ * @param {number} mode
+ * @returns {Promise}
+ */
+ async function measure (mode = 0) {
+ console.log('current1:::',Command.WakeUp)
+ await exec(Command.WakeUp);
+ console.log('current2:::',Command.WakeUp)
+ await waitFor(50);
+ console.log('current3:::',Command.WakeUp)
+ return await exec(Command.measure(mode));
+ }
+
+ /**
+ * 获取测量的 lab 值
+ * @param {number} mode
+ * @returns {Promise<{ L: number, a: number, b: number }>}
+ */
+ async function getLab(mode = 0) {
+ await exec(Command.WakeUp);
+ await waitFor(50);
+ const data: any = await exec(Command.getLab(mode));
+ return {
+ L: uint8ArrayToFloat32(data.slice(5, 9)),
+ a: uint8ArrayToFloat32(data.slice(9, 13)),
+ b: uint8ArrayToFloat32(data.slice(13, 17)),
+ };
+ }
+
+ /**
+ * 测量并获取 lab 值
+ * @param {number} mode
+ * @returns {Promise<{L: number, a: number, b: number}>}
+ */
+ async function measureAndGetLab(mode = 0) {
+ await measure(mode);
+ await waitFor(50);
+ const lab = await getLab(mode);
+ console.log('lab2::',lab)
+ changeStatus({deviceLab:lab})
+ return lab
+ }
+
+ return
+}
+
+
+export const useBluetoothTwo = () => {
+ const res = React.useContext(Context)
+ if(res) {
+ return {...res}
+ } else {
+ return {}
+ }
+
+}
\ No newline at end of file