Browse Source

添加局/段/线接口,车站接口,同步接口

master
zhangjiming 4 months ago
parent
commit
2312462cfb
  1. 2
      .vscode/settings.json
  2. 93
      src/App.tsx
  3. 26
      src/pages/Measure.tsx
  4. 145
      src/pages/MeasureSave.tsx
  5. 21
      src/pages/Mine2.tsx
  6. 16
      src/pages/Setting.tsx
  7. 36
      src/services/apiTypes.ts
  8. 21
      src/store/features/baseData.ts
  9. 33
      src/store/features/contextSlice.ts
  10. 8
      src/store/index.ts
  11. 38
      src/utils/bridge.ts
  12. 82
      src/utils/constant.ts

2
.vscode/settings.json

@ -1,3 +1,3 @@
{ {
"cSpell.words": ["Cascader"]
"cSpell.words": ["Cascader", "MINIPROF"]
} }

93
src/App.tsx

@ -1,21 +1,21 @@
import React, { useEffect } from 'react'; import React, { useEffect } from 'react';
import { Outlet, useLocation, useNavigate } from 'react-router'; import { Outlet, useLocation, useNavigate } from 'react-router';
import { SafeArea, TabBar } from 'antd-mobile';
import { Mask, SafeArea, SpinLoading, TabBar, Toast } from 'antd-mobile';
import icon_1_s from './assets/tabIcon/icon_tab1_s.svg'; import icon_1_s from './assets/tabIcon/icon_tab1_s.svg';
import icon_1_u from './assets/tabIcon/icon_tab1_u.svg'; import icon_1_u from './assets/tabIcon/icon_tab1_u.svg';
import icon_2_s from './assets/tabIcon/icon_tab2_s.svg';
import icon_2_u from './assets/tabIcon/icon_tab2_u.svg';
// import icon_2_s from './assets/tabIcon/icon_tab2_s.svg';
// import icon_2_u from './assets/tabIcon/icon_tab2_u.svg';
import icon_3_s from './assets/tabIcon/icon_tab3_s.svg'; import icon_3_s from './assets/tabIcon/icon_tab3_s.svg';
import icon_3_u from './assets/tabIcon/icon_tab3_u.svg'; import icon_3_u from './assets/tabIcon/icon_tab3_u.svg';
import icon_4_s from './assets/tabIcon/icon_tab4_s.svg'; import icon_4_s from './assets/tabIcon/icon_tab4_s.svg';
import icon_4_u from './assets/tabIcon/icon_tab4_u.svg'; import icon_4_u from './assets/tabIcon/icon_tab4_u.svg';
import { appWebview, bridgeOb, emitBridgeEvent, registerBridgeFunc } from './utils/bridge';
import Bridge, { bridgeOb, emitBridgeEvent } from './utils/bridge';
import { useAppDispatch, useAppSelector } from './utils/hooks'; import { useAppDispatch, useAppSelector } from './utils/hooks';
import { addNewPoint, updateTaskState } from './store/features/measureSlice'; import { addNewPoint, updateTaskState } from './store/features/measureSlice';
import { updateBleList, updateDevice, updateSyncProgress } from './store/features/contextSlice'; import { updateBleList, updateDevice, updateSyncProgress } from './store/features/contextSlice';
import { createWebSocket, sharedWsUrl } from './services/socket'; import { createWebSocket, sharedWsUrl } from './services/socket';
import { fetchRailTypes } from './store/features/baseData';
import { fetchOrgTree, fetchRailTypes, syncBaseData } from './store/features/baseData';
const BottomBar = () => { const BottomBar = () => {
const navigate = useNavigate(); const navigate = useNavigate();
@ -70,11 +70,15 @@ const BottomBar = () => {
function App() { function App() {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const baseState = useAppSelector((state) => state.baseData); const baseState = useAppSelector((state) => state.baseData);
if (baseState.railTypes.length === 0) {
dispatch(fetchRailTypes());
}
useEffect(() => { useEffect(() => {
if (baseState.railTypes.length === 0) {
dispatch(fetchRailTypes());
}
},[baseState.railTypes.length, dispatch])
// 监听推送消息,更新store
useEffect(() => {
const subscription = bridgeOb.subscribe((datagram) => { const subscription = bridgeOb.subscribe((datagram) => {
if (datagram.type === 'measure-event') { if (datagram.type === 'measure-event') {
dispatch(updateTaskState(datagram.data)); dispatch(updateTaskState(datagram.data));
@ -91,32 +95,63 @@ function App() {
return () => subscription.unsubscribe(); return () => subscription.unsubscribe();
}, [dispatch]); }, [dispatch]);
// 开启推送
useEffect(() => { useEffect(() => {
// registerBridgeFunc();
if (appWebview) {
registerBridgeFunc();
} else {
//连接websocket
const wsClient = createWebSocket(sharedWsUrl);
const subscription = wsClient.dataOb.subscribe((data) => {
emitBridgeEvent(data);
});
wsClient.connect();
return () => subscription.unsubscribe();
}
// if (appWebview) {
// registerBridgeFunc();
// } else {
//连接websocket
const wsClient = createWebSocket(sharedWsUrl);
const subscription = wsClient.dataOb.subscribe((data) => {
emitBridgeEvent(data);
});
wsClient.connect();
return () => subscription.unsubscribe();
// }
}, []); }, []);
// 初始同步数据
useEffect(() => {
Bridge.needSyncBaseData().then((res) => {
if (!res.success) {
return Toast.show(res.message);
}
if (res.data.needSync) {
dispatch(syncBaseData())
.unwrap()
.then((res) => {
if (res.success) {
dispatch(fetchOrgTree());
} else {
Toast.show(res.message);
}
});
} else {
dispatch(fetchOrgTree());
}
});
}, [dispatch]);
return ( return (
<div className="App">
<SafeArea position="top" />
<div>
<Outlet />
</div>
<div className="border-t border-[#ebebeb]">
<BottomBar />
<>
<div className="App">
<SafeArea position="top" />
<div>
<Outlet />
</div>
<div className="border-t border-[#ebebeb]">
<BottomBar />
</div>
<SafeArea position="bottom" />
</div> </div>
<SafeArea position="bottom" />
</div>
<Mask visible={baseState.syncingBaseData}>
<div className="flex flex-col items-center gap-4 absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2">
<SpinLoading color="white" />
<p className="text-white text-sm">...</p>
</div>
</Mask>
</>
); );
} }

26
src/pages/Measure.tsx

@ -13,7 +13,7 @@ import { useAppDispatch, useAppSelector } from '../utils/hooks';
import { updateTaskState } from '../store/features/measureSlice'; import { updateTaskState } from '../store/features/measureSlice';
import Bridge from '../utils/bridge'; import Bridge from '../utils/bridge';
import { selectLabeledKtjOrgs, updateRailPoints } from '../store/features/baseData'; import { selectLabeledKtjOrgs, updateRailPoints } from '../store/features/baseData';
import { updateOrg } from '../store/features/contextSlice';
import { refreshStationList, updateOrg } from '../store/features/contextSlice';
import { selectOrgTextArr } from '../store'; import { selectOrgTextArr } from '../store';
export default function Measure() { export default function Measure() {
@ -25,13 +25,11 @@ export default function Measure() {
const measureState = useAppSelector((state) => state.measure); const measureState = useAppSelector((state) => state.measure);
const contextState = useAppSelector((state) => state.context); const contextState = useAppSelector((state) => state.context);
const baseState = useAppSelector((state) => state.baseData); const baseState = useAppSelector((state) => state.baseData);
const canvasRef = useRef<MeasurementCanvasRef>(null);
const [railPickerVisible, setRailPickerVisible] = useState(false); const [railPickerVisible, setRailPickerVisible] = useState(false);
const [railId, setRailId] = useState<(number | string | null)[]>([]); const [railId, setRailId] = useState<(number | string | null)[]>([]);
const canvasRef = useRef<MeasurementCanvasRef>(null);
// 默认选中第一个轨型 // 默认选中第一个轨型
useEffect(() => { useEffect(() => {
if (baseState.railTypes.length > 0) { if (baseState.railTypes.length > 0) {
@ -39,6 +37,19 @@ export default function Measure() {
} }
}, [baseState.railTypes]); }, [baseState.railTypes]);
// 预获取车站信息
useEffect(() => {
if (contextState.currXMCode) {
dispatch(
refreshStationList({
tljCode: contextState.currOrgCode,
gwdCode: contextState.currGWDCode,
xmCode: contextState.currXMCode,
})
);
}
},[contextState.currGWDCode, contextState.currOrgCode, contextState.currXMCode, dispatch]);
function drawRailBaseLine(points: string) { function drawRailBaseLine(points: string) {
const benchmarkShapes = JSON.parse(points) as BenchmarkShape[]; const benchmarkShapes = JSON.parse(points) as BenchmarkShape[];
if (canvasRef.current) { if (canvasRef.current) {
@ -84,11 +95,6 @@ export default function Measure() {
}; };
const onStartClick = () => { const onStartClick = () => {
// if (typeof window.ReactNativeWebView !== "undefined") {
// window.ReactNativeWebView.postMessage(JSON.stringify(["add", 2, 3]));
// } else {
// console.log("当前环境不支持 React Native WebView");
// }
if (!contextState.device.connected) { if (!contextState.device.connected) {
Dialog.alert({ Dialog.alert({
content: '蓝牙未连接,请先连接蓝牙', content: '蓝牙未连接,请先连接蓝牙',

145
src/pages/MeasureSave.tsx

@ -3,8 +3,8 @@ import { useNavigate } from 'react-router';
import icon_arr_r from '../assets/icon_arr_s_r.svg'; import icon_arr_r from '../assets/icon_arr_s_r.svg';
import { ChangeEvent, useState } from 'react'; import { ChangeEvent, useState } from 'react';
import { useAppDispatch, useAppSelector } from '../utils/hooks'; import { useAppDispatch, useAppSelector } from '../utils/hooks';
import { DATA_SOURCE, LINE_CLASSIFY, XB_CODES } from '../utils/constant';
import { SaveMeasureDTO } from '../services/apiTypes';
import { DATA_SOURCE, LINE_CLASSIFY, UNIT_TYPES, XB_CODES } from '../utils/constant';
import { ExtraDesc, SaveMeasureDTO } from '../services/apiTypes';
import Bridge from '../utils/bridge'; import Bridge from '../utils/bridge';
import { resetState } from '../store/features/measureSlice'; import { resetState } from '../store/features/measureSlice';
import { selectOrgTextArr } from '../store'; import { selectOrgTextArr } from '../store';
@ -19,31 +19,74 @@ export default function MeasureSave() {
const orgTextArr = useAppSelector(selectOrgTextArr); const orgTextArr = useAppSelector(selectOrgTextArr);
const [name, setName] = useState(''); const [name, setName] = useState('');
const [batch, setBatch] = useState('');
const [mile, setMile] = useState(10);
const [meter, setMeter] = useState(10);
const [railPickerVisible, setRailPickerVisible] = useState(false); const [railPickerVisible, setRailPickerVisible] = useState(false);
const [dataSourcePickerVisible, setDataSourcePickerVisible] = useState(false); const [dataSourcePickerVisible, setDataSourcePickerVisible] = useState(false);
const [lineClassPickerVisible, setLineClassPickerVisible] = useState(false); const [lineClassPickerVisible, setLineClassPickerVisible] = useState(false);
// const [railId, setRailId] = useState<(number | string | null)[]>([1]);
const [unitTypePickerVisible, setUnitTypePickerVisible] = useState(false);
const [stationPickerVisible, setStationPickerVisible] = useState(false);
const [directionCode, setDirectionCode] = useState<string[]>([XB_CODES[0].value]); const [directionCode, setDirectionCode] = useState<string[]>([XB_CODES[0].value]);
const [dataSourceCode, setDataSourceCode] = useState<string[]>([DATA_SOURCE[0].value]); const [dataSourceCode, setDataSourceCode] = useState<string[]>([DATA_SOURCE[0].value]);
const [lineClassCode, setLineClassCode] = useState<string[]>([LINE_CLASSIFY[0].value]); const [lineClassCode, setLineClassCode] = useState<string[]>([LINE_CLASSIFY[0].value]);
const [stationCode, setStationCode] = useState<string[]>([contextState.stationList[0].value]);
const [unitType, setUnitType] = useState<string[]>([UNIT_TYPES[0].value]);
const onInputChange = (evt: ChangeEvent<HTMLInputElement>) => { const onInputChange = (evt: ChangeEvent<HTMLInputElement>) => {
setName(evt.target.value);
if (evt.target.name === 'name') {
setName(evt.target.value);
} else if (evt.target.name === 'batch') {
setBatch(evt.target.value);
} else if (evt.target.name === 'mile') {
if (/^\d*$/.test(evt.target.value)) {
setMile(+evt.target.value);
}
} else if (evt.target.name === 'meter') {
if (/^\d*$/.test(evt.target.value)) {
setMeter(+evt.target.value);
}
}
}; };
const onSaveBtnClick = () => { const onSaveBtnClick = () => {
if (!name) { if (!name) {
Toast.show('请输入测量名称');
return;
return Toast.show('请输入测量名称');
}
if (!batch) {
return Toast.show('请输入批次号');
} }
const railType = baseState.railTypes.find((r) => r.id === contextState.currRailTypeId); const railType = baseState.railTypes.find((r) => r.id === contextState.currRailTypeId);
const [, gwd, xm] = orgTextArr;
const [tlj, gwd, xm] = orgTextArr;
const desc: ExtraDesc = {
railSize: railType!.name,
tljCode: tlj,
gwdCode: gwd,
xmCode: xm,
xbCode: XB_CODES.find((x) => x.value === directionCode[0])!.label,
stationCode: contextState.stationList.find((s) => s.value === stationCode[0])!.label,
lineClassify: LINE_CLASSIFY.find((l) => l.value === lineClassCode[0])!.label,
dataSource: DATA_SOURCE.find((d) => d.value === dataSourceCode[0])!.label,
unitType: UNIT_TYPES.find((u) => u.value === unitType[0])!.label,
mile,
meter,
};
const dto: SaveMeasureDTO = { const dto: SaveMeasureDTO = {
operatorName: '',
trackShapeCode: railType!.code,
operator: 'klj_test',
dataType: 'MINIPROF',
name, name,
lineName: xm,
location: gwd,
direction: directionCode[0],
batch,
railSize: railType!.code,
tljCode: contextState.currOrgCode,
gwdCode: contextState.currGWDCode,
xmCode: contextState.currXMCode,
xbCode: directionCode[0],
stationCode: stationCode[0],
lineClassify: lineClassCode[0],
dataSource: dataSourceCode[0],
unitType: unitType[0],
mileage: `${mile}+${meter.toString().padStart(3, '0')}`,
extraDesc: JSON.stringify(desc),
}; };
Bridge.saveMeasure(dto).then((res) => { Bridge.saveMeasure(dto).then((res) => {
if (res.success) { if (res.success) {
@ -70,12 +113,43 @@ export default function MeasureSave() {
<span></span> <span></span>
<input <input
type="text" type="text"
name="name"
value={name} value={name}
placeholder="请填写"
placeholder="请填写测量名称"
className="border-0 outline-none self-stretch text-right flex-1 ml-4"
onChange={onInputChange}
/>
</div>
<div className="h-12 flex items-center border-b border-[#eee]">
<span></span>
<input
type="text"
name="batch"
value={batch}
placeholder="请填写批次"
className="border-0 outline-none self-stretch text-right flex-1 ml-4" className="border-0 outline-none self-stretch text-right flex-1 ml-4"
onChange={onInputChange} onChange={onInputChange}
/> />
</div> </div>
<div className="h-12 flex items-center border-b border-[#eee]">
<span></span>
<input
type="text"
name="mile"
value={mile}
className="w-14 h-8 mx-1 border border-[#eee] rounded outline-none text-center ml-auto"
onChange={onInputChange}
/>
<span>+</span>
<input
type="text"
name="meter"
value={meter}
className="w-14 h-8 mx-1 border border-[#eee] rounded outline-none text-center"
onChange={onInputChange}
/>
<span></span>
</div>
<div <div
className="h-12 flex items-center border-b border-[#eee]" className="h-12 flex items-center border-b border-[#eee]"
onClick={() => setDataSourcePickerVisible(true)} onClick={() => setDataSourcePickerVisible(true)}
@ -88,6 +162,16 @@ export default function MeasureSave() {
</div> </div>
<div <div
className="h-12 flex items-center border-b border-[#eee]" className="h-12 flex items-center border-b border-[#eee]"
onClick={() => setStationPickerVisible(true)}
>
<span></span>
<span className="ml-auto mr-4">
{contextState.stationList.find((r) => r.value === stationCode[0])?.label || ''}
</span>
<img src={icon_arr_r} alt="arr" />
</div>
<div
className="h-12 flex items-center border-b border-[#eee]"
onClick={() => setLineClassPickerVisible(true)} onClick={() => setLineClassPickerVisible(true)}
> >
<span>线</span> <span>线</span>
@ -96,13 +180,24 @@ export default function MeasureSave() {
</span> </span>
<img src={icon_arr_r} alt="arr" /> <img src={icon_arr_r} alt="arr" />
</div> </div>
<div className="h-12 flex items-center " onClick={() => setRailPickerVisible(true)}>
<div
className="h-12 flex items-center border-b border-[#eee]"
onClick={() => setRailPickerVisible(true)}
>
<span></span> <span></span>
<span className="ml-auto mr-4"> <span className="ml-auto mr-4">
{XB_CODES.find((r) => r.value === directionCode[0])?.label || ''} {XB_CODES.find((r) => r.value === directionCode[0])?.label || ''}
</span> </span>
<img src={icon_arr_r} alt="arr" /> <img src={icon_arr_r} alt="arr" />
</div> </div>
<div className="h-12 flex items-center " onClick={() => setUnitTypePickerVisible(true)}>
<span></span>
<span className="ml-auto mr-4">
{UNIT_TYPES.find((r) => r.value === unitType[0])?.label || ''}
</span>
<img src={icon_arr_r} alt="arr" />
</div>
</div> </div>
<div <div
className="btn-contained rounded-md h-12 mx-9 my-8 text-base font-medium" className="btn-contained rounded-md h-12 mx-9 my-8 text-base font-medium"
@ -145,6 +240,28 @@ export default function MeasureSave() {
setLineClassCode(v as string[]); setLineClassCode(v as string[]);
}} }}
/> />
<Picker
columns={[UNIT_TYPES]}
visible={unitTypePickerVisible}
onClose={() => {
setUnitTypePickerVisible(false);
}}
value={unitType}
onConfirm={(v) => {
setUnitType(v as string[]);
}}
/>
<Picker
columns={[contextState.stationList]}
visible={stationPickerVisible}
onClose={() => {
setStationPickerVisible(false);
}}
value={stationCode}
onConfirm={(v) => {
setStationCode(v as string[]);
}}
/>
</> </>
); );
} }

21
src/pages/Mine2.tsx

@ -1,10 +1,23 @@
import { List, NavBar } from 'antd-mobile';
import { List, NavBar, Toast } from 'antd-mobile';
import { UnorderedListOutline, SetOutline, UploadOutline } from 'antd-mobile-icons';
import { UnorderedListOutline, SetOutline, UploadOutline, LoopOutline } from 'antd-mobile-icons';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { useAppDispatch } from '../utils/hooks';
import { syncBaseData } from '../store/features/baseData';
export default function Mine2() { export default function Mine2() {
const navigate = useNavigate(); const navigate = useNavigate();
const dispatch = useAppDispatch();
const onSync = async () => {
const res = await dispatch(syncBaseData()).unwrap();
if (res.success) {
Toast.show('同步完成');
} else {
Toast.show(res.message);
}
};
return ( return (
<div> <div>
<NavBar className="bg-white" back={null}> <NavBar className="bg-white" back={null}>
@ -18,10 +31,12 @@ export default function Mine2() {
<List.Item prefix={<UploadOutline />} onClick={() => navigate('/measure/upload')}> <List.Item prefix={<UploadOutline />} onClick={() => navigate('/measure/upload')}>
</List.Item> </List.Item>
<List.Item prefix={<SetOutline />} onClick={() => navigate('/profile/setting')}> <List.Item prefix={<SetOutline />} onClick={() => navigate('/profile/setting')}>
</List.Item> </List.Item>
<List.Item prefix={<LoopOutline />} onClick={onSync}>
</List.Item>
</List> </List>
</div> </div>
</div> </div>

16
src/pages/Setting.tsx

@ -3,7 +3,7 @@ import icon_arr_r from '../assets/icon_arr_s_r.svg';
import { useEffect, useRef, useState } from 'react'; import { useEffect, useRef, useState } from 'react';
import { useNavigate } from 'react-router'; import { useNavigate } from 'react-router';
import { useAppDispatch, useAppSelector } from '../utils/hooks'; import { useAppDispatch, useAppSelector } from '../utils/hooks';
import { fetchConfig, saveConfig } from '../store/features/contextSlice';
import { fetchConfig, resetSettingReqStatus, saveConfig } from '../store/features/contextSlice';
import { standbyMinutes } from '../utils/constant'; import { standbyMinutes } from '../utils/constant';
export default function Setting() { export default function Setting() {
@ -14,17 +14,6 @@ export default function Setting() {
const addrInput = useRef<HTMLInputElement>(null); const addrInput = useRef<HTMLInputElement>(null);
const [standbyPickerVisible, setStandbyPickerVisible] = useState(false); const [standbyPickerVisible, setStandbyPickerVisible] = useState(false);
const [selectStandby, setSelectStandby] = useState<number[]>([context.setting.standbyMinutes]); const [selectStandby, setSelectStandby] = useState<number[]>([context.setting.standbyMinutes]);
// const [addr, setAddr] = useState('');
// const [port, setPort] = useState<number>(80);
// const onAddrChange = (evt: ChangeEvent<HTMLInputElement>) => {
// setAddr(evt.target.value);
// };
// const onPortChange = (evt: ChangeEvent<HTMLInputElement>) => {
// if (/^\d*$/.test(evt.target.value)) {
// setPort(+evt.target.value);
// }
// };
useEffect(() => { useEffect(() => {
if (addrInput.current && context.setting.server) { if (addrInput.current && context.setting.server) {
@ -35,6 +24,9 @@ export default function Setting() {
useEffect(() => { useEffect(() => {
dispatch(fetchConfig()); dispatch(fetchConfig());
return () => {
dispatch(resetSettingReqStatus());
};
}, [dispatch]); }, [dispatch]);
useEffect(() => { useEffect(() => {

36
src/services/apiTypes.ts

@ -43,10 +43,36 @@ export type RailType = {
}; };
export type SaveMeasureDTO = { export type SaveMeasureDTO = {
operatorName: string;
trackShapeCode: string;
operator: string;
name: string; name: string;
lineName: string;
location: string;
direction: string;
tljCode: string;
gwdCode: string;
xmCode: string;
stationCode: string;
dataType: string; // 采集方式
dataSource: string;
railSize: string; // 轨型
lineClassify: string; // 线路分类
batch: string;
xbCode: string; // 行别
mileage: string; // 里程
unitType: string; // 股别
extraDesc: string; // 额外描述
};
export type ExtraDesc = {
railSize: string;
tljCode: string;
gwdCode: string;
xmCode: string;
xbCode: string;
stationCode: string;
lineClassify: string;
dataSource: string;
unitType: string;
mile: number;
meter: number;
}; };
export type StationItem = { key: string; value: string };
export type StationLabelItem = { label: string; value: string };

21
src/store/features/baseData.ts

@ -9,11 +9,13 @@ import { RootState } from '..';
interface BaseDataState { interface BaseDataState {
ktjOrgs: KTJOrg[]; ktjOrgs: KTJOrg[];
railTypes: RailType[]; railTypes: RailType[];
syncingBaseData: boolean;
} }
const initialState: BaseDataState = { const initialState: BaseDataState = {
ktjOrgs: ktjOrgs as KTJOrg[], ktjOrgs: ktjOrgs as KTJOrg[],
railTypes: [], railTypes: [],
syncingBaseData: false,
}; };
export const fetchRailTypes = createAsyncThunk('base/fetchRailTypes', async (_, thunkAPI) => { export const fetchRailTypes = createAsyncThunk('base/fetchRailTypes', async (_, thunkAPI) => {
@ -21,6 +23,14 @@ export const fetchRailTypes = createAsyncThunk('base/fetchRailTypes', async (_,
return res.success ? res.data : null; return res.success ? res.data : null;
}); });
export const syncBaseData = createAsyncThunk('base/syncBaseData', async () => {
return await Bridge.syncBaseData();
});
export const fetchOrgTree = createAsyncThunk('base/fetchOrgTree', async () => {
return await Bridge.getOrgTree();
});
export const baseDataSlice = createSlice({ export const baseDataSlice = createSlice({
name: 'baseData', name: 'baseData',
initialState, initialState,
@ -40,6 +50,17 @@ export const baseDataSlice = createSlice({
builder.addCase(fetchRailTypes.fulfilled, (state, action) => { builder.addCase(fetchRailTypes.fulfilled, (state, action) => {
state.railTypes = action.payload || []; state.railTypes = action.payload || [];
}); });
builder.addCase(syncBaseData.pending, (state) => {
state.syncingBaseData = true;
});
builder.addCase(syncBaseData.fulfilled, (state) => {
state.syncingBaseData = false;
});
builder.addCase(fetchOrgTree.fulfilled, (state, action) => {
if (action.payload.success) {
state.ktjOrgs = action.payload.data;
}
});
}, },
}); });

33
src/store/features/contextSlice.ts

@ -6,8 +6,7 @@ import {
SyncProgress, SyncProgress,
} from '../../services/mobileWsType'; } from '../../services/mobileWsType';
import Bridge from '../../utils/bridge'; import Bridge from '../../utils/bridge';
import { RootState } from '..';
import { ReqStatus, SettingDTO } from '../../services/apiTypes';
import { ReqStatus, SettingDTO, StationLabelItem } from '../../services/apiTypes';
interface ContextState { interface ContextState {
device: PeripheralStatus['data']; device: PeripheralStatus['data'];
@ -15,6 +14,7 @@ interface ContextState {
currOrgCode: string; // 铁路局 currOrgCode: string; // 铁路局
currGWDCode: string; // 工务段 currGWDCode: string; // 工务段
currXMCode: string; // 线名 currXMCode: string; // 线名
stationList: StationLabelItem[];
bleList: BleList['data']; bleList: BleList['data'];
syncProgress: SyncProgress['data']; syncProgress: SyncProgress['data'];
@ -45,6 +45,7 @@ const initialState: ContextState = {
currOrgCode: orgGwdXm ? orgGwdXm[0] : '', currOrgCode: orgGwdXm ? orgGwdXm[0] : '',
currGWDCode: orgGwdXm ? orgGwdXm[1] : '', currGWDCode: orgGwdXm ? orgGwdXm[1] : '',
currXMCode: orgGwdXm ? orgGwdXm[2] : '', currXMCode: orgGwdXm ? orgGwdXm[2] : '',
stationList: [],
bleList: [], bleList: [],
syncProgress: { syncProgress: {
@ -82,6 +83,13 @@ export const refreshSyncProgress = createAsyncThunk('context/refreshSync', async
return res.success ? res.data : null; return res.success ? res.data : null;
}); });
export const refreshStationList = createAsyncThunk(
'context/refreshStationList',
async (params: { tljCode: string; gwdCode: string; xmCode: string }) => {
return await Bridge.getStationList(params);
}
);
export const contextSlice = createSlice({ export const contextSlice = createSlice({
name: 'context', name: 'context',
initialState, initialState,
@ -117,6 +125,11 @@ export const contextSlice = createSlice({
updateSyncProgress: (state, action: PayloadAction<SyncProgress['data']>) => { updateSyncProgress: (state, action: PayloadAction<SyncProgress['data']>) => {
state.syncProgress = action.payload; state.syncProgress = action.payload;
}, },
resetSettingReqStatus: (state) => {
state.settingReqStatus = 'idle';
state.error = undefined;
},
}, },
extraReducers: (builder) => { extraReducers: (builder) => {
builder.addCase(fetchConfig.pending, (state) => { builder.addCase(fetchConfig.pending, (state) => {
@ -145,6 +158,14 @@ export const contextSlice = createSlice({
state.syncProgress = action.payload; state.syncProgress = action.payload;
} }
}); });
builder.addCase(refreshStationList.fulfilled, (state, action) => {
if (action.payload.success) {
state.stationList = action.payload.data.map((item) => ({
label: item.value,
value: item.key,
}));
}
});
}, },
}); });
@ -155,12 +176,8 @@ export const {
updateBleList, updateBleList,
updateBleLinkStatus, updateBleLinkStatus,
updateSyncProgress, updateSyncProgress,
resetSettingReqStatus,
} = contextSlice.actions; } = contextSlice.actions;
export default contextSlice.reducer; export default contextSlice.reducer;
// 铁路局、工务段、线路名 编码数组
export const selectOrgCodes = (state: RootState) => [
state.context.currOrgCode,
state.context.currGWDCode,
state.context.currXMCode,
];

8
src/store/index.ts

@ -1,6 +1,6 @@
import { configureStore, createSelector } from '@reduxjs/toolkit'; import { configureStore, createSelector } from '@reduxjs/toolkit';
import measureSlice from './features/measureSlice'; import measureSlice from './features/measureSlice';
import contextSlice, { selectOrgCodes } from './features/contextSlice';
import contextSlice from './features/contextSlice';
import historySlice from './features/historySlice'; import historySlice from './features/historySlice';
import baseDataSlice, { selectLabeledKtjOrgs } from './features/baseData'; import baseDataSlice, { selectLabeledKtjOrgs } from './features/baseData';
import { textsOfKeys } from '../utils/helper'; import { textsOfKeys } from '../utils/helper';
@ -19,9 +19,9 @@ const store = configureStore({
// 铁路局、工务段、线路名 文本数组 // 铁路局、工务段、线路名 文本数组
export const selectOrgTextArr = createSelector( export const selectOrgTextArr = createSelector(
selectLabeledKtjOrgs, selectLabeledKtjOrgs,
selectOrgCodes,
(ktjOrgs, codes) => {
return textsOfKeys(codes, ktjOrgs);
(state: RootState) => state.context,
(ktjOrgs, ctx) => {
return textsOfKeys([ctx.currOrgCode, ctx.currGWDCode, ctx.currXMCode], ktjOrgs);
} }
); );

38
src/utils/bridge.ts

@ -1,6 +1,13 @@
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
import httpRequest from '../services/httpRequest'; import httpRequest from '../services/httpRequest';
import { Measurement, RailType, SaveMeasureDTO, SettingDTO } from '../services/apiTypes';
import {
KTJOrg,
Measurement,
RailType,
SaveMeasureDTO,
SettingDTO,
StationItem,
} from '../services/apiTypes';
import { MobileDatagram, SyncProgress } from '../services/mobileWsType'; import { MobileDatagram, SyncProgress } from '../services/mobileWsType';
declare global { declare global {
@ -329,10 +336,39 @@ export default class Bridge {
}); });
} }
static saveMeasure(params: SaveMeasureDTO) { static saveMeasure(params: SaveMeasureDTO) {
console.log('保存测量 入参:', params);
return httpRequest<BridgeBaseResult>({ return httpRequest<BridgeBaseResult>({
url: '/api/measure/save', url: '/api/measure/save',
method: 'POST', method: 'POST',
params, params,
}); });
} }
static getOrgTree() {
return httpRequest<BridgeBaseResult<KTJOrg[]>>({
url: '/api/basic/org',
method: 'POST',
params: {},
});
}
static getStationList(params: { tljCode: string; gwdCode: string; xmCode: string }) {
return httpRequest<BridgeBaseResult<StationItem[]>>({
url: '/api/basic/station',
method: 'POST',
params,
});
}
static needSyncBaseData() {
return httpRequest<BridgeBaseResult<{ needSync: boolean }>>({
url: '/api/basic/ktj/check',
method: 'POST',
params: {},
});
}
static syncBaseData() {
return httpRequest<BridgeBaseResult>({
url: '/api/basic/ktj/update',
method: 'POST',
params: {},
});
}
} }

82
src/utils/constant.ts

@ -1690,7 +1690,7 @@ export const MILE_TYPES_MAP = {
}; };
//股别 type 1:直线 2:曲线 //股别 type 1:直线 2:曲线
export const RAIN_TYPES = [
export const UNIT_TYPES = [
{ {
label: '左股', label: '左股',
value: 'SL', value: 'SL',
@ -1701,26 +1701,26 @@ export const RAIN_TYPES = [
value: 'SR', value: 'SR',
type: 1, type: 1,
}, },
{
label: '上股 左股',
value: 'HL',
type: 2,
},
{
label: '上股 右股',
value: 'HR',
type: 2,
},
{
label: '下股 左股',
value: 'LL',
type: 2,
},
{
label: '下股 右股',
value: 'LR',
type: 2,
},
// {
// label: '上股 左股',
// value: 'HL',
// type: 2,
// },
// {
// label: '上股 右股',
// value: 'HR',
// type: 2,
// },
// {
// label: '下股 左股',
// value: 'LL',
// type: 2,
// },
// {
// label: '下股 右股',
// value: 'LR',
// type: 2,
// },
]; ];
export const standbyMinutes = [ export const standbyMinutes = [
@ -1751,30 +1751,30 @@ export const standbyMinutes = [
]; ];
export const DATA_SOURCE = [ export const DATA_SOURCE = [
{
value: 'GCZD',
label: '跟车指导',
},
{
value: 'DQGC',
label: '定期观测',
},
// {
// value: 'GCZD',
// label: '跟车指导',
// },
// {
// value: 'DQGC',
// label: '定期观测',
// },
{ {
value: 'XLDC', value: 'XLDC',
label: '线路调查', label: '线路调查',
}, },
{
value: 'DMYS',
label: '打磨验收',
},
{
value: 'PSPG',
label: '普速评估',
},
{
value: 'GSPG',
label: '高速评估',
},
// {
// value: 'DMYS',
// label: '打磨验收',
// },
// {
// value: 'PSPG',
// label: '普速评估',
// },
// {
// value: 'GSPG',
// label: '高速评估',
// },
{ {
value: 'DCDC', value: 'DCDC',
label: '道岔调查', label: '道岔调查',

Loading…
Cancel
Save