LiLongLong 5 months ago
parent
commit
922586504c
  1. BIN
      public/audio/begin_left.mp3
  2. BIN
      public/audio/begin_right.mp3
  3. BIN
      public/audio/end_left.mp3
  4. BIN
      public/audio/end_right.mp3
  5. 6
      src/App.tsx
  6. 1
      src/assets/icon_battery.svg
  7. 127
      src/components/Header.tsx
  8. 40
      src/pages/measure/components/MeasureAction.tsx
  9. 5
      src/pages/measure/components/MeasureConfig.tsx
  10. 63
      src/services/wsTypes.ts
  11. 8
      src/store/device/deviceState.ts
  12. 16
      src/store/features/contextSlice.ts

BIN
public/audio/begin_left.mp3

BIN
public/audio/begin_right.mp3

BIN
public/audio/end_left.mp3

BIN
public/audio/end_right.mp3

6
src/App.tsx

@ -10,6 +10,7 @@ import { createWebSocket, sharedWsUrl } from "./services/socket";
import { useAppDispatch } from "./utils/hooks"; import { useAppDispatch } from "./utils/hooks";
import { updateDeviceState } from "./store/device/deviceState"; import { updateDeviceState } from "./store/device/deviceState";
import zhCN from 'antd/lib/locale/zh_CN'; // 引入中文语言包 import zhCN from 'antd/lib/locale/zh_CN'; // 引入中文语言包
import { updateDevice } from "./store/features/contextSlice";
const { Header, Footer, Sider, Content } = Layout; const { Header, Footer, Sider, Content } = Layout;
function App() { function App() {
@ -27,8 +28,11 @@ function App() {
// } else { // } else {
// navigate("/login"); // navigate("/login");
// } // }
} else if (data.messageType === "STATE") {
} else if (data.messageType === "STATE" && data.path === "/subdevice/uartchanel/get-channel-state") {
dispatch(updateDeviceState(data.data)); dispatch(updateDeviceState(data.data));
} else if (data.messageType === "STATE" && data.path === "/profiler-state/get-state") {
// console.log(data.data);
dispatch(updateDevice(data.data));
} }
}); });
wsClient.connect(); wsClient.connect();

1
src/assets/icon_battery.svg

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="60" height="30" viewBox="0 0 60 30"><g><path d="M57.8572,8.85957L57.1875,8.85957L57.1875,2.04255C57.1875,0.914483,56.2281,0,55.0446,0L2.14286,0C0.95939,0,0,0.914483,0,2.04255L0,27.9574C0,29.0855,0.95939,30,2.14286,30L55.0446,30C56.2281,30,57.1875,29.0855,57.1875,27.9574L57.1875,21.1404L57.8572,21.1404C59.0406,21.1404,60,20.2259,60,19.0979L60,10.9021C60,9.77406,59.0406,8.85957,57.8572,8.85957ZM52.3661,25.4043L4.82143,25.4043L4.82143,4.59574L52.3661,4.59574L52.3661,25.4043Z" fill="#2759C2" fill-opacity="1" style="mix-blend-mode:passthrough"/></g></svg>

127
src/components/Header.tsx

@ -2,6 +2,7 @@ import { useSelector } from "react-redux";
import bluetooth_nc from "../assets/bluetooth_nc.svg"; import bluetooth_nc from "../assets/bluetooth_nc.svg";
import bluetooth_c from "../assets/bluetooth_c.svg"; import bluetooth_c from "../assets/bluetooth_c.svg";
import icon_usb from "../assets/icon_usb.svg"; import icon_usb from "../assets/icon_usb.svg";
import icon_battery from "../assets/icon_battery.svg";
import icon_avatar from "../assets/icon_avatar.svg"; import icon_avatar from "../assets/icon_avatar.svg";
import icon_logout from "../assets/icon_logout.svg"; import icon_logout from "../assets/icon_logout.svg";
import check_mark from "../assets/check_mark.svg"; import check_mark from "../assets/check_mark.svg";
@ -9,24 +10,27 @@ import { useState, useEffect } from "react";
import { Dropdown, MenuProps, message, Button, Popover } from "antd"; import { Dropdown, MenuProps, message, Button, Popover } from "antd";
import { logout } from "../services/user/user"; import { logout } from "../services/user/user";
import { useNavigate } from "react-router"; import { useNavigate } from "react-router";
import { useAppDispatch } from "../utils/hooks";
import { useAppDispatch, useAppSelector } from "../utils/hooks";
import { updateUser } from "../store/features/contextSlice"; import { updateUser } from "../store/features/contextSlice";
import "./bluetooth.scss"; import "./bluetooth.scss";
import { loginUser } from '../services/wsTypes';
import { loginUser } from "../services/wsTypes";
export default function Header() { export default function Header() {
const navigate = useNavigate(); const navigate = useNavigate();
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
//@ts-ignoref
const deviceState = useSelector(store => store.deviceState);
let [isConnect, setIsConnect] = useState(deviceState.isConnect)//
const [bluetoothInfo, setBluetoothInfo] = useState(deviceState)
const deviceInfo = useAppSelector(store => store.context.device);
const deviceState = useAppSelector(store => store.deviceState);
let [isConnect, setIsConnect] = useState(true);
const [bluetoothInfo, setBluetoothInfo] = useState(deviceState);
//获取当前websocet的状态 //获取当前websocet的状态
const showBlueImg = () => { const showBlueImg = () => {
if (isConnect) { if (isConnect) {
return <Popover content={getBtContent()} title="">
<img src={icon_usb} onClick={onDisconnectBt} alt="" className="ext-base ml-2 h-6" />
return (
<Popover content={getBtContent()} title="">
<section className="bg-white rounded-md h-9 w-10 flex justify-center items-center mr-3">
<img src={icon_usb} alt="" className="h-6" />
</section>
</Popover> </Popover>
);
} }
return null; return null;
// if(!isConnect){ // if(!isConnect){
@ -39,16 +43,19 @@ export default function Header() {
// <img src={icon_usb} onClick={onDisconnectBt} alt="" className="ext-base ml-2 h-6" /> // <img src={icon_usb} onClick={onDisconnectBt} alt="" className="ext-base ml-2 h-6" />
// </Popover> // </Popover>
// } // }
}
};
let list = [{
name:'Kdkow_1',
id:'1',
},{
name:'llwoa_2',
id:'2',
}]
let [bluetoothList, setbluetoothList] = useState(list)
let list = [
{
name: "Kdkow_1",
id: "1",
},
{
name: "llwoa_2",
id: "2",
},
];
let [bluetoothList, setbluetoothList] = useState(list);
//获取mock数据 //获取mock数据
useEffect(() => { useEffect(() => {
// getDeviceInfo().then(res => { // getDeviceInfo().then(res => {
@ -57,20 +64,20 @@ export default function Header() {
// setbluetoothList(res.data.list) // setbluetoothList(res.data.list)
// }) // })
if (context.user.loginUser && context.user.loginUser.nickName) { if (context.user.loginUser && context.user.loginUser.nickName) {
setNickname(context.user.loginUser.nickName)
setNickname(context.user.loginUser.nickName);
} else { } else {
const user = localStorage.getItem('user')
const user = localStorage.getItem("user");
if (user) { if (user) {
let userData = JSON.parse( user || '')
setNickname(userData.nickname)
let userData = JSON.parse(user || "");
setNickname(userData.nickname);
} }
} }
})
});
//@ts-ignore //@ts-ignore
const context = useSelector(store => store.context); const context = useSelector(store => store.context);
const [messageApi, contextHolder] = message.useMessage(); const [messageApi, contextHolder] = message.useMessage();
const [nickname, setNickname] = useState()
const [nickname, setNickname] = useState();
const items: MenuProps["items"] = [ const items: MenuProps["items"] = [
// { // {
// key: "1", // key: "1",
@ -87,38 +94,44 @@ export default function Header() {
onClick: () => { onClick: () => {
logout({}).then(res => { logout({}).then(res => {
if (res.status !== 0) { if (res.status !== 0) {
messageApi.error(res.data.info)
messageApi.error(res.data.info);
} else { } else {
localStorage.setItem('user','')
dispatch(updateUser({
localStorage.setItem("user", "");
dispatch(
updateUser({
loginFlag: false, loginFlag: false,
loginUser:{}
}));
navigate("/login");
}
loginUser: {},
}) })
);
navigate("/login");
} }
});
},
}, },
]; ];
const getBtList = () => { const getBtList = () => {
let Dom = null
let Dom = null;
if (!isConnect) { if (!isConnect) {
Dom = <div>
Dom = (
<div>
{bluetoothList.map(item => { {bluetoothList.map(item => {
return <div className="mt-[1rem]" onClick={connectBt}>
return (
<div className="mt-[1rem]" onClick={connectBt}>
<Button type="link">{item.name}</Button> <Button type="link">{item.name}</Button>
</div> </div>
);
})} })}
</div> </div>
);
} }
return Dom
}
return Dom;
};
//设备已连接 //设备已连接
const getBtContent = () => { const getBtContent = () => {
return <div>
return (
<div>
<div> <div>
<div className="bluetooth_c"> <div className="bluetooth_c">
<img src={check_mark} alt="" className="ext-base ml-2 h-4" /> <img src={check_mark} alt="" className="ext-base ml-2 h-4" />
@ -131,31 +144,41 @@ export default function Header() {
</div> </div>
</div> </div>
</div> </div>
}
);
};
//断开蓝牙连接 //断开蓝牙连接
const onDisconnectBt = () => { const onDisconnectBt = () => {
setIsConnect(false)
}
setIsConnect(false);
};
const connectBt = () => { const connectBt = () => {
setIsConnect(true)
setTimeout(()=>{
},1000)
}
setIsConnect(true);
setTimeout(() => {}, 1000);
};
return ( return (
<> <>
{contextHolder} {contextHolder}
<div className="bg-[--bgColor] h-full flex items-center"> <div className="bg-[--bgColor] h-full flex items-center">
<div className="ml-auto mr-8 flex items-center">
<div className="ml-auto mr-8 flex items-center w-[5rem]">
<section className="ml-auto rounded-md h-9 mr-4 flex items-center bg-white gap-2 pl-4">
<span className="w-[94px]">{deviceInfo.temperature.toFixed(1)} </span>
<span className="w-[120px]">X轴倾斜{deviceInfo.inclinatorX}</span>
<span className="w-[120px]">Y轴倾斜{deviceInfo.inclinatorY}</span>
</section>
<section className="bg-white rounded-md h-9 w-12 relative mr-3 flex justify-center items-center">
<img
src={icon_battery}
className="absolute h-8 w-10 left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2"
alt=""
/>
<p className="text-primary text-xs">{deviceInfo.power.toFixed()}%</p>
</section>
{/* <section className="bg-white rounded-md h-9 w-10 flex justify-center items-center mr-3">
<img src={icon_usb} className="w-6" alt="icon" />
</section> */}
{showBlueImg()} {showBlueImg()}
</div>
<div className="mr-8 flex items-center min-w-[5rem]">
<Dropdown menu={{ items }} trigger={["click"]}> <Dropdown menu={{ items }} trigger={["click"]}>
<section className="flex items-center"> <section className="flex items-center">
<img src={icon_avatar} alt="" className="h-8" /> <img src={icon_avatar} alt="" className="h-8" />

40
src/pages/measure/components/MeasureAction.tsx

@ -199,21 +199,61 @@ export default function MeasureAction() {
case "START_RECORD_LEFT": case "START_RECORD_LEFT":
updated[0].color = "g"; updated[0].color = "g";
updated[1].color = "b"; updated[1].color = "b";
const audio1 = new Audio("/audio/begin_left.mp3");
// 播放音频
audio1
.play()
.then(() => {
console.log("音频开始播放");
})
.catch(err => {
console.error("播放音频时出错:", err);
});
break; break;
case "FINISH_RECORD_LEFT": case "FINISH_RECORD_LEFT":
updated[1].color = "g"; updated[1].color = "g";
updated[2].color = "g"; updated[2].color = "g";
updated[3].color = "b"; updated[3].color = "b";
isLeftFinished.current = true; isLeftFinished.current = true;
const audio2 = new Audio("/audio/end_left.mp3");
// 播放音频
audio2
.play()
.then(() => {
console.log("音频开始播放");
})
.catch(err => {
console.error("播放音频时出错:", err);
});
break; break;
case "START_RECORD_RIGHT": case "START_RECORD_RIGHT":
updated[3].color = "g"; updated[3].color = "g";
updated[4].color = "b"; updated[4].color = "b";
const audio3 = new Audio("/audio/begin_right.mp3");
// 播放音频
audio3
.play()
.then(() => {
console.log("音频开始播放");
})
.catch(err => {
console.error("播放音频时出错:", err);
});
break; break;
case "FINISH_RECORD_RIGHT": case "FINISH_RECORD_RIGHT":
updated[4].color = "g"; updated[4].color = "g";
updated[5].color = "g"; updated[5].color = "g";
setMeasurementFinished(true); setMeasurementFinished(true);
const audio4 = new Audio("/audio/end_right.mp3");
// 播放音频
audio4
.play()
.then(() => {
console.log("音频开始播放");
})
.catch(err => {
console.error("播放音频时出错:", err);
});
break; break;
default: default:
break; break;

5
src/pages/measure/components/MeasureConfig.tsx

@ -42,12 +42,13 @@ export default function MeasureConfig() {
useEffect(() => { useEffect(() => {
form.setFieldsValue({ form.setFieldsValue({
username: userInfo.nickname || "", username: userInfo.nickname || "",
direction: "左"
}); });
}, [userInfo.nickname, form]); }, [userInfo.nickname, form]);
return ( return (
<> <>
{contextHolder} {contextHolder}
{/* <div>width: {window.innerWidth} height: {window.innerHeight}</div> */}
<div className="h-full flex justify-center items-center"> <div className="h-full flex justify-center items-center">
<Form <Form
form={form} form={form}
@ -96,7 +97,7 @@ export default function MeasureConfig() {
{/* <Input /> */} {/* <Input /> */}
<Select <Select
className="w-[5rem]" className="w-[5rem]"
defaultValue="左"
// defaultValue="左"
options={[ options={[
{ value: '左', label: '左侧' }, { value: '左', label: '左侧' },
{ value: '右', label: '右侧' }, { value: '右', label: '右侧' },

63
src/services/wsTypes.ts

@ -1,7 +1,17 @@
// 开始、停止绘制 // 开始、停止绘制
export type TaskState = { export type TaskState = {
messageType: "EVENT"; messageType: "EVENT";
data: "START_RECORD_SIG" | "END_RECORD_SIG" | "FINISHED" | "START_RECORD_LEFT" | "FINISH_RECORD_RIGHT" | "FINISH_RECORD" | "FINISH_RECORD_LEFT" | "END_RECORD_SIG" | "END_RECORD" | "START_RECORD_RIGHT";
data:
| "START_RECORD_SIG"
| "END_RECORD_SIG"
| "FINISHED"
| "START_RECORD_LEFT"
| "FINISH_RECORD_RIGHT"
| "FINISH_RECORD"
| "FINISH_RECORD_LEFT"
| "END_RECORD_SIG"
| "END_RECORD"
| "START_RECORD_RIGHT";
// data: { // data: {
// event: "START_RECORD_SIG" | "END_RECORD_SIG" | "FINISHED" | "START_RECORD_LEFT" | "FINISH_RECORD_RIGHT" | "FINISH_RECORD" | "FINISH_RECORD_LEFT" | "END_RECORD_SIG" | "END_RECORD" | "START_RECORD_RIGHT"; // event: "START_RECORD_SIG" | "END_RECORD_SIG" | "FINISHED" | "START_RECORD_LEFT" | "FINISH_RECORD_RIGHT" | "FINISH_RECORD" | "FINISH_RECORD_LEFT" | "END_RECORD_SIG" | "END_RECORD" | "START_RECORD_RIGHT";
// }; // };
@ -47,11 +57,11 @@ export type ContextMessage = {
}; };
export type loginUser = Partial<{ export type loginUser = Partial<{
id: 3, //数据主键id
account: "test001", //用户账户
nickname: "测试账户001", //用户昵称
userRole: "User", //用户角色,可用值:User,Admin,Dev
isBuiltInUser: false, //是否内置用户(内置用户不可删除)
id: 3; //数据主键id
account: "test001"; //用户账户
nickname: "测试账户001"; //用户昵称
userRole: "User"; //用户角色,可用值:User,Admin,Dev
isBuiltInUser: false; //是否内置用户(内置用户不可删除)
}>; }>;
export const taskStatusDescMap: { [k in MeasureState["data"]["taskStatus"]]: string } = { export const taskStatusDescMap: { [k in MeasureState["data"]["taskStatus"]]: string } = {
@ -59,19 +69,30 @@ export const taskStatusDescMap: { [k in MeasureState["data"]["taskStatus"]]: str
MEASURING: "测量中", MEASURING: "测量中",
WAITING_FOR_MEASURING: "等待测量", WAITING_FOR_MEASURING: "等待测量",
FINISHED: "测量完成", FINISHED: "测量完成",
START_RECORD_LEFT: '',
FINISH_RECORD_RIGHT: '',
FINISH_RECORD:'',
FINISH_RECORD_LEFT: '',
END_RECORD_SIG: '',
END_RECORD: '',
START_RECORD_RIGHT : ''
START_RECORD_LEFT: "",
FINISH_RECORD_RIGHT: "",
FINISH_RECORD: "",
FINISH_RECORD_LEFT: "",
END_RECORD_SIG: "",
END_RECORD: "",
START_RECORD_RIGHT: "",
}; };
// 测量任务状态 // 测量任务状态
export type MeasureState = { export type MeasureState = {
messageType: "STATE"; messageType: "STATE";
data: { data: {
taskStatus: "IDLE" | "MEASURING" | "WAITING_FOR_MEASURING" | "FINISHED" | "START_RECORD_LEFT" | "FINISH_RECORD_RIGHT" | "FINISH_RECORD" | "FINISH_RECORD_LEFT" | "END_RECORD_SIG" | "END_RECORD" | "START_RECORD_RIGHT";
taskStatus:
| "IDLE"
| "MEASURING"
| "WAITING_FOR_MEASURING"
| "FINISHED"
| "START_RECORD_LEFT"
| "FINISH_RECORD_RIGHT"
| "FINISH_RECORD"
| "FINISH_RECORD_LEFT"
| "END_RECORD_SIG"
| "END_RECORD"
| "START_RECORD_RIGHT";
measureSideCnt: 0 | 1 | 2; //已测量数量,0,1,2 最多两边(左边和右边) measureSideCnt: 0 | 1 | 2; //已测量数量,0,1,2 最多两边(左边和右边)
isMeasuringLeftEnd: boolean; //测量左侧完成 isMeasuringLeftEnd: boolean; //测量左侧完成
isMeasuringRightEnd: boolean; //测量右侧完成 isMeasuringRightEnd: boolean; //测量右侧完成
@ -102,4 +123,16 @@ export type ChannelMessage = {
path: "/subdevice/uartchanel/get-channel-state"; path: "/subdevice/uartchanel/get-channel-state";
}; };
export type Datagram = TrackRecordSig | TaskState | ContextMessage | MeasureState | ChannelMessage;
export type DeviceStatus = {
messageType: "STATE";
data: {
isConnected: boolean; //是否链接
power: number; //电量
inclinatorX: number; //x轴倾斜
inclinatorY: number; //y轴倾斜
temperature: number; //温度
};
path: "/profiler-state/get-state";
};
export type Datagram = TrackRecordSig | TaskState | ContextMessage | MeasureState | ChannelMessage | DeviceStatus;

8
src/store/device/deviceState.ts

@ -4,10 +4,10 @@ import { createSlice } from "@reduxjs/toolkit";
import { ChannelMessage } from "../../services/wsTypes"; import { ChannelMessage } from "../../services/wsTypes";
const initialState: ChannelMessage["data"] = { const initialState: ChannelMessage["data"] = {
"isConnect": false, //是否连接
"connectPort": "COM4",//串口名
"sn": "",//连接的设备ID
"descriptivePortName": "COM4 serial ch340" //用于详细系
isConnect: false, //是否连接
connectPort: "COM4", //串口名
sn: "", //连接的设备ID
descriptivePortName: "COM4 serial ch340", //用于详细系
}; };
// 创建一个 Slice // 创建一个 Slice

16
src/store/features/contextSlice.ts

@ -1,15 +1,23 @@
// counterSlice.ts 文件 // counterSlice.ts 文件
import { createSlice, PayloadAction } from "@reduxjs/toolkit"; import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import type { ContextMessage } from "../../services/wsTypes";
import type { ContextMessage, DeviceStatus } from "../../services/wsTypes";
interface ContextSlice { interface ContextSlice {
user: ContextMessage["data"]; user: ContextMessage["data"];
newMeasureAfterSave: boolean; newMeasureAfterSave: boolean;
device: DeviceStatus["data"];
} }
const initialState: ContextSlice = { const initialState: ContextSlice = {
user: { loginFlag: false, loginUser: {} }, user: { loginFlag: false, loginUser: {} },
newMeasureAfterSave: false, newMeasureAfterSave: false,
device: {
isConnected: true, //是否链接
power: 60, //电量
inclinatorX: 0.276, //x轴倾斜
inclinatorY: 3.019, //y轴倾斜
temperature: 32.026, //温度
},
}; };
export const contextSlice = createSlice({ export const contextSlice = createSlice({
@ -19,16 +27,18 @@ export const contextSlice = createSlice({
reducers: { reducers: {
updateUser: (state, action: PayloadAction<ContextMessage["data"]>) => { updateUser: (state, action: PayloadAction<ContextMessage["data"]>) => {
state.user.loginFlag = action.payload.loginFlag; state.user.loginFlag = action.payload.loginFlag;
//@ts-ignore
state.user.loginUser = action.payload.loginUser; state.user.loginUser = action.payload.loginUser;
}, },
switchMeasureAfterSave: (state, action: PayloadAction<boolean>) => { switchMeasureAfterSave: (state, action: PayloadAction<boolean>) => {
state.newMeasureAfterSave = action.payload; state.newMeasureAfterSave = action.payload;
}, },
updateDevice: (state, action: PayloadAction<DeviceStatus["data"]>) => {
state.device = action.payload;
},
}, },
}); });
export const { updateUser, switchMeasureAfterSave } = contextSlice.actions;
export const { updateUser, switchMeasureAfterSave, updateDevice } = contextSlice.actions;
// 默认导出 // 默认导出
export default contextSlice.reducer; export default contextSlice.reducer;
Loading…
Cancel
Save