summaryrefslogtreecommitdiff
path: root/lib/risk-management/table/risks-columns.tsx
diff options
context:
space:
mode:
authorjoonhoekim <26rote@gmail.com>2025-08-14 00:26:53 +0000
committerjoonhoekim <26rote@gmail.com>2025-08-14 00:26:53 +0000
commitdd20ba9785cdbd3d61f6b014d003d3bd9646ad13 (patch)
tree4e99d62311a6c115dbc894084714a29c34bca11a /lib/risk-management/table/risks-columns.tsx
parent33be47506f0aa62b969d82521580a29e95080268 (diff)
(고건) 리스크 관리 페이지 추가
Diffstat (limited to 'lib/risk-management/table/risks-columns.tsx')
-rw-r--r--lib/risk-management/table/risks-columns.tsx352
1 files changed, 352 insertions, 0 deletions
diff --git a/lib/risk-management/table/risks-columns.tsx b/lib/risk-management/table/risks-columns.tsx
new file mode 100644
index 00000000..fe98448a
--- /dev/null
+++ b/lib/risk-management/table/risks-columns.tsx
@@ -0,0 +1,352 @@
+'use client';
+
+/* IMPORT */
+import { Badge } from '@/components/ui/badge';
+import { Button } from '@/components/ui/button';
+import { Checkbox } from '@/components/ui/checkbox';
+import { CircleCheckBig, CircleX, Ellipsis, Handshake, OctagonAlert } from 'lucide-react';
+import { DataTableColumnHeaderSimple } from '@/components/data-table/data-table-column-simple-header';
+import { Dispatch, SetStateAction } from 'react';
+import {
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuTrigger,
+} from '@/components/ui/dropdown-menu';
+import { type ColumnDef } from '@tanstack/react-table';
+import { type DataTableRowAction } from '@/types/table';
+import { type RisksView } from '@/db/schema';
+
+// ----------------------------------------------------------------------------------------------------
+
+/* TYPES */
+interface GetColumnsProps {
+ setRowAction: Dispatch<SetStateAction<DataTableRowAction<RisksView> | null>>,
+};
+
+// ----------------------------------------------------------------------------------------------------
+
+/* FUNCTION FOR GETTING COLUMNS SETTING */
+function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<RisksView>[] {
+
+ // [1] SELECT COLUMN - CHECKBOX
+ const selectColumn: ColumnDef<RisksView> = {
+ id: 'select',
+ header: ({ table }) => (
+ <Checkbox
+ checked={
+ table.getIsAllPageRowsSelected() ||
+ (table.getIsSomePageRowsSelected() && 'indeterminate')
+ }
+ onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}
+ aria-label="select-all"
+ className="translate-y-0.5"
+ />
+ ),
+ cell: ({ row }) => (
+ <Checkbox
+ checked={row.getIsSelected()}
+ onCheckedChange={(value) => row.toggleSelected(!!value)}
+ aria-label="select-row"
+ className="translate-y-0.5"
+ />
+ ),
+ enableSorting: false,
+ enableHiding: false,
+ size: 40,
+ };
+
+ // [2] SOURCE COLUMNS
+ const sourceColumns: ColumnDef<RisksView>[] = [
+ {
+ accessorKey: 'eventType',
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="항목" />
+ ),
+ cell: ({ row }) => {
+ const value = row.getValue<string>('eventType');
+ return (
+ <Badge variant="default">
+ {value}
+ </Badge>
+ );
+ },
+ enableSorting: true,
+ enableHiding: false,
+ meta: {
+ excelHeader: 'Risk Category',
+ group: 'Risk Information',
+ type: 'select',
+ },
+ },
+ {
+ accessorKey: 'vendorCode',
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="협력업체 코드" />
+ ),
+ cell: ({ row }) => {
+ const value = row.getValue<string>('vendorCode');
+ return (
+ <div className="font-regular">
+ {value}
+ </div>
+ );
+ },
+ enableSorting: true,
+ enableHiding: false,
+ meta: {
+ excelHeader: 'Vendor Code',
+ group: 'Risk Information',
+ type: 'text',
+ },
+ },
+ {
+ accessorKey: 'vendorName',
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="협력업체명" />
+ ),
+ cell: ({ row }) => {
+ const value = row.getValue<string>('vendorName');
+ return (
+ <div className="font-regular">
+ {value}
+ </div>
+ );
+ },
+ enableSorting: true,
+ enableHiding: false,
+ meta: {
+ excelHeader: 'Vendor Name',
+ group: 'Risk Information',
+ type: 'text',
+ },
+ },
+ {
+ accessorKey: 'businessNumber',
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="사업자등록번호" />
+ ),
+ cell: ({ row }) => {
+ const value = row.getValue<string>('businessNumber');
+ const digits = value.replace(/\D/g, '');
+ const formattedValue = digits.length === 10
+ ? `${digits.slice(0, 3)}-${digits.slice(3, 5)}-${digits.slice(5)}`
+ : value;
+ return (
+ <div className="font-regular">
+ {formattedValue}
+ </div>
+ );
+ },
+ enableSorting: true,
+ enableHiding: false,
+ meta: {
+ excelHeader: 'Business Number',
+ group: 'Risk Information',
+ type: 'text',
+ },
+ },
+ {
+ accessorKey: 'provider',
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="신용평가사" />
+ ),
+ cell: ({ row }) => {
+ const value = row.getValue<string>('provider');
+ return (
+ <Badge variant="secondary">
+ {value}
+ </Badge>
+ );
+ },
+ enableSorting: true,
+ enableHiding: false,
+ meta: {
+ excelHeader: 'Provider',
+ group: 'Risk Information',
+ type: 'text',
+ },
+ },
+ {
+ accessorKey: 'content',
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="상세 내용" />
+ ),
+ cell: ({ row }) => {
+ const value = row.getValue<string>('content') ?? '-';
+ return (
+ <div className="font-regular max-w-[150px] truncate" title={value}>
+ {value}
+ </div>
+ );
+ },
+ enableSorting: true,
+ enableHiding: false,
+ meta: {
+ excelHeader: 'Risk Content',
+ group: 'Risk Information',
+ type: 'text',
+ },
+ size: 100,
+ },
+ {
+ accessorKey: 'occuredAt',
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="발생일시" />
+ ),
+ cell: ({ row }) => {
+ const date = row.getValue<Date>('occuredAt');
+ return (
+ <div className="font-regular">
+ {date ? new Date(date).toLocaleDateString('ko-KR') : '-'}
+ </div>
+ );
+ },
+ enableSorting: true,
+ enableHiding: false,
+ meta: {
+ excelHeader: 'Occured At',
+ group: 'Risk Information',
+ type: 'date',
+ },
+ },
+ ];
+
+ // [3] INPUT COLUMNS
+ const inputColumns: ColumnDef<RisksView>[] = [
+ {
+ accessorKey: 'eventStatus',
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="리스크 해소 여부" />
+ ),
+ cell: ({ row }) => {
+ const value = row.getValue<boolean>('eventStatus');
+
+ if (value) {
+ return (
+ <div className="flex items-center gap-2 text-destructive font-bold">
+ <CircleX size={20} strokeWidth={2} />
+ 아니오
+ </div>
+ );
+ }
+ return (
+ <div className="flex items-center gap-2 text-primary font-bold">
+ <CircleCheckBig size={20} strokeWidth={2} />
+ 예
+ </div>
+ );
+ },
+ enableSorting: true,
+ enableHiding: false,
+ meta: {
+ excelHeader: 'Risk Not Cleared',
+ group: 'Risk Management',
+ type: 'text',
+ },
+ },
+ {
+ accessorKey: 'managerName',
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="구매 담당자" />
+ ),
+ cell: ({ row }) => {
+ const value = row.getValue<string>('managerName') ?? '-';
+ return (
+ <div className="font-regular">
+ {value}
+ </div>
+ );
+ },
+ enableSorting: true,
+ enableHiding: false,
+ meta: {
+ excelHeader: 'Procurement Manager Name',
+ group: 'Risk Management',
+ type: 'text',
+ },
+ },
+ {
+ accessorKey: 'adminComment',
+ header: ({ column }) => (
+ <DataTableColumnHeaderSimple column={column} title="관리 담당자 의견" />
+ ),
+ cell: ({ row }) => {
+ const value = row.getValue<string>('adminComment') ?? '-';
+ return (
+ <div className="font-regular max-w-[150px] truncate" title={value}>
+ {value}
+ </div>
+ );
+ },
+ enableSorting: true,
+ enableHiding: false,
+ meta: {
+ excelHeader: 'Risk Manager Comment',
+ group: 'Risk Management',
+ type: 'text',
+ },
+ size: 300,
+ },
+ ];
+
+ // [4] ACTIONS COLUMN - DROPDOWN MENU WITH VIEW ACTION
+ const actionsColumn: ColumnDef<RisksView> = {
+ id: 'actions',
+ enableHiding: false,
+ cell: function Cell({ row }) {
+ return (
+ <DropdownMenu>
+ <DropdownMenuTrigger asChild>
+ <Button
+ aria-label="Open menu"
+ variant="ghost"
+ className="flex size-8 p-0 data-[state=open]:bg-muted"
+ >
+ <Ellipsis className="size-4" aria-hidden="true" />
+ </Button>
+ </DropdownMenuTrigger>
+ <DropdownMenuContent align="end" className="w-60">
+ <DropdownMenuItem
+ onSelect={() => setRowAction({ row, type: "update" })}
+ className="cursor-pointer"
+ >
+ <OctagonAlert className="mr-2 size-4" />
+ 리스크 관리
+ </DropdownMenuItem>
+ <DropdownMenuItem
+ onSelect={() => {
+ // 신용정보 관리화면으로 이동
+ }}
+ className="cursor-pointer"
+ >
+ <Handshake className="mr-2 size-4" />
+ 신용정보 확인
+ </DropdownMenuItem>
+ </DropdownMenuContent>
+ </DropdownMenu>
+ )
+ },
+ size: 80,
+ };
+
+ return [
+ selectColumn,
+ {
+ id: 'riskSource',
+ header: '리스크 정보',
+ columns: sourceColumns,
+ },
+ {
+ id: 'riskInput',
+ header: '리스크 관리',
+ columns: inputColumns,
+ },
+ actionsColumn,
+ ];
+};
+
+// ----------------------------------------------------------------------------------------------------
+
+/* EXPORT */
+export default getColumns; \ No newline at end of file