diff --git a/src/mock/recordList.ts b/src/mock/recordList.ts new file mode 100644 index 0000000..cb57224 --- /dev/null +++ b/src/mock/recordList.ts @@ -0,0 +1,38 @@ +export const detailList = [{ + "id": 2703,//数据主键id + "createTime": "2025-03-03 17:05:34",//数据创建时间 + "updateTime": "2025-03-03 17:05:34",//数据修改时间 + "uuid": "650fc0a3-8bb2-4223-973e-72846fd31b82",//数据uuid + "operatorName": "张三",//操作员姓名 + "trackShapeCode": "001",//轨型code + "verificationMethodCode": "aaa",//核校方式code + "name": "京沪铁路",//测量名称 + "lineName": "河北段",//线路名称 + "location": "100米处",//位置 + "direction": "左"///方向 +},{ + "id": 2704,//数据主键id + "createTime": "2025-03-03 17:05:34",//数据创建时间 + "updateTime": "2025-03-03 17:05:34",//数据修改时间 + "uuid": "650fc0a3-8bb2-4223-973e-72846fd31b83",//数据uuid + "operatorName": "李四",//操作员姓名 + "trackShapeCode": "002",//轨型code + "verificationMethodCode": "bbb",//核校方式code + "name": "京昆铁路",//测量名称 + "lineName": "河北段",//线路名称 + "location": "5100米处",//位置 + "direction": "右"///方向 +}] + +export const bluetoothList = [{ + name:'Kdkow_1', + id:'1', +},{ + name:'llwoa_2', + id:'2', +}] + +export const bluetoothInfo = { + type: 'kxy0812', + power: '78%', +} \ No newline at end of file diff --git a/src/pages/measure/components/MeasureAction.tsx b/src/pages/measure/components/MeasureAction.tsx index 07e6d4d..50a7619 100644 --- a/src/pages/measure/components/MeasureAction.tsx +++ b/src/pages/measure/components/MeasureAction.tsx @@ -9,6 +9,10 @@ import ResultLayer from "./graph/ResultLayer"; import MarkLayer from "./graph/MarkLayer"; import { useDispatch, useSelector } from "react-redux"; import { switchMeasureAfterSave } from "../../../store/features/contextSlice"; +import { AnalyzeAngle } from "../../../services/measure/type"; +import { MeasureState, taskStatusDescMap } from "../../../services/wsTypes"; + +const wsClient = createWebSocket(sharedWsUrl); export default function MeasureAction() { const dispatch = useDispatch(); @@ -23,19 +27,21 @@ export default function MeasureAction() { const navigate = useNavigate(); + const [angles, setAngles] = useState([]); + const [taskStatus, setTaskStatus] = useState("IDLE"); + const onAfterSaveChange: CheckboxProps["onChange"] = e => { dispatch(switchMeasureAfterSave(e.target.checked)); }; const onAnalysisBtnClick = () => { // navigate("../detail"); analyzeMeasurement().then(res => { - if (res.status === 0) { - // mask - + if (res.success) { + setAngles(res.data.angles); } else { message.error(res.data.info); } - }) + }); }; const onStart = () => { @@ -61,6 +67,15 @@ export default function MeasureAction() { }); }; + useEffect(() => { + const subscription = wsClient.dataOb.subscribe(data => { + if (data.messageType === "STATE" && data.path === "/measurement-task/get-task-state") { + setTaskStatus(data.data.taskStatus); + } + }); + wsClient.connect(); + return () => subscription.unsubscribe(); + }); return (
@@ -77,10 +92,12 @@ export default function MeasureAction() { setShowResult(checked)} /> 对比线
-
- setShowMark(checked)} /> - 角度线 -
+ {angles.length > 0 && ( +
+ setShowMark(checked)} /> + 角度线 +
+ )}
-
- -
+ {angles.length > 0 && ( +
+ +
+ )}

测量步骤

-
正在测量的状态
+
测量状态: {taskStatusDescMap[taskStatus]}
diff --git a/src/pages/measure/components/MeasureDetail.tsx b/src/pages/measure/components/MeasureDetail.tsx index 76fc0b1..23797e5 100644 --- a/src/pages/measure/components/MeasureDetail.tsx +++ b/src/pages/measure/components/MeasureDetail.tsx @@ -69,7 +69,11 @@ export default function MeasureDetail() { const [tableData, setTableData] = useState([]) const getDetailDataList = () => { getDetailList().then(res => { - setTableData(res.data.list) + if (res.success) { + setTableData(res.data.list) + } else { + setTableData(detailList) + } }).catch(e=>{ //如果接口异常,则使用mock数据 // setTableData(detailList) diff --git a/src/pages/measure/components/graph/MarkLayer.tsx b/src/pages/measure/components/graph/MarkLayer.tsx index f155894..b04045a 100644 --- a/src/pages/measure/components/graph/MarkLayer.tsx +++ b/src/pages/measure/components/graph/MarkLayer.tsx @@ -1,5 +1,6 @@ import { useCallback, useEffect, useRef } from "react"; import { calculatePointOnCircle, findSymmetricPoint } from "../../../../utils"; +import { AnalyzeAngle } from "../../../../services/measure/type"; const marks = [ { x: 9.949007022412, y: 0.1650166186941, degree: -80 }, @@ -17,7 +18,8 @@ export default function MarkLayer(props: { bottomPadding: number; columns: number; rows: number; - visibility: 'hidden' | 'visible'; + visibility: "hidden" | "visible"; + angles: AnalyzeAngle[]; }) { const xStartPx = props.leftPadding; const xEndPx = props.width - props.rightPadding; @@ -29,18 +31,17 @@ export default function MarkLayer(props: { const unitPx = xStepPx / 10; const canvasRef = useRef(null); - const calcPoints = useCallback( - (arr: typeof marks) => { - return arr.map(p => { + const calcPoints = useCallback(() => { + return props.angles + .map(p => ({ ...p, y: -p.y, degree: -p.degree })) + .map(p => { const p1 = calculatePointOnCircle(p.x * unitPx, p.y * unitPx, xStepPx / 2, p.degree); const p2 = findSymmetricPoint(p1.x, p1.y, p.x * unitPx, p.y * unitPx); // 角度文本,向外偏移 const p3 = calculatePointOnCircle(p.x * unitPx, p.y * unitPx, xStepPx / 2 + 10, p.degree); return [p1, p2, p3]; }); - }, - [unitPx, xStepPx] - ); + }, [props.angles, unitPx, xStepPx]); const draw = useCallback( (ctx: CanvasRenderingContext2D) => { @@ -53,7 +54,7 @@ export default function MarkLayer(props: { ctx.textAlign = "center"; ctx.font = "normal 14px system"; - const lines = calcPoints(marks); + const lines = calcPoints(); for (let idx = 0; idx < lines.length; idx++) { const line = lines[idx]; ctx.moveTo(line[0].x, line[0].y); @@ -62,14 +63,14 @@ export default function MarkLayer(props: { ctx.save(); ctx.translate(line[2].x, line[2].y); ctx.rotate(((marks[idx].degree + 90) * Math.PI) / 180); - ctx.fillText(`${-marks[idx].degree}°`, 0, 0); + ctx.fillText(props.angles[idx].describe, 0, 0); ctx.restore(); } ctx.stroke(); // ctx.fillStyle = "skyblue"; // 设置填充颜色 // ctx.fillRect(50, 50, 150, 100); // 绘制一个矩形 }, - [calcPoints, xEndPx, xStartPx, yStartPx, yStepPx] + [calcPoints, props.angles, xEndPx, xStartPx, yStartPx, yStepPx] ); useEffect(() => { @@ -82,7 +83,7 @@ export default function MarkLayer(props: { }, [draw]); return ( -
+
); diff --git a/src/pages/measure/components/graph/ResultLayer.tsx b/src/pages/measure/components/graph/ResultLayer.tsx index c5ba795..b38cdac 100644 --- a/src/pages/measure/components/graph/ResultLayer.tsx +++ b/src/pages/measure/components/graph/ResultLayer.tsx @@ -1,8 +1,8 @@ import { useCallback, useEffect, useRef, useState } from "react"; import points from "../../../../utils/measure.json"; import { createWebSocket, sharedWsUrl } from "../../../../services/socket"; + const wsClient = createWebSocket(sharedWsUrl); -console.log(sharedWsUrl); const pointArr: { x: number; y: number }[] = []; @@ -54,7 +54,7 @@ export default function ResultLayer(props: { const ctx = canvas.getContext("2d"); if (!ctx) return; - if (data.data.event === "START_RECORD_SIG") { + if ('event' in data.data && data.data.event === "START_RECORD_SIG") { // setRtPoints([]); pointArr.length = 0; ctx.resetTransform(); @@ -66,7 +66,7 @@ export default function ResultLayer(props: { ctx.translate(xStartPx + xOffset, yStartPx + yOffset); ctx.beginPath(); }, 0); - } else if (data.data.event === "END_RECORD_SIG") { + } else if ('event' in data.data && data.data.event === "END_RECORD_SIG") { // } } else if (data.path === "/measurement-task/profile-record-ctrl-sig") { diff --git a/src/services/httpRequest.ts b/src/services/httpRequest.ts index 919f7be..2853a21 100644 --- a/src/services/httpRequest.ts +++ b/src/services/httpRequest.ts @@ -1,9 +1,23 @@ import { Subject } from "rxjs"; -export interface BaseResponse { - data: T; +export interface FailResponse { status: number; + success: false; + data: { + info: string; + } +} + +export interface SuccessResponse { + data: T; + success: true; + status: 0; } +export type BaseResponse = SuccessResponse | FailResponse +// export interface BaseResponse { +// data: T; +// status: 0; +// } type HttpReqParam = { url: string; @@ -18,6 +32,12 @@ export type ApiException = "invalidToken" | "serverError"; const exceptionSub = new Subject(); export const exceptionOb = exceptionSub.asObservable(); +function extHandle(res: BaseResponse) { + return { + ...res, + success: res.status === 0, + }; +} export default async function httpRequest({ url, method = "GET", params = {}, encode = "json", headers = {} }: HttpReqParam) { const token = sessionStorage.getItem("token"); @@ -28,7 +48,7 @@ export default async function httpRequest({ url, method = "GET", params = {}, const query = urlEncode(params); const _url = query ? url + "?" + query : url; const res = await fetch(_url, { headers }); - return res.json() as T; + return res.json().then(res => extHandle(res) as T); } else { const body = encode === "json" ? JSON.stringify(params) : urlEncode(params); const _headers = @@ -36,7 +56,7 @@ export default async function httpRequest({ url, method = "GET", params = {}, ? { "Content-Type": "application/json; charset=utf-8", ...headers } : { "Content-Type": "application/x-www-form-urlencoded; charset=utf-8", ...headers }; const res = await fetch(url, { method, headers: _headers, body }); - return res.json() as T; + return res.json().then(res => extHandle(res) as T); } } export function urlEncode(params?: Record) { diff --git a/src/services/measure/analysis.ts b/src/services/measure/analysis.ts index 9aef396..9e793c6 100644 --- a/src/services/measure/analysis.ts +++ b/src/services/measure/analysis.ts @@ -1,5 +1,5 @@ import httpRequest, { type BaseResponse } from "../httpRequest"; -import type { DetailTable } from "../../services/measure/type"; +import type { AnalyzeResult, DetailTable, MeasureRecord } from "../../services/measure/type"; export function startMeasurement() { return httpRequest({ @@ -13,8 +13,9 @@ export function stopMeasurement() { method: "POST", }); } + export function analyzeMeasurement() { - return httpRequest({ + return httpRequest>({ url: "/measurement-task/analyze-measurement", method: "POST", }); @@ -27,29 +28,19 @@ export function saveMeasurement() { } export function getDetailList() { - return httpRequest>({ + return httpRequest>({ url: "/measurement-data/list", method: "POST", }); } -export function delDetail(params:{ids:string}) { +export function delDetail(params: { ids: string }) { return httpRequest({ url: `/measurement-data/delete/${params.ids}`, method: "POST", }); } -export type MeasureRecord = { - operatorName: "张三"; //操作员名称 - // trackShapeCode: "code01"; //轨形code - // verificationMethodCode: "code01"; //核校方式code - name: "某某铁路"; ///测量名称 - lineName: "河北段"; //线路名称 - location: "100米处"; //位置 - // direction: "左"; //方向 -}; - export function createMeasure(params: MeasureRecord) { return httpRequest({ url: "/measurement-task/cache-measurement", diff --git a/src/services/measure/type.ts b/src/services/measure/type.ts index e847046..d10467b 100644 --- a/src/services/measure/type.ts +++ b/src/services/measure/type.ts @@ -7,4 +7,26 @@ export type DetailTable = { operatorName:string; name: string; createTime: string; -} \ No newline at end of file +} + +export type MeasureRecord = { + operatorName: "张三"; //操作员名称 + // trackShapeCode: "code01"; //轨形code + // verificationMethodCode: "code01"; //核校方式code + name: "某某铁路"; ///测量名称 + lineName: "河北段"; //线路名称 + location: "100米处"; //位置 + // direction: "左"; //方向 +}; + + +export type AnalyzeAngle = { + x: number; + y: number; + degree: number; + describe: string; +}; + +export type AnalyzeResult = { + angles: AnalyzeAngle[]; +}; diff --git a/src/services/wsTypes.ts b/src/services/wsTypes.ts index bcc94bd..9f38594 100644 --- a/src/services/wsTypes.ts +++ b/src/services/wsTypes.ts @@ -17,10 +17,22 @@ export type TrackRecordSig = { path: "/measurement-task/profile-record-ctrl-sig"; }; +export const defaultContext: ContextMessage["data"] = { + loginFlag: true, + loginUser: { + id: 3, //数据主键id + account: "test001", //用户账户 + nickname: "测试账户001", //用户昵称 + userRole: "User", //用户角色,可用值:User,Admin,Dev + isBuiltInUser: false, //是否内置用户(内置用户不可删除) + }, + newMeasureAfterSave: false, +}; + export type ContextMessage = { messageType: "DeviceContext"; data: { - loginFlag: boolean; + loginFlag: Boolean; loginUser: Partial<{ id: number; account: string; @@ -34,4 +46,34 @@ export type ContextMessage = { path: "/deviceContext"; }; -export type Datagram = TrackRecordSig | TaskState | ContextMessage; +export const taskStatusDescMap: { [k in MeasureState["data"]["taskStatus"]]: string } = { + IDLE: "空闲", + MEASURING: "测量中", + WAITING_FOR_MEASURING: "等待测量", + FINISHED: "测量完成", +}; + +export type MeasureState = { + messageType: "STATE"; + data: { + taskStatus: "IDLE" | "MEASURING" | "WAITING_FOR_MEASURING" | "FINISHED"; + measureSideCnt: 0 | 1 | 2; //已测量数量,0,1,2 最多两边(左边和右边) + isMeasuringLeftEnd: boolean; //测量左侧完成 + isMeasuringRightEnd: boolean; //测量右侧完成 + motionlessSigFlag: boolean; //滑轮质心是否静止 + inStartMeasuringPos: boolean; //是否在允许开始测量的位置 + // profileRecordDescription: null; //用户填写的新测量信息 + }; + path: "/measurement-task/get-task-state"; +}; + +export const defaultMeasureState = { + taskStatus: "IDLE", + measureSideCnt: 0, //已测量数量,0,1,2 最多两边(左边和右边) + isMeasuringLeftEnd: false, //测量左侧完成 + isMeasuringRightEnd: false, //测量右侧完成 + motionlessSigFlag: true, //滑轮质心是否静止 + inStartMeasuringPos: true, //是否在允许开始测量的位置 +}; + +export type Datagram = TrackRecordSig | TaskState | ContextMessage | MeasureState;