"use client" import { getPersonProjectDashBoard } from "@/components/label/api/project" import { Project } from "@/components/label/api/project/typing" import { Button, Flex, Group, Modal, Stack, Text, TextInput, } from "@mantine/core" import { DatePickerInput, type DatesRangeValue } from "@mantine/dates" import { notifications } from "@mantine/notifications" import { IconRefresh } from "@tabler/icons-react" import dayjs from "dayjs" import "dayjs/locale/zh-cn" import duration from "dayjs/plugin/duration" import { DataTable, DataTableColumn } from "mantine-datatable" import { useRouter } from "next/navigation" import { useCallback, useEffect, useMemo, useState } from "react" dayjs.extend(duration) 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 "-" } interface FilterFormRecord { query_date: DatesRangeValue } function createInitialFilters(): FilterFormRecord { return { query_date: [ dayjs().subtract(1, "month").format("YYYY-MM-DD"), dayjs().format("YYYY-MM-DD"), ], } } const DEFAULT_RECORDS_PER_PAGE_OPTIONS = [10, 15, 20, 50] export default function PersonalProjectTable() { const router = useRouter() const [records, setRecords] = useState< Project.PersonProjectDashboardResponseItem[] >([]) const [loading, setLoading] = useState(false) const [page, setPage] = useState(1) const [pageSize, setPageSize] = useState(50) const [recordsPerPageOptions, setRecordsPerPageOptions] = useState( () => [...DEFAULT_RECORDS_PER_PAGE_OPTIONS] ) const [customPageSizeInput, setCustomPageSizeInput] = useState("") const [customPageSizeModalOpened, setCustomPageSizeModalOpened] = useState(false) const [totalItems, setTotalItems] = useState(0) const [filters, setFilters] = useState(() => createInitialFilters()) const [queryTrigger, setQueryTrigger] = useState(0) const [form, setForm] = useState(createInitialFilters()) 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 appliedParams = useMemo(() => { const obj: Project.ReqPersonProjectDashBoard = { start_date: dayjs().format("YYYY-MM-DD"), end_date: dayjs().format("YYYY-MM-DD"), } if (form.query_date[0] && form.query_date[1]) { obj.start_date = dayjs(form.query_date[0]).format("YYYY-MM-DD") obj.end_date = dayjs(form.query_date[1]).format("YYYY-MM-DD") } return obj }, [form.query_date]) const load = useCallback(async () => { if (!queryTrigger) return setLoading(true) try { const res = await getPersonProjectDashBoard(appliedParams) setRecords(res ?? []) setTotalItems(res?.length ?? 0) setPage(1) } finally { setLoading(false) } }, [appliedParams, queryTrigger]) useEffect(() => { load() }, [load]) useEffect(() => { queueMicrotask(() => { setQueryTrigger((v) => v + 1) }) }, []) const handleSearch = () => { setPage(1) setForm({ ...filters }) setQueryTrigger((v) => v + 1) } useEffect(() => { if (page > totalPages) setPage(totalPages) }, [page, totalPages]) const [currentRowId, setCurrentRowId] = useState(0) const openCustomPageSizeModal = useCallback(() => { setCustomPageSizeModalOpened(true) }, []) const closeCustomPageSizeModal = useCallback(() => { setCustomPageSizeModalOpened(false) setCustomPageSizeInput("") }, []) const handleAddCustomPageSize = useCallback(() => { const rawValue = customPageSizeInput.trim() if (!rawValue) return const size = Number(rawValue) if (!Number.isInteger(size) || size <= 0) { notifications.show({ color: "red", title: "输入无效", message: "请填写大于 0 的整数条数", }) return } if (recordsPerPageOptions.includes(size)) { notifications.show({ color: "blue", title: "已存在", message: `每页 ${size} 条已在可选项中`, }) return } setRecordsPerPageOptions((prev) => [...prev, size].sort((a, b) => a - b)) closeCustomPageSizeModal() notifications.show({ color: "green", title: "添加成功", message: `已新增每页 ${size} 条`, }) }, [closeCustomPageSizeModal, customPageSizeInput, recordsPerPageOptions]) const handleCustomPageSizeEnter = useCallback( (event: React.KeyboardEvent) => { if (event.key !== "Enter") return event.preventDefault() handleAddCustomPageSize() }, [handleAddCustomPageSize] ) const originColumn = useMemo(() => { let column: DataTableColumn[] = [ { accessor: "project_id", title: "项目ID", width: 150, render: (record: Project.PersonProjectDashboardResponseItem) => { return ( { false && setCurrentRowId(record.project_id) false && router.push(`/project/info/detail?id=${record.project_id}`) }} title={record.project_id.toString()} // c={"brand"} style={{ fontSize: "14px", maxWidth: "100%", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis", }}> {record.project_id} ) }, }, { accessor: "project_name", title: "项目名称", width: 160, render: (record: Project.PersonProjectDashboardResponseItem) => { return ( {record.project_name ?? "-"} ) }, }, { accessor: "project_type", title: "所属业务", width: 160, render: (record: Project.PersonProjectDashboardResponseItem) => { return ( {record.project_type ?? "-"} ) }, }, { accessor: "work_time", title: "任务耗时", width: 140, render: (record: Project.PersonProjectDashboardResponseItem) => { return formatDurationSeconds(record.work_time) }, }, { accessor: "project_label_type", title: "标注类别", width: 160, render: (record: Project.PersonProjectDashboardResponseItem) => { return record.project_label_type ?? "-" }, }, ] return column }, [router]) return ( 参与项目 setFilters((s) => ({ ...s, query_date: value, })) } /> width="100%" style={{ width: "100%" }} styles={{ header: { color: "var(--mantine-color-grey-text)", backgroundColor: "var(--mantine-datatable-striped-color)", }, }} withTableBorder withRowBorders pinFirstColumn rowBackgroundColor={(record) => { if (record.project_id === currentRowId) return "var(--mantine-datatable-highlight-on-hover-color-light, var(--mantine-datatable-highlight-on-hover-color))" }} idAccessor="project_id" scrollAreaProps={{ type: "auto" }} records={pageRecords} onRecordsPerPageChange={setPageSize} recordsPerPageOptions={recordsPerPageOptions} columns={originColumn} totalRecords={totalItems} recordsPerPage={pageSize} page={page} onPageChange={setPage} noRecordsText="暂无数据" recordsPerPageLabel="当前页数" renderPagination={({ Controls }) => ( )} /> setCustomPageSizeInput(event.currentTarget.value) } onKeyDown={handleCustomPageSizeEnter} /> ) }