diff options
| author | joonhoekim <26rote@gmail.com> | 2025-06-24 01:51:59 +0000 |
|---|---|---|
| committer | joonhoekim <26rote@gmail.com> | 2025-06-24 01:51:59 +0000 |
| commit | 6824e097d768f724cf439b410ccfb1ab9685ac98 (patch) | |
| tree | 1f297313637878e7a4ad6c89b84d5a2c3e9eb650 /lib/evaluation/table | |
| parent | f4825dd3853188de4688fb4a56c0f4e847da314b (diff) | |
| parent | 4e63d8427d26d0d1b366ddc53650e15f3481fc75 (diff) | |
(merge) 대표님/최겸 작업사항 머지
Diffstat (limited to 'lib/evaluation/table')
| -rw-r--r-- | lib/evaluation/table/evaluation-columns.tsx | 35 | ||||
| -rw-r--r-- | lib/evaluation/table/evaluation-filter-sheet.tsx | 2 | ||||
| -rw-r--r-- | lib/evaluation/table/evaluation-table.tsx | 72 |
3 files changed, 59 insertions, 50 deletions
diff --git a/lib/evaluation/table/evaluation-columns.tsx b/lib/evaluation/table/evaluation-columns.tsx index 0c207a53..821e8182 100644 --- a/lib/evaluation/table/evaluation-columns.tsx +++ b/lib/evaluation/table/evaluation-columns.tsx @@ -11,6 +11,7 @@ import { Button } from "@/components/ui/button"; import { Pencil, Eye, MessageSquare, Check, X, Clock, FileText } from "lucide-react"; import { DataTableColumnHeaderSimple } from "@/components/data-table/data-table-column-simple-header"; import { PeriodicEvaluationView } from "@/db/schema"; +import { DataTableRowAction } from "@/types/table"; @@ -104,7 +105,7 @@ const getProgressBadge = (completed: number, total: number) => { return <Badge variant={variant}>{completed}/{total} ({percentage}%)</Badge>; }; -export function getPeriodicEvaluationsColumns({setRowAction}: GetColumnsProps): ColumnDef<PeriodicEvaluationWithRelations>[] { +export function getPeriodicEvaluationsColumns({setRowAction}: GetColumnsProps): ColumnDef<PeriodicEvaluationView>[] { return [ // ═══════════════════════════════════════════════════════════════ // 선택 및 기본 정보 @@ -136,9 +137,9 @@ export function getPeriodicEvaluationsColumns({setRowAction}: GetColumnsProps): // ░░░ 평가년도 ░░░ { - accessorKey: "evaluationTarget.evaluationYear", + accessorKey: "evaluationYear", header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="평가년도" />, - cell: ({ row }) => <span className="font-medium">{row.original.evaluationTarget?.evaluationYear}</span>, + cell: ({ row }) => <span className="font-medium">{row.original.evaluationYear}</span>, size: 100, }, @@ -154,9 +155,9 @@ export function getPeriodicEvaluationsColumns({setRowAction}: GetColumnsProps): // ░░░ 구분 ░░░ { - accessorKey: "evaluationTarget.division", + accessorKey: "division", header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="구분" />, - cell: ({ row }) => getDivisionBadge(row.original.evaluationTarget?.division || ""), + cell: ({ row }) => getDivisionBadge(row.original.division || ""), size: 80, }, @@ -167,36 +168,36 @@ export function getPeriodicEvaluationsColumns({setRowAction}: GetColumnsProps): header: "협력업체 정보", columns: [ { - accessorKey: "evaluationTarget.vendorCode", + accessorKey: "vendorCode", header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="벤더 코드" />, cell: ({ row }) => ( - <span className="font-mono text-sm">{row.original.evaluationTarget?.vendorCode}</span> + <span className="font-mono text-sm">{row.original.vendorCode}</span> ), size: 120, }, { - accessorKey: "evaluationTarget.vendorName", + accessorKey: "vendorName", header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="벤더명" />, cell: ({ row }) => ( - <div className="truncate max-w-[200px]" title={row.original.evaluationTarget?.vendorName}> - {row.original.evaluationTarget?.vendorName} + <div className="truncate max-w-[200px]" title={row.original.vendorName}> + {row.original.vendorName} </div> ), size: 200, }, { - accessorKey: "evaluationTarget.domesticForeign", + accessorKey: "domesticForeign", header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="내외자" />, - cell: ({ row }) => getDomesticForeignBadge(row.original.evaluationTarget?.domesticForeign || ""), + cell: ({ row }) => getDomesticForeignBadge(row.original.domesticForeign || ""), size: 80, }, { - accessorKey: "evaluationTarget.materialType", + accessorKey: "materialType", header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="자재구분" />, - cell: ({ row }) => getMaterialTypeBadge(row.original.evaluationTarget?.materialType || ""), + cell: ({ row }) => getMaterialTypeBadge(row.original.materialType || ""), size: 120, }, ] @@ -355,10 +356,10 @@ export function getPeriodicEvaluationsColumns({setRowAction}: GetColumnsProps): id: "reviewProgress", header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="리뷰진행" />, cell: ({ row }) => { - const stats = row.original.reviewerStats; - if (!stats) return <span className="text-muted-foreground">-</span>; + const totalReviewers = row.original.totalReviewers || 0; + const completedReviewers = row.original.completedReviewers || 0; - return getProgressBadge(stats.completedReviewers, stats.totalReviewers); + return getProgressBadge(completedReviewers, totalReviewers); }, size: 120, }, diff --git a/lib/evaluation/table/evaluation-filter-sheet.tsx b/lib/evaluation/table/evaluation-filter-sheet.tsx index 7cda4989..7c1e93d8 100644 --- a/lib/evaluation/table/evaluation-filter-sheet.tsx +++ b/lib/evaluation/table/evaluation-filter-sheet.tsx @@ -394,7 +394,7 @@ export function PeriodicEvaluationFilterSheet({ } return ( - <div className="flex flex-col h-full max-h-full bg-[#F5F7FB] px-6 sm:px-8"> + <div className="flex flex-col h-full max-h-full bg-[#F5F7FB] px-6 sm:px-8" style={{backgroundColor:"#F5F7FB", paddingLeft:"2rem", paddingRight:"2rem"}}> {/* Filter Panel Header */} <div className="flex items-center justify-between px-6 min-h-[60px] shrink-0"> <h3 className="text-lg font-semibold whitespace-nowrap">정기평가 검색 필터</h3> diff --git a/lib/evaluation/table/evaluation-table.tsx b/lib/evaluation/table/evaluation-table.tsx index 16f70592..a628475d 100644 --- a/lib/evaluation/table/evaluation-table.tsx +++ b/lib/evaluation/table/evaluation-table.tsx @@ -23,6 +23,7 @@ import { useMemo } from "react" import { PeriodicEvaluationFilterSheet } from "./evaluation-filter-sheet" import { getPeriodicEvaluationsColumns } from "./evaluation-columns" import { PeriodicEvaluationView } from "@/db/schema" +import { getPeriodicEvaluations } from "../service" interface PeriodicEvaluationsTableProps { promises: Promise<[Awaited<ReturnType<typeof getPeriodicEvaluations>>]> @@ -229,16 +230,33 @@ export function PeriodicEvaluationsTable({ promises, evaluationYear, className } const [promiseData] = React.use(promises) const tableData = promiseData + const getSearchParam = React.useCallback((key: string, defaultValue?: string): string => { + return searchParams?.get(key) ?? defaultValue ?? ""; + }, [searchParams]); + + const parseSearchParamHelper = React.useCallback((key: string, defaultValue: any): any => { + try { + const value = getSearchParam(key); + return value ? JSON.parse(value) : defaultValue; + } catch { + return defaultValue; + } + }, [getSearchParam]); + + const parseSearchParam = <T,>(key: string, defaultValue: T): T => { + return parseSearchParamHelper(key, defaultValue); + }; + const initialSettings = React.useMemo(() => ({ - page: parseInt(searchParams.get('page') || '1'), - perPage: parseInt(searchParams.get('perPage') || '10'), - sort: searchParams.get('sort') ? JSON.parse(searchParams.get('sort')!) : [{ id: "createdAt", desc: true }], - filters: searchParams.get('filters') ? JSON.parse(searchParams.get('filters')!) : [], - joinOperator: (searchParams.get('joinOperator') as "and" | "or") || "and", - basicFilters: searchParams.get('basicFilters') ? - JSON.parse(searchParams.get('basicFilters')!) : [], - basicJoinOperator: (searchParams.get('basicJoinOperator') as "and" | "or") || "and", - search: searchParams.get('search') || '', + page: parseInt(getSearchParam('page') || '1'), + perPage: parseInt(getSearchParam('perPage') || '10'), + sort: getSearchParam('sort') ? JSON.parse(getSearchParam('sort')!) : [{ id: "createdAt", desc: true }], + filters: getSearchParam('filters') ? JSON.parse(getSearchParam('filters')!) : [], + joinOperator: (getSearchParam('joinOperator') as "and" | "or") || "and", + basicFilters: getSearchParam('basicFilters') ? + JSON.parse(getSearchParam('basicFilters')!) : [], + basicJoinOperator: (getSearchParam('basicJoinOperator') as "and" | "or") || "and", + search: getSearchParam('search') || '', columnVisibility: {}, columnOrder: [], pinnedColumns: { left: [], right: ["actions"] }, @@ -267,22 +285,22 @@ export function PeriodicEvaluationsTable({ promises, evaluationYear, className } ) const filterFields: DataTableFilterField<PeriodicEvaluationView>[] = [ - { id: "evaluationTarget.vendorCode", label: "벤더 코드" }, - { id: "evaluationTarget.vendorName", label: "벤더명" }, + { id: "vendorCode", label: "벤더 코드" }, + { id: "vendorName", label: "벤더명" }, { id: "status", label: "진행상태" }, ] const advancedFilterFields: DataTableAdvancedFilterField<PeriodicEvaluationView>[] = [ - { id: "evaluationTarget.evaluationYear", label: "평가년도", type: "number" }, + { id: "evaluationYear", label: "평가년도", type: "number" }, { id: "evaluationPeriod", label: "평가기간", type: "text" }, { - id: "evaluationTarget.division", label: "구분", type: "select", options: [ + id: "division", label: "구분", type: "select", options: [ { label: "해양", value: "PLANT" }, { label: "조선", value: "SHIP" }, ] }, - { id: "evaluationTarget.vendorCode", label: "벤더 코드", type: "text" }, - { id: "evaluationTarget.vendorName", label: "벤더명", type: "text" }, + { id: "vendorCode", label: "벤더 코드", type: "text" }, + { id: "vendorName", label: "벤더명", type: "text" }, { id: "status", label: "진행상태", type: "select", options: [ { label: "제출대기", value: "PENDING_SUBMISSION" }, @@ -305,24 +323,14 @@ export function PeriodicEvaluationsTable({ promises, evaluationYear, className } { id: "finalizedAt", label: "최종확정일", type: "date" }, ] - const currentSettings = useMemo(() => { - return getCurrentSettings() - }, [getCurrentSettings]) + const currentSettings = React.useMemo(() => getCurrentSettings(), [getCurrentSettings]); - function getColKey<T>(c: ColumnDef<T>): string | undefined { - if ("accessorKey" in c && c.accessorKey) return c.accessorKey as string - if ("id" in c && c.id) return c.id as string - return undefined - } + const initialState = React.useMemo(() => ({ + sorting: initialSettings.sort.filter((s: any) => columns.some((c: any) => ("accessorKey" in c ? c.accessorKey : c.id) === s.id)), + columnVisibility: currentSettings.columnVisibility, + columnPinning: currentSettings.pinnedColumns, + }), [columns, currentSettings, initialSettings.sort]); - const initialState = useMemo(() => { - return { - sorting: initialSettings.sort.filter(s => - columns.some(c => getColKey(c) === s.id)), - columnVisibility: currentSettings.columnVisibility, - columnPinning: currentSettings.pinnedColumns, - } - }, [columns, currentSettings, initialSettings.sort]) const { table } = useDataTable({ data: tableData.data, @@ -344,7 +352,7 @@ export function PeriodicEvaluationsTable({ promises, evaluationYear, className } const getActiveBasicFilterCount = () => { try { - const basicFilters = searchParams.get('basicFilters') + const basicFilters = getSearchParam('basicFilters') return basicFilters ? JSON.parse(basicFilters).length : 0 } catch (e) { return 0 |
