출발지 목적지 선택
This commit is contained in:
parent
c657d6f7a0
commit
d7ee63a857
|
|
@ -53,6 +53,7 @@ export const DividerLineComponent: React.FC<DividerLineComponentProps> = ({
|
||||||
};
|
};
|
||||||
|
|
||||||
// DOM에 전달하면 안 되는 React-specific props 필터링
|
// DOM에 전달하면 안 되는 React-specific props 필터링
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
const {
|
const {
|
||||||
selectedScreen,
|
selectedScreen,
|
||||||
onZoneComponentDrop,
|
onZoneComponentDrop,
|
||||||
|
|
@ -70,8 +71,40 @@ export const DividerLineComponent: React.FC<DividerLineComponentProps> = ({
|
||||||
tableName: _tableName,
|
tableName: _tableName,
|
||||||
onRefresh: _onRefresh,
|
onRefresh: _onRefresh,
|
||||||
onClose: _onClose,
|
onClose: _onClose,
|
||||||
|
// 추가된 props 필터링
|
||||||
|
webType: _webType,
|
||||||
|
autoGeneration: _autoGeneration,
|
||||||
|
isInteractive: _isInteractive,
|
||||||
|
formData: _formData,
|
||||||
|
onFormDataChange: _onFormDataChange,
|
||||||
|
menuId: _menuId,
|
||||||
|
menuObjid: _menuObjid,
|
||||||
|
onSave: _onSave,
|
||||||
|
userId: _userId,
|
||||||
|
userName: _userName,
|
||||||
|
companyCode: _companyCode,
|
||||||
|
isInModal: _isInModal,
|
||||||
|
readonly: _readonly,
|
||||||
|
originalData: _originalData,
|
||||||
|
allComponents: _allComponents,
|
||||||
|
onUpdateLayout: _onUpdateLayout,
|
||||||
|
selectedRows: _selectedRows,
|
||||||
|
selectedRowsData: _selectedRowsData,
|
||||||
|
onSelectedRowsChange: _onSelectedRowsChange,
|
||||||
|
sortBy: _sortBy,
|
||||||
|
sortOrder: _sortOrder,
|
||||||
|
tableDisplayData: _tableDisplayData,
|
||||||
|
flowSelectedData: _flowSelectedData,
|
||||||
|
flowSelectedStepId: _flowSelectedStepId,
|
||||||
|
onFlowSelectedDataChange: _onFlowSelectedDataChange,
|
||||||
|
onConfigChange: _onConfigChange,
|
||||||
|
refreshKey: _refreshKey,
|
||||||
|
flowRefreshKey: _flowRefreshKey,
|
||||||
|
onFlowRefresh: _onFlowRefresh,
|
||||||
|
isPreview: _isPreview,
|
||||||
|
groupedData: _groupedData,
|
||||||
...domProps
|
...domProps
|
||||||
} = props;
|
} = props as any;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={componentStyle} className={className} {...domProps}>
|
<div style={componentStyle} className={className} {...domProps}>
|
||||||
|
|
|
||||||
|
|
@ -103,11 +103,36 @@ export function LocationSwapSelectorComponent(props: LocationSwapSelectorProps)
|
||||||
const departureValue = formData[departureField] || "";
|
const departureValue = formData[departureField] || "";
|
||||||
const destinationValue = formData[destinationField] || "";
|
const destinationValue = formData[destinationField] || "";
|
||||||
|
|
||||||
|
// 기본 옵션 (포항/광양)
|
||||||
|
const DEFAULT_OPTIONS: LocationOption[] = [
|
||||||
|
{ value: "pohang", label: "포항" },
|
||||||
|
{ value: "gwangyang", label: "광양" },
|
||||||
|
];
|
||||||
|
|
||||||
// 옵션 로드
|
// 옵션 로드
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const loadOptions = async () => {
|
const loadOptions = async () => {
|
||||||
if (dataSource.type === "static") {
|
console.log("[LocationSwapSelector] 옵션 로드 시작:", { dataSource, isDesignMode });
|
||||||
setOptions(dataSource.staticOptions || []);
|
|
||||||
|
// 정적 옵션 처리 (기본값)
|
||||||
|
// type이 없거나 static이거나, table인데 tableName이 없는 경우
|
||||||
|
const shouldUseStatic =
|
||||||
|
!dataSource.type ||
|
||||||
|
dataSource.type === "static" ||
|
||||||
|
(dataSource.type === "table" && !dataSource.tableName) ||
|
||||||
|
(dataSource.type === "code" && !dataSource.codeCategory);
|
||||||
|
|
||||||
|
if (shouldUseStatic) {
|
||||||
|
const staticOpts = dataSource.staticOptions || [];
|
||||||
|
// 정적 옵션이 설정되어 있으면 사용
|
||||||
|
if (staticOpts.length > 0 && staticOpts[0]?.value) {
|
||||||
|
console.log("[LocationSwapSelector] 정적 옵션 사용:", staticOpts);
|
||||||
|
setOptions(staticOpts);
|
||||||
|
} else {
|
||||||
|
// 기본값 (포항/광양)
|
||||||
|
console.log("[LocationSwapSelector] 기본 옵션 사용:", DEFAULT_OPTIONS);
|
||||||
|
setOptions(DEFAULT_OPTIONS);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -159,17 +184,7 @@ export function LocationSwapSelectorComponent(props: LocationSwapSelectorProps)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!isDesignMode) {
|
|
||||||
loadOptions();
|
loadOptions();
|
||||||
} else {
|
|
||||||
// 디자인 모드에서는 샘플 데이터
|
|
||||||
setOptions([
|
|
||||||
{ value: "seoul", label: "서울" },
|
|
||||||
{ value: "busan", label: "부산" },
|
|
||||||
{ value: "pohang", label: "포항" },
|
|
||||||
{ value: "gwangyang", label: "광양" },
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}, [dataSource, isDesignMode]);
|
}, [dataSource, isDesignMode]);
|
||||||
|
|
||||||
// 출발지 변경
|
// 출발지 변경
|
||||||
|
|
@ -250,7 +265,7 @@ export function LocationSwapSelectorComponent(props: LocationSwapSelectorProps)
|
||||||
<Select
|
<Select
|
||||||
value={departureValue}
|
value={departureValue}
|
||||||
onValueChange={handleDepartureChange}
|
onValueChange={handleDepartureChange}
|
||||||
disabled={loading || isDesignMode}
|
disabled={loading}
|
||||||
>
|
>
|
||||||
<SelectTrigger className="h-auto w-full max-w-[120px] border-0 bg-transparent p-0 text-center text-lg font-bold shadow-none focus:ring-0">
|
<SelectTrigger className="h-auto w-full max-w-[120px] border-0 bg-transparent p-0 text-center text-lg font-bold shadow-none focus:ring-0">
|
||||||
<SelectValue placeholder="선택">
|
<SelectValue placeholder="선택">
|
||||||
|
|
@ -259,12 +274,16 @@ export function LocationSwapSelectorComponent(props: LocationSwapSelectorProps)
|
||||||
</span>
|
</span>
|
||||||
</SelectValue>
|
</SelectValue>
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent position="popper" sideOffset={4}>
|
||||||
{options.map((option) => (
|
{options.length > 0 ? (
|
||||||
|
options.map((option) => (
|
||||||
<SelectItem key={option.value} value={option.value}>
|
<SelectItem key={option.value} value={option.value}>
|
||||||
{option.label}
|
{option.label}
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
))}
|
))
|
||||||
|
) : (
|
||||||
|
<div className="px-2 py-1.5 text-sm text-muted-foreground">옵션 없음</div>
|
||||||
|
)}
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -276,7 +295,6 @@ export function LocationSwapSelectorComponent(props: LocationSwapSelectorProps)
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="icon"
|
size="icon"
|
||||||
onClick={handleSwap}
|
onClick={handleSwap}
|
||||||
disabled={isDesignMode || !departureValue || !destinationValue}
|
|
||||||
className={cn(
|
className={cn(
|
||||||
"mx-2 h-10 w-10 rounded-full border bg-background transition-transform hover:bg-muted",
|
"mx-2 h-10 w-10 rounded-full border bg-background transition-transform hover:bg-muted",
|
||||||
isSwapping && "rotate-180"
|
isSwapping && "rotate-180"
|
||||||
|
|
@ -292,7 +310,7 @@ export function LocationSwapSelectorComponent(props: LocationSwapSelectorProps)
|
||||||
<Select
|
<Select
|
||||||
value={destinationValue}
|
value={destinationValue}
|
||||||
onValueChange={handleDestinationChange}
|
onValueChange={handleDestinationChange}
|
||||||
disabled={loading || isDesignMode}
|
disabled={loading}
|
||||||
>
|
>
|
||||||
<SelectTrigger className="h-auto w-full max-w-[120px] border-0 bg-transparent p-0 text-center text-lg font-bold shadow-none focus:ring-0">
|
<SelectTrigger className="h-auto w-full max-w-[120px] border-0 bg-transparent p-0 text-center text-lg font-bold shadow-none focus:ring-0">
|
||||||
<SelectValue placeholder="선택">
|
<SelectValue placeholder="선택">
|
||||||
|
|
@ -301,12 +319,16 @@ export function LocationSwapSelectorComponent(props: LocationSwapSelectorProps)
|
||||||
</span>
|
</span>
|
||||||
</SelectValue>
|
</SelectValue>
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent position="popper" sideOffset={4}>
|
||||||
{options.map((option) => (
|
{options.length > 0 ? (
|
||||||
|
options.map((option) => (
|
||||||
<SelectItem key={option.value} value={option.value}>
|
<SelectItem key={option.value} value={option.value}>
|
||||||
{option.label}
|
{option.label}
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
))}
|
))
|
||||||
|
) : (
|
||||||
|
<div className="px-2 py-1.5 text-sm text-muted-foreground">옵션 없음</div>
|
||||||
|
)}
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -328,17 +350,21 @@ export function LocationSwapSelectorComponent(props: LocationSwapSelectorProps)
|
||||||
<Select
|
<Select
|
||||||
value={departureValue}
|
value={departureValue}
|
||||||
onValueChange={handleDepartureChange}
|
onValueChange={handleDepartureChange}
|
||||||
disabled={loading || isDesignMode}
|
disabled={loading}
|
||||||
>
|
>
|
||||||
<SelectTrigger className="h-10">
|
<SelectTrigger className="h-10">
|
||||||
<SelectValue placeholder="선택" />
|
<SelectValue placeholder="선택" />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent position="popper" sideOffset={4}>
|
||||||
{options.map((option) => (
|
{options.length > 0 ? (
|
||||||
|
options.map((option) => (
|
||||||
<SelectItem key={option.value} value={option.value}>
|
<SelectItem key={option.value} value={option.value}>
|
||||||
{option.label}
|
{option.label}
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
))}
|
))
|
||||||
|
) : (
|
||||||
|
<div className="px-2 py-1.5 text-sm text-muted-foreground">옵션 없음</div>
|
||||||
|
)}
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -349,7 +375,6 @@ export function LocationSwapSelectorComponent(props: LocationSwapSelectorProps)
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="icon"
|
size="icon"
|
||||||
onClick={handleSwap}
|
onClick={handleSwap}
|
||||||
disabled={isDesignMode}
|
|
||||||
className="mt-5 h-10 w-10"
|
className="mt-5 h-10 w-10"
|
||||||
>
|
>
|
||||||
<ArrowLeftRight className="h-4 w-4" />
|
<ArrowLeftRight className="h-4 w-4" />
|
||||||
|
|
@ -361,17 +386,21 @@ export function LocationSwapSelectorComponent(props: LocationSwapSelectorProps)
|
||||||
<Select
|
<Select
|
||||||
value={destinationValue}
|
value={destinationValue}
|
||||||
onValueChange={handleDestinationChange}
|
onValueChange={handleDestinationChange}
|
||||||
disabled={loading || isDesignMode}
|
disabled={loading}
|
||||||
>
|
>
|
||||||
<SelectTrigger className="h-10">
|
<SelectTrigger className="h-10">
|
||||||
<SelectValue placeholder="선택" />
|
<SelectValue placeholder="선택" />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent position="popper" sideOffset={4}>
|
||||||
{options.map((option) => (
|
{options.length > 0 ? (
|
||||||
|
options.map((option) => (
|
||||||
<SelectItem key={option.value} value={option.value}>
|
<SelectItem key={option.value} value={option.value}>
|
||||||
{option.label}
|
{option.label}
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
))}
|
))
|
||||||
|
) : (
|
||||||
|
<div className="px-2 py-1.5 text-sm text-muted-foreground">옵션 없음</div>
|
||||||
|
)}
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -389,17 +418,21 @@ export function LocationSwapSelectorComponent(props: LocationSwapSelectorProps)
|
||||||
<Select
|
<Select
|
||||||
value={departureValue}
|
value={departureValue}
|
||||||
onValueChange={handleDepartureChange}
|
onValueChange={handleDepartureChange}
|
||||||
disabled={loading || isDesignMode}
|
disabled={loading}
|
||||||
>
|
>
|
||||||
<SelectTrigger className="h-8 flex-1 text-sm">
|
<SelectTrigger className="h-8 flex-1 text-sm">
|
||||||
<SelectValue placeholder={departureLabel} />
|
<SelectValue placeholder={departureLabel} />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent position="popper" sideOffset={4}>
|
||||||
{options.map((option) => (
|
{options.length > 0 ? (
|
||||||
|
options.map((option) => (
|
||||||
<SelectItem key={option.value} value={option.value}>
|
<SelectItem key={option.value} value={option.value}>
|
||||||
{option.label}
|
{option.label}
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
))}
|
))
|
||||||
|
) : (
|
||||||
|
<div className="px-2 py-1.5 text-sm text-muted-foreground">옵션 없음</div>
|
||||||
|
)}
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
|
|
||||||
|
|
@ -409,7 +442,6 @@ export function LocationSwapSelectorComponent(props: LocationSwapSelectorProps)
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="sm"
|
size="sm"
|
||||||
onClick={handleSwap}
|
onClick={handleSwap}
|
||||||
disabled={isDesignMode}
|
|
||||||
className="h-8 w-8 p-0"
|
className="h-8 w-8 p-0"
|
||||||
>
|
>
|
||||||
<ArrowLeftRight className="h-4 w-4" />
|
<ArrowLeftRight className="h-4 w-4" />
|
||||||
|
|
@ -419,17 +451,21 @@ export function LocationSwapSelectorComponent(props: LocationSwapSelectorProps)
|
||||||
<Select
|
<Select
|
||||||
value={destinationValue}
|
value={destinationValue}
|
||||||
onValueChange={handleDestinationChange}
|
onValueChange={handleDestinationChange}
|
||||||
disabled={loading || isDesignMode}
|
disabled={loading}
|
||||||
>
|
>
|
||||||
<SelectTrigger className="h-8 flex-1 text-sm">
|
<SelectTrigger className="h-8 flex-1 text-sm">
|
||||||
<SelectValue placeholder={destinationLabel} />
|
<SelectValue placeholder={destinationLabel} />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent position="popper" sideOffset={4}>
|
||||||
{options.map((option) => (
|
{options.length > 0 ? (
|
||||||
|
options.map((option) => (
|
||||||
<SelectItem key={option.value} value={option.value}>
|
<SelectItem key={option.value} value={option.value}>
|
||||||
{option.label}
|
{option.label}
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
))}
|
))
|
||||||
|
) : (
|
||||||
|
<div className="px-2 py-1.5 text-sm text-muted-foreground">옵션 없음</div>
|
||||||
|
)}
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -139,13 +139,83 @@ export function LocationSwapSelectorConfigPanel({
|
||||||
<SelectValue placeholder="선택" />
|
<SelectValue placeholder="선택" />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectItem value="static">정적 옵션 (하드코딩)</SelectItem>
|
<SelectItem value="static">고정 옵션 (포항/광양 등)</SelectItem>
|
||||||
<SelectItem value="table">테이블</SelectItem>
|
<SelectItem value="table">테이블에서 가져오기</SelectItem>
|
||||||
<SelectItem value="code">코드 관리</SelectItem>
|
<SelectItem value="code">코드 관리에서 가져오기</SelectItem>
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* 고정 옵션 설정 (type이 static일 때) */}
|
||||||
|
{(!config?.dataSource?.type || config?.dataSource?.type === "static") && (
|
||||||
|
<div className="space-y-3 rounded-md bg-amber-50 p-3 dark:bg-amber-950">
|
||||||
|
<h4 className="text-sm font-medium">고정 옵션 설정</h4>
|
||||||
|
<div className="grid grid-cols-2 gap-2">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label>옵션 1 (값)</Label>
|
||||||
|
<Input
|
||||||
|
value={config?.dataSource?.staticOptions?.[0]?.value || ""}
|
||||||
|
onChange={(e) => {
|
||||||
|
const options = config?.dataSource?.staticOptions || [];
|
||||||
|
const newOptions = [...options];
|
||||||
|
newOptions[0] = { ...newOptions[0], value: e.target.value };
|
||||||
|
handleChange("dataSource.staticOptions", newOptions);
|
||||||
|
}}
|
||||||
|
placeholder="예: pohang"
|
||||||
|
className="h-8 text-xs"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label>옵션 1 (표시명)</Label>
|
||||||
|
<Input
|
||||||
|
value={config?.dataSource?.staticOptions?.[0]?.label || ""}
|
||||||
|
onChange={(e) => {
|
||||||
|
const options = config?.dataSource?.staticOptions || [];
|
||||||
|
const newOptions = [...options];
|
||||||
|
newOptions[0] = { ...newOptions[0], label: e.target.value };
|
||||||
|
handleChange("dataSource.staticOptions", newOptions);
|
||||||
|
}}
|
||||||
|
placeholder="예: 포항"
|
||||||
|
className="h-8 text-xs"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="grid grid-cols-2 gap-2">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label>옵션 2 (값)</Label>
|
||||||
|
<Input
|
||||||
|
value={config?.dataSource?.staticOptions?.[1]?.value || ""}
|
||||||
|
onChange={(e) => {
|
||||||
|
const options = config?.dataSource?.staticOptions || [];
|
||||||
|
const newOptions = [...options];
|
||||||
|
newOptions[1] = { ...newOptions[1], value: e.target.value };
|
||||||
|
handleChange("dataSource.staticOptions", newOptions);
|
||||||
|
}}
|
||||||
|
placeholder="예: gwangyang"
|
||||||
|
className="h-8 text-xs"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label>옵션 2 (표시명)</Label>
|
||||||
|
<Input
|
||||||
|
value={config?.dataSource?.staticOptions?.[1]?.label || ""}
|
||||||
|
onChange={(e) => {
|
||||||
|
const options = config?.dataSource?.staticOptions || [];
|
||||||
|
const newOptions = [...options];
|
||||||
|
newOptions[1] = { ...newOptions[1], label: e.target.value };
|
||||||
|
handleChange("dataSource.staticOptions", newOptions);
|
||||||
|
}}
|
||||||
|
placeholder="예: 광양"
|
||||||
|
className="h-8 text-xs"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<p className="text-xs text-amber-700 dark:text-amber-300">
|
||||||
|
고정된 2개 장소만 사용할 때 설정하세요. (예: 포항 ↔ 광양)
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* 테이블 선택 (type이 table일 때) */}
|
{/* 테이블 선택 (type이 table일 때) */}
|
||||||
{config?.dataSource?.type === "table" && (
|
{config?.dataSource?.type === "table" && (
|
||||||
<>
|
<>
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,28 @@ export class LocationSwapSelectorRenderer extends AutoRegisteringComponentRender
|
||||||
static componentDefinition = LocationSwapSelectorDefinition;
|
static componentDefinition = LocationSwapSelectorDefinition;
|
||||||
|
|
||||||
render(): React.ReactElement {
|
render(): React.ReactElement {
|
||||||
return <LocationSwapSelectorComponent {...this.props} />;
|
const { component, formData, onFormDataChange, isDesignMode, style, ...restProps } = this.props;
|
||||||
|
|
||||||
|
// component.componentConfig에서 설정 가져오기
|
||||||
|
const componentConfig = component?.componentConfig || {};
|
||||||
|
|
||||||
|
console.log("[LocationSwapSelectorRenderer] render:", {
|
||||||
|
componentConfig,
|
||||||
|
formData,
|
||||||
|
isDesignMode
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<LocationSwapSelectorComponent
|
||||||
|
id={component?.id}
|
||||||
|
style={style}
|
||||||
|
isDesignMode={isDesignMode}
|
||||||
|
formData={formData}
|
||||||
|
onFormDataChange={onFormDataChange}
|
||||||
|
componentConfig={componentConfig}
|
||||||
|
{...restProps}
|
||||||
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,12 +20,15 @@ export const LocationSwapSelectorDefinition = createComponentDefinition({
|
||||||
defaultConfig: {
|
defaultConfig: {
|
||||||
// 데이터 소스 설정
|
// 데이터 소스 설정
|
||||||
dataSource: {
|
dataSource: {
|
||||||
type: "table", // "table" | "code" | "static"
|
type: "static", // "table" | "code" | "static"
|
||||||
tableName: "", // 장소 테이블명
|
tableName: "", // 장소 테이블명
|
||||||
valueField: "location_code", // 값 필드
|
valueField: "location_code", // 값 필드
|
||||||
labelField: "location_name", // 표시 필드
|
labelField: "location_name", // 표시 필드
|
||||||
codeCategory: "", // 코드 관리 카테고리 (type이 "code"일 때)
|
codeCategory: "", // 코드 관리 카테고리 (type이 "code"일 때)
|
||||||
staticOptions: [], // 정적 옵션 (type이 "static"일 때)
|
staticOptions: [
|
||||||
|
{ value: "pohang", label: "포항" },
|
||||||
|
{ value: "gwangyang", label: "광양" },
|
||||||
|
], // 정적 옵션 (type이 "static"일 때)
|
||||||
},
|
},
|
||||||
// 필드 매핑
|
// 필드 매핑
|
||||||
departureField: "departure", // 출발지 저장 필드
|
departureField: "departure", // 출발지 저장 필드
|
||||||
|
|
|
||||||
|
|
@ -271,6 +271,9 @@ export class ButtonActionExecutor {
|
||||||
case "geolocation":
|
case "geolocation":
|
||||||
return await this.handleGeolocation(config, context);
|
return await this.handleGeolocation(config, context);
|
||||||
|
|
||||||
|
case "swap_fields":
|
||||||
|
return await this.handleSwapFields(config, context);
|
||||||
|
|
||||||
case "update_field":
|
case "update_field":
|
||||||
return await this.handleUpdateField(config, context);
|
return await this.handleUpdateField(config, context);
|
||||||
|
|
||||||
|
|
@ -3412,6 +3415,59 @@ export class ButtonActionExecutor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 필드 값 교환 액션 처리 (예: 출발지 ↔ 도착지)
|
||||||
|
*/
|
||||||
|
private static async handleSwapFields(config: ButtonActionConfig, context: ButtonActionContext): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
console.log("🔄 필드 값 교환 액션 실행:", { config, context });
|
||||||
|
|
||||||
|
const { formData, onFormDataChange } = context;
|
||||||
|
|
||||||
|
// 교환할 필드 확인
|
||||||
|
const fieldA = config.swapFieldA;
|
||||||
|
const fieldB = config.swapFieldB;
|
||||||
|
|
||||||
|
if (!fieldA || !fieldB) {
|
||||||
|
toast.error("교환할 필드가 설정되지 않았습니다.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 현재 값 가져오기
|
||||||
|
const valueA = formData?.[fieldA];
|
||||||
|
const valueB = formData?.[fieldB];
|
||||||
|
|
||||||
|
console.log("🔄 교환 전:", { [fieldA]: valueA, [fieldB]: valueB });
|
||||||
|
|
||||||
|
// 값 교환
|
||||||
|
if (onFormDataChange) {
|
||||||
|
onFormDataChange(fieldA, valueB);
|
||||||
|
onFormDataChange(fieldB, valueA);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 관련 필드도 함께 교환 (예: 위도/경도)
|
||||||
|
if (config.swapRelatedFields && config.swapRelatedFields.length > 0) {
|
||||||
|
for (const related of config.swapRelatedFields) {
|
||||||
|
const relatedValueA = formData?.[related.fieldA];
|
||||||
|
const relatedValueB = formData?.[related.fieldB];
|
||||||
|
if (onFormDataChange) {
|
||||||
|
onFormDataChange(related.fieldA, relatedValueB);
|
||||||
|
onFormDataChange(related.fieldB, relatedValueA);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("🔄 교환 후:", { [fieldA]: valueB, [fieldB]: valueA });
|
||||||
|
|
||||||
|
toast.success(config.successMessage || "값이 교환되었습니다.");
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("❌ 필드 값 교환 오류:", error);
|
||||||
|
toast.error(config.errorMessage || "값 교환 중 오류가 발생했습니다.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 필드 값 변경 액션 처리 (예: status를 active로 변경)
|
* 필드 값 변경 액션 처리 (예: status를 active로 변경)
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue