diff options
| author | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-05-29 05:17:13 +0000 |
|---|---|---|
| committer | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-05-29 05:17:13 +0000 |
| commit | 37f55540833c2d5894513eca9fc8f7c6233fc2d2 (patch) | |
| tree | 6807978e7150358b3444c33b825c83e2c9cda8e8 /lib/forms/services.ts | |
| parent | 4b9bdb29e637f67761beb2db7f75dab0432d6712 (diff) | |
(대표님) 0529 14시 16분 변경사항 저장 (Vendor Data, Docu)
Diffstat (limited to 'lib/forms/services.ts')
| -rw-r--r-- | lib/forms/services.ts | 140 |
1 files changed, 90 insertions, 50 deletions
diff --git a/lib/forms/services.ts b/lib/forms/services.ts index 8f40162c..0fbe68a6 100644 --- a/lib/forms/services.ts +++ b/lib/forms/services.ts @@ -10,6 +10,7 @@ import { formEntries, formMetas, forms, + tagClassAttributes, tagClasses, tags, tagSubfieldOptions, @@ -154,23 +155,85 @@ export async function revalidateForms(contractItemId: number) { } } +export interface EditableFieldsInfo { + tagNo: string; + editableFields: string[]; // 편집 가능한 필드 키 목록 +} + +// TAG별 편집 가능 필드 조회 함수 +async function getEditableFieldsByTag( + contractItemId: number, + projectId: number +): Promise<Map<string, string[]>> { + try { + // 1. 해당 contractItemId의 모든 태그 조회 + const tagList = await db + .select({ + tagNo: tags.tagNo, + tagClass: tags.class + }) + .from(tags) + .where(eq(tags.contractItemId, contractItemId)); + + const editableFieldsMap = new Map<string, string[]>(); + + // 2. 각 태그별로 편집 가능 필드 계산 + for (const tag of tagList) { + try { + // 2-1. tagClasses에서 해당 class(label)와 projectId로 tagClass 찾기 + const tagClassResult = await db + .select({ id: tagClasses.id }) + .from(tagClasses) + .where( + and( + eq(tagClasses.label, tag.tagClass), + eq(tagClasses.projectId, projectId) + ) + ) + .limit(1); + + if (tagClassResult.length === 0) { + console.warn(`No tagClass found for class: ${tag.tagClass}, projectId: ${projectId}`); + editableFieldsMap.set(tag.tagNo, []); // 편집 불가능 + continue; + } + + // 2-2. tagClassAttributes에서 편집 가능한 필드 목록 조회 + const editableAttributes = await db + .select({ attId: tagClassAttributes.attId }) + .from(tagClassAttributes) + .where(eq(tagClassAttributes.tagClassId, tagClassResult[0].id)) + .orderBy(tagClassAttributes.seq); + + // 2-3. attId 목록 저장 + const editableFields = editableAttributes.map(attr => attr.attId); + editableFieldsMap.set(tag.tagNo, editableFields); + + } catch (error) { + console.error(`Error processing tag ${tag.tagNo}:`, error); + editableFieldsMap.set(tag.tagNo, []); // 에러 시 편집 불가능 + } + } + + return editableFieldsMap; + } catch (error) { + console.error('Error getting editable fields by tag:', error); + return new Map(); + } +} /** * "가장 최신 1개 row"를 가져오고, * data가 배열이면 그 배열을 반환, * 그리고 이 로직 전체를 unstable_cache로 감싸 캐싱. */ export async function getFormData(formCode: string, contractItemId: number) { - // 고유 캐시 키 (formCode + contractItemId) const cacheKey = `form-data-${formCode}-${contractItemId}`; console.log(cacheKey, "getFormData") try { - // 1) unstable_cache로 전체 로직을 감싼다 const result = await unstable_cache( async () => { - // --- 기존 로직 시작 (projectId 고려하도록 수정) --- - - // (0) contractItemId로부터 projectId 조회 + // 기존 로직으로 projectId, columns, data 가져오기 const contractItemResult = await db .select({ projectId: projects.id @@ -183,12 +246,11 @@ export async function getFormData(formCode: string, contractItemId: number) { if (contractItemResult.length === 0) { console.warn(`[getFormData] No contract item found with ID: ${contractItemId}`); - return { columns: null, data: [] }; + return { columns: null, data: [], editableFieldsMap: new Map() }; } const projectId = contractItemResult[0].projectId; - // (1) form_metas 조회 - 이제 projectId도 조건에 포함 const metaRows = await db .select() .from(formMetas) @@ -204,10 +266,9 @@ export async function getFormData(formCode: string, contractItemId: number) { const meta = metaRows[0] ?? null; if (!meta) { console.warn(`[getFormData] No form meta found for formCode: ${formCode} and projectId: ${projectId}`); - return { columns: null, data: [] }; + return { columns: null, data: [], editableFieldsMap: new Map() }; } - // (2) form_entries에서 (formCode, contractItemId)에 해당하는 "가장 최신" 한 행 const entryRows = await db .select() .from(formEntries) @@ -222,19 +283,11 @@ export async function getFormData(formCode: string, contractItemId: number) { const entry = entryRows[0] ?? null; - // columns: DB에 저장된 JSON (DataTableColumnJSON[]) let columns = meta.columns as DataTableColumnJSON[]; - - // 제외할 key들 정의 const excludeKeys = ['CLS_ID', 'BF_TAG_NO', 'TAG_TYPE_ID', 'PIC_NO']; - - // 제외할 key들을 가진 컬럼들을 필터링해서 제거 columns = columns.filter(col => !excludeKeys.includes(col.key)); columns.forEach((col) => { - // 이미 displayLabel이 있으면 그대로 두고, - // 없으면 uom이 있으면 "label (uom)" 형태, - // 둘 다 없으면 label만 쓴다. if (!col.displayLabel) { if (col.uom) { col.displayLabel = `${col.label} (${col.uom})`; @@ -244,39 +297,35 @@ export async function getFormData(formCode: string, contractItemId: number) { } }); - // data: 만약 entry가 없거나, data가 아닌 형태면 빈 배열 let data: Array<Record<string, any>> = []; if (entry) { if (Array.isArray(entry.data)) { data = entry.data; } else { - console.warn( - "formEntries data was not an array. Using empty array." - ); + console.warn("formEntries data was not an array. Using empty array."); } } - return { columns, data, projectId }; // projectId도 반환 (필요시) - // --- 기존 로직 끝 --- + // *** 새로 추가: 편집 가능 필드 정보 계산 *** + const editableFieldsMap = await getEditableFieldsByTag(contractItemId, projectId); + + return { columns, data, editableFieldsMap }; }, - [cacheKey], // 캐시 키 의존성 + [cacheKey], { - revalidate: 60, // 1분 캐시 - tags: [cacheKey], // 캐시 태그 + revalidate: 60, + tags: [cacheKey], } )(); return result; } catch (cacheError) { console.error(`[getFormData] Cache operation failed:`, cacheError); - - // --- fallback: 캐시 문제 시 직접 쿼리 시도 --- + + // Fallback logic (기존과 동일하게 editableFieldsMap 추가) try { - console.log( - `[getFormData] Fallback DB query for (${formCode}, ${contractItemId})` - ); + console.log(`[getFormData] Fallback DB query for (${formCode}, ${contractItemId})`); - // (0) contractItemId로부터 projectId 조회 const contractItemResult = await db .select({ projectId: projects.id @@ -289,12 +338,11 @@ export async function getFormData(formCode: string, contractItemId: number) { if (contractItemResult.length === 0) { console.warn(`[getFormData] Fallback: No contract item found with ID: ${contractItemId}`); - return { columns: null, data: [] }; + return { columns: null, data: [], editableFieldsMap: new Map() }; } const projectId = contractItemResult[0].projectId; - // (1) form_metas - projectId 고려 const metaRows = await db .select() .from(formMetas) @@ -310,10 +358,9 @@ export async function getFormData(formCode: string, contractItemId: number) { const meta = metaRows[0] ?? null; if (!meta) { console.warn(`[getFormData] Fallback: No form meta found for formCode: ${formCode} and projectId: ${projectId}`); - return { columns: null, data: [] }; + return { columns: null, data: [], editableFieldsMap: new Map() }; } - // (2) form_entries const entryRows = await db .select() .from(formEntries) @@ -329,17 +376,10 @@ export async function getFormData(formCode: string, contractItemId: number) { const entry = entryRows[0] ?? null; let columns = meta.columns as DataTableColumnJSON[]; - - // 제외할 key들 정의 const excludeKeys = ['CLS_ID', 'BF_TAG_NO', 'TAG_TYPE_ID', 'PIC_NO']; - - // 제외할 key들을 가진 컬럼들을 필터링해서 제거 columns = columns.filter(col => !excludeKeys.includes(col.key)); columns.forEach((col) => { - // 이미 displayLabel이 있으면 그대로 두고, - // 없으면 uom이 있으면 "label (uom)" 형태, - // 둘 다 없으면 label만 쓴다. if (!col.displayLabel) { if (col.uom) { col.displayLabel = `${col.label} (${col.uom})`; @@ -354,21 +394,21 @@ export async function getFormData(formCode: string, contractItemId: number) { if (Array.isArray(entry.data)) { data = entry.data; } else { - console.warn( - "formEntries data was not an array. Using empty array (fallback)." - ); + console.warn("formEntries data was not an array. Using empty array (fallback)."); } } - return { columns, data, projectId }; // projectId도 반환 (필요시) + // Fallback에서도 편집 가능 필드 정보 계산 + const editableFieldsMap = await getEditableFieldsByTag(contractItemId, projectId); + + return { columns, data, projectId, editableFieldsMap }; } catch (dbError) { console.error(`[getFormData] Fallback DB query failed:`, dbError); - return { columns: null, data: [] }; + return { columns: null, data: [], editableFieldsMap: new Map() }; } } } - -/** +/**1 * contractId와 formCode(itemCode)를 사용하여 contractItemId를 찾는 서버 액션 * * @param contractId - 계약 ID |
