fix(person/collection): fix card

This commit is contained in:
2026-02-05 14:53:28 +08:00
parent 885bf210c3
commit 04611e98e3
2 changed files with 444 additions and 106 deletions

File diff suppressed because one or more lines are too long

View File

@@ -23,16 +23,21 @@ import {
Badge,
Button,
Collapse,
Flex,
Group,
Loader,
Pagination,
Paper,
Select,
SimpleGrid,
Stack,
Text,
TextInput,
UnstyledButton,
} from "@mantine/core"
import { notifications } from "@mantine/notifications"
import {
IconCalendar,
IconChevronDown,
IconChevronUp,
IconRefresh,
@@ -41,9 +46,10 @@ import {
IconStarFilled,
} from "@tabler/icons-react"
import dayjs from "dayjs"
import { DataTable, DataTableColumn } from "mantine-datatable"
import { User2 } from "lucide-react"
import { useRouter, useSearchParams } from "next/navigation"
import { useCallback, useEffect, useMemo, useState } from "react"
import { CardCoverIcon } from "./components/ProjectIcon"
type PageType = "all" | "collect" | "dynamic"
@@ -191,85 +197,85 @@ export default function CollectionPage() {
})
}, [])
const columns = useMemo(() => {
const cols: DataTableColumn<Project.DataProps>[] = [
{
accessor: "id",
title: "项目ID",
width: 90,
},
{
accessor: "name",
title: "项目名称",
width: 220,
render: (record) => (
<Button
variant="subtle"
size="xs"
style={{
paddingLeft: 6,
paddingRight: 6,
maxWidth: 220,
}}
onClick={() => {
const url = type
? `/management/person/collection/detail?id=${record.id}&type=${type}`
: `/management/person/collection/detail?id=${record.id}`
router.push(url)
}}>
<Text
size="sm"
style={{
maxWidth: 200,
overflow: "hidden",
textOverflow: "ellipsis",
whiteSpace: "nowrap",
}}>
{record.name}
</Text>
</Button>
),
},
{
accessor: "project_type",
title: "所属业务",
width: 140,
render: (record) => record.project_type ?? "-",
},
{
accessor: "status",
title: "状态",
width: 110,
render: (record) => (
<Badge color={statusBadgeColor(record.status)}>
{STATUS_CODE.get(record.status) ?? record.status}
</Badge>
),
},
{
accessor: "owner",
title: "负责人",
width: 120,
render: (record) => record.owner ?? "-",
},
{
accessor: "label_schema_name",
title: "标注方案",
width: 160,
render: (record) => record.label_schema_name ?? "-",
},
{
accessor: "update_at",
title: "更新时间",
width: 160,
render: (record) => record.update_at ?? record.create_at ?? "-",
},
{
accessor: "operation",
title: "操作",
width: 80,
textAlign: "center",
render: (record) => (
const currentPage = storeParams.page_number ?? 1
const pageSize = storeParams.page_size ?? 15
const ProjectCard = (record: Project.DataProps) => {
return (
<Paper
key={record.id}
withBorder
radius="md"
shadow="sm"
style={{
borderColor: "rgba(0,0,0,0.06)",
height: 240,
padding: 14,
display: "flex",
flexDirection: "column",
justifyContent: "space-between",
background: "white",
}}>
<Group justify="space-between" wrap="nowrap">
<Flex flex={1}>
<CardCoverIcon width={68} height={68} />
<Stack gap={0}>
<Flex align="center">
<UnstyledButton
variant="subtle"
size="sm"
style={{
paddingLeft: 6,
paddingRight: 6,
justifyContent: "flex-start",
width: "100%",
}}
onClick={() => {
const url = type
? `/management/person/collection/detail?id=${record.id}&type=${type}`
: `/management/person/collection/detail?id=${record.id}`
router.push(url)
}}>
<Text
fw={700}
c={"brand"}
style={{
maxWidth: "100%",
overflow: "hidden",
textOverflow: "ellipsis",
whiteSpace: "nowrap",
}}>
{record.name}
</Text>
</UnstyledButton>
<Badge
color={statusBadgeColor(record.status)}
style={{
width: "-webkit-fill-available",
}}>
{STATUS_CODE.get(record.status) ?? record.status}
</Badge>
</Flex>
<Flex align="center" px={6} gap={6}>
<User2
color="var(--mantine-color-dimmed)"
width={14}
height={14}
/>
<Text size="sm">{record.owner ?? "-"}</Text>
</Flex>
<Flex align="center" px={6} gap={6}>
<IconCalendar
color="var(--mantine-color-dimmed)"
width={14}
height={14}
/>
<Text size="sm">
{record.create_at ? record.create_at.split(" ")[0] : "-"}
</Text>
</Flex>
</Stack>
</Flex>
<ActionIcon
variant="subtle"
color={record.is_collect ? "yellow" : "gray"}
@@ -284,7 +290,7 @@ export default function CollectionPage() {
title: "操作成功",
message: record.is_collect ? "已取消收藏" : "已收藏",
})
load()
setQueryTrigger((v) => v + 1)
} catch (e) {
notifications.show({
color: "red",
@@ -299,11 +305,64 @@ export default function CollectionPage() {
<IconStar size={16} />
)}
</ActionIcon>
),
},
]
return cols
}, [load, router, type])
</Group>
<Stack gap={6} style={{ flex: 1, minHeight: 0, marginTop: 8 }}>
<Text size="sm" c="dimmed">
{record.remarks ? record.remarks : "暂无备注"}
</Text>
</Stack>
</Paper>
)
}
const PaginationBar = (props: {
currentPage: number
pageSize: number
total: number
onChangePage: (page: number) => void
onChangePageSize: (size: number) => void
}) => {
const pageCount = Math.max(
1,
Math.ceil((props.total ?? 0) / props.pageSize)
)
return (
<div
style={{
height: 36,
display: "flex",
alignItems: "center",
justifyContent: "flex-end",
gap: 12,
paddingLeft: 12,
paddingRight: 12,
}}>
<Select
size="xs"
value={String(props.pageSize)}
data={[15, 45, 99].map((n) => ({
label: `${n}/页`,
value: String(n),
}))}
onChange={(v) => {
const next = Number(v)
if (!Number.isFinite(next)) return
props.onChangePageSize(next)
}}
allowDeselect={false}
style={{ width: 92 }}
/>
<Pagination
size="sm"
withControls
total={pageCount}
value={Math.min(props.currentPage, pageCount)}
onChange={props.onChangePage}
/>
</div>
)
}
return (
<Stack w="100%" h="calc(100vh - 56px)" p="md" gap="md">
@@ -500,36 +559,70 @@ export default function CollectionPage() {
display: "flex",
flexDirection: "column",
}}>
<Group gap={0} align="stretch" style={{ flex: 1, minHeight: 0 }}>
<DataTable<Project.DataProps>
width="100%"
style={{ width: "100%" }}
withTableBorder
withRowBorders
pinFirstColumn
pinLastColumn
scrollAreaProps={{ type: "auto" }}
fetching={loading}
records={records}
columns={columns}
totalRecords={total}
recordsPerPage={storeParams.page_size ?? 15}
page={storeParams.page_number ?? 1}
onPageChange={(p) => {
<div
style={{
flex: 1,
minHeight: 0,
overflowY: "auto",
paddingRight: 2,
}}>
{loading ? (
<div
style={{
height: "100%",
minHeight: 220,
display: "flex",
alignItems: "center",
justifyContent: "center",
}}>
<Loader size="sm" />
</div>
) : records.length ? (
<div
style={{
display: "grid",
gridTemplateColumns: "repeat(auto-fill, minmax(280px, 1fr))",
gap: 16,
}}>
{records.map(ProjectCard)}
</div>
) : (
<div
style={{
height: "100%",
minHeight: 220,
border: "1px solid rgba(0,0,0,0.06)",
borderRadius: 12,
background: "rgba(0,0,0,0.02)",
display: "flex",
alignItems: "center",
justifyContent: "center",
}}>
<Text size="lg" c="dimmed" fw={600}>
</Text>
</div>
)}
</div>
<div style={{ height: 36, marginTop: 16 }}>
<PaginationBar
currentPage={currentPage}
pageSize={pageSize}
total={total ?? 0}
onChangePage={(p) => {
setSearchParams({ ...storeParams, page_number: p }, type)
setQueryTrigger((v) => v + 1)
}}
onRecordsPerPageChange={(s) => {
onChangePageSize={(s) => {
setSearchParams(
{ ...storeParams, page_number: 1, page_size: s },
type
)
setQueryTrigger((v) => v + 1)
}}
recordsPerPageOptions={[10, 15, 20, 50]}
noRecordsText="暂无数据"
/>
</Group>
</div>
</Paper>
</Stack>
)