You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
177 lines
5.1 KiB
177 lines
5.1 KiB
import { ActionSheet, Dialog, InfiniteScroll, List, NavBar, Toast } from 'antd-mobile';
|
|
import { useNavigate } from 'react-router-dom';
|
|
|
|
import { MoreOutline } from 'antd-mobile-icons';
|
|
import { useCallback, useEffect, useState } from 'react';
|
|
|
|
import MeasureItem from '../components/MeasureItem';
|
|
import { Measurement } from '../services/apiTypes';
|
|
import Bridge, { bridgeOb } from '../utils/bridge';
|
|
import { useAppDispatch, useAppSelector } from '../utils/hooks';
|
|
import { refreshSyncProgress } from '../store/features/contextSlice';
|
|
|
|
const PAGE_SIZE = 10;
|
|
|
|
export default function UploadList() {
|
|
const navigate = useNavigate();
|
|
const dispatch = useAppDispatch();
|
|
|
|
const context = useAppSelector((state) => state.context);
|
|
|
|
const [showMenu, setShowMenu] = useState(false);
|
|
const [list, setList] = useState<Measurement[]>([]);
|
|
const [noMore, setNoMore] = useState(false);
|
|
|
|
const actions = [
|
|
{
|
|
text: '重试上传',
|
|
key: 'retry',
|
|
onClick: async () => {
|
|
setShowMenu(false);
|
|
const res = await Bridge.retryFailureSync();
|
|
if (!res.success) {
|
|
Toast.show(res.message);
|
|
}
|
|
},
|
|
},
|
|
{
|
|
text: '清空列表',
|
|
key: 'clear',
|
|
onClick: () => {
|
|
setShowMenu(false);
|
|
if (context.syncProgress.status === 'uploading') {
|
|
Dialog.confirm({
|
|
content: '存在未完成的任务,确定清空?',
|
|
onConfirm: () => {
|
|
clearSyncList();
|
|
},
|
|
});
|
|
} else {
|
|
clearSyncList();
|
|
}
|
|
},
|
|
},
|
|
{
|
|
text: '清空已完成任务',
|
|
key: 'clearCompleted',
|
|
onClick: async () => {
|
|
setShowMenu(false);
|
|
const res = await Bridge.clearFinishedSync();
|
|
if (res.success) {
|
|
loadData();
|
|
} else {
|
|
Toast.show(res.message);
|
|
}
|
|
},
|
|
},
|
|
];
|
|
|
|
function clearSyncList() {
|
|
Bridge.clearSyncList().then((res) => {
|
|
if (res.success) {
|
|
loadData();
|
|
} else {
|
|
Toast.show(res.message);
|
|
}
|
|
});
|
|
}
|
|
const loadData = useCallback(() => {
|
|
dispatch(refreshSyncProgress());
|
|
Bridge.getSyncTaskList({ pageNum: 1, size: PAGE_SIZE }).then((res) => {
|
|
if (res.success) {
|
|
const nList = res.data.list.map((r) => ({ ...r, extraDescObj: JSON.parse(r.extraDesc) }));
|
|
setList(nList);
|
|
setNoMore(res.data.list.length < PAGE_SIZE);
|
|
} else {
|
|
Toast.show(res.message);
|
|
}
|
|
});
|
|
}, [dispatch]);
|
|
|
|
async function loadMoreData() {
|
|
const pageNum = Math.floor(list.length / PAGE_SIZE);
|
|
const res = await Bridge.getSyncTaskList({ pageNum: pageNum + 1, size: PAGE_SIZE });
|
|
if (res.success) {
|
|
const nList = res.data.list.map((r) => ({ ...r, extraDescObj: JSON.parse(r.extraDesc) }));
|
|
setList(list.concat(nList));
|
|
setNoMore(res.data.list.length < PAGE_SIZE);
|
|
} else {
|
|
Toast.show(res.message);
|
|
}
|
|
}
|
|
|
|
useEffect(() => {
|
|
loadData();
|
|
}, [loadData]);
|
|
|
|
useEffect(() => {
|
|
const subscription = bridgeOb.subscribe((datagram) => {
|
|
if (datagram.type === 'sync-item-finish') {
|
|
const item = list.find((item) => item.id === datagram.data.id);
|
|
if (item) {
|
|
item.syncStatus = datagram.data.success ? 'finish' : 'fail';
|
|
}
|
|
}
|
|
});
|
|
return () => subscription.unsubscribe();
|
|
}, [list]);
|
|
|
|
const back = () => navigate(-1);
|
|
|
|
const right = (
|
|
<div
|
|
onClick={() => setShowMenu(!showMenu)}
|
|
className="flex justify-end gap-x-2"
|
|
style={{ fontSize: 24 }}
|
|
>
|
|
<MoreOutline />
|
|
</div>
|
|
);
|
|
|
|
const statusText = () => {
|
|
if (context.syncProgress.status === 'finished') {
|
|
return '完成';
|
|
} else if (context.syncProgress.status === 'paused') {
|
|
return '暂停';
|
|
} else if (context.syncProgress.status === 'uploading') {
|
|
return '上传中';
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div>
|
|
<NavBar className="bg-white" onBack={back} right={right}>
|
|
上传记录
|
|
</NavBar>
|
|
<div className="main-page-content">
|
|
<header className="h-8 bg-[#EEE] flex items-center px-4">
|
|
<span>剩余任务{context.syncProgress.remaining}个</span>
|
|
<i className="border-l border-[#999] h-3 mx-2" />
|
|
<span>失败{context.syncProgress.fail}个</span>
|
|
<p className="ml-auto text-primary">{statusText()}</p>
|
|
</header>
|
|
<main
|
|
className="relative overflow-x-hidden overflow-y-auto"
|
|
style={{ height: 'calc(100% - 32px)' }}
|
|
>
|
|
{list.length > 0 ? (
|
|
<List>
|
|
{list.map((item) => (
|
|
<List.Item key={item.id}>
|
|
<MeasureItem
|
|
item={item}
|
|
onDetail={() => navigate(`/measure/record/${item.id}`)}
|
|
/>
|
|
</List.Item>
|
|
))}
|
|
<InfiniteScroll loadMore={loadMoreData} hasMore={!noMore} />
|
|
</List>
|
|
) : (
|
|
<p className="absolute text-title left-1/2 top-1/3 -translate-x-1/2">暂无数据</p>
|
|
)}
|
|
</main>
|
|
</div>
|
|
<ActionSheet visible={showMenu} actions={actions} onClose={() => setShowMenu(false)} />
|
|
</div>
|
|
);
|
|
}
|