feat: [quality] 수주처 선택 UI + client_id 연동 + 수정 저장 개선
- 수주처를 텍스트 입력에서 거래처 검색 선택으로 변경 - 수주 선택 시 거래처+모델 필터 연동 (양방향) - ProductInspection/Api에 clientId 매핑 추가 - 수정 시 새 개소 locations 필터 (NaN ID 에러 해결) - SupplierSearchModal 콜백에 id 반환 추가
This commit is contained in:
@@ -48,6 +48,9 @@ const OrderSelectModal = dynamic(
|
||||
const ProductInspectionInputModal = dynamic(
|
||||
() => import('./ProductInspectionInputModal').then(mod => ({ default: mod.ProductInspectionInputModal })),
|
||||
);
|
||||
const SupplierSearchModal = dynamic(
|
||||
() => import('@/components/material/ReceivingManagement/SupplierSearchModal').then(mod => ({ default: mod.SupplierSearchModal })),
|
||||
);
|
||||
import type { InspectionFormData, OrderSettingItem, OrderSelectItem, OrderGroup, ProductInspectionData } from './types';
|
||||
import {
|
||||
emptyConstructionSite,
|
||||
@@ -77,6 +80,7 @@ export function InspectionCreate() {
|
||||
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const [orderModalOpen, setOrderModalOpen] = useState(false);
|
||||
const [clientModalOpen, setClientModalOpen] = useState(false);
|
||||
|
||||
// 제품검사 입력 모달
|
||||
const [inspectionInputOpen, setInspectionInputOpen] = useState(false);
|
||||
@@ -123,10 +127,15 @@ export function InspectionCreate() {
|
||||
changeReason: '',
|
||||
}]
|
||||
);
|
||||
setFormData((prev) => ({
|
||||
...prev,
|
||||
orderItems: [...prev.orderItems, ...newOrderItems],
|
||||
}));
|
||||
setFormData((prev) => {
|
||||
const updated = { ...prev, orderItems: [...prev.orderItems, ...newOrderItems] };
|
||||
// 수주처 미선택 상태에서 수주 선택 시 → 수주처 자동 채움
|
||||
if (!prev.clientId && items.length > 0 && items[0].clientId) {
|
||||
updated.clientId = items[0].clientId ?? undefined;
|
||||
updated.client = items[0].clientName || '';
|
||||
}
|
||||
return updated;
|
||||
});
|
||||
}, []);
|
||||
|
||||
// ===== 수주 항목 삭제 =====
|
||||
@@ -238,9 +247,9 @@ export function InspectionCreate() {
|
||||
toast.error('현장명은 필수 입력 항목입니다.');
|
||||
return { success: false, error: '현장명을 입력해주세요.' };
|
||||
}
|
||||
if (!formData.client.trim()) {
|
||||
toast.error('수주처는 필수 입력 항목입니다.');
|
||||
return { success: false, error: '수주처를 입력해주세요.' };
|
||||
if (!formData.clientId) {
|
||||
toast.error('수주처는 필수 선택 항목입니다.');
|
||||
return { success: false, error: '수주처를 선택해주세요.' };
|
||||
}
|
||||
|
||||
setIsSubmitting(true);
|
||||
@@ -400,11 +409,29 @@ export function InspectionCreate() {
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label>수주처 <span className="text-red-500">*</span></Label>
|
||||
<Input
|
||||
value={formData.client}
|
||||
onChange={(e) => updateField('client', e.target.value)}
|
||||
placeholder="수주처 입력"
|
||||
/>
|
||||
<div className="flex gap-2">
|
||||
<Input
|
||||
value={formData.client}
|
||||
readOnly
|
||||
placeholder="거래처를 선택하세요"
|
||||
className="cursor-pointer bg-muted/30"
|
||||
onClick={() => setClientModalOpen(true)}
|
||||
/>
|
||||
{formData.clientId && (
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
className="h-9 w-9 shrink-0"
|
||||
onClick={() => {
|
||||
updateField('client', '');
|
||||
updateField('clientId', undefined);
|
||||
}}
|
||||
>
|
||||
<Trash2 className="w-4 h-4 text-muted-foreground" />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label>담당자</Label>
|
||||
@@ -691,16 +718,28 @@ export function InspectionCreate() {
|
||||
[formData.orderItems]
|
||||
);
|
||||
|
||||
// 이미 선택된 수주가 있으면 같은 거래처+모델만 필터
|
||||
// 수주 선택 필터: 기본정보 수주처 또는 이미 선택된 수주 기준
|
||||
const orderFilter = useMemo(() => {
|
||||
if (formData.orderItems.length === 0) return { clientId: undefined, itemId: undefined, label: undefined };
|
||||
const first = formData.orderItems[0];
|
||||
return {
|
||||
clientId: first.clientId ?? undefined,
|
||||
itemId: first.itemId ?? undefined,
|
||||
label: [first.clientName, first.itemName].filter(Boolean).join(' / ') || undefined,
|
||||
};
|
||||
}, [formData.orderItems]);
|
||||
// 기본정보에서 수주처가 선택된 경우 → 해당 거래처 필터
|
||||
if (formData.clientId) {
|
||||
const firstItem = formData.orderItems[0];
|
||||
return {
|
||||
clientId: formData.clientId,
|
||||
itemId: firstItem?.itemId ?? undefined,
|
||||
label: [formData.client, firstItem?.itemName].filter(Boolean).join(' / ') || undefined,
|
||||
};
|
||||
}
|
||||
// 수주가 선택된 경우 → 첫 수주 기준 필터
|
||||
if (formData.orderItems.length > 0) {
|
||||
const first = formData.orderItems[0];
|
||||
return {
|
||||
clientId: first.clientId ?? undefined,
|
||||
itemId: first.itemId ?? undefined,
|
||||
label: [first.clientName, first.itemName].filter(Boolean).join(' / ') || undefined,
|
||||
};
|
||||
}
|
||||
return { clientId: undefined, itemId: undefined, label: undefined };
|
||||
}, [formData.clientId, formData.client, formData.orderItems]);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -725,6 +764,17 @@ export function InspectionCreate() {
|
||||
filterLabel={orderFilter.label}
|
||||
/>
|
||||
|
||||
{/* 거래처(수주처) 검색 모달 */}
|
||||
<SupplierSearchModal
|
||||
open={clientModalOpen}
|
||||
onOpenChange={setClientModalOpen}
|
||||
onSelectSupplier={(supplier) => {
|
||||
updateField('clientId', Number(supplier.id));
|
||||
updateField('client', supplier.name);
|
||||
setClientModalOpen(false);
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* 제품검사 입력 모달 */}
|
||||
<ProductInspectionInputModal
|
||||
open={inspectionInputOpen}
|
||||
|
||||
Reference in New Issue
Block a user