Files
labelmain/app/management/person/dashboard/components/PersonalProjectTable.tsx
2026-02-03 18:05:47 +08:00

129 lines
3.8 KiB
TypeScript

"use client"
import { getPersonProjectDashBoard } from "@/components/label/api/project"
import {
Button,
Group,
Pagination,
ScrollArea,
Select,
Table,
} from "@mantine/core"
import { IconRefresh } from "@tabler/icons-react"
import dayjs from "dayjs"
import duration from "dayjs/plugin/duration"
import { useCallback, useEffect, useMemo, useState } from "react"
dayjs.extend(duration)
const pageSizeOptions = [50, 100, 200]
function formatDurationSeconds(seconds?: number | null) {
const value = seconds ?? 0
if (!value) return "-"
const durationObj = dayjs.duration(value, "seconds")
const hours = durationObj.hours()
const minutes = durationObj.minutes()
if (hours) return `${hours}小时${minutes}分钟`
if (minutes) return `${minutes}分钟`
return "-"
}
export default function PersonalProjectTable() {
const [records, setRecords] = useState<any[]>([])
const [loading, setLoading] = useState(false)
const [page, setPage] = useState(1)
const [pageSize, setPageSize] = useState(50)
const totalPages = useMemo(() => {
const totalItems = records.length
return Math.max(1, Math.ceil(totalItems / pageSize))
}, [pageSize, records.length])
const pageRecords = useMemo(() => {
const start = (page - 1) * pageSize
return records.slice(start, start + pageSize)
}, [page, pageSize, records])
const load = useCallback(async () => {
setLoading(true)
try {
const res = await getPersonProjectDashBoard()
setRecords(res ?? [])
setPage(1)
} finally {
setLoading(false)
}
}, [])
useEffect(() => {
load()
}, [load])
useEffect(() => {
if (page > totalPages) setPage(totalPages)
}, [page, totalPages])
return (
<Group
gap="sm"
h="100%"
align="stretch"
style={{ flexDirection: "column" }}>
<Group justify="flex-end">
<Button
variant="filled"
onClick={load}
loading={loading}
leftSection={<IconRefresh size={16} />}>
</Button>
</Group>
<Group gap={0} align="stretch" style={{ flex: 1, minHeight: 0 }}>
<ScrollArea style={{ flex: 1 }}>
<Table withTableBorder withColumnBorders striped highlightOnHover>
<Table.Thead>
<Table.Tr>
<Table.Th style={{ width: 96 }}>ID</Table.Th>
<Table.Th style={{ width: 160 }}></Table.Th>
<Table.Th style={{ width: 160 }}></Table.Th>
<Table.Th style={{ width: 140 }}></Table.Th>
<Table.Th style={{ width: 160 }}></Table.Th>
</Table.Tr>
</Table.Thead>
<Table.Tbody>
{pageRecords.map((record) => (
<Table.Tr key={record.project_id}>
<Table.Td>{record.project_id ?? "-"}</Table.Td>
<Table.Td>{record.project_name ?? "-"}</Table.Td>
<Table.Td>{record.project_type ?? "-"}</Table.Td>
<Table.Td>{formatDurationSeconds(record.work_time)}</Table.Td>
<Table.Td>{record.project_label_type ?? "-"}</Table.Td>
</Table.Tr>
))}
</Table.Tbody>
</Table>
</ScrollArea>
</Group>
<Group justify="space-between">
<Group gap="xs">
<Select
w={120}
value={String(pageSize)}
data={pageSizeOptions.map((v) => String(v))}
allowDeselect={false}
onChange={(value) => {
const next = Number(value)
if (!Number.isFinite(next)) return
setPageSize(next)
setPage(1)
}}
/>
</Group>
<Pagination value={page} onChange={setPage} total={totalPages} />
</Group>
</Group>
)
}