|
|
@ -1,8 +1,7 @@ |
|
|
|
import React, { useState, useEffect, useRef, useCallback, useMemo } from "react"; |
|
|
|
import { Button, Checkbox, CheckboxProps, Drawer, Input, InputNumber, message, Select, Spin, Switch } from "antd"; |
|
|
|
import { Button, Checkbox, CheckboxProps, Drawer, Form, Input, InputNumber, message, Modal, Select, Spin, Switch } from "antd"; |
|
|
|
import { useNavigate } from "react-router"; |
|
|
|
import { |
|
|
|
fetchAnalysisReport, |
|
|
|
getAlignPointsByRailSize, |
|
|
|
getReport, |
|
|
|
startMeasurement, |
|
|
@ -11,7 +10,7 @@ import { |
|
|
|
import { getBaseRecordPointSetByCode, gx_list } from "../../../services/track/trackShape" |
|
|
|
import { createWebSocket, sharedWsUrl } from "../../../services/socket"; |
|
|
|
import { switchMeasureAfterSave } from "../../../store/features/contextSlice"; |
|
|
|
import measureState, { updateGxState, updateMeasureData } from "../../../store/measure/measureState"; |
|
|
|
import { updateGxState, updateMeasureData, updateMeasureName } from "../../../store/measure/measureState"; |
|
|
|
import { AnalysisReport, trackItem } from "../../../services/measure/type"; |
|
|
|
import { MeasureState, ResultRecordData, TaskState, TrackRecordSig } from "../../../services/wsTypes"; |
|
|
|
import { useAppDispatch, useAppSelector } from "../../../utils/hooks"; |
|
|
@ -26,6 +25,8 @@ import icon_rightR from "../../../assets/icon_rightR.svg"; |
|
|
|
import MeasurementCanvas, { AnalysisData, BenchmarkShape, MeasurementCanvasRef, Point } from "./konva/MeasurementCanvas"; |
|
|
|
import "./MeasureAction.scss"; |
|
|
|
import { GX_CODE } from "../../../constant"; |
|
|
|
import type { InputRef } from 'antd/es/input'; |
|
|
|
const { confirm } = Modal; |
|
|
|
// 创建 websocket 客户端
|
|
|
|
const wsClient = createWebSocket(sharedWsUrl); |
|
|
|
export default function MeasureAction() { |
|
|
@ -33,6 +34,7 @@ export default function MeasureAction() { |
|
|
|
const navigate = useNavigate(); |
|
|
|
const deviceInfo = useAppSelector(store => store.context.device); |
|
|
|
const measureState = useAppSelector((store) => store.measureState); |
|
|
|
const measureName = localStorage.getItem("measureName"); |
|
|
|
const [railSize, setRailSize] = useState<string>(GX_CODE) |
|
|
|
const STEP_COLOR_GREEN = "green"; |
|
|
|
const STEP_COLOR_BLUE = "blue"; |
|
|
@ -45,14 +47,16 @@ export default function MeasureAction() { |
|
|
|
|
|
|
|
/** ----------------------- 状态 ----------------------- **/ |
|
|
|
const [showGrid, setShowGrid] = useState(true); |
|
|
|
const [showStandard, setShowStandard] = useState(true); |
|
|
|
const [showStandard, setShowStandard] = useState(false); |
|
|
|
const [showMark, setShowMark] = useState(true); |
|
|
|
// showMark的备份,记录showMark最近一次的值
|
|
|
|
const [angleMarkBackup, setAngleMarkBackup] = useState(true); |
|
|
|
const afterSave = useAppSelector(store => store.context.newMeasureAfterSave); |
|
|
|
const [startBtnText, setStartBtnText] = useState("开始测量"); |
|
|
|
const [measurementFinished, setMeasurementFinished] = useState(false); |
|
|
|
|
|
|
|
const [isMeasurementModalOpen, setIsMeasurementModalOpen] = useState(false) |
|
|
|
const [form] = Form.useForm(); |
|
|
|
const inputRef = useRef<InputRef>(null); |
|
|
|
// 【分析】之后,会得到分析报告
|
|
|
|
const [analysisReport, setAnalysisReport] = useState<AnalysisReport | null>(null); |
|
|
|
|
|
|
@ -128,18 +132,28 @@ export default function MeasureAction() { |
|
|
|
}; |
|
|
|
|
|
|
|
const [startLoading, setStartLoading] = useState(false) |
|
|
|
// 开始/重新测量按钮点击事件
|
|
|
|
const onStart = useCallback(() => { |
|
|
|
// if (!deviceInfo.isConnected) {
|
|
|
|
// message.error("请先连接设备");
|
|
|
|
// return;
|
|
|
|
// }
|
|
|
|
const onChooseNameStart = () => { |
|
|
|
if (!deviceInfo.isConnected) { |
|
|
|
message.error("请先连接设备"); |
|
|
|
return; |
|
|
|
} |
|
|
|
if (startBtnText === '开始测量') { |
|
|
|
// 输入测量名称
|
|
|
|
setIsMeasurementModalOpen(true) |
|
|
|
setTimeout(() => { |
|
|
|
if(inputRef.current){ |
|
|
|
form.setFieldsValue({ |
|
|
|
name: measureName || '', |
|
|
|
}); |
|
|
|
inputRef.current.focus() |
|
|
|
} |
|
|
|
}, 100) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const onContinueMeasure = () => { |
|
|
|
setStartLoading(true) |
|
|
|
setAudioList([]) |
|
|
|
// if(deviceInfo.power < 20){
|
|
|
|
// message.error('电量低于20%,请充电后再测量!')
|
|
|
|
// return
|
|
|
|
// }
|
|
|
|
// 重置测量相关状态
|
|
|
|
setMeasurementFinished(false); |
|
|
|
setAnalysisReport(null); |
|
|
@ -168,18 +182,36 @@ export default function MeasureAction() { |
|
|
|
setStatusList(list); |
|
|
|
message.success("已通知设备开始测量"); |
|
|
|
setStartBtnText("重新测量"); |
|
|
|
const audioReady = new Audio("/audio/ready.mp3"); |
|
|
|
// 播放音频
|
|
|
|
audioReady |
|
|
|
.play() |
|
|
|
.then(() => { |
|
|
|
console.log("音频开始播放 已准备好"); |
|
|
|
}) |
|
|
|
.catch(err => { |
|
|
|
console.error("播放音频时出错:", err); |
|
|
|
}); |
|
|
|
setShowStandard(false) |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
// 开始/重新测量按钮点击事件
|
|
|
|
const onStart = useCallback(async () => { |
|
|
|
|
|
|
|
if (!deviceInfo.isConnected) { |
|
|
|
message.error("请先连接设备"); |
|
|
|
return; |
|
|
|
} |
|
|
|
if(deviceInfo.power < 10){ |
|
|
|
confirm({ |
|
|
|
title: '电量提示', |
|
|
|
content: '电量低于10%,测量过程会有丢包风险,请确认是否继续测量!', |
|
|
|
okText:'确认', |
|
|
|
cancelText:'取消', |
|
|
|
onOk() { |
|
|
|
onContinueMeasure() |
|
|
|
}, |
|
|
|
onCancel() { |
|
|
|
console.log('Cancel'); |
|
|
|
}, |
|
|
|
}); |
|
|
|
return |
|
|
|
} |
|
|
|
else { |
|
|
|
onContinueMeasure() |
|
|
|
} |
|
|
|
}, [initialStatusList, startBtnText, deviceInfo]); |
|
|
|
|
|
|
|
//停止测量
|
|
|
@ -248,13 +280,7 @@ export default function MeasureAction() { |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
const [audioList, setAudioList] = useState<HTMLAudioElement[]>([]) |
|
|
|
const pauseAudio = () => { |
|
|
|
audioList.forEach(audio => { |
|
|
|
audio.pause() |
|
|
|
}) |
|
|
|
} |
|
|
|
const [status, setStatus] = useState(0) |
|
|
|
const [status, setStatus] = useState(0) |
|
|
|
/** ----------------------- WebSocket 消息处理 ----------------------- **/ |
|
|
|
useEffect(() => { |
|
|
|
// 处理任务状态消息
|
|
|
@ -271,6 +297,15 @@ export default function MeasureAction() { |
|
|
|
* RECORD_THE_2ND_SIDE: 测量第二线曲线 |
|
|
|
* FINISHED: 第二条曲线测量完成 |
|
|
|
*/ |
|
|
|
if(type === 'WAITING_FOR_RECORD_THE_1ST_SIDE') { |
|
|
|
setStatus(1); |
|
|
|
}else if(type === 'WAITING_FOR_RECORD_THE_2ND_SIDE') { |
|
|
|
setStatus(2); |
|
|
|
} |
|
|
|
if((['START_RECORD_LEFT', 'START_RECORD_RIGHT'].includes(type) && status === 1) || (['FINISH_RECORD_LEFT', 'FINISH_RECORD_RIGHT'].includes(type) && status === 1) || ['FINISH_RECORD'].includes(type)) { |
|
|
|
const audio = new Audio('/audio/ticking.wav'); |
|
|
|
audio.play().then(() => {}); |
|
|
|
} |
|
|
|
setStatusList(prev => { |
|
|
|
const updated = [...prev]; |
|
|
|
switch (type) { |
|
|
@ -286,95 +321,37 @@ export default function MeasureAction() { |
|
|
|
break; |
|
|
|
case 'START_RECORD_LEFT': |
|
|
|
case 'START_RECORD_RIGHT': |
|
|
|
if (status === 1) { |
|
|
|
if (status === 1) { |
|
|
|
updated[0].color = STEP_COLOR_GREEN; |
|
|
|
updated[1].color = STEP_COLOR_BLUE; |
|
|
|
} else if (status === 2) { |
|
|
|
updated[3].color = STEP_COLOR_GREEN; |
|
|
|
updated[4].color = STEP_COLOR_BLUE; |
|
|
|
} |
|
|
|
const audio1 = new Audio("/audio/measuring.mp3"); |
|
|
|
// 播放音频
|
|
|
|
audio1 |
|
|
|
.play() |
|
|
|
.then(() => { |
|
|
|
console.log("音频开始播放"); |
|
|
|
}) |
|
|
|
.catch(err => { |
|
|
|
console.error("播放音频时出错:", err); |
|
|
|
}); |
|
|
|
setAudioList([...audioList, audio1]) |
|
|
|
break; |
|
|
|
case "FINISH_RECORD_LEFT": |
|
|
|
case "FINISH_RECORD_RIGHT": |
|
|
|
pauseAudio() |
|
|
|
if (status === 1) { |
|
|
|
updated[1].color = STEP_COLOR_GREEN; |
|
|
|
updated[2].color = STEP_COLOR_GREEN; |
|
|
|
updated[3].color = STEP_COLOR_BLUE; |
|
|
|
const line1Audio = new Audio("/audio/side_end.mp3"); |
|
|
|
// 播放音频
|
|
|
|
line1Audio |
|
|
|
.play() |
|
|
|
.then(() => { |
|
|
|
console.log("音频开始播放"); |
|
|
|
}) |
|
|
|
.catch(err => { |
|
|
|
console.error("播放音频时出错:", err); |
|
|
|
}); |
|
|
|
setAudioList([...audioList, line1Audio]) |
|
|
|
}else if(status === 2) { |
|
|
|
updated[3].color = STEP_COLOR_GREEN; |
|
|
|
updated[4].color = STEP_COLOR_BLUE; |
|
|
|
const audio2 = new Audio("/audio/measure_end.mp3"); |
|
|
|
// 播放音频
|
|
|
|
audio2 |
|
|
|
.play() |
|
|
|
.then(() => { |
|
|
|
console.log("音频开始播放"); |
|
|
|
}) |
|
|
|
.catch(err => { |
|
|
|
console.error("播放音频时出错:", err); |
|
|
|
}); |
|
|
|
setAudioList([...audioList, audio2]) |
|
|
|
setMeasurementFinished(true); |
|
|
|
} |
|
|
|
updated[1].color = STEP_COLOR_GREEN; |
|
|
|
updated[2].color = STEP_COLOR_GREEN; |
|
|
|
updated[3].color = STEP_COLOR_BLUE; |
|
|
|
isLeftFinished.current = true; |
|
|
|
|
|
|
|
|
|
|
|
break; |
|
|
|
case "FINISH_RECORD": |
|
|
|
updated.forEach(item => { |
|
|
|
item.color = STEP_COLOR_GREEN |
|
|
|
}) |
|
|
|
const audioFinish= new Audio("/audio/measure_end.mp3");//measure_end
|
|
|
|
// 播放音频
|
|
|
|
audioFinish |
|
|
|
.play() |
|
|
|
.then(() => { |
|
|
|
console.log("音频开始播放"); |
|
|
|
}) |
|
|
|
.catch(err => { |
|
|
|
console.error("播放音频时出错:", err); |
|
|
|
}); |
|
|
|
updated.forEach(u => (u.color = STEP_COLOR_GREEN)); |
|
|
|
setCaLoading(true) |
|
|
|
setLoadingText('正在处理测量数据...') |
|
|
|
setMeasurementFinished(true); |
|
|
|
break; |
|
|
|
case "WRONG_SIDE": |
|
|
|
const audio5 = new Audio("/audio/alert_left.mp3"); |
|
|
|
// 播放音频
|
|
|
|
audio5 |
|
|
|
.play() |
|
|
|
.then(() => { |
|
|
|
console.log("音频开始播放"); |
|
|
|
}) |
|
|
|
.catch(err => { |
|
|
|
console.error("播放音频时出错:", err); |
|
|
|
}); |
|
|
|
// 把状态全部置灰
|
|
|
|
updated.forEach(u => (u.color = STEP_COLOR_GREY)); |
|
|
|
// 调用停止测量
|
|
|
@ -383,6 +360,7 @@ export default function MeasureAction() { |
|
|
|
default: |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
return updated; |
|
|
|
}); |
|
|
|
}; |
|
|
@ -400,8 +378,11 @@ export default function MeasureAction() { |
|
|
|
|
|
|
|
// 处理测量后的数据
|
|
|
|
const handleMeasureResult = (pointData: ResultRecordData["data"]) => { |
|
|
|
canvasRef.current?.setMeasurementDataLeft([...pointData.outline1]); |
|
|
|
canvasRef.current?.setMeasurementDataRight([...pointData.outline2]); |
|
|
|
// canvasRef.current?.setMeasurementDataLeft([...pointData.outline1]);
|
|
|
|
// canvasRef.current?.setMeasurementDataRight([...pointData.outline2]);
|
|
|
|
canvasRef.current?.setMeasurementCalibrationData(pointData) |
|
|
|
setshowCalibration(true)//校准线
|
|
|
|
setShowStandard(true) |
|
|
|
} |
|
|
|
|
|
|
|
const subscription = wsClient.dataOb.subscribe(data => { |
|
|
@ -530,6 +511,27 @@ export default function MeasureAction() { |
|
|
|
return item |
|
|
|
} |
|
|
|
|
|
|
|
const handleOk = async () => { |
|
|
|
try { |
|
|
|
// 手动触发校验并获取字段值
|
|
|
|
const values = await form.validateFields(); |
|
|
|
localStorage.setItem("measureName", values.name); |
|
|
|
// dispatch(updateMeasureName(values.name))
|
|
|
|
// 校验成功,处理表单数据
|
|
|
|
console.log('表单数据校验成功:', values); |
|
|
|
onStart() |
|
|
|
message.success('开始测量'); |
|
|
|
handleCancel() |
|
|
|
} catch (errorInfo) { |
|
|
|
// 校验失败,antd会自动显示错误信息
|
|
|
|
console.log('表单数据校验失败:', errorInfo); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
const handleCancel = () => { |
|
|
|
setIsMeasurementModalOpen(false) |
|
|
|
} |
|
|
|
|
|
|
|
/** ----------------------- 渲染 ----------------------- **/ |
|
|
|
return ( |
|
|
|
<> |
|
|
@ -728,6 +730,30 @@ export default function MeasureAction() { |
|
|
|
</> |
|
|
|
)} |
|
|
|
</Drawer> |
|
|
|
<Modal |
|
|
|
title="测量名称" |
|
|
|
closable={{ 'aria-label': 'Custom Close Button' }} |
|
|
|
open={isMeasurementModalOpen} |
|
|
|
onOk={handleOk} |
|
|
|
onCancel={handleCancel} |
|
|
|
> |
|
|
|
<Form |
|
|
|
form={form} |
|
|
|
labelCol={{ span: 8 }} |
|
|
|
wrapperCol={{ span: 12 }} |
|
|
|
size="large" |
|
|
|
initialValues={{ remember: true }} |
|
|
|
autoComplete="off" |
|
|
|
> |
|
|
|
<Form.Item |
|
|
|
label="测量名称" |
|
|
|
name="name" |
|
|
|
rules={[{ required: true, message: "请输入测量名称" }]} |
|
|
|
> |
|
|
|
<Input ref={inputRef} placeholder="请输入测量名称" /> |
|
|
|
</Form.Item> |
|
|
|
</Form> |
|
|
|
</Modal> |
|
|
|
</> |
|
|
|
); |
|
|
|
} |