fix: 수주등록 모달 및 품목 검색 UI 개선
- 품목 검색 모달에서 컬럼명 대신 라벨명 표시 * ItemSelectionModal에 columnLabels prop 추가 * ModalRepeaterTableComponent에서 columns 설정의 라벨 매핑 생성 * 테이블 헤더에 한글 라벨 표시 (품번, 품명, 규격, 재질 등) - 이미 추가된 품목은 검색 결과에서 완전 제외 * filteredResults로 중복 항목 필터링 * 회색 표시 대신 목록에서 아예 제거 * 사용자 친화적인 안내 메시지 추가 - 수주등록 버튼 크기 및 렌더링 수정 * 기본 크기를 200x40에서 120x40으로 변경 (다른 버튼과 통일) * h-full w-full 클래스 적용하여 컨테이너 크기에 맞게 렌더링 * style prop의 width/height 제거하여 Tailwind 클래스 우선순위 문제 해결 - 수주등록 모달에 판매 유형 및 무역 정보 추가 * 국내/해외 판매 선택 기능 * 해외 판매 시 무역 정보 섹션 표시 (인코텀즈, 결제조건, 통화 등) * 거래처 정보 확장 (담당자, 납품처, 납품장소) - 품목 반복 테이블 컬럼 조정 * 품목번호를 품번으로 변경 * 비고 컬럼 제거 * 규격, 재질 컬럼 추가 * 납품일을 납기일로 변경
This commit is contained in:
parent
64e6fd1920
commit
e6949bdd67
|
|
@ -27,7 +27,7 @@ interface OrderItemRepeaterTableProps {
|
|||
// 수주 등록 전용 컬럼 설정 (고정)
|
||||
const ORDER_COLUMNS: RepeaterColumnConfig[] = [
|
||||
{
|
||||
field: "id",
|
||||
field: "item_number",
|
||||
label: "품번",
|
||||
editable: false,
|
||||
width: "120px",
|
||||
|
|
@ -36,14 +36,20 @@ const ORDER_COLUMNS: RepeaterColumnConfig[] = [
|
|||
field: "item_name",
|
||||
label: "품명",
|
||||
editable: false,
|
||||
width: "200px",
|
||||
width: "180px",
|
||||
},
|
||||
{
|
||||
field: "item_number",
|
||||
label: "품목번호",
|
||||
field: "specification",
|
||||
label: "규격",
|
||||
editable: false,
|
||||
width: "150px",
|
||||
},
|
||||
{
|
||||
field: "material",
|
||||
label: "재질",
|
||||
editable: false,
|
||||
width: "120px",
|
||||
},
|
||||
{
|
||||
field: "quantity",
|
||||
label: "수량",
|
||||
|
|
@ -71,18 +77,11 @@ const ORDER_COLUMNS: RepeaterColumnConfig[] = [
|
|||
},
|
||||
{
|
||||
field: "delivery_date",
|
||||
label: "납품일",
|
||||
label: "납기일",
|
||||
type: "date",
|
||||
editable: true,
|
||||
width: "130px",
|
||||
},
|
||||
{
|
||||
field: "note",
|
||||
label: "비고",
|
||||
type: "text",
|
||||
editable: true,
|
||||
width: "200px",
|
||||
},
|
||||
];
|
||||
|
||||
// 수주 등록 전용 계산 공식 (고정)
|
||||
|
|
@ -104,19 +103,20 @@ export function OrderItemRepeaterTable({
|
|||
// 고정 설정 (수주 등록 전용)
|
||||
sourceTable="item_info"
|
||||
sourceColumns={[
|
||||
"id",
|
||||
"item_name",
|
||||
"item_number",
|
||||
"item_name",
|
||||
"specification",
|
||||
"material",
|
||||
"unit",
|
||||
"selling_price",
|
||||
]}
|
||||
sourceSearchFields={["item_name", "id", "item_number"]}
|
||||
sourceSearchFields={["item_name", "item_number", "specification"]}
|
||||
modalTitle="품목 검색 및 선택"
|
||||
modalButtonText="품목 검색"
|
||||
multiSelect={true}
|
||||
columns={ORDER_COLUMNS}
|
||||
calculationRules={ORDER_CALCULATION_RULES}
|
||||
uniqueField="id"
|
||||
uniqueField="item_number"
|
||||
|
||||
// 외부에서 제어 가능한 prop
|
||||
value={value}
|
||||
|
|
|
|||
|
|
@ -39,12 +39,28 @@ export function OrderRegistrationModal({
|
|||
// 입력 방식
|
||||
const [inputMode, setInputMode] = useState<string>("customer_first");
|
||||
|
||||
// 판매 유형 (국내/해외)
|
||||
const [salesType, setSalesType] = useState<string>("domestic");
|
||||
|
||||
// 단가 기준 (기준단가/거래처별단가)
|
||||
const [priceType, setPriceType] = useState<string>("standard");
|
||||
|
||||
// 폼 데이터
|
||||
const [formData, setFormData] = useState<any>({
|
||||
customerCode: "",
|
||||
customerName: "",
|
||||
contactPerson: "",
|
||||
deliveryDestination: "",
|
||||
deliveryAddress: "",
|
||||
deliveryDate: "",
|
||||
memo: "",
|
||||
// 무역 정보 (해외 판매 시)
|
||||
incoterms: "",
|
||||
paymentTerms: "",
|
||||
currency: "KRW",
|
||||
portOfLoading: "",
|
||||
portOfDischarge: "",
|
||||
hsCode: "",
|
||||
});
|
||||
|
||||
// 선택된 품목 목록
|
||||
|
|
@ -70,13 +86,32 @@ export function OrderRegistrationModal({
|
|||
setIsSaving(true);
|
||||
|
||||
// 수주 등록 API 호출
|
||||
const response = await apiClient.post("/orders", {
|
||||
const orderData: any = {
|
||||
inputMode,
|
||||
salesType,
|
||||
priceType,
|
||||
customerCode: formData.customerCode,
|
||||
contactPerson: formData.contactPerson,
|
||||
deliveryDestination: formData.deliveryDestination,
|
||||
deliveryAddress: formData.deliveryAddress,
|
||||
deliveryDate: formData.deliveryDate,
|
||||
items: selectedItems,
|
||||
memo: formData.memo,
|
||||
});
|
||||
};
|
||||
|
||||
// 해외 판매 시 무역 정보 추가
|
||||
if (salesType === "export") {
|
||||
orderData.tradeInfo = {
|
||||
incoterms: formData.incoterms,
|
||||
paymentTerms: formData.paymentTerms,
|
||||
currency: formData.currency,
|
||||
portOfLoading: formData.portOfLoading,
|
||||
portOfDischarge: formData.portOfDischarge,
|
||||
hsCode: formData.hsCode,
|
||||
};
|
||||
}
|
||||
|
||||
const response = await apiClient.post("/orders", orderData);
|
||||
|
||||
if (response.data.success) {
|
||||
toast.success("수주가 등록되었습니다");
|
||||
|
|
@ -107,11 +142,22 @@ export function OrderRegistrationModal({
|
|||
// 폼 초기화
|
||||
const resetForm = () => {
|
||||
setInputMode("customer_first");
|
||||
setSalesType("domestic");
|
||||
setPriceType("standard");
|
||||
setFormData({
|
||||
customerCode: "",
|
||||
customerName: "",
|
||||
contactPerson: "",
|
||||
deliveryDestination: "",
|
||||
deliveryAddress: "",
|
||||
deliveryDate: "",
|
||||
memo: "",
|
||||
incoterms: "",
|
||||
paymentTerms: "",
|
||||
currency: "KRW",
|
||||
portOfLoading: "",
|
||||
portOfDischarge: "",
|
||||
hsCode: "",
|
||||
});
|
||||
setSelectedItems([]);
|
||||
};
|
||||
|
|
@ -133,55 +179,129 @@ export function OrderRegistrationModal({
|
|||
</DialogHeader>
|
||||
|
||||
<div className="space-y-6">
|
||||
{/* 입력 방식 선택 */}
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="inputMode" className="text-xs sm:text-sm">
|
||||
입력 방식 *
|
||||
</Label>
|
||||
<Select value={inputMode} onValueChange={setInputMode}>
|
||||
<SelectTrigger className="h-8 text-xs sm:h-10 sm:text-sm">
|
||||
<SelectValue placeholder="입력 방식 선택" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="customer_first">거래처 우선</SelectItem>
|
||||
<SelectItem value="quotation">견대 방식</SelectItem>
|
||||
<SelectItem value="unit_price">단가 방식</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
{/* 상단 셀렉트 박스 3개 */}
|
||||
<div className="grid grid-cols-1 sm:grid-cols-3 gap-4">
|
||||
{/* 입력 방식 */}
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="inputMode" className="text-xs sm:text-sm flex items-center gap-1">
|
||||
<span className="text-amber-500">📝</span> 입력 방식
|
||||
</Label>
|
||||
<Select value={inputMode} onValueChange={setInputMode}>
|
||||
<SelectTrigger className="h-8 text-xs sm:h-10 sm:text-sm">
|
||||
<SelectValue placeholder="입력 방식 선택" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="customer_first">거래처 우선</SelectItem>
|
||||
<SelectItem value="quotation">견대 방식</SelectItem>
|
||||
<SelectItem value="unit_price">단가 방식</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
{/* 판매 유형 */}
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="salesType" className="text-xs sm:text-sm flex items-center gap-1">
|
||||
<span className="text-blue-500">🌏</span> 판매 유형
|
||||
</Label>
|
||||
<Select value={salesType} onValueChange={setSalesType}>
|
||||
<SelectTrigger className="h-8 text-xs sm:h-10 sm:text-sm">
|
||||
<SelectValue placeholder="판매 유형 선택" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="domestic">국내 판매</SelectItem>
|
||||
<SelectItem value="export">해외 판매</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
{/* 단가 기준 */}
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="priceType" className="text-xs sm:text-sm flex items-center gap-1">
|
||||
<span className="text-green-500">💰</span> 단가 방식
|
||||
</Label>
|
||||
<Select value={priceType} onValueChange={setPriceType}>
|
||||
<SelectTrigger className="h-8 text-xs sm:h-10 sm:text-sm">
|
||||
<SelectValue placeholder="단가 방식 선택" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="standard">기준 단가</SelectItem>
|
||||
<SelectItem value="customer">거래처별 단가</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 입력 방식에 따른 동적 폼 */}
|
||||
{/* 거래처 정보 (항상 표시) */}
|
||||
{inputMode === "customer_first" && (
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
{/* 거래처 검색 */}
|
||||
<div className="space-y-2">
|
||||
<Label className="text-xs sm:text-sm">거래처 *</Label>
|
||||
<OrderCustomerSearch
|
||||
value={formData.customerCode}
|
||||
onChange={(code, fullData) => {
|
||||
setFormData({
|
||||
...formData,
|
||||
customerCode: code || "",
|
||||
customerName: fullData?.customer_name || "",
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<div className="rounded-lg border border-gray-200 bg-gray-50/50 p-4 space-y-4">
|
||||
<div className="flex items-center gap-2 text-sm font-semibold text-gray-700">
|
||||
<span>🏢</span>
|
||||
<span>거래처 정보</span>
|
||||
</div>
|
||||
|
||||
{/* 납품일 */}
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="deliveryDate" className="text-xs sm:text-sm">
|
||||
납품일
|
||||
</Label>
|
||||
<Input
|
||||
id="deliveryDate"
|
||||
type="date"
|
||||
value={formData.deliveryDate}
|
||||
onChange={(e) =>
|
||||
setFormData({ ...formData, deliveryDate: e.target.value })
|
||||
}
|
||||
className="h-8 text-xs sm:h-10 sm:text-sm"
|
||||
/>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
|
||||
{/* 거래처 */}
|
||||
<div className="space-y-2">
|
||||
<Label className="text-xs sm:text-sm">거래처 *</Label>
|
||||
<OrderCustomerSearch
|
||||
value={formData.customerCode}
|
||||
onChange={(code, fullData) => {
|
||||
setFormData({
|
||||
...formData,
|
||||
customerCode: code || "",
|
||||
customerName: fullData?.customer_name || "",
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 담당자 */}
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="contactPerson" className="text-xs sm:text-sm">
|
||||
담당자
|
||||
</Label>
|
||||
<Input
|
||||
id="contactPerson"
|
||||
placeholder="담당자"
|
||||
value={formData.contactPerson}
|
||||
onChange={(e) =>
|
||||
setFormData({ ...formData, contactPerson: e.target.value })
|
||||
}
|
||||
className="h-8 text-xs sm:h-10 sm:text-sm"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 납품처 */}
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="deliveryDestination" className="text-xs sm:text-sm">
|
||||
납품처
|
||||
</Label>
|
||||
<Input
|
||||
id="deliveryDestination"
|
||||
placeholder="납품처"
|
||||
value={formData.deliveryDestination}
|
||||
onChange={(e) =>
|
||||
setFormData({ ...formData, deliveryDestination: e.target.value })
|
||||
}
|
||||
className="h-8 text-xs sm:h-10 sm:text-sm"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 납품장소 */}
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="deliveryAddress" className="text-xs sm:text-sm">
|
||||
납품장소
|
||||
</Label>
|
||||
<Input
|
||||
id="deliveryAddress"
|
||||
placeholder="납품장소"
|
||||
value={formData.deliveryAddress}
|
||||
onChange={(e) =>
|
||||
setFormData({ ...formData, deliveryAddress: e.target.value })
|
||||
}
|
||||
className="h-8 text-xs sm:h-10 sm:text-sm"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
|
@ -228,6 +348,140 @@ export function OrderRegistrationModal({
|
|||
</div>
|
||||
)}
|
||||
|
||||
{/* 무역 정보 (해외 판매 시에만 표시) */}
|
||||
{salesType === "export" && (
|
||||
<div className="rounded-lg border border-blue-200 bg-blue-50/50 p-4 space-y-4">
|
||||
<div className="flex items-center gap-2 text-sm font-semibold text-blue-700">
|
||||
<span>🌏</span>
|
||||
<span>무역 정보</span>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 sm:grid-cols-3 gap-4">
|
||||
{/* 인코텀즈 */}
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="incoterms" className="text-xs sm:text-sm">
|
||||
인코텀즈
|
||||
</Label>
|
||||
<Select
|
||||
value={formData.incoterms}
|
||||
onValueChange={(value) =>
|
||||
setFormData({ ...formData, incoterms: value })
|
||||
}
|
||||
>
|
||||
<SelectTrigger className="h-8 text-xs sm:h-10 sm:text-sm">
|
||||
<SelectValue placeholder="선택" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="EXW">EXW</SelectItem>
|
||||
<SelectItem value="FOB">FOB</SelectItem>
|
||||
<SelectItem value="CIF">CIF</SelectItem>
|
||||
<SelectItem value="DDP">DDP</SelectItem>
|
||||
<SelectItem value="DAP">DAP</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
{/* 결제 조건 */}
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="paymentTerms" className="text-xs sm:text-sm">
|
||||
결제 조건
|
||||
</Label>
|
||||
<Select
|
||||
value={formData.paymentTerms}
|
||||
onValueChange={(value) =>
|
||||
setFormData({ ...formData, paymentTerms: value })
|
||||
}
|
||||
>
|
||||
<SelectTrigger className="h-8 text-xs sm:h-10 sm:text-sm">
|
||||
<SelectValue placeholder="선택" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="advance">선결제</SelectItem>
|
||||
<SelectItem value="cod">착불</SelectItem>
|
||||
<SelectItem value="lc">신용장(L/C)</SelectItem>
|
||||
<SelectItem value="net30">NET 30</SelectItem>
|
||||
<SelectItem value="net60">NET 60</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
{/* 통화 */}
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="currency" className="text-xs sm:text-sm">
|
||||
통화
|
||||
</Label>
|
||||
<Select
|
||||
value={formData.currency}
|
||||
onValueChange={(value) =>
|
||||
setFormData({ ...formData, currency: value })
|
||||
}
|
||||
>
|
||||
<SelectTrigger className="h-8 text-xs sm:h-10 sm:text-sm">
|
||||
<SelectValue placeholder="통화 선택" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="KRW">KRW (원)</SelectItem>
|
||||
<SelectItem value="USD">USD (달러)</SelectItem>
|
||||
<SelectItem value="EUR">EUR (유로)</SelectItem>
|
||||
<SelectItem value="JPY">JPY (엔)</SelectItem>
|
||||
<SelectItem value="CNY">CNY (위안)</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 sm:grid-cols-3 gap-4">
|
||||
{/* 선적항 */}
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="portOfLoading" className="text-xs sm:text-sm">
|
||||
선적항
|
||||
</Label>
|
||||
<Input
|
||||
id="portOfLoading"
|
||||
placeholder="선적항"
|
||||
value={formData.portOfLoading}
|
||||
onChange={(e) =>
|
||||
setFormData({ ...formData, portOfLoading: e.target.value })
|
||||
}
|
||||
className="h-8 text-xs sm:h-10 sm:text-sm"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 도착항 */}
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="portOfDischarge" className="text-xs sm:text-sm">
|
||||
도착항
|
||||
</Label>
|
||||
<Input
|
||||
id="portOfDischarge"
|
||||
placeholder="도착항"
|
||||
value={formData.portOfDischarge}
|
||||
onChange={(e) =>
|
||||
setFormData({ ...formData, portOfDischarge: e.target.value })
|
||||
}
|
||||
className="h-8 text-xs sm:h-10 sm:text-sm"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* HS Code */}
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="hsCode" className="text-xs sm:text-sm">
|
||||
HS Code
|
||||
</Label>
|
||||
<Input
|
||||
id="hsCode"
|
||||
placeholder="HS Code"
|
||||
value={formData.hsCode}
|
||||
onChange={(e) =>
|
||||
setFormData({ ...formData, hsCode: e.target.value })
|
||||
}
|
||||
className="h-8 text-xs sm:h-10 sm:text-sm"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 메모 */}
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="memo" className="text-xs sm:text-sm">
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ export function ItemSelectionModal({
|
|||
alreadySelected = [],
|
||||
uniqueField,
|
||||
onSelect,
|
||||
columnLabels = {},
|
||||
}: ItemSelectionModalProps) {
|
||||
const [localSearchText, setLocalSearchText] = useState("");
|
||||
const [selectedItems, setSelectedItems] = useState<any[]>([]);
|
||||
|
|
@ -92,6 +93,9 @@ export function ItemSelectionModal({
|
|||
);
|
||||
};
|
||||
|
||||
// 이미 추가된 항목 제외한 결과 필터링
|
||||
const filteredResults = results.filter((item) => !isAlreadyAdded(item));
|
||||
|
||||
// 선택된 항목인지 확인
|
||||
const isSelected = (item: any): boolean => {
|
||||
return selectedItems.some((selected) =>
|
||||
|
|
@ -169,13 +173,13 @@ export function ItemSelectionModal({
|
|||
key={col}
|
||||
className="px-4 py-2 text-left font-medium text-muted-foreground"
|
||||
>
|
||||
{col}
|
||||
{columnLabels[col] || col}
|
||||
</th>
|
||||
))}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{loading && results.length === 0 ? (
|
||||
{loading && filteredResults.length === 0 ? (
|
||||
<tr>
|
||||
<td
|
||||
colSpan={sourceColumns.length + (multiSelect ? 1 : 0)}
|
||||
|
|
@ -185,46 +189,36 @@ export function ItemSelectionModal({
|
|||
<p className="mt-2 text-muted-foreground">검색 중...</p>
|
||||
</td>
|
||||
</tr>
|
||||
) : results.length === 0 ? (
|
||||
) : filteredResults.length === 0 ? (
|
||||
<tr>
|
||||
<td
|
||||
colSpan={sourceColumns.length + (multiSelect ? 1 : 0)}
|
||||
className="px-4 py-8 text-center text-muted-foreground"
|
||||
>
|
||||
검색 결과가 없습니다
|
||||
{results.length > 0
|
||||
? "모든 항목이 이미 추가되었습니다"
|
||||
: "검색 결과가 없습니다"}
|
||||
</td>
|
||||
</tr>
|
||||
) : (
|
||||
results.map((item, index) => {
|
||||
const alreadyAdded = isAlreadyAdded(item);
|
||||
filteredResults.map((item, index) => {
|
||||
const selected = isSelected(item);
|
||||
|
||||
return (
|
||||
<tr
|
||||
key={index}
|
||||
className={`border-t transition-colors ${
|
||||
alreadyAdded
|
||||
? "bg-muted/50 opacity-50"
|
||||
: selected
|
||||
selected
|
||||
? "bg-primary/10"
|
||||
: "hover:bg-accent cursor-pointer"
|
||||
}`}
|
||||
onClick={() => {
|
||||
if (!alreadyAdded) {
|
||||
handleToggleItem(item);
|
||||
}
|
||||
}}
|
||||
onClick={() => handleToggleItem(item)}
|
||||
>
|
||||
{multiSelect && (
|
||||
<td className="px-4 py-2">
|
||||
<Checkbox
|
||||
checked={selected}
|
||||
disabled={alreadyAdded}
|
||||
onCheckedChange={() => {
|
||||
if (!alreadyAdded) {
|
||||
handleToggleItem(item);
|
||||
}
|
||||
}}
|
||||
onCheckedChange={() => handleToggleItem(item)}
|
||||
/>
|
||||
</td>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -92,6 +92,12 @@ export function ModalRepeaterTableComponent({
|
|||
onChange(newData);
|
||||
};
|
||||
|
||||
// 컬럼명 -> 라벨명 매핑 생성
|
||||
const columnLabels = columns.reduce((acc, col) => {
|
||||
acc[col.field] = col.label;
|
||||
return acc;
|
||||
}, {} as Record<string, string>);
|
||||
|
||||
return (
|
||||
<div className={cn("space-y-4", className)}>
|
||||
{/* 추가 버튼 */}
|
||||
|
|
@ -130,6 +136,7 @@ export function ModalRepeaterTableComponent({
|
|||
alreadySelected={value}
|
||||
uniqueField={uniqueField}
|
||||
onSelect={handleAddItems}
|
||||
columnLabels={columnLabels}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -65,5 +65,6 @@ export interface ItemSelectionModalProps {
|
|||
alreadySelected: any[]; // 이미 선택된 항목들 (중복 방지용)
|
||||
uniqueField?: string;
|
||||
onSelect: (items: any[]) => void;
|
||||
columnLabels?: Record<string, string>; // 컬럼명 -> 라벨명 매핑
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,14 +23,17 @@ export function OrderRegistrationModalRenderer({
|
|||
}: OrderRegistrationModalRendererProps) {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
// style에서 width, height 제거 (h-full w-full로 제어)
|
||||
const { width, height, ...restStyle } = style || {};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
variant={buttonVariant}
|
||||
size={buttonSize}
|
||||
onClick={() => setIsOpen(true)}
|
||||
style={style}
|
||||
className="w-full h-full"
|
||||
className="h-full w-full"
|
||||
style={restStyle}
|
||||
>
|
||||
<Plus className="mr-2 h-4 w-4" />
|
||||
{buttonText}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ export const OrderRegistrationModalDefinition: Omit<ComponentDefinition, "render
|
|||
tags: ["수주", "주문", "영업", "모달"],
|
||||
|
||||
defaultSize: {
|
||||
width: 200,
|
||||
width: 120,
|
||||
height: 40,
|
||||
},
|
||||
|
||||
|
|
@ -29,7 +29,7 @@ export const OrderRegistrationModalDefinition: Omit<ComponentDefinition, "render
|
|||
|
||||
defaultProps: {
|
||||
style: {
|
||||
width: "200px",
|
||||
width: "120px",
|
||||
height: "40px",
|
||||
},
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in New Issue