import StepItem, { StepName, StepState } from '../components/StepItem'; import { useNavigate } from 'react-router-dom'; import CustomNavBar from '../components/CustomNavBar'; import MeasurementCanvas, { BenchmarkShape, MeasurementCanvasRef, Point, } from '../components/konva/MeasurementCanvas'; import { useEffect, useRef, useState } from 'react'; import RailTypeBtn from '../components/RailTypeBtn'; import { Cascader, Dialog, Input, Mask, Picker, SpinLoading, Toast } from 'antd-mobile'; import { useAppDispatch, useAppSelector } from '../utils/hooks'; import { updateMeasureData, updateTaskState } from '../store/features/measureSlice'; import Bridge from '../utils/bridge'; import { selectLabeledKtjOrgs, updateRailPoints } from '../store/features/baseData'; import { updateOrg } from '../store/features/contextSlice'; import { selectOrgTextArr } from '../store'; import icon_left from "../assets/icon_left.svg"; import icon_right from "../assets/icon_right.svg"; import icon_up from "../assets/icon_up.svg"; import icon_down from "../assets/icon_down.svg"; import icon_leftR from "../assets/icon_leftR.svg"; import icon_rightR from "../assets/icon_rightR.svg"; export default function Measure() { const navigate = useNavigate(); const dispatch = useAppDispatch(); const labeledKtjOrgs = useAppSelector(selectLabeledKtjOrgs); const orgTextArr = useAppSelector(selectOrgTextArr); const measureState = useAppSelector((state) => state.measure); const contextState = useAppSelector((state) => state.context); const baseState = useAppSelector((state) => state.baseData); const [railPickerVisible, setRailPickerVisible] = useState(false); const [railId, setRailId] = useState<(number | string | null)[]>([]); const canvasRef = useRef(null); const [railSize, setRailSize] = useState<(number | string | null)>(); const iconWidth = 35; // 默认选中第一个轨型 useEffect(() => { if (baseState.railTypes.length > 0) { let railData = baseState.railTypes[0] setRailId([railData.id]); setRailSize(railData.code) } }, [baseState.railTypes]); function drawRailBaseLine(points: string) { const benchmarkShapes = JSON.parse(points) as BenchmarkShape[]; if (canvasRef.current) { canvasRef.current.setBenchmarkData(benchmarkShapes); } } // 检查轨型有没有坐标,如果有,绘制轨型基准线,如果没,拉取再绘制其线 useEffect(() => { if (railId.length > 0) { const r = baseState.railTypes.find((rail) => rail.id === railId[0]); if (!r) return; if (!!r.points) { drawRailBaseLine(r.points); return; } Bridge.getTrackPoint({ code: r.code }).then((res) => { if (res.success) { dispatch(updateRailPoints(res.data)); drawRailBaseLine(res.data.points!); } else { Toast.show(res.message); } }); } }, [baseState.railTypes, dispatch, railId]); // 绘制测量坐标线 useEffect(() => { if (canvasRef.current) { canvasRef.current.setMeasurementDataLeft(measureState.leftPoints); } }, [measureState.leftPoints]); useEffect(() => { if (canvasRef.current) { canvasRef.current.setMeasurementDataRight(measureState.rightPoints); } }, [measureState.rightPoints]); const onSaveClick = () => { dispatch(updateMeasureData(newMeasureData)) navigate('/measure/save'); }; const [caloading, setCaloading] = useState(false) const [showCalibration, setshowCalibration] = useState(false) const onCalibrationBtnClick = () => { setCaloading(true) Bridge.alignPoints({railSize:railSize || 'GX-60'}).then(res=>{ if(res.success){ setshowCalibration(true) canvasRef.current?.setMeasurementCalibrationData(res.data) }else{ } setCaloading(false) }).catch(e=>{ setCaloading(false) Toast.show({ content: 服务器异常, position: 'top', }) }) } const onStartClick = () => { setshowCalibration(false) dispatch(updateMeasureData([])) if (!contextState.device.connected) { Dialog.alert({ content: '蓝牙未连接,请先连接蓝牙', onConfirm: () => { navigate('/home/bluetooth'); }, }); return; } if (baseState.ktjOrgs.length === 0) { Dialog.alert({ content: '请在基础数据同步完成后重试', onConfirm: () => { navigate('/home/mine'); }, }); return; } if (!contextState.currOrgCode) { Dialog.alert({ content: '请选择铁路局/工务段/线路', onConfirm: () => { onOrgBarClick(); }, }); return; } // if (contextState.device.power < 20) { // Toast.show("电量低于20%,请充电后测量"); // return; // } Bridge.startMeasure().then((res) => { if (res.success) { dispatch(updateTaskState('START_RECORD_SIG')); } else { Toast.show(res.message); } openAudio() }); }; const openAudio = () => { const audioReady = new Audio("/audio/ready.mp3"); // 播放音频 audioReady .play() .then(() => { console.log("音频开始播放 已准备好"); }) .catch(err => { console.error("播放音频时出错:", err); }); } const onOrgBarClick = async () => { if (baseState.ktjOrgs.length === 0) { Dialog.alert({ content: '请在基础数据同步完成后重试', onConfirm: () => { navigate('/home/mine'); }, }); return; } const value = await Cascader.prompt({ options: labeledKtjOrgs, placeholder: '请选择', }); // Toast.show(value ? `你选择了 ${value.join(' - ')}` : '你没有进行选择'); if (value) { dispatch(updateOrg(value as string[])); } }; function stepState(step: StepName): StepState { if (!measureState.taskState) { return 'none'; } switch (measureState.taskState) { case 'START_RECORD_SIG': case 'WRONG_SIDE': if (step === 'left_ready') { return 'ongoing'; } else { return 'none'; } case 'START_RECORD_LEFT': if (step === 'left_ready') { return 'done'; } else if (step === 'left_begin') { return 'ongoing'; } else { return 'none'; } case 'FINISH_RECORD_LEFT': if (step === 'left_ready' || step === 'left_begin' || step === 'left_end') { return 'done'; } else if (step === 'right_ready') { return 'ongoing'; } else { return 'none'; } case 'START_RECORD_RIGHT': if (step === 'right_begin') { return 'ongoing'; } else if (step === 'right_end') { return 'none'; } else { return 'done'; } case 'FINISH_RECORD_RIGHT': { return 'done'; } default: return 'none'; } } function railName() { return baseState.railTypes.find((r) => r.id === railId[0])?.name || ''; } function onRailSizeChange(ids:(number | string | null)[]){ if(ids && ids.length){ setRailId(ids); let id = ids[0] const codes = baseState.railTypes.map(item => { if(item.id === id){ return item.code } }) if(codes && codes.length){ setRailSize(codes[0]) } } } //上下移动 const timerRef = useRef(null); const handlePressStart = (type:string) => { timerRef.current = setInterval(() => { console.log('你进行了长按操作!'); onHandleMove(type) }, 500); }; const handlePressEnd = () => { if (timerRef.current) { clearInterval(timerRef.current); timerRef.current = null; } }; const onMoveLine = (type:string) => { console.log('这是点击') onHandleMove(type) } const onHandleMove = (type:string) => { let list = canvasRef.current?.getMeasurementCalibrationData() if(list && list.length){ list.forEach(item => { if(type === 'up'){//向上移动,原数据减y X轴不动 item.y = item.y - distance/1000; } if(type === 'down'){//向上移动,原数据加y X轴不动 item.y = item.y + distance/1000; } if(type === 'left'){//向左移动,原数据减x Y轴不动 item.x = item.x - distance/1000; } if(type === 'right'){//向右移动,原数据加x Y轴不动 item.x = item.x + distance/1000; } }) canvasRef.current?.setMeasurementCalibrationData(list) setNewMeasureData(list) } } const handleRotationPressStart = (type:string) => { timerRef.current = setInterval(() => { onRotationLine(type) }, 500); } //旋转 let [measurementRotation, setMeasurementRotation] = useState(0) let [newMeasureData, setNewMeasureData] = useState() let [angle, setAngle] = useState(5);//角度单位 分 let [distance, setDistance] = useState(100) const onRotationLine = (type:string) => { let mrValue = 0 if(type === 'left'){//逆时针 mrValue = measurementRotation - (angle/60) * Math.PI / 180; } if(type === 'right'){//顺时针 mrValue = measurementRotation + (angle/60) * Math.PI / 180; } let list = canvasRef.current?.getMeasurementCalibrationData() if(list && list.length){ list.forEach((item, index) => { let cloneItem = rotatePoint(item, mrValue) item.x = cloneItem.x item.y = cloneItem.y }) canvasRef.current?.setMeasurementCalibrationData(list) setNewMeasureData(list) } } const rotatePoint = (pt:{x:number;y:number}, angle:number) => { const item = { x: pt.x * Math.cos(angle) - pt.y * Math.sin(angle), y: pt.x * Math.sin(angle) + pt.y * Math.cos(angle) }; return item } const handleContextMenu = (e:any) => { e.preventDefault(); }; return ( <>
{/**正在校准时的loading */} {caloading &&
正在校准...
} {/**测量区 */}
{/**选择轨型区 */} {railId.length > 0 && (
setRailPickerVisible(true)} />
)}
{/**局段线区 */}

{contextState.currOrgCode ? orgTextArr.join('/') : '点击此处选择铁路局和工务段'}

修改
{/**手动校准区 */} {showCalibration &&
(onMoveLine("left"))} onTouchStart={()=>handlePressStart("left")} onTouchEnd={handlePressEnd} onContextMenu={handleContextMenu} className="text-[20px] ml-[5px]" alt="左移"/> (onMoveLine("right"))} onTouchStart={()=>handlePressStart("right")} onTouchEnd={handlePressEnd} onContextMenu={handleContextMenu} className="text-[20px] ml-[5px]" alt="右移"/> (onMoveLine("up"))} onTouchStart={()=>handlePressStart("up")} onTouchEnd={handlePressEnd} onContextMenu={handleContextMenu} className="text-[20px] ml-[5px]" alt="上移"/> (onMoveLine("down"))} onTouchStart={()=>handlePressStart("down")} onTouchEnd={handlePressEnd} onContextMenu={handleContextMenu} className="text-[20px] ml-[5px]" alt="下移"/> (onRotationLine("left"))} onTouchStart={()=>handleRotationPressStart("left")} onTouchEnd={handlePressEnd} onContextMenu={handleContextMenu} className="text-[20px] ml-[5px]" alt="逆时针旋转"/> (onRotationLine("right"))} onTouchStart={()=>handleRotationPressStart("right")} onTouchEnd={handlePressEnd} onContextMenu={handleContextMenu} className="text-[20px] ml-[5px]" alt="顺时针旋转"/>
} {/**按钮操作区 */}
{/**测量状态区 */}
({ label: t.name, value: t.id }))]} visible={railPickerVisible} onClose={() => { setRailPickerVisible(false); }} value={railId} onConfirm={(v) => { onRailSizeChange(v) }} /> ); }