6 changed files with 294 additions and 18 deletions
-
28src/components/GroupItem.tsx
-
63src/components/MeasureGroups.tsx
-
45src/components/MeasurementItem.tsx
-
3src/index.tsx
-
34src/pages/Measure.tsx
-
139src/pages/Mine2.tsx
@ -0,0 +1,28 @@ |
|||||
|
import icon_check_s from '../assets/icon_check_s_s.svg'; |
||||
|
import icon_check_u from '../assets/icon_check_s_u.svg'; |
||||
|
|
||||
|
export default function GroupItem({ |
||||
|
title, |
||||
|
editMode = false, |
||||
|
selected = false, |
||||
|
onGroupSelect, |
||||
|
}: { |
||||
|
title: string; |
||||
|
editMode?: boolean; |
||||
|
selected?: boolean; |
||||
|
onGroupSelect?: () => void; |
||||
|
}) { |
||||
|
const select = () => { |
||||
|
if (editMode) { |
||||
|
return <img className="w-[14px]" src={selected ? icon_check_s : icon_check_u} alt="icon" />; |
||||
|
} |
||||
|
return null; |
||||
|
}; |
||||
|
|
||||
|
return ( |
||||
|
<div className="px-5 py-2 text-sm flex gap-x-3" onClick={onGroupSelect}> |
||||
|
{select()} |
||||
|
<span>{title}</span> |
||||
|
</div> |
||||
|
); |
||||
|
} |
@ -0,0 +1,63 @@ |
|||||
|
import { InfiniteScroll, List } from 'antd-mobile'; |
||||
|
import { Measurement } from '../services/apiTypes'; |
||||
|
import { useNavigate } from 'react-router'; |
||||
|
import GroupItem from './GroupItem'; |
||||
|
import MeasurementItem from './MeasurementItem'; |
||||
|
import * as R from 'ramda'; |
||||
|
|
||||
|
export default function MeasureGroups({ |
||||
|
dataList, |
||||
|
editMode, |
||||
|
hasMore, |
||||
|
loadMore, |
||||
|
onItemSelect, |
||||
|
onGroupSelect, |
||||
|
selectedIds, |
||||
|
}: { |
||||
|
dataList: Array<{ groupName: string; list: Measurement[] }>; |
||||
|
editMode: boolean; |
||||
|
hasMore: boolean; |
||||
|
loadMore: () => Promise<void>; |
||||
|
onItemSelect: (groupIndex: number, id: number) => void; |
||||
|
onGroupSelect: (groupIndex: number) => void; |
||||
|
selectedIds: Array<number>; |
||||
|
}) { |
||||
|
const navigate = useNavigate(); |
||||
|
|
||||
|
const isSubset = (ids: number[]) => R.intersection(selectedIds, ids).length === ids.length; |
||||
|
|
||||
|
return ( |
||||
|
<div> |
||||
|
{dataList.length > 0 ? ( |
||||
|
<> |
||||
|
{dataList.map((group, idx) => ( |
||||
|
<div key={group.groupName}> |
||||
|
<GroupItem |
||||
|
title={group.groupName} |
||||
|
editMode={editMode} |
||||
|
selected={isSubset(group.list.map((item) => item.id))} |
||||
|
onGroupSelect={() => onGroupSelect(idx)} |
||||
|
/> |
||||
|
<List> |
||||
|
{group.list.map((item) => ( |
||||
|
<List.Item key={item.id}> |
||||
|
<MeasurementItem |
||||
|
item={item} |
||||
|
editMode={editMode} |
||||
|
selected={selectedIds.includes(item.id)} |
||||
|
onSelected={() => onItemSelect(idx, item.id)} |
||||
|
onDetail={() => navigate(`/measure/record/${item.id}`)} |
||||
|
/> |
||||
|
</List.Item> |
||||
|
))} |
||||
|
</List> |
||||
|
</div> |
||||
|
))} |
||||
|
<InfiniteScroll loadMore={loadMore} hasMore={hasMore} /> |
||||
|
</> |
||||
|
) : ( |
||||
|
<p className="absolute text-title left-1/2 top-1/3 -translate-x-1/2">暂无数据</p> |
||||
|
)} |
||||
|
</div> |
||||
|
); |
||||
|
} |
@ -0,0 +1,45 @@ |
|||||
|
import icon_check_s from '../assets/icon_check_s_s.svg'; |
||||
|
import icon_check_u from '../assets/icon_check_s_u.svg'; |
||||
|
import icon_arr from '../assets/icon_arr_p_r.svg'; |
||||
|
import { Measurement } from '../services/apiTypes'; |
||||
|
|
||||
|
export default function MeasurementItem({ |
||||
|
item, |
||||
|
editMode, |
||||
|
selected, |
||||
|
onDetail, |
||||
|
onSelected, |
||||
|
}: { |
||||
|
item: Measurement; |
||||
|
editMode: boolean; |
||||
|
selected: boolean; |
||||
|
onDetail?: () => void; |
||||
|
onSelected?: () => void; |
||||
|
}) { |
||||
|
return ( |
||||
|
<div className="flex mx-2 gap-3" onClick={editMode ? onSelected : undefined}> |
||||
|
{editMode && ( |
||||
|
<div className="flex justify-center items-center"> |
||||
|
<img className="w-[14px]" src={selected ? icon_check_s : icon_check_u} alt="icon" /> |
||||
|
</div> |
||||
|
)} |
||||
|
<main className="flex-1"> |
||||
|
<header className="flex items-center gap-2"> |
||||
|
<h1 className="text-[15px] font-medium ">{item.name}</h1> |
||||
|
{/* <span className="text-sm text-[#b7b7b7]">{item.createAt.replace('T',' ').split(' ')[1]}</span> */} |
||||
|
</header> |
||||
|
<main className="flex mt-2"> |
||||
|
<p className="flex-1 text-sm ">{`${item.line}`}</p> |
||||
|
<p className="flex-1 text-sm ">{`${item.section}`}</p> |
||||
|
<p className="flex-1 text-sm ">{`${item.direction}方向`}</p> |
||||
|
</main> |
||||
|
</main> |
||||
|
{!editMode && ( |
||||
|
<aside className="flex items-center" onClick={onDetail}> |
||||
|
<span className="mr-2 text-sm text-primary font-medium">查看</span> |
||||
|
<img src={icon_arr} alt="arr" className="h-[10px]" /> |
||||
|
</aside> |
||||
|
)} |
||||
|
</div> |
||||
|
); |
||||
|
} |
@ -0,0 +1,139 @@ |
|||||
|
import { NavBar, Toast } from 'antd-mobile'; |
||||
|
import { useEffect, useRef, useState } from 'react'; |
||||
|
import { Measurement } from '../services/apiTypes'; |
||||
|
import Bridge from '../utils/bridge'; |
||||
|
import MeasureGroups from '../components/MeasureGroups'; |
||||
|
import { MoreOutline } from 'antd-mobile-icons'; |
||||
|
import * as R from 'ramda'; |
||||
|
|
||||
|
const PAGE_SIZE = 10; |
||||
|
|
||||
|
const dataList: Array<{ groupName: string; list: Measurement[] }> = [ |
||||
|
{ |
||||
|
groupName: '2025-03-02', |
||||
|
list: [ |
||||
|
{ |
||||
|
id: 1, |
||||
|
name: '测量名称1', |
||||
|
createAt: '2025-03-02 10:20', |
||||
|
line: '京沪线', |
||||
|
section: 'A段', |
||||
|
direction: '上行', |
||||
|
railId: 2, |
||||
|
leftPoints: '[]', |
||||
|
rightPoints: '[]', |
||||
|
bureau: '北京铁路局', |
||||
|
upload: false, |
||||
|
}, |
||||
|
{ |
||||
|
id: 2, |
||||
|
name: '测量名称2', |
||||
|
createAt: '2025-03-02 12:22', |
||||
|
line: '京沪线', |
||||
|
section: 'B段', |
||||
|
direction: '下行', |
||||
|
railId: 2, |
||||
|
leftPoints: '[]', |
||||
|
rightPoints: '[]', |
||||
|
bureau: '北京铁路局', |
||||
|
upload: false, |
||||
|
}, |
||||
|
{ |
||||
|
id: 3, |
||||
|
name: '测量名称3', |
||||
|
createAt: '2025-03-02 12:20', |
||||
|
line: '京沪线', |
||||
|
section: 'C段', |
||||
|
direction: '上行', |
||||
|
railId: 2, |
||||
|
leftPoints: '[]', |
||||
|
rightPoints: '[]', |
||||
|
bureau: '北京铁路局', |
||||
|
upload: false, |
||||
|
}, |
||||
|
], |
||||
|
}, |
||||
|
{ |
||||
|
groupName: '2025-02-01', |
||||
|
list: [ |
||||
|
{ |
||||
|
id: 4, |
||||
|
name: '测量名称2', |
||||
|
createAt: '2025-03-02 10:20', |
||||
|
line: '京沪线', |
||||
|
section: 'D段', |
||||
|
direction: '下行', |
||||
|
railId: 2, |
||||
|
leftPoints: '[]', |
||||
|
rightPoints: '[]', |
||||
|
bureau: '北京铁路局', |
||||
|
upload: false, |
||||
|
}, |
||||
|
{ |
||||
|
id: 5, |
||||
|
name: '测量名称2', |
||||
|
createAt: '2025-03-02 10:20', |
||||
|
line: '京沪线', |
||||
|
section: 'E段', |
||||
|
direction: '下行', |
||||
|
railId: 2, |
||||
|
leftPoints: '[]', |
||||
|
rightPoints: '[]', |
||||
|
bureau: '北京铁路局', |
||||
|
upload: false, |
||||
|
}, |
||||
|
], |
||||
|
}, |
||||
|
]; |
||||
|
|
||||
|
export default function Mine2() { |
||||
|
const [editMode, setEditMode] = useState(false); |
||||
|
const [selectedIds, setSelectedIds] = useState<number[]>([]); |
||||
|
async function loadMoreRecords() {} |
||||
|
|
||||
|
const onItemSelect = (groupIdx: number, id: number) => { |
||||
|
if (selectedIds.includes(id)) { |
||||
|
setSelectedIds(R.reject((item) => item === id, selectedIds)); |
||||
|
} else { |
||||
|
setSelectedIds([...selectedIds, id]); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
const onGroupSelect = (groupIdx: number) => { |
||||
|
const ids = dataList[groupIdx].list.map((item) => item.id); |
||||
|
if (R.intersection(selectedIds, ids).length === ids.length) { |
||||
|
setSelectedIds(R.difference(selectedIds, ids)); |
||||
|
} else { |
||||
|
setSelectedIds(R.union(selectedIds, ids)); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
const right = ( |
||||
|
<div |
||||
|
onClick={() => setEditMode(!editMode)} |
||||
|
className="flex justify-end" |
||||
|
style={{ fontSize: 24 }} |
||||
|
> |
||||
|
<MoreOutline /> |
||||
|
</div> |
||||
|
); |
||||
|
|
||||
|
return ( |
||||
|
<div> |
||||
|
<NavBar className="bg-white" back={null} right={right}> |
||||
|
我的 |
||||
|
</NavBar> |
||||
|
<div className="home-page-content overflow-x-hidden overflow-y-auto"> |
||||
|
<MeasureGroups |
||||
|
dataList={dataList} |
||||
|
editMode={editMode} |
||||
|
hasMore={false} |
||||
|
loadMore={loadMoreRecords} |
||||
|
onItemSelect={onItemSelect} |
||||
|
onGroupSelect={onGroupSelect} |
||||
|
selectedIds={selectedIds} |
||||
|
/> |
||||
|
</div> |
||||
|
</div> |
||||
|
); |
||||
|
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue