14 changed files with 515 additions and 159 deletions
-
6public/index.html
-
8src/App.tsx
-
45src/components/MeasureItem.tsx
-
24src/components/MineSegment.tsx
-
68src/components/UnuploadList.tsx
-
33src/components/UploadedList.tsx
-
4src/index.tsx
-
29src/pages/MeasureSave.tsx
-
205src/pages/Mine.tsx
-
13src/services/apiTypes.ts
-
48src/store/features/historySlice.ts
-
2src/store/index.ts
-
130src/utils/bridge.ts
-
59src/utils/constant.ts
@ -0,0 +1,24 @@ |
|||
export default function MineSegment({ |
|||
tabIndex, |
|||
setTabIndex, |
|||
}: { |
|||
tabIndex: number; |
|||
setTabIndex: (idx: number) => void; |
|||
}) { |
|||
return ( |
|||
<section className="px-4 py-5 flex"> |
|||
<div |
|||
className={`flex-1 h-10 rounded-l-md ${tabIndex === 0 ? 'btn-contained' : 'btn-elevated'}`} |
|||
onClick={() => setTabIndex(0)} |
|||
> |
|||
测量数据 |
|||
</div> |
|||
<div |
|||
className={`flex-1 h-10 rounded-r-md ${tabIndex === 1 ? 'btn-contained' : 'btn-elevated'}`} |
|||
onClick={() => setTabIndex(1)} |
|||
> |
|||
未上传数据 |
|||
</div> |
|||
</section> |
|||
); |
|||
} |
@ -0,0 +1,68 @@ |
|||
import { InfiniteScroll, List } from 'antd-mobile'; |
|||
import { Measurement } from '../services/apiTypes'; |
|||
import { MeasureItemEx, UpdateState } from './MeasureItem'; |
|||
import { useNavigate } from 'react-router'; |
|||
import { useAppSelector } from '../utils/hooks'; |
|||
|
|||
export default function UnuploadList({ |
|||
dataList, |
|||
selectIds, |
|||
onItemSelected, |
|||
onUpload, |
|||
hasMore, |
|||
loadMore, |
|||
}: { |
|||
dataList: Measurement[]; |
|||
selectIds: number[]; |
|||
onItemSelected: (id: number) => void; |
|||
onUpload: () => void; |
|||
hasMore: boolean; |
|||
loadMore: () => Promise<void>; |
|||
}) { |
|||
const navigate = useNavigate(); |
|||
const historyState = useAppSelector((state) => state.history); |
|||
|
|||
function uploadState(id: number): UpdateState { |
|||
const item = historyState.uploadRecordsStatus.find((item) => item.id === id); |
|||
if (item) { |
|||
return item.state; |
|||
} else { |
|||
return 'idle'; |
|||
} |
|||
} |
|||
|
|||
return ( |
|||
<> |
|||
<div className="flex items-center gap-3 px-4 mb-4"> |
|||
<button |
|||
className="btn-contained rounded-md h-9 w-[100px]" |
|||
disabled={selectIds.length === 0} |
|||
onClick={selectIds.length === 0 ? undefined : onUpload} |
|||
> |
|||
上传 |
|||
</button> |
|||
<p className="text-sm text-[#AFAFAF]">可在设置页面配置上传地址</p> |
|||
</div> |
|||
<div className="unUpload-list overflow-x-hidden overflow-y-auto"> |
|||
{dataList.length > 0 ? ( |
|||
<List> |
|||
{dataList.map((item) => ( |
|||
<List.Item key={item.id}> |
|||
<MeasureItemEx |
|||
item={item} |
|||
uploadState={uploadState(item.id)} |
|||
selected={selectIds.includes(item.id)} |
|||
onSelected={() => onItemSelected(item.id)} |
|||
onDetail={() => navigate(`/measure/record/${item.id}`)} |
|||
/> |
|||
</List.Item> |
|||
))} |
|||
<InfiniteScroll loadMore={loadMore} hasMore={hasMore} /> |
|||
</List> |
|||
) : ( |
|||
<p className="absolute text-title left-1/2 top-1/3 -translate-x-1/2">暂无数据</p> |
|||
)} |
|||
</div> |
|||
</> |
|||
); |
|||
} |
@ -0,0 +1,33 @@ |
|||
import { InfiniteScroll, List } from 'antd-mobile'; |
|||
import { Measurement } from '../services/apiTypes'; |
|||
import MeasureItem from './MeasureItem'; |
|||
import { useNavigate } from 'react-router'; |
|||
|
|||
export default function UploadedList({ |
|||
dataList, |
|||
hasMore, |
|||
loadMore, |
|||
}: { |
|||
dataList: Measurement[]; |
|||
hasMore: boolean; |
|||
loadMore: () => Promise<void>; |
|||
}) { |
|||
const navigate = useNavigate(); |
|||
|
|||
return ( |
|||
<div className="all-list relative overflow-x-hidden overflow-y-auto"> |
|||
{dataList.length > 0 ? ( |
|||
<List> |
|||
{dataList.map((item) => ( |
|||
<List.Item key={item.id}> |
|||
<MeasureItem item={item} onDetail={() => navigate(`/measure/record/${item.id}`)} /> |
|||
</List.Item> |
|||
))} |
|||
<InfiniteScroll loadMore={loadMore} hasMore={hasMore} /> |
|||
</List> |
|||
) : ( |
|||
<p className="absolute text-title left-1/2 top-1/3 -translate-x-1/2">暂无数据</p> |
|||
)} |
|||
</div> |
|||
); |
|||
} |
@ -0,0 +1,13 @@ |
|||
export type Measurement = { |
|||
id: number; |
|||
name: string; |
|||
railId: number; |
|||
bureau: string; |
|||
line: string; |
|||
section: string; |
|||
direction: string; |
|||
createAt: string; // Date;
|
|||
leftPoints: string; // json: 坐标数组
|
|||
rightPoints: string; // json: 坐标数组
|
|||
upload: boolean; |
|||
}; |
@ -0,0 +1,48 @@ |
|||
import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit'; |
|||
import { Measurement } from '../../services/apiTypes'; |
|||
import Bridge from '../../utils/bridge'; |
|||
|
|||
interface HistoryState { |
|||
uploadedRecords: Measurement[]; |
|||
hasMoreUploadedRecords: boolean; |
|||
unuploadRecords: Measurement[]; |
|||
hasMoreUnuploadRecords: boolean; |
|||
|
|||
uploadRecordsStatus: Array<{ id: number; state: 'pending' | 'uploading' | 'uploaded' }>; |
|||
} |
|||
|
|||
const initialState: HistoryState = { |
|||
uploadedRecords: [], |
|||
hasMoreUploadedRecords: true, |
|||
unuploadRecords: [], |
|||
hasMoreUnuploadRecords: true, |
|||
|
|||
uploadRecordsStatus: [], |
|||
}; |
|||
|
|||
export const getUploadedRecords = createAsyncThunk( |
|||
'history/getUploaded', |
|||
async ({ lastId, size }: { lastId?: number; size: number }) => { |
|||
return Bridge.getUploadedRecords({ lastId, size }); |
|||
} |
|||
); |
|||
|
|||
export const historySlice = createSlice({ |
|||
name: 'history', |
|||
initialState, |
|||
reducers: { |
|||
updateUploadStatus: (state, action: PayloadAction<Array<{ id: number; state: 'pending' | 'uploading' | 'uploaded' }>>) => { |
|||
state.uploadRecordsStatus = action.payload |
|||
} |
|||
}, |
|||
extraReducers: (builder) => { |
|||
// builder.addCase(getUploadedRecords.fulfilled, (state, action) => {
|
|||
// if (action.payload.success) {
|
|||
// state.uploadedRecords = state.uploadedRecords.concat(action.payload.data);
|
|||
// }
|
|||
// });
|
|||
}, |
|||
}); |
|||
|
|||
export const { updateUploadStatus } = historySlice.actions; |
|||
export default historySlice.reducer; |
Write
Preview
Loading…
Cancel
Save
Reference in new issue