diff options
Diffstat (limited to 'lib/docu-list-rule/code-groups')
7 files changed, 140 insertions, 30 deletions
diff --git a/lib/docu-list-rule/code-groups/service.ts b/lib/docu-list-rule/code-groups/service.ts index c99588a5..843bafa2 100644 --- a/lib/docu-list-rule/code-groups/service.ts +++ b/lib/docu-list-rule/code-groups/service.ts @@ -3,7 +3,8 @@ import { revalidatePath } from "next/cache" import db from "@/db/db" import { codeGroups, comboBoxSettings } from "@/db/schema/docu-list-rule" -import { eq, sql, count } from "drizzle-orm" +import { projects } from "@/db/schema/projects" +import { eq, sql, count, and } from "drizzle-orm" import { unstable_noStore } from "next/cache" // Code Groups 목록 조회 @@ -24,7 +25,8 @@ export async function getCodeGroups(input: any) { ${codeGroups.groupId} ILIKE ${searchTerm} OR ${codeGroups.description} ILIKE ${searchTerm} OR ${codeGroups.codeFormat} ILIKE ${searchTerm} OR - ${codeGroups.controlType} ILIKE ${searchTerm} + ${codeGroups.controlType} ILIKE ${searchTerm} OR + ${projects.code} ILIKE ${searchTerm} )` } @@ -68,14 +70,20 @@ export async function getCodeGroups(input: any) { if (input.sort && input.sort.length > 0) { const sortField = input.sort[0] // 안전성 체크: 필드가 실제 테이블에 존재하는지 확인 - if (sortField && sortField.id && typeof sortField.id === "string" && sortField.id in codeGroups) { + if (sortField && sortField.id && typeof sortField.id === "string") { const direction = sortField.desc ? sql`DESC` : sql`ASC` - const col = codeGroups[sortField.id as keyof typeof codeGroups] - orderBy = sql`${col} ${direction}` + + // 프로젝트 코드 정렬 처리 + if (sortField.id === "projectCode") { + orderBy = sql`${projects.code} ${direction}` + } else if (sortField.id in codeGroups) { + const col = codeGroups[sortField.id as keyof typeof codeGroups] + orderBy = sql`${col} ${direction}` + } } } - // 데이터 조회 + // 데이터 조회 (프로젝트 정보 포함) const data = await db .select({ id: codeGroups.id, @@ -87,38 +95,44 @@ export async function getCodeGroups(input: any) { isActive: codeGroups.isActive, createdAt: codeGroups.createdAt, updatedAt: codeGroups.updatedAt, + projectId: codeGroups.projectId, + projectCode: projects.code, + projectName: projects.name, }) .from(codeGroups) + .leftJoin(projects, eq(codeGroups.projectId, projects.id)) .where(whereConditions) .orderBy(orderBy) .limit(perPage) .offset(offset) - // 총 개수 조회 (Document Class 제외) - const [{ count: total }] = await db - .select({ count: count() }) + // 총 개수 조회 (프로젝트 정보 포함) + const totalCountResult = await db + .select({ count: sql<number>`count(*)` }) .from(codeGroups) + .leftJoin(projects, eq(codeGroups.projectId, projects.id)) .where(whereConditions) - const pageCount = Math.ceil(total / perPage) + const totalCount = totalCountResult[0]?.count || 0 return { data, - pageCount, - total, + totalCount, + pageCount: Math.ceil(totalCount / perPage), } } catch (error) { console.error("Error fetching code groups:", error) return { data: [], + totalCount: 0, pageCount: 0, - total: 0, } } } // Code Group 생성 export async function createCodeGroup(input: { + projectId: number // projectCode를 projectId로 변경 description: string codeFormat?: string expressions?: string @@ -126,11 +140,14 @@ export async function createCodeGroup(input: { isActive?: boolean }) { try { - // 마지막 Code Group의 groupId를 찾아서 다음 번호 생성 (DOC_CLASS 제외) + // 해당 프로젝트의 마지막 Code Group의 groupId를 찾아서 다음 번호 생성 (DOC_CLASS 제외) const lastCodeGroup = await db .select({ groupId: codeGroups.groupId }) .from(codeGroups) - .where(sql`${codeGroups.groupId} != 'DOC_CLASS'`) + .where(and( + eq(codeGroups.projectId, input.projectId), // projectId로 변경 + sql`${codeGroups.groupId} != 'DOC_CLASS'` + )) .orderBy(sql`CAST(SUBSTRING(${codeGroups.groupId}, 6) AS INTEGER) DESC`) .limit(1) @@ -148,6 +165,7 @@ export async function createCodeGroup(input: { const [newCodeGroup] = await db .insert(codeGroups) .values({ + projectId: input.projectId, // projectId로 변경 groupId: newGroupId, description: input.description, codeFormat: input.codeFormat, diff --git a/lib/docu-list-rule/code-groups/table/code-groups-add-dialog.tsx b/lib/docu-list-rule/code-groups/table/code-groups-add-dialog.tsx index bf044f1a..a0143239 100644 --- a/lib/docu-list-rule/code-groups/table/code-groups-add-dialog.tsx +++ b/lib/docu-list-rule/code-groups/table/code-groups-add-dialog.tsx @@ -33,10 +33,12 @@ import { SelectTrigger, SelectValue, } from "@/components/ui/select" -import { createCodeGroup } from "../service" +import { createCodeGroup } from "@/lib/docu-list-rule/code-groups/service" +import { getProjectLists } from "@/lib/projects/service" import { z } from "zod" const createCodeGroupSchema = z.object({ + projectId: z.string().min(1, "프로젝트는 필수입니다."), description: z.string().min(1, "Description은 필수입니다."), codeFormat: z.string().optional().refine((val) => { if (!val) return true; // 빈 값은 허용 @@ -54,16 +56,44 @@ interface CodeGroupsAddDialogProps { export function CodeGroupsAddDialog({ onSuccess }: CodeGroupsAddDialogProps) { const [open, setOpen] = React.useState(false) const [isLoading, setIsLoading] = React.useState(false) + const [projects, setProjects] = React.useState<Array<{ id: number; code: string; name: string }>>([]) const form = useForm<CreateCodeGroupFormValues>({ resolver: zodResolver(createCodeGroupSchema), defaultValues: { + projectId: "", description: "", codeFormat: "", controlType: "", }, }) + // 프로젝트 목록 로드 + React.useEffect(() => { + if (open) { + const loadProjects = async () => { + try { + const result = await getProjectLists({ + page: 1, + perPage: 1000, + search: "", + sort: [], + filters: [], + joinOperator: "and", + flags: [] + }) + if (result.data) { + setProjects(result.data) + } + } catch (error) { + console.error("Failed to load projects:", error) + toast.error("프로젝트 목록을 불러오는데 실패했습니다.") + } + } + loadProjects() + } + }, [open]) + // Code Format을 기반으로 정규식 자동 생성 함수 const generateExpression = (codeFormat: string): string => { if (!codeFormat) return '' @@ -121,6 +151,7 @@ export function CodeGroupsAddDialog({ onSuccess }: CodeGroupsAddDialogProps) { const expressions = generateExpression(data.codeFormat || "") const result = await createCodeGroup({ + projectId: parseInt(data.projectId), description: data.description, codeFormat: data.codeFormat, expressions: expressions, @@ -156,6 +187,7 @@ export function CodeGroupsAddDialog({ onSuccess }: CodeGroupsAddDialogProps) { <DialogTitle>Code Group 생성</DialogTitle> <DialogDescription> 새로운 Code Group을 생성합니다. + <span className="text-red-500 mt-1 block text-sm">* 표시된 항목은 필수 입력사항입니다.</span> </DialogDescription> </DialogHeader> @@ -163,10 +195,35 @@ export function CodeGroupsAddDialog({ onSuccess }: CodeGroupsAddDialogProps) { <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4"> <FormField control={form.control} + name="projectId" + render={({ field }) => ( + <FormItem> + <FormLabel>프로젝트 *</FormLabel> + <Select onValueChange={field.onChange} defaultValue={field.value}> + <FormControl> + <SelectTrigger> + <SelectValue placeholder="프로젝트를 선택하세요" /> + </SelectTrigger> + </FormControl> + <SelectContent> + {projects.map((project) => ( + <SelectItem key={project.id} value={project.id.toString()}> + {project.code} - {project.name} + </SelectItem> + ))} + </SelectContent> + </Select> + <FormMessage /> + </FormItem> + )} + /> + + <FormField + control={form.control} name="description" render={({ field }) => ( <FormItem> - <FormLabel>Description</FormLabel> + <FormLabel>Description *</FormLabel> <FormControl> <Input placeholder="예: PROJECT NO" {...field} /> </FormControl> diff --git a/lib/docu-list-rule/code-groups/table/code-groups-edit-sheet.tsx b/lib/docu-list-rule/code-groups/table/code-groups-edit-sheet.tsx index 74ebc05a..7dc714a7 100644 --- a/lib/docu-list-rule/code-groups/table/code-groups-edit-sheet.tsx +++ b/lib/docu-list-rule/code-groups/table/code-groups-edit-sheet.tsx @@ -34,8 +34,8 @@ import { SelectTrigger, SelectValue, } from "@/components/ui/select" -import { updateCodeGroup } from "../service" -import { codeGroups } from "@/db/schema/codeGroups" +import { updateCodeGroup } from "@/lib/docu-list-rule/code-groups/service" +import { codeGroups } from "@/db/schema/docu-list-rule" import { z } from "zod" const updateCodeGroupSchema = z.object({ diff --git a/lib/docu-list-rule/code-groups/table/code-groups-table-columns.tsx b/lib/docu-list-rule/code-groups/table/code-groups-table-columns.tsx index c15dd676..01047c50 100644 --- a/lib/docu-list-rule/code-groups/table/code-groups-table-columns.tsx +++ b/lib/docu-list-rule/code-groups/table/code-groups-table-columns.tsx @@ -103,6 +103,19 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef<typeof // ---------------------------------------------------------------- const dataColumns: ColumnDef<typeof codeGroups.$inferSelect>[] = [ { + accessorKey: "projectCode", + enableResizing: true, + header: ({ column }) => ( + <DataTableColumnHeaderSimple column={column} title="프로젝트 코드" /> + ), + meta: { + excelHeader: "프로젝트 코드", + type: "text", + }, + cell: ({ row }) => row.getValue("projectCode") ?? "", + minSize: 120 + }, + { accessorKey: "groupId", enableResizing: true, header: ({ column }) => ( diff --git a/lib/docu-list-rule/code-groups/table/code-groups-table-toolbar.tsx b/lib/docu-list-rule/code-groups/table/code-groups-table-toolbar.tsx index d2d9efb4..4dc3334c 100644 --- a/lib/docu-list-rule/code-groups/table/code-groups-table-toolbar.tsx +++ b/lib/docu-list-rule/code-groups/table/code-groups-table-toolbar.tsx @@ -3,9 +3,9 @@ import * as React from "react" import { type Table } from "@tanstack/react-table" -import { DeleteCodeGroupsDialog } from "./delete-code-groups-dialog" -import { CodeGroupsAddDialog } from "./code-groups-add-dialog" -import { codeGroups } from "@/db/schema/codeGroups" +import { DeleteCodeGroupsDialog } from "@/lib/docu-list-rule/code-groups/table/delete-code-groups-dialog" +import { CodeGroupsAddDialog } from "@/lib/docu-list-rule/code-groups/table/code-groups-add-dialog" +import { codeGroups } from "@/db/schema/docu-list-rule" interface CodeGroupsTableToolbarActionsProps<TData> { table: Table<TData> diff --git a/lib/docu-list-rule/code-groups/table/code-groups-table.tsx b/lib/docu-list-rule/code-groups/table/code-groups-table.tsx index 8873c34c..0029ed91 100644 --- a/lib/docu-list-rule/code-groups/table/code-groups-table.tsx +++ b/lib/docu-list-rule/code-groups/table/code-groups-table.tsx @@ -9,10 +9,10 @@ import type { DataTableFilterField, DataTableRowAction, } from "@/types/table" -import { getColumns } from "./code-groups-table-columns"; -import { DeleteCodeGroupsDialog } from "./delete-code-groups-dialog"; -import { CodeGroupsEditSheet } from "./code-groups-edit-sheet"; -import { CodeGroupsTableToolbarActions } from "./code-groups-table-toolbar"; +import { getColumns } from "@/lib/docu-list-rule/code-groups/table/code-groups-table-columns"; +import { DeleteCodeGroupsDialog } from "@/lib/docu-list-rule/code-groups/table/delete-code-groups-dialog"; +import { CodeGroupsEditSheet } from "@/lib/docu-list-rule/code-groups/table/code-groups-edit-sheet"; +import { CodeGroupsTableToolbarActions } from "@/lib/docu-list-rule/code-groups/table/code-groups-table-toolbar"; import { codeGroups } from "@/db/schema/docu-list-rule"; interface CodeGroupsTableProps { @@ -68,12 +68,34 @@ export function CodeGroupsTable({ promises }: CodeGroupsTableProps) { enableAdvancedFilter: true, initialState: { columnPinning: { right: ["actions"] }, + expanded: {}, }, - getRowId: (originalRow) => String(originalRow.groupId), + getRowId: (originalRow) => String(originalRow.id), shallow: false, - clearOnDefault: true, + clearOnDefault: false, }) + // 컴포넌트 마운트 후 그룹핑 설정 + React.useEffect(() => { + if (data && table.getState().grouping.length === 0) { + table.setGrouping(["projectCode"]) + } + }, [table, data]) + + // 정렬 시 펼쳐진 상태 유지 + React.useEffect(() => { + const currentExpanded = table.getState().expanded + if (Object.keys(currentExpanded).length > 0) { + // 약간의 지연 후 현재 펼쳐진 상태를 다시 설정 + const timer = setTimeout(() => { + table.setExpanded(currentExpanded) + }, 100) + return () => clearTimeout(timer) + } + }, [table.getState().sorting, table]) + + + return ( <> <DataTable table={table}> diff --git a/lib/docu-list-rule/code-groups/table/delete-code-groups-dialog.tsx b/lib/docu-list-rule/code-groups/table/delete-code-groups-dialog.tsx index 66a8d7c2..6f2217bd 100644 --- a/lib/docu-list-rule/code-groups/table/delete-code-groups-dialog.tsx +++ b/lib/docu-list-rule/code-groups/table/delete-code-groups-dialog.tsx @@ -27,8 +27,8 @@ import { DrawerTitle, DrawerTrigger, } from "@/components/ui/drawer" -import { codeGroups } from "@/db/schema/codeGroups" -import { deleteCodeGroup } from "../service" +import { codeGroups } from "@/db/schema/docu-list-rule" +import { deleteCodeGroup } from "@/lib/docu-list-rule/code-groups/service" interface DeleteCodeGroupsDialogProps extends React.ComponentPropsWithoutRef<typeof Dialog> { |
