summaryrefslogtreecommitdiff
path: root/lib/docu-list-rule/document-class
diff options
context:
space:
mode:
Diffstat (limited to 'lib/docu-list-rule/document-class')
-rw-r--r--lib/docu-list-rule/document-class/service.ts132
-rw-r--r--lib/docu-list-rule/document-class/table/document-class-add-dialog.tsx21
-rw-r--r--lib/docu-list-rule/document-class/table/document-class-table-columns.tsx43
3 files changed, 103 insertions, 93 deletions
diff --git a/lib/docu-list-rule/document-class/service.ts b/lib/docu-list-rule/document-class/service.ts
index d92f3a95..9d3ff23a 100644
--- a/lib/docu-list-rule/document-class/service.ts
+++ b/lib/docu-list-rule/document-class/service.ts
@@ -149,51 +149,16 @@ export async function createDocumentClassCodeGroup(input: {
description?: string
}) {
try {
- // Value 자동 변환: "A", "AB", "A Class", "A CLASS" 등을 "A Class", "AB Class" 형태로 변환
- const formatValue = (input: string): string => {
- // 공백 제거 및 대소문자 정규화
- const cleaned = input.trim().toLowerCase()
-
- // "class"가 포함되어 있으면 제거
- const withoutClass = cleaned.replace(/\s*class\s*/g, '')
-
- // 알파벳과 숫자만 추출
- const letters = withoutClass.replace(/[^a-z0-9]/g, '')
-
- if (letters.length === 0) {
- return input.trim() // 변환할 수 없으면 원본 반환
- }
-
- // 첫 글자를 대문자로 변환하고 "Class" 추가
- return letters.charAt(0).toUpperCase() + letters.slice(1) + " Class"
- }
-
- const formattedValue = formatValue(input.value)
-
- // 해당 프로젝트의 자동으로 code 생성 (예: "DOC_CLASS_001", "DOC_CLASS_002" 등)
- const existingClasses = await db
- .select({ code: documentClasses.code })
- .from(documentClasses)
- .where(eq(documentClasses.projectId, input.projectId)) // projectId로 변경
- .orderBy(desc(documentClasses.code))
-
- let newCode = "DOC_CLASS_001"
- if (existingClasses.length > 0) {
- const lastClass = existingClasses[0]
- if (lastClass.code) {
- const lastNumber = parseInt(lastClass.code.replace("DOC_CLASS_", "")) || 0
- newCode = `DOC_CLASS_${String(lastNumber + 1).padStart(3, '0')}`
- }
- }
+ // Value는 1자리 대문자 알파벳 그대로 저장 (API DOC_CLASS 전송용)
+ const formattedValue = input.value.trim().toUpperCase()
const [newDocumentClass] = await db
.insert(documentClasses)
.values({
- projectId: input.projectId, // projectId로 변경
- code: newCode,
- value: formattedValue,
+ projectId: input.projectId,
+ value: formattedValue, // "A", "B", "C" 등 1자리
description: input.description || "",
- codeGroupId: null, // Code Group 연결 제거
+ codeGroupId: null,
isActive: true,
})
.returning({ id: documentClasses.id })
@@ -222,31 +187,13 @@ export async function updateDocumentClassCodeGroup(input: {
description?: string
}) {
try {
- // Value 자동 변환: "A", "AB", "A Class", "A CLASS" 등을 "A Class", "AB Class" 형태로 변환
- const formatValue = (value: string): string => {
- // 공백 제거 및 대소문자 정규화
- const cleaned = value.trim().toLowerCase()
-
- // "class"가 포함되어 있으면 제거
- const withoutClass = cleaned.replace(/\s*class\s*/g, '')
-
- // 알파벳과 숫자만 추출
- const letters = withoutClass.replace(/[^a-z0-9]/g, '')
-
- if (letters.length === 0) {
- return value.trim() // 변환할 수 없으면 원본 반환
- }
-
- // 첫 글자를 대문자로 변환하고 "Class" 추가
- return letters.charAt(0).toUpperCase() + letters.slice(1) + " Class"
- }
-
- const formattedValue = formatValue(input.value)
+ // Value는 1자리 대문자 알파벳 그대로 저장 (API DOC_CLASS 전송용)
+ const formattedValue = input.value.trim().toUpperCase()
const [updatedDocumentClass] = await db
.update(documentClasses)
.set({
- value: formattedValue,
+ value: formattedValue, // "A", "B", "C" 등 1자리
description: input.description || "",
updatedAt: new Date(),
})
@@ -630,4 +577,67 @@ export async function getProjectKindScheduleSetting(projectCode: string): Promis
console.error('Error fetching schedule settings:', error)
return []
}
+}
+
+/**
+ * 프로젝트의 Document Class와 해당 Stage 옵션 매핑 조회
+ * @param projectCode 프로젝트 코드 (예: "SN2190")
+ * @returns Document Class별 허용 Stage 목록 맵
+ */
+export async function getProjectDocumentClassStages(projectCode: string): Promise<Record<string, string[]>> {
+ try {
+ // 1. 프로젝트 ID 조회
+ const project = await db
+ .select({ id: projects.id })
+ .from(projects)
+ .where(eq(projects.code, projectCode))
+ .limit(1);
+
+ if (!project.length) {
+ console.warn(`[getProjectDocumentClassStages] 프로젝트를 찾을 수 없습니다: ${projectCode}`);
+ return {};
+ }
+
+ const projectId = project[0].id;
+
+ // 2. 프로젝트의 모든 Document Class와 옵션 조회
+ const documentClassesWithOptions = await db
+ .select({
+ docClassValue: documentClasses.value,
+ optionCode: documentClassOptions.optionCode,
+ })
+ .from(documentClasses)
+ .leftJoin(
+ documentClassOptions,
+ eq(documentClasses.id, documentClassOptions.documentClassId)
+ )
+ .where(
+ and(
+ eq(documentClasses.projectId, projectId),
+ eq(documentClasses.isActive, true),
+ eq(documentClassOptions.isActive, true)
+ )
+ )
+ .orderBy(documentClasses.value, documentClassOptions.sdq);
+
+ // 3. Document Class별로 Stage 목록 그룹핑
+ const stageMap: Record<string, string[]> = {};
+
+ for (const row of documentClassesWithOptions) {
+ if (!row.docClassValue || !row.optionCode) continue;
+
+ if (!stageMap[row.docClassValue]) {
+ stageMap[row.docClassValue] = [];
+ }
+
+ stageMap[row.docClassValue].push(row.optionCode);
+ }
+
+ console.log(`[getProjectDocumentClassStages] ${projectCode}: ${Object.keys(stageMap).length}개 Document Class, 총 ${Object.values(stageMap).flat().length}개 Stage 옵션`);
+
+ return stageMap;
+ } catch (error) {
+ console.error('[getProjectDocumentClassStages] 오류:', error);
+ return {};
+ }
} \ No newline at end of file
diff --git a/lib/docu-list-rule/document-class/table/document-class-add-dialog.tsx b/lib/docu-list-rule/document-class/table/document-class-add-dialog.tsx
index e2cfc39e..6e8ac686 100644
--- a/lib/docu-list-rule/document-class/table/document-class-add-dialog.tsx
+++ b/lib/docu-list-rule/document-class/table/document-class-add-dialog.tsx
@@ -32,7 +32,10 @@ import { createDocumentClassCodeGroup } from "@/lib/docu-list-rule/document-clas
import { useParams } from "next/navigation"
const createDocumentClassSchema = z.object({
- value: z.string().min(1, "Value는 필수입니다."),
+ value: z.string()
+ .min(1, "Value는 필수입니다.")
+ .max(1, "Value는 1자리만 입력 가능합니다. (예: A, B, 0, 1)")
+ .regex(/^[A-Z0-9]$/, "대문자 알파벳 또는 숫자 1자리만 입력 가능합니다. (예: A, B, 0, 1)"),
description: z.string().optional(),
})
@@ -117,8 +120,17 @@ export function DocumentClassAddDialog({
<FormItem>
<FormLabel>Value *</FormLabel>
<FormControl>
- <Input {...field} placeholder="예: A Class" />
+ <Input
+ {...field}
+ placeholder="예: A"
+ maxLength={1}
+ className="uppercase"
+ onChange={(e) => field.onChange(e.target.value.toUpperCase())}
+ />
</FormControl>
+ <div className="text-xs text-muted-foreground mt-1">
+ 💡 대문자 알파벳 또는 숫자 1자리 (A, B, 0, 1 등) - API DOC_CLASS로 전송됩니다
+ </div>
<FormMessage />
</FormItem>
)}
@@ -131,8 +143,11 @@ export function DocumentClassAddDialog({
<FormItem>
<FormLabel>Description</FormLabel>
<FormControl>
- <Input {...field} placeholder="예: A Class Description (선택사항)" />
+ <Input {...field} placeholder="예: General Documents (선택사항)" />
</FormControl>
+ <div className="text-xs text-muted-foreground mt-1">
+ 선택사항: Document Class에 대한 추가 설명
+ </div>
<FormMessage />
</FormItem>
)}
diff --git a/lib/docu-list-rule/document-class/table/document-class-table-columns.tsx b/lib/docu-list-rule/document-class/table/document-class-table-columns.tsx
index 8c391def..9d8d91e0 100644
--- a/lib/docu-list-rule/document-class/table/document-class-table-columns.tsx
+++ b/lib/docu-list-rule/document-class/table/document-class-table-columns.tsx
@@ -107,43 +107,28 @@ export function getColumns({ setRowAction, onDetail }: GetColumnsProps): ColumnD
// ----------------------------------------------------------------
const dataColumns: ColumnDef<typeof documentClasses.$inferSelect>[] = [
{
- accessorKey: "code",
- enableResizing: true,
- header: ({ column }) => (
- <DataTableColumnHeaderSimple column={column} title="코드" />
- ),
- meta: {
- excelHeader: "코드",
- type: "text",
- },
- cell: ({ row }) => row.getValue("code") ?? "",
- minSize: 80
- },
- {
accessorKey: "value",
enableResizing: true,
header: ({ column }) => (
- <DataTableColumnHeaderSimple column={column} title="값" />
+ <DataTableColumnHeaderSimple column={column} title="클래스" />
),
meta: {
- excelHeader: "값",
+ excelHeader: "클래스",
type: "text",
},
- cell: ({ row }) => row.getValue("value") ?? "",
- minSize: 80
- },
- {
- accessorKey: "description",
- enableResizing: true,
- header: ({ column }) => (
- <DataTableColumnHeaderSimple column={column} title="설명" />
- ),
- meta: {
- excelHeader: "설명",
- type: "text",
+ cell: ({ row }) => {
+ const value = row.getValue("value") as string
+ const description = row.getValue("description") as string
+ return (
+ <div className="flex items-center gap-2">
+ <span className="font-mono font-bold text-lg">{value}</span>
+ {description && (
+ <span className="text-muted-foreground text-sm">- {description}</span>
+ )}
+ </div>
+ )
},
- cell: ({ row }) => row.getValue("description") ?? "",
- minSize: 80
+ minSize: 250
},
{