From 0a6c5fbfcc253fac125f875725fb61dfbde0918f Mon Sep 17 00:00:00 2001 From: SeongHyun Kim Date: Tue, 25 Nov 2025 17:32:52 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20=EC=88=98=EC=A3=BC=EA=B4=80=EB=A6=AC=20?= =?UTF-8?q?=EB=82=A9=EA=B8=B0=EC=9D=BC=20DATE=20=ED=98=95=EC=8B=9D=20?= =?UTF-8?q?=EC=A0=80=EC=9E=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 프론트엔드: EditModal에 날짜 정규화 함수 추가 (YYYY-MM-DD 형식) - 백엔드: convertValueForPostgreSQL에서 DATE 타입 문자열 그대로 유지 - 기존 TIMESTAMP 형식 변환을 DATE 타입 문자열 유지로 변경 - 날짜 변환 로직에서 YYYY-MM-DD 형식 문자열 변환 제거 closes #납기일-TIMESTAMP-형식-저장-이슈 --- .../src/services/dynamicFormService.ts | 22 +++-- frontend/components/screen/EditModal.tsx | 87 +++++++++++++++---- 2 files changed, 86 insertions(+), 23 deletions(-) diff --git a/backend-node/src/services/dynamicFormService.ts b/backend-node/src/services/dynamicFormService.ts index e9485620..1ed28140 100644 --- a/backend-node/src/services/dynamicFormService.ts +++ b/backend-node/src/services/dynamicFormService.ts @@ -99,10 +99,18 @@ export class DynamicFormService { } try { - // YYYY-MM-DD 형식인 경우 시간 추가해서 Date 객체 생성 + // YYYY-MM-DD 형식인 경우 if (/^\d{4}-\d{2}-\d{2}$/.test(value)) { - console.log(`📅 날짜 타입 변환: ${value} -> Date 객체`); - return new Date(value + "T00:00:00"); + // DATE 타입이면 문자열 그대로 유지 + if (lowerDataType === "date") { + console.log(`📅 날짜 문자열 유지: ${value} -> "${value}" (DATE 타입)`); + return value; // 문자열 그대로 반환 + } + // TIMESTAMP 타입이면 Date 객체로 변환 + else { + console.log(`📅 날짜시간 변환: ${value} -> Date 객체 (TIMESTAMP 타입)`); + return new Date(value + "T00:00:00"); + } } // 다른 날짜 형식도 Date 객체로 변환 else { @@ -300,13 +308,13 @@ export class DynamicFormService { ) { // YYYY-MM-DD HH:mm:ss 형태의 문자열을 Date 객체로 변환 if (value.match(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/)) { - console.log(`📅 날짜 변환: ${key} = "${value}" -> Date 객체`); + console.log(`📅 날짜시간 변환: ${key} = "${value}" -> Date 객체`); dataToInsert[key] = new Date(value); } - // YYYY-MM-DD 형태의 문자열을 Date 객체로 변환 + // YYYY-MM-DD 형태의 문자열은 그대로 유지 (DATE 타입으로 저장) else if (value.match(/^\d{4}-\d{2}-\d{2}$/)) { - console.log(`📅 날짜 변환: ${key} = "${value}" -> Date 객체`); - dataToInsert[key] = new Date(value + "T00:00:00"); + console.log(`📅 날짜 유지: ${key} = "${value}" -> 문자열 그대로 (DATE 타입)`); + // dataToInsert[key] = value; // 문자열 그대로 유지 (이미 올바른 형식) } } }); diff --git a/frontend/components/screen/EditModal.tsx b/frontend/components/screen/EditModal.tsx index f9b803b2..e44eef4e 100644 --- a/frontend/components/screen/EditModal.tsx +++ b/frontend/components/screen/EditModal.tsx @@ -316,6 +316,33 @@ export const EditModal: React.FC = ({ className }) => { screenId: modalState.screenId, }); + // 🆕 날짜 필드 정규화 함수 (YYYY-MM-DD 형식으로 변환) + const normalizeDateField = (value: any): string | null => { + if (!value) return null; + + // ISO 8601 형식 (2025-11-26T00:00:00.000Z) 또는 Date 객체 + if (value instanceof Date || typeof value === "string") { + try { + const date = new Date(value); + if (isNaN(date.getTime())) return null; + + // YYYY-MM-DD 형식으로 변환 + const year = date.getFullYear(); + const month = String(date.getMonth() + 1).padStart(2, "0"); + const day = String(date.getDate()).padStart(2, "0"); + return `${year}-${month}-${day}`; + } catch (error) { + console.warn("날짜 변환 실패:", value, error); + return null; + } + } + + return null; + }; + + // 날짜 필드 목록 + const dateFields = ["item_due_date", "delivery_date", "due_date", "order_date"]; + let insertedCount = 0; let updatedCount = 0; let deletedCount = 0; @@ -333,6 +360,17 @@ export const EditModal: React.FC = ({ className }) => { delete insertData.id; // id는 자동 생성되므로 제거 + // 🆕 날짜 필드 정규화 (YYYY-MM-DD 형식으로 변환) + dateFields.forEach((fieldName) => { + if (insertData[fieldName]) { + const normalizedDate = normalizeDateField(insertData[fieldName]); + if (normalizedDate) { + insertData[fieldName] = normalizedDate; + console.log(`📅 [날짜 정규화] ${fieldName}: ${currentData[fieldName]} → ${normalizedDate}`); + } + } + }); + // 🆕 groupByColumns의 값을 강제로 포함 (order_no 등) if (modalState.groupByColumns && modalState.groupByColumns.length > 0) { modalState.groupByColumns.forEach((colName) => { @@ -348,23 +386,32 @@ export const EditModal: React.FC = ({ className }) => { // 🆕 공통 필드 추가 (거래처, 담당자, 납품처, 메모 등) // formData에서 품목별 필드가 아닌 공통 필드를 복사 const commonFields = [ - 'partner_id', // 거래처 - 'manager_id', // 담당자 - 'delivery_partner_id', // 납품처 - 'delivery_address', // 납품장소 - 'memo', // 메모 - 'order_date', // 주문일 - 'due_date', // 납기일 - 'shipping_method', // 배송방법 - 'status', // 상태 - 'sales_type', // 영업유형 + "partner_id", // 거래처 + "manager_id", // 담당자 + "delivery_partner_id", // 납품처 + "delivery_address", // 납품장소 + "memo", // 메모 + "order_date", // 주문일 + "due_date", // 납기일 + "shipping_method", // 배송방법 + "status", // 상태 + "sales_type", // 영업유형 ]; commonFields.forEach((fieldName) => { // formData에 값이 있으면 추가 if (formData[fieldName] !== undefined && formData[fieldName] !== null) { - insertData[fieldName] = formData[fieldName]; - console.log(`🔗 [공통 필드] ${fieldName} 값 추가:`, formData[fieldName]); + // 날짜 필드인 경우 정규화 + if (dateFields.includes(fieldName)) { + const normalizedDate = normalizeDateField(formData[fieldName]); + if (normalizedDate) { + insertData[fieldName] = normalizedDate; + console.log(`🔗 [공통 필드 - 날짜] ${fieldName} 값 추가:`, normalizedDate); + } + } else { + insertData[fieldName] = formData[fieldName]; + console.log(`🔗 [공통 필드] ${fieldName} 값 추가:`, formData[fieldName]); + } } }); @@ -404,8 +451,15 @@ export const EditModal: React.FC = ({ className }) => { } // 🆕 값 정규화 함수 (타입 통일) - const normalizeValue = (val: any): any => { + const normalizeValue = (val: any, fieldName?: string): any => { if (val === null || val === undefined || val === "") return null; + + // 날짜 필드인 경우 YYYY-MM-DD 형식으로 정규화 + if (fieldName && dateFields.includes(fieldName)) { + const normalizedDate = normalizeDateField(val); + return normalizedDate; + } + if (typeof val === "string" && !isNaN(Number(val))) { // 숫자로 변환 가능한 문자열은 숫자로 return Number(val); @@ -422,13 +476,14 @@ export const EditModal: React.FC = ({ className }) => { } // 🆕 타입 정규화 후 비교 - const currentValue = normalizeValue(currentData[key]); - const originalValue = normalizeValue(originalItemData[key]); + const currentValue = normalizeValue(currentData[key], key); + const originalValue = normalizeValue(originalItemData[key], key); // 값이 변경된 경우만 포함 if (currentValue !== originalValue) { console.log(`🔍 [품목 수정 감지] ${key}: ${originalValue} → ${currentValue}`); - changedData[key] = currentData[key]; // 원본 값 사용 (문자열 그대로) + // 날짜 필드는 정규화된 값 사용, 나머지는 원본 값 사용 + changedData[key] = dateFields.includes(key) ? currentValue : currentData[key]; } });