From 7272574666886476eec0d9e2a30edccd9d5e2ee4 Mon Sep 17 00:00:00 2001 From: zhangjiming Date: Mon, 10 Mar 2025 15:38:50 +0800 Subject: [PATCH] =?UTF-8?q?=E6=A0=B7=E5=BC=8F=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/measure/components/MeasureAction.scss | 5 + src/pages/measure/components/MeasureAction.tsx | 759 ++++++++++++------------ 2 files changed, 383 insertions(+), 381 deletions(-) create mode 100644 src/pages/measure/components/MeasureAction.scss diff --git a/src/pages/measure/components/MeasureAction.scss b/src/pages/measure/components/MeasureAction.scss new file mode 100644 index 0000000..307ab80 --- /dev/null +++ b/src/pages/measure/components/MeasureAction.scss @@ -0,0 +1,5 @@ +.analysis-table { + width: 300px; + height: calc(100% - 60px) ;// calc(100vh - var(--headerHeight) - var(--footerHeight) - 3rem - 60px); + overflow: auto; +} \ No newline at end of file diff --git a/src/pages/measure/components/MeasureAction.tsx b/src/pages/measure/components/MeasureAction.tsx index 24598ff..d1802b5 100644 --- a/src/pages/measure/components/MeasureAction.tsx +++ b/src/pages/measure/components/MeasureAction.tsx @@ -1,411 +1,408 @@ -import React, { useState, useEffect, useRef } from 'react'; +import React, { useState, useEffect, useRef } from "react"; import { Button, Checkbox, CheckboxProps, message, Switch } from "antd"; import { useNavigate } from "react-router"; import { - fetchAnalysisReport, - getBaseRecordPointSetByCode, - saveMeasurement, - startMeasurement, + fetchAnalysisReport, + getBaseRecordPointSetByCode, + saveMeasurement, + startMeasurement, } from "../../../services/measure/analysis"; import { createWebSocket, sharedWsUrl } from "../../../services/socket"; import { switchMeasureAfterSave } from "../../../store/features/contextSlice"; import { AnalysisReport, AnalyzeAngle } from "../../../services/measure/type"; import { MeasureState, taskStatusDescMap } from "../../../services/wsTypes"; import { useAppDispatch, useAppSelector } from "../../../utils/hooks"; -import Gr_round from '../../../assets/green_round.svg'; -import Bl_round from '../../../assets/blue_round.svg'; -import MeasurementCanvas, { - AnalysisData, - BenchmarkShape, - MeasurementCanvasRef, -} from "./konva/MeasurementCanvas"; +import Gr_round from "../../../assets/green_round.svg"; +import Bl_round from "../../../assets/blue_round.svg"; +import MeasurementCanvas, { AnalysisData, BenchmarkShape, MeasurementCanvasRef } from "./konva/MeasurementCanvas"; +import "./MeasureAction.scss"; // 创建 websocket 客户端 const wsClient = createWebSocket(sharedWsUrl); export default function MeasureAction() { - const dispatch = useAppDispatch(); - const navigate = useNavigate(); + const dispatch = useAppDispatch(); + const navigate = useNavigate(); - /** ----------------------- 引用 ----------------------- **/ - const canvasRef = useRef(null); - const leftPoints = useRef<{ x: number; y: number }[]>([]); - const rightPoints = useRef<{ x: number; y: number }[]>([]); - const isLeftFinished = useRef(false); + /** ----------------------- 引用 ----------------------- **/ + const canvasRef = useRef(null); + const leftPoints = useRef<{ x: number; y: number }[]>([]); + const rightPoints = useRef<{ x: number; y: number }[]>([]); + const isLeftFinished = useRef(false); - /** ----------------------- 状态 ----------------------- **/ - const [showGrid, setShowGrid] = useState(true); - const [showStandard, setShowStandard] = useState(true); - const [showMark, setShowMark] = useState(true); - const [angleMarkBackup, setAngleMarkBackup] = useState(true); - const afterSave = useAppSelector((store) => store.context.newMeasureAfterSave); - const [angles, setAngles] = useState([]); - const [taskStatus, setTaskStatus] = useState("IDLE"); - const [startBtnText, setStartBtnText] = useState("开始测量"); - const [measurementFinished, setMeasurementFinished] = useState(false); - const [analysisClicked, setAnalysisClicked] = useState(false); - const [saveClicked, setSaveClicked] = useState(false); - const [analysisReport, setAnalysisReport] = useState(null); - const [showAnalysisTable, setShowAnalysisTable] = useState(false); - const [taskStatusName, setTaskStatusName] = useState(""); + /** ----------------------- 状态 ----------------------- **/ + const [showGrid, setShowGrid] = useState(true); + const [showStandard, setShowStandard] = useState(true); + const [showMark, setShowMark] = useState(true); + const [angleMarkBackup, setAngleMarkBackup] = useState(true); + const afterSave = useAppSelector(store => store.context.newMeasureAfterSave); + const [angles, setAngles] = useState([]); + const [taskStatus, setTaskStatus] = useState("IDLE"); + const [startBtnText, setStartBtnText] = useState("开始测量"); + const [measurementFinished, setMeasurementFinished] = useState(false); + const [analysisClicked, setAnalysisClicked] = useState(false); + const [saveClicked, setSaveClicked] = useState(false); + const [analysisReport, setAnalysisReport] = useState(null); + const [showAnalysisTable, setShowAnalysisTable] = useState(false); + const [taskStatusName, setTaskStatusName] = useState(""); - // 初始状态列表 - const initialStatusList = [ - { statusCode: "START_RECORD_LEFT", name: "请移动到顶部,停顿2秒", background: "#ececec", isReady: false, color: "h" }, - { statusCode: "START_RECORD_LEFT", name: "开始测量左侧", background: "#ececec", isReady: false, color: "h" }, - { statusCode: "START_RECORD_LEFT", name: "左侧测量完成", background: "#ececec", isReady: false, color: "h" }, - { statusCode: "START_RECORD_LEFT", name: "请移动到顶部,停顿2秒", background: "#ececec", isReady: false, color: "h" }, - { statusCode: "START_RECORD_LEFT", name: "开始测量右侧", background: "#ececec", isReady: false, color: "h" }, - { statusCode: "START_RECORD_LEFT", name: "右侧测量完成", background: "#ececec", isReady: false, color: "h" }, - ]; - const [statusList, setStatusList] = useState(initialStatusList); + // 初始状态列表 + const initialStatusList = [ + { statusCode: "START_RECORD_LEFT", name: "请移动到顶部,停顿2秒", background: "#ececec", isReady: false, color: "h" }, + { statusCode: "START_RECORD_LEFT", name: "开始测量左侧", background: "#ececec", isReady: false, color: "h" }, + { statusCode: "START_RECORD_LEFT", name: "左侧测量完成", background: "#ececec", isReady: false, color: "h" }, + { statusCode: "START_RECORD_LEFT", name: "请移动到顶部,停顿2秒", background: "#ececec", isReady: false, color: "h" }, + { statusCode: "START_RECORD_LEFT", name: "开始测量右侧", background: "#ececec", isReady: false, color: "h" }, + { statusCode: "START_RECORD_LEFT", name: "右侧测量完成", background: "#ececec", isReady: false, color: "h" }, + ]; + const [statusList, setStatusList] = useState(initialStatusList); - /** ----------------------- 事件处理函数 ----------------------- **/ - // 切换保存后自动开始新测量 - const onAfterSaveChange: CheckboxProps["onChange"] = (e) => { - dispatch(switchMeasureAfterSave(e.target.checked)); - }; + /** ----------------------- 事件处理函数 ----------------------- **/ + // 切换保存后自动开始新测量 + const onAfterSaveChange: CheckboxProps["onChange"] = e => { + dispatch(switchMeasureAfterSave(e.target.checked)); + }; - // 分析按钮点击事件 - const onAnalysisBtnClick = () => { - setAnalysisClicked(true); - fetchAnalysisReport("6001").then((res) => { - if (res.success) { - const report: AnalysisReport = res.data; - console.log(report); - // 更新 canvas 的分析数据 - if (report && report.angleAnalysisList) { - const analysisData: AnalysisData[] = report.angleAnalysisList.map((item) => ({ - pointA: { x: parseFloat(item.pointA.x), y: parseFloat(item.pointA.y) }, - pointB: { x: parseFloat(item.pointB.x), y: parseFloat(item.pointB.y) }, - base: { x: parseFloat(item.pointA.x), y: parseFloat(item.pointA.y) }, - measure: { x: parseFloat(item.pointB.x), y: parseFloat(item.pointB.y) }, - distance: parseFloat(item.distance), - describe: item.describe, - })); - canvasRef.current?.setAnalysisData(analysisData); - } - setAnalysisReport(report); - setShowAnalysisTable(true); - } else { - message.error("分析报告请求失败: " + res.data.info); - } - }); - }; + // 分析按钮点击事件 + const onAnalysisBtnClick = () => { + setAnalysisClicked(true); + fetchAnalysisReport("6001").then(res => { + if (res.success) { + const report: AnalysisReport = res.data; + console.log(report); + // 更新 canvas 的分析数据 + if (report && report.angleAnalysisList) { + const analysisData: AnalysisData[] = report.angleAnalysisList.map(item => ({ + pointA: { x: parseFloat(item.pointA.x), y: parseFloat(item.pointA.y) }, + pointB: { x: parseFloat(item.pointB.x), y: parseFloat(item.pointB.y) }, + base: { x: parseFloat(item.pointA.x), y: parseFloat(item.pointA.y) }, + measure: { x: parseFloat(item.pointB.x), y: parseFloat(item.pointB.y) }, + distance: parseFloat(item.distance), + describe: item.describe, + })); + canvasRef.current?.setAnalysisData(analysisData); + } + setAnalysisReport(report); + setShowAnalysisTable(true); + } else { + message.error("分析报告请求失败: " + res.data.info); + } + }); + }; - // 开始/重新测量按钮点击事件 - const onStart = () => { - if (startBtnText === "新测量") { - navigate("../newMeasure"); - return; - } - // 重置测量相关状态 - setShowAnalysisTable(false); - setMeasurementFinished(false); - setAnalysisClicked(false); - setSaveClicked(false); - isLeftFinished.current = false; - leftPoints.current = []; - rightPoints.current = []; - canvasRef.current?.clearShapes(); - canvasRef.current?.resetCanvas(); - if (startBtnText === "重新测量") { - setStatusList(initialStatusList); - } - startMeasurement().then((res) => { - if (res.status !== 0) { - message.error(res.data.info); - setTaskStatusName(taskStatusDescMap["IDLE"]); - } else { - const newStatusList = [...initialStatusList]; - newStatusList[0].color = "b"; - setStatusList(newStatusList); - message.success("已通知设备开始测量"); - setTaskStatusName(taskStatusDescMap["IDLE"]); - setStartBtnText("重新测量"); - } - }); - }; + // 开始/重新测量按钮点击事件 + const onStart = () => { + if (startBtnText === "新测量") { + navigate("../newMeasure"); + return; + } + // 重置测量相关状态 + setShowAnalysisTable(false); + setMeasurementFinished(false); + setAnalysisClicked(false); + setSaveClicked(false); + isLeftFinished.current = false; + leftPoints.current = []; + rightPoints.current = []; + canvasRef.current?.clearShapes(); + canvasRef.current?.resetCanvas(); + if (startBtnText === "重新测量") { + setStatusList(initialStatusList); + } + startMeasurement().then(res => { + if (res.status !== 0) { + message.error(res.data.info); + setTaskStatusName(taskStatusDescMap["IDLE"]); + } else { + const newStatusList = [...initialStatusList]; + newStatusList[0].color = "b"; + setStatusList(newStatusList); + message.success("已通知设备开始测量"); + setTaskStatusName(taskStatusDescMap["IDLE"]); + setStartBtnText("重新测量"); + } + }); + }; - // 保存按钮点击事件 - const onSaveBtnClick = () => { - setSaveClicked(true); - saveMeasurement().then((res) => { - if (res.status !== 0) { - message.error(res.data.info); - } else { - message.success("保存成功"); - if (afterSave) { - navigate("../config"); - } else { - setStartBtnText("新测量"); - } - } - }); - }; + // 保存按钮点击事件 + const onSaveBtnClick = () => { + setSaveClicked(true); + saveMeasurement().then(res => { + if (res.status !== 0) { + message.error(res.data.info); + } else { + message.success("保存成功"); + if (afterSave) { + navigate("../config"); + } else { + setStartBtnText("新测量"); + } + } + }); + }; - // 辅助函数:渲染状态项的背景颜色 - const renderStatusBackground = (item: typeof initialStatusList[0]) => - item.statusCode === "START_RECORD_LEFT" ? item.background : ""; + // 辅助函数:渲染状态项的背景颜色 + const renderStatusBackground = (item: (typeof initialStatusList)[0]) => + item.statusCode === "START_RECORD_LEFT" ? item.background : ""; - // 辅助函数:渲染状态项的图标 - const renderStatusIcon = (item: typeof initialStatusList[0]) => { - if (item.color === "g") { - return green; - } else if (item.color === "b") { - return blue; - } else { - return ( -
- ); - } - }; + // 辅助函数:渲染状态项的图标 + const renderStatusIcon = (item: (typeof initialStatusList)[0]) => { + if (item.color === "g") { + return green; + } else if (item.color === "b") { + return blue; + } else { + return ( +
+ ); + } + }; - /** ----------------------- WebSocket 消息处理 ----------------------- **/ - useEffect(() => { - // 处理任务状态消息 - const handleStateMessage = (data: any) => { - if (!data.data) return; - if (data.data.taskStatus === "IDLE") { - setTaskStatusName("空闲"); - } else if (!data.data.isMeasuringLeftEnd) { - setTaskStatusName("左侧正在测量"); - setStatusList((prev) => { - const updated = [...prev]; - updated[0].isReady = true; - return updated; - }); - } else if (data.data.isMeasuringLeftEnd && !data.data.isMeasuringRightEnd) { - setTaskStatusName("右侧正在测量"); - } else { - setTaskStatusName(taskStatusDescMap[data.data.taskStatus as keyof typeof taskStatusDescMap]); + /** ----------------------- WebSocket 消息处理 ----------------------- **/ + useEffect(() => { + // 处理任务状态消息 + const handleStateMessage = (data: any) => { + if (!data.data) return; + if (data.data.taskStatus === "IDLE") { + setTaskStatusName("空闲"); + } else if (!data.data.isMeasuringLeftEnd) { + setTaskStatusName("左侧正在测量"); + setStatusList(prev => { + const updated = [...prev]; + updated[0].isReady = true; + return updated; + }); + } else if (data.data.isMeasuringLeftEnd && !data.data.isMeasuringRightEnd) { + setTaskStatusName("右侧正在测量"); + } else { + setTaskStatusName(taskStatusDescMap[data.data.taskStatus as keyof typeof taskStatusDescMap]); + } + setTaskStatus(data.data.taskStatus); + }; - } - setTaskStatus(data.data.taskStatus); - }; + // 处理事件消息 + const handleEventMessage = (data: any) => { + setStatusList(prev => { + const updated = [...prev]; + switch (data.data) { + case "START_RECORD_LEFT": + updated[0].color = "g"; + updated[1].color = "b"; + break; + case "FINISH_RECORD_LEFT": + updated[1].color = "g"; + updated[2].color = "g"; + updated[3].color = "b"; + isLeftFinished.current = true; + break; + case "START_RECORD_RIGHT": + updated[3].color = "g"; + updated[4].color = "b"; + break; + case "FINISH_RECORD_RIGHT": + updated[4].color = "g"; + updated[5].color = "g"; + setMeasurementFinished(true); + break; + default: + break; + } + return updated; + }); + }; - // 处理事件消息 - const handleEventMessage = (data: any) => { - setStatusList((prev) => { - const updated = [...prev]; - switch (data.data) { - case "START_RECORD_LEFT": - updated[0].color = "g"; - updated[1].color = "b"; - break; - case "FINISH_RECORD_LEFT": - updated[1].color = "g"; - updated[2].color = "g"; - updated[3].color = "b"; - isLeftFinished.current = true; - break; - case "START_RECORD_RIGHT": - updated[3].color = "g"; - updated[4].color = "b"; - break; - case "FINISH_RECORD_RIGHT": - updated[4].color = "g"; - updated[5].color = "g"; - setMeasurementFinished(true); - break; - default: - break; - } - return updated; - }); - }; + // 处理点数据消息 + const handlePointReport = (data: any) => { + const pointData = data.data as { x: number; y: number }; + console.log(`pointData === ${pointData.x},${pointData.y}`); + if (!isLeftFinished.current) { + leftPoints.current.push(pointData); + canvasRef.current?.setMeasurementDataLeft([...leftPoints.current]); + } else { + rightPoints.current.push(pointData); + canvasRef.current?.setMeasurementDataRight([...rightPoints.current]); + } + }; - // 处理点数据消息 - const handlePointReport = (data: any) => { - const pointData = data.data as { x: number; y: number }; - console.log(`pointData === ${pointData.x},${pointData.y}`); - if (!isLeftFinished.current) { - leftPoints.current.push(pointData); - canvasRef.current?.setMeasurementDataLeft([...leftPoints.current]); - } else { - rightPoints.current.push(pointData); - canvasRef.current?.setMeasurementDataRight([...rightPoints.current]); - } - }; + const subscription = wsClient.dataOb.subscribe((data: any) => { + if (data.messageType === "STATE" && data.path === "/measurement-task/get-task-state") { + handleStateMessage(data); + } else if (data.messageType === "EVENT" && data.path === "/measurement-task/event") { + handleEventMessage(data); + } else if (data.messageType === "STATE" && data.path === "/measurement-task/point-report") { + handlePointReport(data); + } + }); + wsClient.connect(); + return () => subscription.unsubscribe(); + }, []); - const subscription = wsClient.dataOb.subscribe((data: any) => { - if (data.messageType === "STATE" && data.path === "/measurement-task/get-task-state") { - handleStateMessage(data); - } else if (data.messageType === "EVENT" && data.path === "/measurement-task/event") { - handleEventMessage(data); - } else if (data.messageType === "STATE" && data.path === "/measurement-task/point-report") { - handlePointReport(data); - } - }); - wsClient.connect(); - return () => subscription.unsubscribe(); - }, []); + /** ----------------------- 页面加载获取基础图形数据 ----------------------- **/ + useEffect(() => { + getBaseRecordPointSetByCode("6001").then(res => { + if (res.success) { + const benchmarkShapes = JSON.parse(res.data.points) as BenchmarkShape[]; + if (canvasRef.current) { + console.log("解析后的基础图形数据:", benchmarkShapes); + canvasRef.current.setBenchmarkData(benchmarkShapes); + } + } + }); + }, []); - /** ----------------------- 页面加载获取基础图形数据 ----------------------- **/ - useEffect(() => { - getBaseRecordPointSetByCode("6001").then((res) => { - if (res.success) { - const benchmarkShapes = JSON.parse(res.data.points) as BenchmarkShape[]; - if (canvasRef.current) { - console.log("解析后的基础图形数据:", benchmarkShapes); - canvasRef.current.setBenchmarkData(benchmarkShapes); - } - } - }); - }, []); + /** ----------------------- 渲染 ----------------------- **/ + return ( +
+ {/* 左侧区域:包含开关区域和测量画布 */} +
+
+ {/* 参考线开关 */} +
+ setShowGrid(checked)} /> + 参考线 +
+ {/* 标准线开关 */} +
+ { + setShowStandard(checked); + if (!checked) { + setAngleMarkBackup(showMark); + setShowMark(false); + } else { + setShowMark(angleMarkBackup); + } + }} + /> + 标准线 +
+ {/* 角度线开关,仅在点击分析按钮后显示 */} + {analysisClicked && ( +
+ { + setShowMark(checked); + setAngleMarkBackup(checked); + }} + /> + 角度线 +
+ )} +
+
+ +
+
+ {/* 右侧区域:根据 showAnalysisTable 状态显示测量步骤或分析表格 */} +
+ {showAnalysisTable && analysisReport ? ( + <> +
+ + + + + + + + + + + {analysisReport.angleAnalysisList.map((item, index) => ( + + + + + ))} + +
W1垂直磨耗{analysisReport.w1}
轨头宽度 + {analysisReport.railHeadWidth} +
{item.describe}{item.distance}
+
- /** ----------------------- 渲染 ----------------------- **/ - return ( -
- {/* 左侧区域:包含开关区域和测量画布 */} -
-
- {/* 参考线开关 */} -
- setShowGrid(checked)} /> - 参考线 -
- {/* 标准线开关 */} -
- { - setShowStandard(checked); - if (!checked) { - setAngleMarkBackup(showMark); - setShowMark(false); - } else { - setShowMark(angleMarkBackup); - } - }} - /> - 标准线 -
- {/* 角度线开关,仅在点击分析按钮后显示 */} - {analysisClicked && ( -
- { - setShowMark(checked); - setAngleMarkBackup(checked); - }} - /> - 角度线 -
- )} -
-
- -
-
- {/* 右侧区域:根据 showAnalysisTable 状态显示测量步骤或分析表格 */} -
- {showAnalysisTable && analysisReport ? ( -
- - - - - - - - - - - {analysisReport.angleAnalysisList.map((item, index) => ( - - - - - ))} - - - - -
W1垂直磨耗{analysisReport.w1}
轨头宽度{analysisReport.railHeadWidth}
{item.describe}{item.distance}
- -
-
- ) : ( -
-

测量步骤

-
- {statusList.map((item, index) => ( -
-
- {renderStatusIcon(item)} -
{item.name}
-
-
- ))} -
-
- - - - - 保存后自动开始新测量 - -
-
- )} -
-
- ); -} \ No newline at end of file + + + ) : ( +
+

测量步骤

+
+ {statusList.map((item, index) => ( +
+
+ {renderStatusIcon(item)} +
{item.name}
+
+
+ ))} +
+
+ + + + + 保存后自动开始新测量 + +
+
+ )} +
+
+ ); +}