From 2472e7d36f66f94d29fb2d70551168d684265bb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EC=98=81=EB=B3=B4?= Date: Fri, 20 Mar 2026 15:50:30 +0900 Subject: [PATCH 1/5] =?UTF-8?q?fix:=20[=EC=A0=9C=ED=92=88=EA=B2=80?= =?UTF-8?q?=EC=82=AC]=20=EA=B2=80=EC=82=AC=20=EC=99=84=EB=A3=8C=20?= =?UTF-8?q?=ED=98=B8=EC=B6=9C=20=EA=B2=BD=EB=A1=9C=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?+=20=EC=99=84=EB=A3=8C=20=ED=9B=84=20=EB=AA=A9=EB=A1=9D=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - completeInspection 호출 URL을 /api/v1/inspections → /api/v1/quality/documents로 수정 (잘못된 production 모듈 호출로 "검사결과는 필수항목입니다" 에러 발생하던 문제) - 검사 완료 성공 시 목록 페이지(/quality/inspections)로 이동하도록 수정 Co-Authored-By: Claude Opus 4.6 (1M context) --- .../quality/InspectionManagement/InspectionDetail.tsx | 4 ++-- src/components/quality/InspectionManagement/actions.ts | 9 +-------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/src/components/quality/InspectionManagement/InspectionDetail.tsx b/src/components/quality/InspectionManagement/InspectionDetail.tsx index 17aed631..3c2a98b5 100644 --- a/src/components/quality/InspectionManagement/InspectionDetail.tsx +++ b/src/components/quality/InspectionManagement/InspectionDetail.tsx @@ -286,7 +286,7 @@ export function InspectionDetail({ id }: InspectionDetailProps) { if (result.success) { toast.success('검사가 완료 처리되었습니다.'); setShowCompleteDialog(false); - loadInspection(); + router.push('/quality/inspections'); } else { toast.error(result.error || '검사 완료 처리에 실패했습니다.'); } @@ -296,7 +296,7 @@ export function InspectionDetail({ id }: InspectionDetailProps) { } finally { setIsCompleting(false); } - }, [id, loadInspection]); + }, [id, router]); // ===== 수정 제출 ===== const handleSubmit = useCallback(async (): Promise<{ success: boolean; error?: string }> => { diff --git a/src/components/quality/InspectionManagement/actions.ts b/src/components/quality/InspectionManagement/actions.ts index 992f4285..c11c8d43 100644 --- a/src/components/quality/InspectionManagement/actions.ts +++ b/src/components/quality/InspectionManagement/actions.ts @@ -675,22 +675,15 @@ export async function deleteInspection(id: string): Promise<{ export async function completeInspection( id: string, - data?: { result?: '합격' | '불합격' } ): Promise<{ success: boolean; data?: ProductInspection; error?: string; __authError?: boolean; }> { - const apiData: Record = {}; - if (data?.result) { - apiData.result = data.result === '합격' ? 'pass' : 'fail'; - } - const result = await executeServerAction({ - url: buildApiUrl(`/api/v1/inspections/${id}/complete`), + url: buildApiUrl(`/api/v1/quality/documents/${id}/complete`), method: 'PATCH', - body: apiData, errorMessage: '검사 완료 처리에 실패했습니다.', }); From 3607beee121062a4a6f26c4c47ae804a84343752 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EC=98=81=EB=B3=B4?= Date: Fri, 20 Mar 2026 16:15:50 +0900 Subject: [PATCH 2/5] =?UTF-8?q?fix:=20[=EC=A0=9C=ED=92=88=EA=B2=80?= =?UTF-8?q?=EC=82=AC]=20=EC=9A=B0=ED=8E=B8=EB=B2=88=ED=98=B8=20=EC=B0=BE?= =?UTF-8?q?=EA=B8=B0=20=EA=B8=B0=EB=8A=A5=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - InspectionCreate, InspectionDetail에 useDaumPostcode 훅 연결 - 우편번호 찾기 버튼 onClick → openPostcode 바인딩 - 주소 필드 readOnly 처리 (우편번호 검색으로만 입력) - useMemo deps에 openPostcode 추가 (stale closure 방지) Co-Authored-By: Claude Opus 4.6 (1M context) --- .../InspectionManagement/InspectionCreate.tsx | 20 +++++++++++++++++-- .../InspectionManagement/InspectionDetail.tsx | 20 +++++++++++++++++-- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/src/components/quality/InspectionManagement/InspectionCreate.tsx b/src/components/quality/InspectionManagement/InspectionCreate.tsx index 95427ad3..374602c2 100644 --- a/src/components/quality/InspectionManagement/InspectionCreate.tsx +++ b/src/components/quality/InspectionManagement/InspectionCreate.tsx @@ -13,6 +13,7 @@ import { useState, useCallback, useMemo } from 'react'; import dynamic from 'next/dynamic'; import { useRouter } from 'next/navigation'; +import { useDaumPostcode } from '@/hooks/useDaumPostcode'; import { Plus, Trash2, ClipboardCheck } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; @@ -61,6 +62,20 @@ import { export function InspectionCreate() { const router = useRouter(); + // Daum 우편번호 서비스 + const { openPostcode } = useDaumPostcode({ + onComplete: (result) => { + setFormData(prev => ({ + ...prev, + scheduleInfo: { + ...prev.scheduleInfo, + sitePostalCode: result.zonecode, + siteAddress: result.address, + }, + })); + }, + }); + // 폼 상태 const [formData, setFormData] = useState({ qualityDocNumber: '', @@ -663,7 +678,7 @@ export function InspectionCreate() { onChange={(e) => updateNested('scheduleInfo', 'sitePostalCode', e.target.value)} className="w-28" /> - @@ -674,6 +689,7 @@ export function InspectionCreate() { value={formData.scheduleInfo.siteAddress} onChange={(e) => updateNested('scheduleInfo', 'siteAddress', e.target.value)} placeholder="주소 입력" + readOnly />
@@ -710,7 +726,7 @@ export function InspectionCreate() {
- ), [formData, orderSummary, orderGroups, updateField, updateNested, handleRemoveOrderItem, handleOpenInspectionInput, handleUpdateOrderItemField, orderModalOpen]); + ), [formData, orderSummary, orderGroups, updateField, updateNested, handleRemoveOrderItem, handleOpenInspectionInput, handleUpdateOrderItemField, orderModalOpen, openPostcode]); // 이미 선택된 수주 ID 목록 (orderId 기준, 중복 제거) const excludeOrderIds = useMemo( diff --git a/src/components/quality/InspectionManagement/InspectionDetail.tsx b/src/components/quality/InspectionManagement/InspectionDetail.tsx index 3c2a98b5..9f8c1c0e 100644 --- a/src/components/quality/InspectionManagement/InspectionDetail.tsx +++ b/src/components/quality/InspectionManagement/InspectionDetail.tsx @@ -13,6 +13,7 @@ import { useState, useCallback, useEffect, useMemo } from 'react'; import dynamic from 'next/dynamic'; import { useRouter, useSearchParams } from 'next/navigation'; +import { useDaumPostcode } from '@/hooks/useDaumPostcode'; import { FileText, PlayCircle, @@ -124,6 +125,20 @@ export function InspectionDetail({ id }: InspectionDetailProps) { const searchParams = useSearchParams(); const isEditModeParam = searchParams.get('mode') === 'edit'; + // Daum 우편번호 서비스 + const { openPostcode } = useDaumPostcode({ + onComplete: (result) => { + setFormData(prev => ({ + ...prev, + scheduleInfo: { + ...prev.scheduleInfo, + sitePostalCode: result.zonecode, + siteAddress: result.address, + }, + })); + }, + }); + // 상세 데이터 const [inspection, setInspection] = useState(null); const [isLoading, setIsLoading] = useState(true); @@ -1259,7 +1274,7 @@ export function InspectionDetail({ id }: InspectionDetailProps) { onChange={(e) => updateNested('scheduleInfo', 'sitePostalCode', e.target.value)} className="w-28" /> - @@ -1269,6 +1284,7 @@ export function InspectionDetail({ id }: InspectionDetailProps) { updateNested('scheduleInfo', 'siteAddress', e.target.value)} + readOnly />
@@ -1305,7 +1321,7 @@ export function InspectionDetail({ id }: InspectionDetailProps) {
); - }, [inspection, formData, orderSummary, orderGroups, updateField, updateNested, handleRemoveOrderItem, handleOpenInspectionInput, handleUpdateOrderItemField, orderModalOpen, renderFqcBadge, renderFqcProgressBar]); + }, [inspection, formData, orderSummary, orderGroups, updateField, updateNested, handleRemoveOrderItem, handleOpenInspectionInput, handleUpdateOrderItemField, orderModalOpen, renderFqcBadge, renderFqcProgressBar, openPostcode]); // ===== 모드 & Config ===== const mode = isEditMode ? 'edit' : 'view'; From f197538e2e976e61fd3838fe6cab61bd7b089c52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EC=98=81=EB=B3=B4?= Date: Fri, 20 Mar 2026 16:27:15 +0900 Subject: [PATCH 3/5] =?UTF-8?q?fix:=20[=EA=B3=B5=ED=86=B5]=20=ED=95=98?= =?UTF-8?q?=EB=8B=A8=20=EA=B3=A0=EC=A0=95=20=EC=95=A1=EC=85=98=EB=B0=94=20?= =?UTF-8?q?=EC=8B=9C=EA=B0=81=EC=A0=81=20=EA=B5=AC=EB=B6=84=20=EA=B0=95?= =?UTF-8?q?=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 배경 불투명 처리 (bg-background/95 → bg-background) - 상단 보더 강화 (border-t-2 border-t-primary/20) - 입력 필드와 액션바가 구분되지 않던 문제 해결 Co-Authored-By: Claude Opus 4.6 (1M context) --- .../IntegratedDetailTemplate/components/DetailActions.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/templates/IntegratedDetailTemplate/components/DetailActions.tsx b/src/components/templates/IntegratedDetailTemplate/components/DetailActions.tsx index c92d4962..e30db252 100644 --- a/src/components/templates/IntegratedDetailTemplate/components/DetailActions.tsx +++ b/src/components/templates/IntegratedDetailTemplate/components/DetailActions.tsx @@ -110,7 +110,7 @@ export function DetailActions({ // 모바일: 좌우 여백 16px (left-4 right-4) // 태블릿/데스크탑: 사이드바 펼침(w-64=256px), 접힘(w-24=96px) + 콘텐츠 패딩(24px) 맞춤 const stickyStyles = sticky - ? `fixed bottom-4 left-4 right-4 px-4 py-3 bg-background/95 backdrop-blur rounded-xl border shadow-lg z-50 transition-all duration-300 md:bottom-6 md:px-6 md:right-[24px] ${sidebarCollapsed ? 'md:left-[120px]' : 'md:left-[280px]'}` + ? `fixed bottom-4 left-4 right-4 px-4 py-3 bg-background border-t-4 border-t-primary/20 border rounded-xl shadow-lg z-50 transition-all duration-300 md:bottom-6 md:px-6 md:right-[24px] ${sidebarCollapsed ? 'md:left-[120px]' : 'md:left-[280px]'}` : ''; // 공통 레이아웃: 왼쪽(뒤로) | 오른쪽(액션들) From 478c05b875b3b115d79eac5741a2aaa405e095fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EC=98=81=EB=B3=B4?= Date: Fri, 20 Mar 2026 16:38:31 +0900 Subject: [PATCH 4/5] =?UTF-8?q?Revert=20"fix:=20[=EA=B3=B5=ED=86=B5]=20?= =?UTF-8?q?=ED=95=98=EB=8B=A8=20=EA=B3=A0=EC=A0=95=20=EC=95=A1=EC=85=98?= =?UTF-8?q?=EB=B0=94=20=EC=8B=9C=EA=B0=81=EC=A0=81=20=EA=B5=AC=EB=B6=84=20?= =?UTF-8?q?=EA=B0=95=ED=99=94"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 954cddfd1e94ec13dfb64e5fbcd0cfd27f619635. --- .../IntegratedDetailTemplate/components/DetailActions.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/templates/IntegratedDetailTemplate/components/DetailActions.tsx b/src/components/templates/IntegratedDetailTemplate/components/DetailActions.tsx index e30db252..c92d4962 100644 --- a/src/components/templates/IntegratedDetailTemplate/components/DetailActions.tsx +++ b/src/components/templates/IntegratedDetailTemplate/components/DetailActions.tsx @@ -110,7 +110,7 @@ export function DetailActions({ // 모바일: 좌우 여백 16px (left-4 right-4) // 태블릿/데스크탑: 사이드바 펼침(w-64=256px), 접힘(w-24=96px) + 콘텐츠 패딩(24px) 맞춤 const stickyStyles = sticky - ? `fixed bottom-4 left-4 right-4 px-4 py-3 bg-background border-t-4 border-t-primary/20 border rounded-xl shadow-lg z-50 transition-all duration-300 md:bottom-6 md:px-6 md:right-[24px] ${sidebarCollapsed ? 'md:left-[120px]' : 'md:left-[280px]'}` + ? `fixed bottom-4 left-4 right-4 px-4 py-3 bg-background/95 backdrop-blur rounded-xl border shadow-lg z-50 transition-all duration-300 md:bottom-6 md:px-6 md:right-[24px] ${sidebarCollapsed ? 'md:left-[120px]' : 'md:left-[280px]'}` : ''; // 공통 레이아웃: 왼쪽(뒤로) | 오른쪽(액션들) From d84a76411ebe9c7ebd6ca7d3d93ea99c7cdfe1fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B0=95=EC=98=81=EB=B3=B4?= Date: Mon, 23 Mar 2026 09:55:27 +0900 Subject: [PATCH 5/5] =?UTF-8?q?fix:=20[=EA=B2=AC=EC=A0=81]=20=ED=92=88?= =?UTF-8?q?=EB=AA=A9=EA=B2=80=EC=83=89=20bomCategory=20=ED=95=84=ED=84=B0?= =?UTF-8?q?=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ItemSearchSheet에서 bomCategory prop 제거하여 탭 구분 없이 전체 품목 검색 가능하도록 수정 Co-Authored-By: Claude Opus 4.6 (1M context) --- src/components/quotes/LocationDetailPanel.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/quotes/LocationDetailPanel.tsx b/src/components/quotes/LocationDetailPanel.tsx index 4744931e..7ec0f74d 100644 --- a/src/components/quotes/LocationDetailPanel.tsx +++ b/src/components/quotes/LocationDetailPanel.tsx @@ -769,7 +769,6 @@ export function LocationDetailPanel({ open={itemSearchOpen} onOpenChange={setItemSearchOpen} tabLabel={detailTabs.find((t) => t.value === activeTab)?.label} - bomCategory={activeTab !== "etc" ? activeTab : undefined} onSelectItem={async (item) => { if (!location) return;