diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..5b82025
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+ "cSpell.words": ["Cascader"]
+}
diff --git a/src/App.tsx b/src/App.tsx
index 2d5e42f..8c5bf03 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -14,7 +14,7 @@ import { appWebview, bridgeOb, emitBridgeEvent, registerBridgeFunc } from './uti
import { useAppDispatch } from './utils/hooks';
import { addNewPoint, updateTaskState } from './store/features/measureSlice';
import { DeviceStatus, TrackRecordSig } from './services/wsTypes';
-import { updateDevice } from './store/features/contextSlice';
+import { updateBleList, updateDevice, updateSyncProgress } from './store/features/contextSlice';
import { createWebSocket, sharedWsUrl } from './services/socket';
import { updateUploadStatus } from './store/features/historySlice';
@@ -72,27 +72,24 @@ function App() {
const dispatch = useAppDispatch();
useEffect(() => {
- const subscription = bridgeOb.subscribe(({ func, data }) => {
- if (func === 'measureTaskEvent') {
- if (Array.isArray(data)) return;
- dispatch(updateTaskState(data.event));
- } else if (func === 'measurePointEvent') {
- if (Array.isArray(data)) return;
- dispatch(addNewPoint(data as TrackRecordSig['data']));
- } else if (func === 'peripheralStatus') {
- if (Array.isArray(data)) return;
- dispatch(updateDevice(data as DeviceStatus['data']));
- } else if (func === 'uploadRecordsStatus') {
- if (Array.isArray(data)) {
- dispatch(updateUploadStatus(data))
- }
- }
+ const subscription = bridgeOb.subscribe((datagram) => {
+ if (datagram.type === 'measure-event') {
+ dispatch(updateTaskState(datagram.data.event));
+ } else if (datagram.type === 'measure-point') {
+ dispatch(addNewPoint(datagram.data));
+ } else if (datagram.type === 'peripheral-status') {
+ dispatch(updateDevice(datagram.data));
+ } else if (datagram.type === 'ble-list') {
+ dispatch(updateBleList(datagram.data));
+ } else if (datagram.type === 'sync-progress') {
+ dispatch(updateSyncProgress(datagram.data));
+ }
});
return () => subscription.unsubscribe();
}, [dispatch]);
useEffect(() => {
- // registerBridgeFunc();
+ // registerBridgeFunc();
if (appWebview) {
registerBridgeFunc();
} else {
diff --git a/src/components/CustomNavBar.tsx b/src/components/CustomNavBar.tsx
index 9f1b1ee..7d04842 100644
--- a/src/components/CustomNavBar.tsx
+++ b/src/components/CustomNavBar.tsx
@@ -15,7 +15,7 @@ export default function CustomNavBar({ title }: { title: string }) {
{/** 温度,水平仪 */}
温度: {device.temperature}°C
X轴倾斜: {device.inclinatorX}
@@ -25,7 +25,7 @@ export default function CustomNavBar({ title }: { title: string }) {
{title}
{/** 蓝牙连接状态 */}
- {device.isConnected ? (
+ {device.connected ? (
setShowDetail(!showDetail)}
@@ -37,7 +37,7 @@ export default function CustomNavBar({ title }: { title: string }) {
src={icon_arr_d}
alt="arr"
style={{
- transform: device.isConnected && showDetail ? 'rotate(180deg)' : 'rotate(0deg)',
+ transform: device.connected && showDetail ? 'rotate(180deg)' : 'rotate(0deg)',
transition: 'transform 300ms',
}}
/>
diff --git a/src/pages/Measure.tsx b/src/pages/Measure.tsx
index 68c10d7..d8143a2 100644
--- a/src/pages/Measure.tsx
+++ b/src/pages/Measure.tsx
@@ -14,6 +14,8 @@ import { useAppDispatch, useAppSelector } from '../utils/hooks';
import { updateTaskState } from '../store/features/measureSlice';
import Bridge from '../utils/bridge';
import { selectLabeledKtjOrgs } from '../store/features/baseData';
+import { updateOrg } from '../store/features/contextSlice';
+import { textsOfKeys } from '../utils/helper';
// declare global {
// interface Window {
@@ -38,11 +40,12 @@ export default function Measure() {
const dispatch = useAppDispatch();
const labeledKtjOrgs = useAppSelector((state) => selectLabeledKtjOrgs(state.baseData));
const measureState = useAppSelector((state) => state.measure);
+ const contextState = useAppSelector((state) => state.context);
const canvasRef = useRef
(null);
const [railPickerVisible, setRailPickerVisible] = useState(false);
- const [orgPickerVisible, setOrgPickerVisible] = useState(false);
+
const [railId, setRailId] = useState<(number | string | null)[]>([1]);
// 绘制轨型基准线
@@ -66,6 +69,13 @@ export default function Measure() {
}
}, [measureState.rightPoints]);
+ const orgTextArr = () => {
+ return textsOfKeys(
+ [contextState.currOrgCode, contextState.currGWDCode, contextState.currXMCode],
+ labeledKtjOrgs
+ );
+ };
+
const onSaveClick = () => {
navigate('/measure/save');
};
@@ -90,7 +100,10 @@ export default function Measure() {
options: labeledKtjOrgs,
placeholder: '请选择',
});
- Toast.show(value ? `你选择了 ${value.join(' - ')}` : '你没有进行选择');
+ // Toast.show(value ? `你选择了 ${value.join(' - ')}` : '你没有进行选择');
+ if (value) {
+ dispatch(updateOrg(value as string[]));
+ }
};
function stepState(step: StepName): StepState {
if (!measureState.taskState) {
@@ -176,10 +189,10 @@ export default function Measure() {
className="h-10 bg-[#e3e8f5] flex justify-between items-center px-4"
onClick={onOrgBarClick}
>
- 北京铁路局 /客运段/京沪线/左侧
-
- 修改
-
+
+ {contextState.currOrgCode ? orgTextArr().join('/') : '点击此处选择铁路局和工务段'}
+
+ 修改
diff --git a/src/pages/Setting.tsx b/src/pages/Setting.tsx
index 009fce2..914da8a 100644
--- a/src/pages/Setting.tsx
+++ b/src/pages/Setting.tsx
@@ -42,37 +42,6 @@ export default function Setting() {
- {/*
-
-
信息设置
-
-
-
-
铁路局名称
-
北京铁路局
-

-
-
-
线路名称
-
京沪线
-

-
-
-
路段名称
-
客运段
-

-
-
- 方向
-
-
-
- */}
-
保存
diff --git a/src/services/mobileWsType.ts b/src/services/mobileWsType.ts
new file mode 100644
index 0000000..12346aa
--- /dev/null
+++ b/src/services/mobileWsType.ts
@@ -0,0 +1,66 @@
+export type PeripheralStatus = {
+ type: 'peripheral-status';
+ data: {
+ connected: boolean;
+ power: number;
+ inclinatorX: number;
+ inclinatorY: number;
+ temperature: number;
+ };
+};
+
+export type MeasureEvent = {
+ type: 'measure-event';
+ data: {
+ event:
+ | 'START_RECORD_LEFT'
+ | 'FINISH_RECORD_LEFT'
+ | 'START_RECORD_RIGHT'
+ | 'FINISH_RECORD_RIGHT'
+ | 'WRONG_SIDE';
+ };
+};
+
+export type MeasurePoint = {
+ type: 'measure-point';
+ data: {
+ x: number;
+ y: number;
+ };
+};
+
+export type BleList = {
+ type: 'ble-list';
+ data: Array<{
+ mac: string; // 蓝牙设备的 MAC 地址(唯一标识)
+ name: string; // 蓝牙设备的可读名称(如型号/别名)
+ linked: boolean; //该设备是否已链接
+ // ... 后续补充
+ }>;
+};
+
+export type SyncProgress = {
+ type: 'sync-progress'; // 数据类型:同步进度状态上报
+ data: {
+ remaining: number; // 剩余未同步数量
+ fail: number; // 同步失败数量
+ total: number; // 总数量
+ finish: boolean; // 是否同步完成(true 表示全部完成)
+ };
+};
+
+export type SyncItemFinish = {
+ type: 'sync-item-finish'; // 数据类型:单项数据同步完成上报
+ data: {
+ id: number; // 数据同步任务的 ID
+ success: boolean; // 是否同步成功(true 表示成功,false 表示失败)
+ };
+};
+
+export type MobileDatagram =
+ | PeripheralStatus
+ | MeasureEvent
+ | MeasurePoint
+ | BleList
+ | SyncProgress
+ | SyncItemFinish;
diff --git a/src/services/socket.ts b/src/services/socket.ts
index 28c87da..3c2e869 100644
--- a/src/services/socket.ts
+++ b/src/services/socket.ts
@@ -1,4 +1,5 @@
import { Subject } from "rxjs";
+import { MobileDatagram } from "./mobileWsType";
export type SocketState = "open" | "close" | "error";
@@ -9,7 +10,7 @@ class WebSocketClient {
private maxReconnectAttempts: number = 5;
private reconnectInterval: number = 3000;
- private dataSub = new Subject<{ func: string; data: Record | any[] }>();
+ private dataSub = new Subject();
get dataOb() {
return this.dataSub.asObservable();
}
@@ -53,7 +54,7 @@ class WebSocketClient {
// 接收消息的处理
this.ws.onmessage = (event: MessageEvent) => {
try {
- const data = JSON.parse(event.data) as { func: string; data: Record | any[] };
+ const data = JSON.parse(event.data) as MobileDatagram;
// console.log("🚀 ~ WebSocketClient ~ bindEvents ~ data:", data);
// if (data.type === "cmd") {
// this.dataSub.next({ type: data.type, data: { ...data.data, success: data.data.status === "D0000" } });
diff --git a/src/store/features/contextSlice.ts b/src/store/features/contextSlice.ts
index ba342d7..d0f5041 100644
--- a/src/store/features/contextSlice.ts
+++ b/src/store/features/contextSlice.ts
@@ -1,35 +1,78 @@
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
-import { DeviceStatus } from '../../services/wsTypes';
+import { BleList, PeripheralStatus, SyncItemFinish, SyncProgress } from '../../services/mobileWsType';
interface ContextState {
- device: DeviceStatus['data'];
- currRailTypeId: number;
+ device: PeripheralStatus['data'];
+ currRailTypeId: number; // 当前选择的轨型
+ currOrgCode: string; // 铁路局
+ currGWDCode: string; // 工务段
+ currXMCode: string; // 线名
+
+ bleList: BleList["data"];
+ syncProgress: SyncProgress["data"];
+ syncItems: Array
+}
+
+const orgGwdXmStr = localStorage.getItem('org_gwd_xm');
+let orgGwdXm: string[] | undefined;
+if (orgGwdXmStr) {
+ orgGwdXm = orgGwdXmStr.split(',');
}
const initialState: ContextState = {
device: {
- isConnected: true, //是否链接
+ connected: true, //是否已连接蓝牙
power: 60, //电量
inclinatorX: 0.276, //x轴倾斜
inclinatorY: 3.019, //y轴倾斜
temperature: 32.026, //温度
},
- // 当前选择的轨型
+
currRailTypeId: 1,
+
+ currOrgCode: orgGwdXm ? orgGwdXm[0] : '',
+ currGWDCode: orgGwdXm ? orgGwdXm[1] : '',
+ currXMCode: orgGwdXm ? orgGwdXm[2] : '',
+
+ bleList: [],
+ syncProgress: {
+ remaining: 0,
+ fail: 0,
+ total: 0,
+ finish: true,
+ },
+ syncItems:[]
};
export const contextSlice = createSlice({
name: 'context',
initialState,
reducers: {
- updateDevice: (state, action: PayloadAction) => {
+ updateOrg: (state, action: PayloadAction) => {
+ state.currOrgCode = action.payload[0];
+ state.currGWDCode = action.payload[1];
+ state.currXMCode = action.payload[2];
+ localStorage.setItem('org_gwd_xm', action.payload.join(','))
+ },
+
+ updateDevice: (state, action: PayloadAction) => {
state.device = action.payload;
},
+
updateRailTypeId: (state, action: PayloadAction) => {
state.currRailTypeId = action.payload;
},
+
+ updateBleList:(state, action: PayloadAction) => {
+ state.bleList = action.payload
+ },
+
+ updateSyncProgress: (state, action: PayloadAction) => {
+ state.syncProgress = action.payload;
+ },
+
},
});
-export const { updateDevice, updateRailTypeId } = contextSlice.actions;
+export const { updateOrg, updateDevice, updateRailTypeId, updateBleList, updateSyncProgress } = contextSlice.actions;
export default contextSlice.reducer;
diff --git a/src/utils/bridge.ts b/src/utils/bridge.ts
index f75629b..e2d675d 100644
--- a/src/utils/bridge.ts
+++ b/src/utils/bridge.ts
@@ -1,6 +1,7 @@
import { Subject } from 'rxjs';
import httpRequest from '../services/httpRequest';
import { Measurement } from '../services/apiTypes';
+import { MobileDatagram } from '../services/mobileWsType';
declare global {
interface Window {
@@ -81,18 +82,18 @@ type ShowModelParam = Partial<{
// 是否运行在 原生APP 的 WebView 中
export const appWebview = navigator.userAgent.includes('iFlyTop-mobile');
-const bridgeSub = new Subject<{ func: string; data: Record | any[] }>();
+const bridgeSub = new Subject();
export const bridgeOb = bridgeSub.asObservable();
-export function emitBridgeEvent(event: { func: string; data: Record | any[] }) {
+export function emitBridgeEvent(event: MobileDatagram) {
bridgeSub.next(event);
}
export function registerBridgeFunc() {
- window.bridgeFunc = {
- peripheralStatus: (param: string) => {
- bridgeSub.next({ func: 'peripheralStatus', data: JSON.parse(param) });
- },
- };
+// window.bridgeFunc = {
+// peripheralStatus: (param: string) => {
+// bridgeSub.next({ func: 'peripheralStatus', data: JSON.parse(param) });
+// },
+// };
// window.bridgeCall = (func, param) => {
// const res = window.bridgeFunc[func].call(null, param);
@@ -113,16 +114,6 @@ export default class Bridge {
if (appWebview) {
window.WebViewJavascriptBridge.registerHandler(name, func);
}
-
- // window.bridgeFunc.peripheralStatus(
- // JSON.stringify({
- // isConnected: true,
- // power: 99,
- // inclinatorx: 0.22,
- // inclinatorY: 3.01,
- // temperature: 32.02,
- // })
- // );
}
static showModal(param: ShowModelParam) {
@@ -147,7 +138,7 @@ export default class Bridge {
resolve(JSON.parse(res));
});
} else {
- return httpRequest({ url: '/api/mobile/startMeasure', method: 'POST' });
+ return httpRequest({ url: '/api/measure/start', method: 'POST' });
}
}
diff --git a/src/utils/helper.ts b/src/utils/helper.ts
index 11eff67..34af101 100644
--- a/src/utils/helper.ts
+++ b/src/utils/helper.ts
@@ -1,4 +1,4 @@
-import { KTJOrg } from "../services/apiTypes";
+import { KTJOrg } from '../services/apiTypes';
export type LabelKTJOrg = {
label: string;
@@ -14,6 +14,7 @@ export type LabelKTJOrg = {
};
export function labeledKtjOrgs(ktjOrgs: KTJOrg[]): LabelKTJOrg[] {
+ console.log('为科天健JSON数组加标签');
return ktjOrgs.map((org) => {
const _org: LabelKTJOrg = {
label: org.value || org.key,
@@ -30,3 +31,13 @@ export function labeledKtjOrgs(ktjOrgs: KTJOrg[]): LabelKTJOrg[] {
return _org;
});
}
+
+export function textsOfKeys(keys: string[], orgs: LabelKTJOrg[]): string[] {
+ const l1 = orgs.find((item) => item.value === keys[0]);
+ if (!l1) return [];
+ const l2 = l1.children.find((item) => item.value === keys[1]);
+ if (!l2) return [];
+ const l3 = l2.children.find((item) => item.value === keys[2]);
+ if (!l3) return [];
+ return [l1.label, l2.label, l3.label];
+}