연쇄관계 관리
This commit is contained in:
@@ -19,11 +19,13 @@ import {
|
||||
AlertDialogTitle,
|
||||
} from "@/components/ui/alert-dialog";
|
||||
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card";
|
||||
import { ChevronDown, ChevronUp, Plus, Trash2, RefreshCw } from "lucide-react";
|
||||
import { ChevronDown, ChevronUp, Plus, Trash2, RefreshCw, Loader2 } from "lucide-react";
|
||||
import { toast } from "sonner";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { apiClient } from "@/lib/api/client";
|
||||
import { generateNumberingCode } from "@/lib/api/numberingRule";
|
||||
import { useCascadingDropdown } from "@/hooks/useCascadingDropdown";
|
||||
import { CascadingDropdownConfig } from "@/types/screen-management";
|
||||
|
||||
import {
|
||||
UniversalFormModalComponentProps,
|
||||
@@ -36,6 +38,83 @@ import {
|
||||
} from "./types";
|
||||
import { defaultConfig, generateUniqueId } from "./config";
|
||||
|
||||
/**
|
||||
* 🔗 연쇄 드롭다운 Select 필드 컴포넌트
|
||||
*/
|
||||
interface CascadingSelectFieldProps {
|
||||
fieldId: string;
|
||||
config: CascadingDropdownConfig;
|
||||
parentValue?: string | number | null;
|
||||
value?: string;
|
||||
onChange: (value: string) => void;
|
||||
placeholder?: string;
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
const CascadingSelectField: React.FC<CascadingSelectFieldProps> = ({
|
||||
fieldId,
|
||||
config,
|
||||
parentValue,
|
||||
value,
|
||||
onChange,
|
||||
placeholder,
|
||||
disabled,
|
||||
}) => {
|
||||
const { options, loading } = useCascadingDropdown({
|
||||
config,
|
||||
parentValue,
|
||||
});
|
||||
|
||||
const getPlaceholder = () => {
|
||||
if (!parentValue) {
|
||||
return config.emptyParentMessage || "상위 항목을 먼저 선택하세요";
|
||||
}
|
||||
if (loading) {
|
||||
return config.loadingMessage || "로딩 중...";
|
||||
}
|
||||
if (options.length === 0) {
|
||||
return config.noOptionsMessage || "선택 가능한 항목이 없습니다";
|
||||
}
|
||||
return placeholder || "선택하세요";
|
||||
};
|
||||
|
||||
const isDisabled = disabled || !parentValue || loading;
|
||||
|
||||
return (
|
||||
<Select
|
||||
value={value || ""}
|
||||
onValueChange={onChange}
|
||||
disabled={isDisabled}
|
||||
>
|
||||
<SelectTrigger id={fieldId} className="w-full">
|
||||
{loading ? (
|
||||
<div className="flex items-center gap-2">
|
||||
<Loader2 className="h-4 w-4 animate-spin" />
|
||||
<span className="text-muted-foreground text-sm">로딩 중...</span>
|
||||
</div>
|
||||
) : (
|
||||
<SelectValue placeholder={getPlaceholder()} />
|
||||
)}
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{options.length === 0 ? (
|
||||
<div className="text-muted-foreground px-2 py-4 text-center text-sm">
|
||||
{!parentValue
|
||||
? config.emptyParentMessage || "상위 항목을 먼저 선택하세요"
|
||||
: config.noOptionsMessage || "선택 가능한 항목이 없습니다"}
|
||||
</div>
|
||||
) : (
|
||||
options.map((option) => (
|
||||
<SelectItem key={option.value} value={option.value}>
|
||||
{option.label}
|
||||
</SelectItem>
|
||||
))
|
||||
)}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 범용 폼 모달 컴포넌트
|
||||
*
|
||||
@@ -837,6 +916,24 @@ export function UniversalFormModalComponent({
|
||||
);
|
||||
|
||||
case "select": {
|
||||
// 🆕 연쇄 드롭다운 처리
|
||||
if (field.cascading?.enabled) {
|
||||
const cascadingConfig = field.cascading;
|
||||
const parentValue = formData[cascadingConfig.parentField];
|
||||
|
||||
return (
|
||||
<CascadingSelectField
|
||||
fieldId={fieldKey}
|
||||
config={cascadingConfig as CascadingDropdownConfig}
|
||||
parentValue={parentValue}
|
||||
value={value}
|
||||
onChange={onChangeHandler}
|
||||
placeholder={field.placeholder || "선택하세요"}
|
||||
disabled={isDisabled}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
// 다중 컬럼 저장이 활성화된 경우
|
||||
const lfgMappings = field.linkedFieldGroup?.mappings;
|
||||
if (field.linkedFieldGroup?.enabled && field.linkedFieldGroup?.sourceTable && lfgMappings && lfgMappings.length > 0) {
|
||||
|
||||
Reference in New Issue
Block a user