feat: first commit
This commit is contained in:
17
src/components/user-job-list/index.less
Normal file
17
src/components/user-job-list/index.less
Normal file
@ -0,0 +1,17 @@
|
||||
@import '@/styles/variables.less';
|
||||
|
||||
.user-job-list {
|
||||
&__list-date-group {
|
||||
height: 72px;
|
||||
font-size: 24px;
|
||||
line-height: 72px;
|
||||
padding: 0 24px;
|
||||
color: @blColor;
|
||||
}
|
||||
|
||||
&__list-card {
|
||||
&.last {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
165
src/components/user-job-list/index.tsx
Normal file
165
src/components/user-job-list/index.tsx
Normal file
@ -0,0 +1,165 @@
|
||||
import { List, PullRefresh } from '@taroify/core';
|
||||
import classNames from 'classnames';
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
|
||||
import JobCard from '@/components/job-card';
|
||||
import ListPlaceholder from '@/components/list-placeholder';
|
||||
import { UserJobType } from '@/constants/job';
|
||||
import { JobInfo, GetUserJobRequest } from '@/types/job';
|
||||
import { logWithPrefix } from '@/utils/common';
|
||||
import { requestUserJobList as requestData } from '@/utils/job';
|
||||
|
||||
import './index.less';
|
||||
|
||||
interface IRequestProps extends Partial<GetUserJobRequest> {
|
||||
type: number;
|
||||
}
|
||||
|
||||
export interface IJobListProps extends IRequestProps {
|
||||
refreshDisabled?: boolean;
|
||||
listHeight?: number;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const FIRST_PAGE = 0;
|
||||
const PAGE_SIZE = 40;
|
||||
const PREFIX = 'user-job-list';
|
||||
const log = logWithPrefix(PREFIX);
|
||||
|
||||
function UserJobList(props: IJobListProps) {
|
||||
const { className, listHeight, refreshDisabled, type = UserJobType.MyDeclared, keyWord } = props;
|
||||
const [refreshing, setRefreshing] = useState(false);
|
||||
const [hasMore, setHasMore] = useState(true);
|
||||
const [loadingMore, setLoadingMore] = useState(false);
|
||||
const [loadMoreError, setLoadMoreError] = useState(false);
|
||||
const [dataMap, setDataMap] = useState<Map<string, JobInfo[]>>(new Map());
|
||||
const currentPage = useRef<number>(FIRST_PAGE);
|
||||
const requestProps = useRef<IRequestProps>({ type });
|
||||
|
||||
const dateGroups = [...dataMap.keys()].sort().reverse();
|
||||
|
||||
const handleRefresh = useCallback(async () => {
|
||||
log('start pull refresh');
|
||||
try {
|
||||
setRefreshing(true);
|
||||
setLoadMoreError(false);
|
||||
const { page, hasMore: more, dataMap: map } = await requestData({ ...requestProps.current, page: 1 });
|
||||
setHasMore(more);
|
||||
setDataMap(map);
|
||||
currentPage.current = page;
|
||||
log('pull refresh success');
|
||||
} catch (e) {
|
||||
setDataMap(new Map());
|
||||
setHasMore(false);
|
||||
setLoadMoreError(true);
|
||||
currentPage.current = FIRST_PAGE;
|
||||
log('pull refresh failed');
|
||||
} finally {
|
||||
setRefreshing(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleLoadMore = useCallback(async () => {
|
||||
log('start load more', hasMore);
|
||||
if (!hasMore) {
|
||||
return;
|
||||
}
|
||||
setLoadMoreError(false);
|
||||
setLoadingMore(true);
|
||||
try {
|
||||
const {
|
||||
page,
|
||||
hasMore: more,
|
||||
dataMap: map,
|
||||
} = await requestData({ ...requestProps.current, page: currentPage.current + 1 });
|
||||
const newMap = new Map(dataMap);
|
||||
for (const date of map.keys()) {
|
||||
const newJobs = map.get(date) || [];
|
||||
if (newMap.has(date)) {
|
||||
const jobs = newMap.get(date);
|
||||
jobs?.push(...newJobs);
|
||||
} else {
|
||||
newMap.set(date, newJobs);
|
||||
}
|
||||
}
|
||||
setDataMap(newMap);
|
||||
setHasMore(more);
|
||||
currentPage.current = page;
|
||||
log('load more success');
|
||||
} catch (e) {
|
||||
setLoadMoreError(true);
|
||||
log('load more failed');
|
||||
} finally {
|
||||
setLoadingMore(false);
|
||||
}
|
||||
}, [dataMap, currentPage, hasMore]);
|
||||
|
||||
useEffect(() => {
|
||||
log('request params changed');
|
||||
requestProps.current = { type, keyWord, pageSize: PAGE_SIZE };
|
||||
}, [type, keyWord]);
|
||||
|
||||
// 初始化数据&配置变更后刷新数据
|
||||
useEffect(() => {
|
||||
const refresh = async () => {
|
||||
log('props changed, start refresh list data');
|
||||
try {
|
||||
setDataMap(new Map());
|
||||
setLoadingMore(true);
|
||||
setLoadMoreError(false);
|
||||
const { page, hasMore: more, dataMap: map } = await requestData({ ...requestProps.current, page: 1 });
|
||||
setHasMore(more);
|
||||
setDataMap(map);
|
||||
currentPage.current = page;
|
||||
} catch (e) {
|
||||
setDataMap(new Map());
|
||||
setHasMore(false);
|
||||
setLoadMoreError(true);
|
||||
currentPage.current = FIRST_PAGE;
|
||||
} finally {
|
||||
log('props changed, refresh list data end');
|
||||
setLoadingMore(false);
|
||||
}
|
||||
};
|
||||
refresh();
|
||||
}, [type, keyWord]);
|
||||
|
||||
return (
|
||||
<PullRefresh
|
||||
className={classNames(`${PREFIX}__pull-refresh`, className)}
|
||||
loading={refreshing}
|
||||
onRefresh={handleRefresh}
|
||||
disabled={refreshDisabled}
|
||||
>
|
||||
<List
|
||||
hasMore={hasMore}
|
||||
onLoad={handleLoadMore}
|
||||
loading={loadingMore || refreshing}
|
||||
disabled={loadMoreError}
|
||||
fixedHeight={typeof listHeight !== 'undefined'}
|
||||
style={listHeight ? { height: `${listHeight}px` } : undefined}
|
||||
>
|
||||
{dateGroups.map(date => {
|
||||
const jobs = dataMap.get(date) || [];
|
||||
return (
|
||||
<>
|
||||
<div className={`${PREFIX}__list-date-group`} key={date}>
|
||||
{date}
|
||||
</div>
|
||||
{jobs.map((item, index) => (
|
||||
<JobCard
|
||||
data={item}
|
||||
key={item.id}
|
||||
className={classNames(`${PREFIX}__list-card`, { last: index === jobs.length - 1 })}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
})}
|
||||
<ListPlaceholder hasMore={hasMore} loadingMore={loadingMore} loadMoreError={loadMoreError} />
|
||||
</List>
|
||||
</PullRefresh>
|
||||
);
|
||||
}
|
||||
|
||||
export default UserJobList;
|
||||
Reference in New Issue
Block a user