import React from 'react'; import { Button, Checkbox, CheckboxProps, message, Switch } from "antd"; import { useEffect, useRef, useState } from "react"; import { useNavigate } from "react-router"; import { 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"; const wsClient = createWebSocket(sharedWsUrl); export default function MeasureAction() { const dispatch = useAppDispatch(); const navigate = useNavigate(); // MeasurementCanvas 的 ref 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 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 onAnalysisBtnClick = () => { // 分析按钮只允许点击一次 setAnalysisClicked(true); fetchAnalysisReport("6001").then((res) => { if (res.success) { const report: AnalysisReport = res.data; console.log(res.data); // 更新 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 与 measure 分别设置为 pointA 与 pointB 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); let name = taskStatusDescMap["IDLE"]; setTaskStatusName(name); } else { const newStatusList = [...initialStatusList]; newStatusList[0].color = "b"; setStatusList(newStatusList); message.success("已通知设备开始测量"); let name = taskStatusDescMap["IDLE"]; setTaskStatusName(name); // 测量启动成功后,按钮文本变为“重新测量” 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 [taskStatusName, setTaskStatusName] = useState(""); useEffect(() => { const subscription = wsClient.dataOb.subscribe((data) => { // 处理任务状态消息 if (data.messageType === "STATE" && data.path === "/measurement-task/get-task-state") { if (!data.data) return; if (data.data.taskStatus === "IDLE") { setTaskStatusName("空闲"); } else if (!data.data.isMeasuringLeftEnd) { setTaskStatusName("左侧正在测量"); statusList[0].isReady = true; setStatusList([...statusList]); } else if (data.data.isMeasuringLeftEnd && !data.data.isMeasuringRightEnd) { setTaskStatusName("右侧正在测量"); } else { let name = taskStatusDescMap[data.data.taskStatus]; setTaskStatusName(name); } setTaskStatus(data.data.taskStatus); } // 处理状态变化事件 if (data.messageType === "EVENT" && data.path === "/measurement-task/event") { if (data.data === "START_RECORD_LEFT") { statusList[0].color = "g"; statusList[1].color = "b"; } else if (data.data === "FINISH_RECORD_LEFT") { statusList[1].color = "g"; statusList[2].color = "g"; statusList[3].color = "b"; // 左侧测量结束后,切换到右侧数据累计 isLeftFinished.current = true; } else if (data.data === "START_RECORD_RIGHT") { statusList[3].color = "g"; statusList[4].color = "b"; } else if (data.data === "FINISH_RECORD_RIGHT") { statusList[4].color = "g"; statusList[5].color = "g"; // 接收到 FINISH_RECORD_RIGHT 后认为测量完成 setMeasurementFinished(true); } setStatusList([...statusList]); } if (data.messageType === "STATE" && (data as any).path === "/measurement-task/point-report") { const pointData = ((data as unknown) as { data: { x: number; y: number } }).data; 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]); } } }); wsClient.connect(); return () => subscription.unsubscribe(); }, [statusList]); // 页面加载时获取基础图形数据,并传入 MeasurementCanvas 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); } } }); }, []); type StatusCodeData = { statusCode: string; name: string; background: string; isReady: boolean; color: string; }; const onHandleChangeStatus = (item: StatusCodeData) => { let backgroundColor = ""; if (item.statusCode === "START_RECORD_LEFT") { backgroundColor = item.background; } return backgroundColor; }; const onHandleIcon = (item: StatusCodeData, index: number) => { if (item.color === "g") { return ; } else if (item.color === "b") { return ; } else if (item.color === "h") { return (
); } }; return (
{/* 左侧区域:包含开关区域和测量画布 */}
setShowGrid(checked)} /> 参考线
{ setShowStandard(checked); if (!checked) { // 关闭标准线时,备份当前角度线状态,并关闭角度线 setAngleMarkBackup(showMark); setShowMark(false); } else { // 打开标准线时,恢复角度线之前的状态 setShowMark(angleMarkBackup); } }} /> 标准线
{ 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) => { return (
{onHandleIcon(item, index)}
{item.name}
); })}
保存后自动开始新测量
)}
); }