From c05596247bf396260375f3e193300650b731ee61 Mon Sep 17 00:00:00 2001 From: dujinkim Date: Fri, 5 Sep 2025 01:26:30 +0000 Subject: (대표님) EDP 데이터 입력 진행률 계산 서비스 구현 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/forms/services.ts | 202 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 198 insertions(+), 4 deletions(-) (limited to 'lib/forms') diff --git a/lib/forms/services.ts b/lib/forms/services.ts index 2f7caec3..bf4fc3a0 100644 --- a/lib/forms/services.ts +++ b/lib/forms/services.ts @@ -163,7 +163,7 @@ export interface EditableFieldsInfo { } // TAG별 편집 가능 필드 조회 함수 -async function getEditableFieldsByTag( +export async function getEditableFieldsByTag( contractItemId: number, projectId: number ): Promise> { @@ -664,11 +664,21 @@ export async function syncMissingTags( * data: [{ TAG_NO, ...}, ...] 배열에서 TAG_NO 매칭되는 항목을 업데이트 * 업데이트 후, revalidateTag()로 캐시 무효화. */ -type UpdateResponse = { +export interface UpdateResponse { success: boolean; message: string; - data?: any; -}; + data?: { + updatedCount?: number; + failedCount?: number; + updatedTags?: string[]; + notFoundTags?: string[]; + updateTimestamp?: string; + error?: any; + invalidRows?: any[]; + TAG_NO?: string; + updatedFields?: string[]; + }; +} export async function updateFormDataInDB( formCode: string, @@ -801,6 +811,190 @@ export async function updateFormDataInDB( }; } } + +export async function updateFormDataBatchInDB( + formCode: string, + contractItemId: number, + newDataArray: Record[] +): Promise { + try { + // 입력 유효성 검사 + if (!newDataArray || newDataArray.length === 0) { + return { + success: false, + message: "업데이트할 데이터가 없습니다.", + }; + } + + // TAG_NO 유효성 검사 + const invalidRows = newDataArray.filter(row => !row.TAG_NO); + if (invalidRows.length > 0) { + return { + success: false, + message: `${invalidRows.length}개 행에 TAG_NO가 없습니다.`, + data: { invalidRows } + }; + } + + // 1) DB에서 현재 데이터 가져오기 + const entries = await db + .select() + .from(formEntries) + .where( + and( + eq(formEntries.formCode, formCode), + eq(formEntries.contractItemId, contractItemId) + ) + ) + .limit(1); + + if (!entries || entries.length === 0) { + return { + success: false, + message: `폼 데이터를 찾을 수 없습니다. (formCode=${formCode}, contractItemId=${contractItemId})`, + }; + } + + const entry = entries[0]; + + // 데이터 형식 검증 + if (!entry.data) { + return { + success: false, + message: "폼 데이터가 없습니다.", + }; + } + + const dataArray = entry.data as Array>; + if (!Array.isArray(dataArray)) { + return { + success: false, + message: "폼 데이터가 올바른 형식이 아닙니다. 배열 형식이어야 합니다.", + }; + } + + // 2) 모든 변경사항을 한번에 적용 + const updatedArray = [...dataArray]; + const updatedTags: string[] = []; + const notFoundTags: string[] = []; + const updateTimestamp = new Date().toISOString(); + + // 각 import row에 대해 업데이트 수행 + for (const newData of newDataArray) { + const TAG_NO = newData.TAG_NO; + const idx = updatedArray.findIndex(item => item.TAG_NO === TAG_NO); + + if (idx >= 0) { + // 기존 데이터와 병합 + const oldItem = updatedArray[idx]; + updatedArray[idx] = { + ...oldItem, + ...newData, + TAG_NO: oldItem.TAG_NO, // TAG_NO는 변경 불가 + TAG_DESC: oldItem.TAG_DESC, // TAG_DESC도 보존 + status: "Updated", // Excel import 표시 + lastUpdated: updateTimestamp // 업데이트 시각 추가 + }; + updatedTags.push(TAG_NO); + } else { + // TAG를 찾을 수 없는 경우 + notFoundTags.push(TAG_NO); + } + } + + // 하나도 업데이트할 항목이 없는 경우 + if (updatedTags.length === 0) { + return { + success: false, + message: `업데이트할 수 있는 TAG를 찾을 수 없습니다. 모든 ${notFoundTags.length}개 TAG가 데이터베이스에 없습니다.`, + data: { + updatedCount: 0, + failedCount: notFoundTags.length, + notFoundTags + } + }; + } + + // 3) DB에 한 번만 저장 + try { + await db + .update(formEntries) + .set({ + data: updatedArray, + updatedAt: new Date(), + }) + .where(eq(formEntries.id, entry.id)); + + } catch (dbError) { + console.error("Database update error:", dbError); + + if (dbError instanceof DrizzleError) { + return { + success: false, + message: `데이터베이스 업데이트 오류: ${dbError.message}`, + data: { + updatedCount: 0, + failedCount: newDataArray.length, + error: dbError + } + }; + } + + return { + success: false, + message: "데이터베이스 업데이트 중 오류가 발생했습니다.", + data: { + updatedCount: 0, + failedCount: newDataArray.length + } + }; + } + + // 4) 캐시 무효화 + try { + const cacheTag = `form-data-${formCode}-${contractItemId}`; + console.log(`Cache invalidated: ${cacheTag}`); + revalidateTag(cacheTag); + } catch (cacheError) { + // 캐시 무효화 실패는 경고만 + console.warn("Cache revalidation warning:", cacheError); + } + + // 5) 성공 응답 + const message = notFoundTags.length > 0 + ? `${updatedTags.length}개 항목이 업데이트되었습니다. (${notFoundTags.length}개 TAG는 찾을 수 없음)` + : `${updatedTags.length}개 항목이 성공적으로 업데이트되었습니다.`; + + return { + success: true, + message: message, + data: { + updatedCount: updatedTags.length, + updatedTags, + notFoundTags: notFoundTags.length > 0 ? notFoundTags : undefined, + failedCount: notFoundTags.length, + updateTimestamp + }, + }; + + } catch (error) { + // 예상치 못한 오류 처리 + console.error("Unexpected error in updateFormDataBatchInDB:", error); + + return { + success: false, + message: error instanceof Error + ? `예상치 못한 오류가 발생했습니다: ${error.message}` + : "알 수 없는 오류가 발생했습니다.", + data: { + updatedCount: 0, + failedCount: newDataArray.length, + error: error + } + }; + } +} + // FormColumn Type (동일) export interface FormColumn { key: string; -- cgit v1.2.3