Browse Source

优化测量校准

feat_upload_server_url_0416
LiLongLong 4 months ago
parent
commit
6f1a3064a6
  1. 2
      .env
  2. BIN
      build.zip
  3. 2
      package.json
  4. 31
      src/App.tsx
  5. 84
      src/components/Header.tsx
  6. 61
      src/components/syncData.tsx
  7. 18
      src/pages/measure/components/Detail.tsx
  8. 103
      src/pages/measure/components/MeasureAction.tsx
  9. 69
      src/pages/measure/components/MeasureDetail.tsx
  10. 102
      src/pages/measure/components/konva/MeasurementCanvas.tsx
  11. 15
      src/services/measure/analysis.ts
  12. 1
      src/services/measure/type.ts
  13. 13
      src/services/wsTypes.ts
  14. 4
      src/store/index.ts
  15. 8
      src/store/ktj/orgState.ts
  16. 22
      src/store/measure/measureState.ts

2
.env

@ -1 +1 @@
REACT_APP_WS_URL=127.0.0.1:8080/ws
REACT_APP_WS_URL=192.168.1.146:8080/ws

BIN
build.zip

2
package.json

@ -2,7 +2,7 @@
"name": "outline",
"version": "0.1.0",
"private": true,
"proxy": "http://127.0.0.1:8080",
"proxy": "http://192.168.1.146:8080",
"dependencies": {
"@babel/core": "^7.16.0",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.3",

31
src/App.tsx

@ -2,16 +2,17 @@ import React, { useEffect, useState } from "react";
import "./App.scss";
import { Outlet, useNavigate } from "react-router";
import { Layout, ConfigProvider } from "antd";
import { Layout, ConfigProvider, message} from "antd";
import { default as AppHeader } from "./components/Header";
import { default as AppFooter } from "./components/Footer";
import SideMenu from "./components/SideMenu";
import { createWebSocket, sharedWsUrl } from "./services/socket";
import { useAppDispatch } from "./utils/hooks";
import { updateDeviceState } from "./store/device/deviceState";
import { setSyncData } from "./store/ktj/orgState";
import zhCN from 'antd/lib/locale/zh_CN'; // 引入中文语言包
import { updateDevice } from "./store/features/contextSlice";
import { getStatus } from "./services/ktj/org";
import { getStatus, update } from "./services/ktj/org";
import SyncData from "./components/syncData";
const { Header, Footer, Sider, Content } = Layout;
@ -36,6 +37,25 @@ function App() {
} else if (data.messageType === "STATE" && data.path === "/api/profiler-state/get-state") {
// console.log(data.data);
dispatch(updateDevice(data.data));
}else if(data.path === "/get-task-progress"){
let syncData = data.data;
if(syncData){
let {
progress,
success
} = syncData;
if(syncData.hasOwnProperty('success') && !success){
message.error(syncData.message)
}
//取整
progress = Math.floor(progress)
dispatch(setSyncData(progress))
if(progress!== 100){
setIsSync(true)
}else{
setIsSync(false)
}
}
}
});
wsClient.connect();
@ -59,8 +79,9 @@ function App() {
const [isSync, setIsSync] = useState(false)
const queryStatus = () => {
getStatus().then(res => {
console.log('res-----是否需要同步数据------', res.data)
setIsSync(res.data)
if(res.data){
update();
}
})
}
@ -102,7 +123,7 @@ function App() {
</Layout>
</Layout>
</ConfigProvider>
{isSync && <SyncData isShowModal={isSync} closeModal={closeModal}></SyncData>}
{isSync && <SyncData isShowModal={isSync} closeModal={closeModal} setIsSync={setIsSync}></SyncData>}
</div>
);
}

84
src/components/Header.tsx

@ -14,14 +14,12 @@ import { useAppDispatch, useAppSelector } from "../utils/hooks";
import { updateUser } from "../store/features/contextSlice";
import "./bluetooth.scss";
import { update } from "../services/ktj/org";
import SyncData from "./syncData";
export default function Header() {
const navigate = useNavigate();
const dispatch = useAppDispatch();
const deviceInfo = useAppSelector(store => store.context.device);
const deviceState = useAppSelector(store => store.deviceState);
const userInfo = useAppSelector(store => store.context.user.loginUser);
let [isConnect, setIsConnect] = useState(deviceState.isConnect);
//获取当前websocet的状态
const showBlueImg = () => {
if (deviceState.isConnect) {
@ -34,30 +32,8 @@ export default function Header() {
);
}
return null;
// if(!isConnect){
// return <Popover content={getBtList()} title="可连接设备">
// <div ></div>
// <img src={bluetooth_nc} alt="" className="ext-base ml-2 h-6" />
// </Popover>
// }else {
// return <Popover content={getBtContent()} title="">
// <img src={icon_usb} onClick={onDisconnectBt} alt="" className="ext-base ml-2 h-6" />
// </Popover>
// }
};
let list = [
{
name: "Kdkow_1",
id: "1",
},
{
name: "llwoa_2",
id: "2",
},
];
let [bluetoothList, setbluetoothList] = useState(list);
//获取mock数据
useEffect(() => {
if (userInfo.nickname || userInfo.account) {
setNickname(userInfo.nickname || userInfo.account);
@ -71,36 +47,10 @@ export default function Header() {
}, [userInfo.nickname, userInfo.account]);
//同步科天健基础数据
const [isShowModal, setIsShowModal] = useState(false)
const onSyncKTJData = () => {
setIsShowModal(true)
update()
}
const closeModal = () => {
setIsShowModal(false)
}
// const [percent, setPercent] = useState(0)
// useEffect(() => {
// const intervalId = setInterval(() => {
// if (percent < 100) {
// const randomIncrement = Math.floor(Math.random() * 10) + 1;
// const newProgress = Math.min(percent + randomIncrement, 100);
// setPercent(newProgress);
// } else {
// clearInterval(intervalId);
// }
// }, 1000);
// if(percent >= 90){
// clearInterval(intervalId);
// }
// return () => {
// clearInterval(intervalId);
// };
// }, [isShowModal,percent]);
const [messageApi, contextHolder] = message.useMessage();
const [nickname, setNickname] = useState<string>();
const items: MenuProps["items"] = [
@ -133,24 +83,6 @@ export default function Header() {
},
];
const getBtList = () => {
let Dom = null;
if (!isConnect) {
Dom = (
<div>
{bluetoothList.map(item => {
return (
<div className="mt-[1rem]" onClick={connectBt}>
<Button type="link">{item.name}</Button>
</div>
);
})}
</div>
);
}
return Dom;
};
//设备已连接
const getBtContent = () => {
return (
@ -169,16 +101,6 @@ export default function Header() {
);
};
//断开蓝牙连接
const onDisconnectBt = () => {
setIsConnect(false);
};
const connectBt = () => {
setIsConnect(true);
setTimeout(() => {}, 1000);
};
return (
<>
{contextHolder}
@ -200,9 +122,6 @@ export default function Header() {
</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()}
<div className="mr-8 flex items-center min-w-[5rem]">
<Dropdown menu={{ items }} trigger={["click"]}>
@ -213,7 +132,6 @@ export default function Header() {
</Dropdown>
</div>
</div>
{isShowModal && <SyncData isShowModal={isShowModal} closeModal={closeModal}></SyncData>}
</>
);
}

61
src/components/syncData.tsx

@ -1,60 +1,31 @@
import { useState, useEffect } from "react";
import { Progress } from "antd";
import { message, Progress } from "antd";
import { useAppDispatch, useAppSelector } from "../utils/hooks";
import "./sync.scss";
import { update } from "../services/ktj/org";
export default function SyncData(props:{isShowModal:boolean, closeModal:Function}) {
//同步科天健基础数据
const onSyncKTJData = () => {
update().then(res => {
setPercent(100)
props.closeModal()
setTimeout(() => {
setPercent(0)
}, 2000);
})
}
useEffect(()=>{
onSyncKTJData()
}, [props.isShowModal])
export default function SyncData(props:{isShowModal:boolean, closeModal:Function, setIsSync:Function}) {
const [percent, setPercent] = useState(0)
useEffect(() => {
const intervalId = setInterval(() => {
if (percent < 100) {
const randomIncrement = Math.floor(Math.random() * 3) + 1;
const newProgress = Math.min(percent + randomIncrement, 100);
setPercent(newProgress);
} else {
clearInterval(intervalId);
}
}, 1000);
if(percent >= 90){
clearInterval(intervalId);
const syncDataProcess = useAppSelector(store => store.orgState.syncDataProcess);
useEffect(()=>{
setPercent(syncDataProcess)
if(syncDataProcess === 100){
props.closeModal();
props.setIsSync(false)
}
return () => {
clearInterval(intervalId);
};
}, [props.isShowModal,percent]);
},[syncDataProcess])
const styleObj:any = {
position: "absolute",
marginTop: "-200px",
color: "#0051b9",
color: "#1677ff",
fontSize: "20px"
}
return (
<>
<div
className="fixed inset-0 bg-red opacity-50 z-50 cursor-pointer flex justify-center items-center" style={{background:"#202020"}}
>
<div style={styleObj}></div>
<div className="flex w-[60vw] justify-center items-center margin-auto">
<Progress type="circle" format={(percent) => <span style={{ color: '#0051b9' }}>{percent}%</span>} percent={percent}/>
</div>
<div className="fixed inset-0 bg-red opacity-50 z-50 cursor-pointer flex justify-center items-center" style={{background:"#202020"}} >
<div style={styleObj}></div>
<div className="flex w-[60vw] justify-center items-center margin-auto">
<Progress type="circle" format={(percent) => <span style={{ color: '#1677ff' }}>{percent}%</span>} percent={percent}/>
</div>
</>
</div>
);
}

18
src/pages/measure/components/Detail.tsx

@ -6,22 +6,26 @@ import { useNavigate, useParams } from 'react-router-dom';
import type { AnalysisReport } from "../../../services/measure/type";
import { AnalysisData, BenchmarkShape, MeasurementCanvasRef } from './konva/MeasurementCanvas';
import MeasurementCanvas from "./konva/MeasurementCanvas";
import {
getReport
} from "../../../services/measure/analysis";
import { getReport } from "../../../services/measure/analysis";
import { getBaseRecordPointSetByCode } from "../../../services/track/trackShape"
import { GX_CODE } from '../../../constant';
import { useAppSelector } from "../../../utils/hooks";
export default function MeasureDetail() {
const {id} = useParams()
const measureState = useAppSelector((store) => store.measureState);
const [measureId, setMeasureId] = useState<number>(Number(id))
useEffect(()=>{
onShowDetail(measureId)
}, [])
const [gxCode, setGxCode] = useState<string>('')
useEffect(()=>{
setGxCode(measureState.gxCode)
}, [measureState])
const onShowDetail = (measureId:number)=> {
//获取基线
getBaseRecordPointSetByCode(GX_CODE).then(res => {
getBaseRecordPointSetByCode(gxCode).then(res => {
if (res.success && res.data && res.data.points) {
const benchmarkShapes = JSON.parse(res.data.points) as BenchmarkShape[];
if (canvasRef.current) {
@ -42,7 +46,7 @@ export default function MeasureDetail() {
//法线
const onDetaiResult = (uuid:string) => {
getReport(uuid,GX_CODE).then(res=> {
getReport(uuid,gxCode).then(res=> {
if (res.success) {
const report: AnalysisReport = res.data;
console.log(report);

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

@ -1,13 +1,15 @@
import React, { useState, useEffect, useRef, useCallback, useMemo } from "react";
import { Button, Checkbox, CheckboxProps, Drawer, message, Select, Switch } from "antd";
import { Button, Checkbox, CheckboxProps, Drawer, message, Select, Spin, Switch } from "antd";
import { useNavigate } from "react-router";
import {
fetchAnalysisReport,
getAlignPointsByRailSize,
startMeasurement,
} from "../../../services/measure/analysis";
import { getBaseRecordPointSetByCode, gx_list } from "../../../services/track/trackShape"
import { createWebSocket, sharedWsUrl } from "../../../services/socket";
import { switchMeasureAfterSave } from "../../../store/features/contextSlice";
import measureState, { updateGxState } from "../../../store/measure/measureState";
import { AnalysisReport, trackItem } from "../../../services/measure/type";
import { MeasureState, TaskState, TrackRecordSig } from "../../../services/wsTypes";
import { useAppDispatch, useAppSelector } from "../../../utils/hooks";
@ -23,6 +25,9 @@ const wsClient = createWebSocket(sharedWsUrl);
export default function MeasureAction() {
const dispatch = useAppDispatch();
const navigate = useNavigate();
const measureState = useAppSelector((store) => store.measureState);
const [gxCode, setGxCode] = useState<string>(GX_CODE)
const STEP_COLOR_GREEN = "green";
const STEP_COLOR_BLUE = "blue";
const STEP_COLOR_GREY = "grey";
@ -67,13 +72,18 @@ export default function MeasureAction() {
dispatch(switchMeasureAfterSave(e.target.checked));
};
useEffect(()=>{
setGxCode(measureState.gxCode)
}, [measureState])
// 分析按钮点击事件
const onAnalysisBtnClick = () => {
if (analysisReport) {
setOpenDrawer(true);
return;
}
fetchAnalysisReport(GX_CODE).then(res => {
fetchAnalysisReport(gxCode).then(res => {
if (res.success) {
const report: AnalysisReport = res.data;
console.log(report);
@ -104,7 +114,7 @@ export default function MeasureAction() {
// 重置测量相关状态
setMeasurementFinished(false);
setAnalysisReport(null);
setshowCalibration(false)//校准线
isLeftFinished.current = false;
leftPoints.current = [];
rightPoints.current = [];
@ -162,6 +172,25 @@ export default function MeasureAction() {
// });
};
//校准
const [showCalibration, setshowCalibration] = useState(false)
const [caloading, setCaLoading] = useState(false)
const onCalibrationBtnClick = () => {
setCaLoading(true)
//获取校准数据
getAlignPointsByRailSize({railSize:railSize}).then(res => {
if(res.success){
setshowCalibration(true)
canvasRef.current?.setMeasurementCalibrationData(res.data)
}else{
message.error('校准失败!')
}
setCaLoading(false)
}).catch(e=>{
message.error('校准失败!')
})
}
// 辅助函数:渲染状态项的图标
const renderStatusIcon = (item: (typeof initialStatusList)[0]) => {
if (item.color === STEP_COLOR_GREEN) {
@ -299,13 +328,14 @@ export default function MeasureAction() {
return () => subscription.unsubscribe();
}, [onStart]);
/** ----------------------- 页面加载获取基础图形数据 ----------------------- **/
/** ----------------------- 页面加载获取基础图形数据 -------基线---------------- **/
useEffect(() => {
queryBasePoints(GX_CODE)
queryBasePoints(gxCode)
//获取轨型
getTrackDataList()
}, []);
//获取测量基线
const queryBasePoints = (gxCode:string) => {
getBaseRecordPointSetByCode(gxCode).then(res => {
if (res.success) {
@ -343,11 +373,18 @@ export default function MeasureAction() {
},[trackList])
//当前选择的轨型 默认"GX-60"
const [railSize, setRailSize] = useState<string>(GX_CODE)
const onTrackChange = (value: string) => {
setRailSize(value)
queryBasePoints(value)
//缓存至STORE
dispatch(updateGxState(value))
}
const onExport = () => {};
const onExport = () => {
};
/** ----------------------- 渲染 ----------------------- **/
return (
<>
@ -410,26 +447,27 @@ export default function MeasureAction() {
)}
</section>
</div>
<div className="relative">
<MeasurementCanvas
width={800}
height={600}
logicalExtent={{ minX: -50, maxX: 50, minY: -20, maxY: 60 }}
gridStep={1}
origin={{ x: 0, y: 20 }}
pixelPerMm={8}
maxZoom={10}
showGrid={showGrid}
showBenchmark={showStandard}
showAnalysis={showMark}
showScale={false}
scaleInterval={1}
showCoordinates={showGrid}
ref={canvasRef}
/>
</div>
<Spin spinning={caloading} tip="正在校准...">
<div className="relative">
<MeasurementCanvas
width={800}
height={650}
logicalExtent={{ minX: -50, maxX: 50, minY: -20, maxY: 60 }}
gridStep={1}
origin={{ x: 0, y: 20 }}
pixelPerMm={8}
maxZoom={10}
showGrid={showGrid}
showBenchmark={showStandard}
showAnalysis={showMark}
showScale={false}
scaleInterval={1}
showCoordinates={showGrid}
showCalibration={showCalibration}
ref={canvasRef}
/>
</div>
</Spin>
</div>
{/* 右侧区域:根据 showAnalysisTable 状态显示测量步骤或分析表格 */}
<div className="min-w-[300px] flex-auto py-6 flex flex-col items-center">
@ -469,6 +507,15 @@ export default function MeasureAction() {
>
</Button>
{/* <Button
style={{ width: 200 }}
size="large"
type="primary"
onClick={onCalibrationBtnClick}
disabled={!measurementFinished}
>
</Button> */}
<Checkbox checked={afterSave} onChange={onAfterSaveChange}>
</Checkbox>
@ -508,11 +555,11 @@ export default function MeasureAction() {
</tbody>
</table>
</div>
<div className="mt-5 flex justify-center">
{/* <div className="mt-5 flex justify-center">
<Button style={{ minWidth: 200 }} size="large" type="primary" onClick={onExport}>
</Button>
</div>
</div> */}
</>
)}
</Drawer>

69
src/pages/measure/components/MeasureDetail.tsx

@ -1,6 +1,6 @@
import {getDetailList, delDetail, getDetail, getPointByUuid, getPointsById} from '../../../services/measure/analysis'
import {getDetailList, delDetail, getDetail, getPointByUuid, getPointsById, getAlignPointById} from '../../../services/measure/analysis'
import { useState, useEffect, useRef } from 'react'
import {message, Button, type TableColumnsType, type TableProps, Modal, Table, Pagination, Input, Select, Switch, Progress } from 'antd';
import {message, Button, type TableColumnsType, type TableProps, Modal, Table, Pagination, Input, Select, Switch, Progress, Flex, Spin } from 'antd';
import type { AnalysisReport, DetailTable, SearchParams } from "../../../services/measure/type";
import { ExclamationCircleFilled, CheckCircleOutlined, WarningOutlined } from '@ant-design/icons';
import { AnalysisData, BenchmarkShape, MeasurementCanvasRef } from './konva/MeasurementCanvas';
@ -176,27 +176,14 @@ export default function MeasureDetail() {
const handleCloseUpload = () => {
}
const onDel = (item:DetailTable) => {
confirm({
title: '提示',
icon: <ExclamationCircleFilled />,
content: '请确认是否删除选中的数据',
okText:'确认',
cancelText:'取消',
onOk() {
doDel({ids:item.id})
},
onCancel() {
console.log('Cancel');
},
});
}
const [currentRecord, setCurrentRecord] = useState<Partial<DetailTable>>({})
const onShowDetail = async (item:DetailTable)=> {
//获取基线
setIsModalOpen(true)
let res = await getBaseRecordPointSetByCode(GX_CODE)
setCurrentRecord(item)
setshowCalibration(false)
let res = await getBaseRecordPointSetByCode(item.railSize)
if (res.success && res.data && res.data.points) {
const benchmarkShapes = JSON.parse(res.data.points) as BenchmarkShape[];
if(!benchmarkShapes || !benchmarkShapes.length){
@ -215,11 +202,10 @@ export default function MeasureDetail() {
if(resData){
// navigate(`/measure/detail/${item.id}`)
//@ts-ignore
getRecordByUuid(resData.data.uuid)
// getRecordByUuid(resData.data.uuid)
//@ts-ignore
onDetaiResult(resData.data.uuid)
}
//获取测量的坐标点
getMeasurePoints(item)
}
@ -267,7 +253,8 @@ export default function MeasureDetail() {
//法线
const [analysisReport, setAnalysisReport] = useState<AnalysisReport>();
const onDetaiResult = (uuid:string) => {
getReport(uuid,GX_CODE).then(res=> {
const gxValue= currentRecord.railSize || GX_CODE
getReport(uuid, gxValue).then(res=> {
if (res.success) {
const report: AnalysisReport = res.data;
console.log(report);
@ -381,6 +368,26 @@ export default function MeasureDetail() {
setIsModalOpen(false)
}
//校准
const [showCalibration, setshowCalibration] = useState(false)
const [caloading, setCaLoading] = useState(false)
const handleCalibration = () => {
setCaLoading(true)
if(currentRecord && currentRecord.id){
getAlignPointById({id:currentRecord.id}).then(res=>{
if(res.success){
setshowCalibration(true)
canvasRef.current?.setMeasurementCalibrationData(res.data)
}else{
message.error('校准失败!')
}
setCaLoading(false)
}).catch(e=>{
message.error('校准失败!')
})
}
}
useEffect(() => {
const intervalId = setInterval(() => {
@ -406,7 +413,7 @@ export default function MeasureDetail() {
{isModalOpen ?
<div className="pt-[5px]">
<div className="flex">
<div className="ml-[7rem]">
<div className="ml-[2rem]">
<Switch defaultChecked onChange={checked => setShowGrid(checked)} />
<span>线</span>
</div>
@ -438,11 +445,10 @@ export default function MeasureDetail() {
<span>线</span>
</div>
</div>
<div className="flex ml-[7rem] mt-[5px]">
<div className="flex ml-[2rem] mt-[5px]">
<MeasurementCanvas
width={800}
height={600}
height={700}
logicalExtent={{ minX: -50, maxX: 50, minY: -20, maxY: 60 }}
gridStep={1}
origin={{ x: 0, y: 20 }}
@ -454,6 +460,7 @@ export default function MeasureDetail() {
showScale={false}
scaleInterval={1}
showCoordinates={true}
showCalibration={showCalibration}
ref={canvasRef}
/>
@ -494,15 +501,20 @@ export default function MeasureDetail() {
</tbody>
</table>
</div>
{/* <div className="flex justify-center mt-[1.5rem]" >
<Button type="primary" onClick={handleCalibration} className='w-[150px]'>
</Button>
</div> */}
<div className="flex justify-center mt-[1.5rem]" >
<Button type="primary" onClick={handleCancel} className='w-[200px]'>
<Button type="primary" onClick={handleCancel} className='w-[150px]'>
</Button>
</div>
</div>
}
</div>
</div>
:
<>
@ -537,6 +549,7 @@ export default function MeasureDetail() {
</div>
<div>
<Table<DetailTable>
style={{height:"70vh"}}
locale={{
emptyText: '无数据',
}}

102
src/pages/measure/components/konva/MeasurementCanvas.tsx

@ -62,11 +62,13 @@ export interface MeasurementCanvasProps {
initialBenchmarkData?: BenchmarkShape[];
initialMeasurementDataLeft?: Point[];
initialMeasurementDataRight?: Point[];
initMeasurementCalibrationData?: Point[];
initialAnalysisData?: AnalysisData[];
// 控制是否显示标准线(benchmark shapes)
showBenchmark?: boolean;
// 控制是否显示分析线
showAnalysis?: boolean;
showCalibration?: boolean;
}
export interface MeasurementCanvasRef {
@ -75,6 +77,7 @@ export interface MeasurementCanvasRef {
setBenchmarkData: (data: BenchmarkShape[]) => void;
setMeasurementDataLeft: (data: Point[]) => void;
setMeasurementDataRight: (data: Point[]) => void;
setMeasurementCalibrationData: (data: Point[]) => void;
setMeasurementData: (data: Point[]) => void;
setAnalysisData: (data: AnalysisData[]) => void;
redraw: () => void;
@ -106,9 +109,11 @@ const MeasurementCanvas = forwardRef<MeasurementCanvasRef, MeasurementCanvasProp
initialBenchmarkData = [],
initialMeasurementDataLeft = [],
initialMeasurementDataRight = [],
initMeasurementCalibrationData = [],
initialAnalysisData = [],
showBenchmark = true,
showAnalysis = true,
showCalibration = false
} = props;
// Stage 物理中心(像素)
@ -141,6 +146,7 @@ const MeasurementCanvas = forwardRef<MeasurementCanvasRef, MeasurementCanvasProp
const rightPointsRef = useRef<Point[]>([...initialMeasurementDataRight]);
const [measurementDataLeft, setMeasurementDataLeftState] = useState<Point[]>(initialMeasurementDataLeft);
const [measurementDataRight, setMeasurementDataRightState] = useState<Point[]>(initialMeasurementDataRight);
const [measurementCalibrationData, setMeasurementCalibrationDataState] = useState<Point[]>(initMeasurementCalibrationData);
const [measurementData, setMeasurementDataState] = useState<Point[]>([]);
const refreshInterval = 50;
const refreshTimer = useRef<number | null>(null);
@ -190,6 +196,10 @@ const MeasurementCanvas = forwardRef<MeasurementCanvasRef, MeasurementCanvasProp
redraw: () => {
setScale((prev) => prev);
},
setMeasurementCalibrationData: (data: Point[])=>{
setMeasurementCalibrationDataState(data)
}
}));
const stageRef = useRef<any>(null);
@ -482,9 +492,11 @@ const MeasurementCanvas = forwardRef<MeasurementCanvasRef, MeasurementCanvasProp
);
};
const renderMeasurementCurveRight = () => {
if (measurementDataRight.length === 0) return null;
const pts = measurementDataRight
//校准线
const [points, setPoints] = useState<{x:number;y:number}[]>([])
const renderMeasurementCalibration = () => {
if (!measurementCalibrationData || measurementCalibrationData.length === 0) return null;
const pts = measurementCalibrationData
.map((pt) => {
const p = transform(pt);
return [p.x, p.y];
@ -498,6 +510,79 @@ const MeasurementCanvas = forwardRef<MeasurementCanvasRef, MeasurementCanvasProp
tension={1}
lineCap="round"
lineJoin="round"
ref={lineRef}
draggable
onDragStart={onHandDragStrat}
onDragEnd={onHandleDragEnd}
onDragMove={onHandleDragMove}
/>
);
}
// 拖动开始时的 X 坐标
const [dragStartX, setDragStartX] = useState(0);
// 拖动开始时的 Y 坐标
const [dragStartY, setDragStartY] = useState(0);
// 拖动偏移量 X
const [dragOffsetX, setDragOffsetX] = useState(0);
// 拖动偏移量 Y
const [dragOffsetY, setDragOffsetY] = useState(0);
// 是否正在拖动
const [isDragging, setIsDragging] = useState(false);
// 折线的引用
const lineRef = useRef<any>(null);
// 拖动开始的处理函数
const onHandDragStrat = (e:any) => {
setIsDragging(true);
if (lineRef.current) {
const pos = lineRef.current.position();
setDragStartX(pos.x);
setDragStartY(pos.y);
const offset = stageRef.current.getPointerPosition();
if (offset) {
setDragOffsetX(offset.x);
setDragOffsetY(offset.y);
}
console.log('start========', pos.x, pos.y, offset.x, offset.y)
}
};
// 拖动过程中的处理函数
const onHandleDragMove = (e:any) => {
if (isDragging && lineRef.current && e.nativeEvent) {
const pos = lineRef.current.position();
const newX = pos.x + (e.nativeEvent.offsetX - dragOffsetX);
const newY = pos.y + (e.nativeEvent.offsetY - dragOffsetY);
lineRef.current.position({ x: newX, y: newY });
console.log('Move========', pos.x, pos.y, newX, newY)
}
};
// 拖动结束的处理函数
const onHandleDragEnd = (e:any) => {
const newPoints = lineRef.current.points();
const newCoords = [];
for (let i = 0; i < newPoints.length; i += 2) {
newCoords.push({ x: newPoints[i], y: newPoints[i + 1] });
}
console.log('原坐标点:', measurementCalibrationData);
console.log('移动后的新坐标点:', newCoords);
};
const renderMeasurementCurveRight = () => {
if (measurementDataRight.length === 0) return null;
const pts = measurementDataRight.map((pt) => {
const p = transform(pt);
return [p.x, p.y];
}).flat();
return (
<Line
points={pts}
stroke="red"
strokeWidth={2}
tension={1}
lineCap="round"
lineJoin="round"
/>
);
};
@ -534,7 +619,6 @@ const MeasurementCanvas = forwardRef<MeasurementCanvasRef, MeasurementCanvasProp
);
});
};
return (
<div
style={{
@ -556,11 +640,17 @@ const MeasurementCanvas = forwardRef<MeasurementCanvasRef, MeasurementCanvasProp
onWheel={handleWheel}
style={{ background: "#fff" }}
>
<Layer>
{showGrid && renderGridAndAxes()}
{/**基线层 */}
{showBenchmark && renderBenchmarkShapes()}
{renderMeasurementCurveLeft()}
{renderMeasurementCurveRight()}
{/**左线层 校准时不显示*/}
{!showCalibration && renderMeasurementCurveLeft()}
{/**右线层 */}
{!showCalibration && renderMeasurementCurveRight()}
{/**校准层 */}
{showCalibration && renderMeasurementCalibration()}
{renderMeasurementCurve()}
{showAnalysis && renderAnalysis()}
</Layer>

15
src/services/measure/analysis.ts

@ -124,3 +124,18 @@ export function getPointsById(params:{id:number}){
});
}
//测量记录校正测量
export function getAlignPointById(params:{id:number}){
return httpRequest<BaseResponse>({
url: `/api/measurement-data/getAlignPointById/${params.id}`,
method: "POST",
});
}
//开始测量校正测量
export function getAlignPointsByRailSize(params:{railSize:string}){
return httpRequest<BaseResponse>({
url: `/api/align/catch/points/${params.railSize}`,
method: "GET",
});
}

1
src/services/measure/type.ts

@ -16,6 +16,7 @@ export type DetailTable = {
direction:string;
dataSource:string;
extraDesc:string;
railSize:string;
}
export type MeasureRecord = {

13
src/services/wsTypes.ts

@ -137,4 +137,15 @@ export type DeviceStatus = {
path: "/api/profiler-state/get-state";
};
export type Datagram = TrackRecordSig | TaskState | ContextMessage | MeasureState | ChannelMessage | DeviceStatus;
export type ProgressStatus = {
messageType: "SYNC";
data: {
progress: number; //同步进度
message: string; //消息
success: boolean;//同步状态
};
path: "/get-task-progress";
};
export type Datagram = TrackRecordSig | TaskState | ContextMessage | MeasureState | ChannelMessage | DeviceStatus | ProgressStatus;

4
src/store/index.ts

@ -5,6 +5,7 @@ import counterSlice from "./features/counterSlice";
import contextSlice from "./features/contextSlice";
import deviceStateSlice from "./device/deviceState";
import orgStateSlice from "./ktj/orgState";
import measureStateSlice from "./measure/measureState";
// configureStore创建一个redux数据
const store = configureStore({
// 合并多个Slice
@ -12,7 +13,8 @@ const store = configureStore({
counter: counterSlice,
context: contextSlice,
deviceState: deviceStateSlice,
orgState: orgStateSlice
orgState: orgStateSlice,
measureState:measureStateSlice
},
});

8
src/store/ktj/orgState.ts

@ -3,14 +3,18 @@ import { createSlice } from '@reduxjs/toolkit';
const orgSlice = createSlice({
name: 'orgData',
initialState: {
value: null
value: null,
syncDataProcess:0
},
reducers: {
setOrgData: (state, action) => {
state.value = action.payload;
},
setSyncData: (state, action) => {
state.syncDataProcess = action.payload
}
}
});
export const { setOrgData } = orgSlice.actions;
export const { setOrgData, setSyncData } = orgSlice.actions;
export default orgSlice.reducer;

22
src/store/measure/measureState.ts

@ -0,0 +1,22 @@
import { createSlice } from "@reduxjs/toolkit";
const initialState = {
gxCode:''
}
// 创建一个 Slice
export const measureStateSlice = createSlice({
name: "measureState",
initialState,
// 定义 reducers 并生成关联的操作
reducers: {
// 更新轨型
updateGxState: (state, { payload }) => {
state.gxCode = payload.gxCode || "GX-60";
},
},
});
export const { updateGxState } = measureStateSlice.actions;
// 默认导出
export default measureStateSlice.reducer;
Loading…
Cancel
Save