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