Merge branch 'ksh'
This commit is contained in:
@@ -64,6 +64,9 @@ export function OrderRegistrationModal({
|
||||
// 선택된 품목 목록
|
||||
const [selectedItems, setSelectedItems] = useState<any[]>([]);
|
||||
|
||||
// 납기일 일괄 적용 플래그 (딱 한 번만 실행)
|
||||
const [isDeliveryDateApplied, setIsDeliveryDateApplied] = useState(false);
|
||||
|
||||
// 저장 중
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
|
||||
@@ -158,6 +161,45 @@ export function OrderRegistrationModal({
|
||||
hsCode: "",
|
||||
});
|
||||
setSelectedItems([]);
|
||||
setIsDeliveryDateApplied(false); // 플래그 초기화
|
||||
};
|
||||
|
||||
// 품목 목록 변경 핸들러 (납기일 일괄 적용 로직 포함)
|
||||
const handleItemsChange = (newItems: any[]) => {
|
||||
// 1️⃣ 플래그가 이미 true면 그냥 업데이트만 (일괄 적용 완료 상태)
|
||||
if (isDeliveryDateApplied) {
|
||||
setSelectedItems(newItems);
|
||||
return;
|
||||
}
|
||||
|
||||
// 2️⃣ 품목이 없으면 그냥 업데이트
|
||||
if (newItems.length === 0) {
|
||||
setSelectedItems(newItems);
|
||||
return;
|
||||
}
|
||||
|
||||
// 3️⃣ 현재 상태: 납기일이 있는 행과 없는 행 개수 체크
|
||||
const itemsWithDate = newItems.filter((item) => item.delivery_date);
|
||||
const itemsWithoutDate = newItems.filter((item) => !item.delivery_date);
|
||||
|
||||
// 4️⃣ 조건: 정확히 1개만 날짜가 있고, 나머지는 모두 비어있을 때 일괄 적용
|
||||
if (itemsWithDate.length === 1 && itemsWithoutDate.length > 0) {
|
||||
// 5️⃣ 전체 일괄 적용
|
||||
const selectedDate = itemsWithDate[0].delivery_date;
|
||||
const updatedItems = newItems.map((item) => ({
|
||||
...item,
|
||||
delivery_date: selectedDate, // 모든 행에 동일한 납기일 적용
|
||||
}));
|
||||
|
||||
setSelectedItems(updatedItems);
|
||||
setIsDeliveryDateApplied(true); // 플래그 활성화 (다음부터는 일괄 적용 안 함)
|
||||
|
||||
console.log("✅ 납기일 일괄 적용 완료:", selectedDate);
|
||||
console.log(` - 대상: ${itemsWithoutDate.length}개 행에 ${selectedDate} 적용`);
|
||||
} else {
|
||||
// 그냥 업데이트
|
||||
setSelectedItems(newItems);
|
||||
}
|
||||
};
|
||||
|
||||
// 전체 금액 계산
|
||||
@@ -338,7 +380,7 @@ export function OrderRegistrationModal({
|
||||
<Label className="text-xs sm:text-sm">추가된 품목</Label>
|
||||
<OrderItemRepeaterTable
|
||||
value={selectedItems}
|
||||
onChange={setSelectedItems}
|
||||
onChange={handleItemsChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -316,6 +316,33 @@ export const EditModal: React.FC<EditModalProps> = ({ 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<EditModalProps> = ({ 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<EditModalProps> = ({ 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<EditModalProps> = ({ 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<EditModalProps> = ({ 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];
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -122,10 +122,6 @@ const ResizableDialogContent = React.forwardRef<
|
||||
|
||||
// 1순위: userStyle에서 크기 추출 (화면관리에서 지정한 크기 - 항상 초기값으로 사용)
|
||||
if (userStyle) {
|
||||
console.log("🔍 userStyle 감지:", userStyle);
|
||||
console.log("🔍 userStyle.width 타입:", typeof userStyle.width, "값:", userStyle.width);
|
||||
console.log("🔍 userStyle.height 타입:", typeof userStyle.height, "값:", userStyle.height);
|
||||
|
||||
const styleWidth = typeof userStyle.width === 'string'
|
||||
? parseInt(userStyle.width)
|
||||
: userStyle.width;
|
||||
@@ -133,31 +129,15 @@ const ResizableDialogContent = React.forwardRef<
|
||||
? parseInt(userStyle.height)
|
||||
: userStyle.height;
|
||||
|
||||
console.log("📏 파싱된 크기:", {
|
||||
styleWidth,
|
||||
styleHeight,
|
||||
"styleWidth truthy?": !!styleWidth,
|
||||
"styleHeight truthy?": !!styleHeight,
|
||||
minWidth,
|
||||
maxWidth,
|
||||
minHeight,
|
||||
maxHeight
|
||||
});
|
||||
|
||||
if (styleWidth && styleHeight) {
|
||||
const finalSize = {
|
||||
width: Math.max(minWidth, Math.min(maxWidth, styleWidth)),
|
||||
height: Math.max(minHeight, Math.min(maxHeight, styleHeight)),
|
||||
};
|
||||
console.log("✅ userStyle 크기 사용:", finalSize);
|
||||
return finalSize;
|
||||
} else {
|
||||
console.log("❌ styleWidth 또는 styleHeight가 falsy:", { styleWidth, styleHeight });
|
||||
}
|
||||
}
|
||||
|
||||
console.log("⚠️ userStyle 없음, defaultWidth/defaultHeight 사용:", { defaultWidth, defaultHeight });
|
||||
|
||||
// 2순위: 현재 렌더링된 크기 사용 (주석처리 - 모달이 열린 후 늘어나는 현상 방지)
|
||||
// if (contentRef.current) {
|
||||
// const rect = contentRef.current.getBoundingClientRect();
|
||||
@@ -209,7 +189,6 @@ const ResizableDialogContent = React.forwardRef<
|
||||
// 사용자가 리사이징한 크기 우선
|
||||
setSize({ width: savedSize.width, height: savedSize.height });
|
||||
setUserResized(true);
|
||||
console.log("✅ 사용자 리사이징 크기 적용:", savedSize);
|
||||
} else if (userStyle && userStyle.width && userStyle.height) {
|
||||
// 화면관리에서 설정한 크기
|
||||
const styleWidth = typeof userStyle.width === 'string'
|
||||
@@ -224,7 +203,6 @@ const ResizableDialogContent = React.forwardRef<
|
||||
width: Math.max(minWidth, Math.min(maxWidth, styleWidth)),
|
||||
height: Math.max(minHeight, Math.min(maxHeight, styleHeight)),
|
||||
};
|
||||
console.log("🔄 userStyle 크기 적용:", newSize);
|
||||
setSize(newSize);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user