diff --git a/frontend/components/v2/config-panels/V2InputConfigPanel.tsx b/frontend/components/v2/config-panels/V2InputConfigPanel.tsx index b6239bfe..65157fd7 100644 --- a/frontend/components/v2/config-panels/V2InputConfigPanel.tsx +++ b/frontend/components/v2/config-panels/V2InputConfigPanel.tsx @@ -9,7 +9,6 @@ import React, { useState, useEffect } from "react"; import { Label } from "@/components/ui/label"; import { Input } from "@/components/ui/input"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; -import { Separator } from "@/components/ui/separator"; import { Checkbox } from "@/components/ui/checkbox"; import { AutoGenerationType, AutoGenerationConfig } from "@/types/screen"; import { AutoGenerationUtils } from "@/lib/utils/autoGeneration"; @@ -19,44 +18,33 @@ import { NumberingRuleConfig } from "@/types/numbering-rule"; interface V2InputConfigPanelProps { config: Record; onChange: (config: Record) => void; - menuObjid?: number; // 메뉴 OBJID (채번 규칙 필터링용) + menuObjid?: number; } export const V2InputConfigPanel: React.FC = ({ config, onChange, menuObjid }) => { - // 채번 규칙 목록 상태 const [numberingRules, setNumberingRules] = useState([]); const [loadingRules, setLoadingRules] = useState(false); - - // 부모 메뉴 목록 상태 (채번규칙 사용을 위한 선택) const [parentMenus, setParentMenus] = useState([]); const [loadingMenus, setLoadingMenus] = useState(false); - - // 선택된 메뉴 OBJID const [selectedMenuObjid, setSelectedMenuObjid] = useState(() => { return config.autoGeneration?.selectedMenuObjid || menuObjid; }); - // 설정 업데이트 핸들러 const updateConfig = (field: string, value: any) => { onChange({ ...config, [field]: value }); }; - // 부모 메뉴 목록 로드 (사용자 메뉴의 레벨 2만) useEffect(() => { const loadMenus = async () => { setLoadingMenus(true); try { const { apiClient } = await import("@/lib/api/client"); const response = await apiClient.get("/admin/menus"); - if (response.data.success && response.data.data) { const allMenus = response.data.data; - - // 사용자 메뉴(menu_type='1')의 레벨 2만 필터링 - const level2UserMenus = allMenus.filter((menu: any) => + const level2UserMenus = allMenus.filter((menu: any) => menu.menu_type === '1' && menu.lev === 2 ); - setParentMenus(level2UserMenus); } } catch (error) { @@ -68,22 +56,13 @@ export const V2InputConfigPanel: React.FC = ({ config, loadMenus(); }, []); - // 채번 규칙 목록 로드 (선택된 메뉴 기준) useEffect(() => { const loadRules = async () => { - if (config.autoGeneration?.type !== "numbering_rule") { - return; - } - - if (!selectedMenuObjid) { - setNumberingRules([]); - return; - } - + if (config.autoGeneration?.type !== "numbering_rule") return; + if (!selectedMenuObjid) { setNumberingRules([]); return; } setLoadingRules(true); try { const response = await getAvailableNumberingRules(selectedMenuObjid); - if (response.success && response.data) { setNumberingRules(response.data); } @@ -94,61 +73,56 @@ export const V2InputConfigPanel: React.FC = ({ config, setLoadingRules(false); } }; - loadRules(); }, [selectedMenuObjid, config.autoGeneration?.type]); return ( -
- {/* 입력 타입 */} -
- - +
+ {/* INPUT TYPE 섹션 */} +
+

INPUT TYPE

+
+ 입력 타입 +
+ +
+
- {/* 채번 타입 전용 설정 */} + {/* NUMBERING 섹션 - 채번 타입 전용 */} {config.inputType === "numbering" && ( -
- -
-

채번 타입 안내

-

+

+

NUMBERING

+
+

채번 규칙은 테이블 관리에서 컬럼별로 설정됩니다. -
화면에 배치된 컬럼의 채번 규칙이 자동으로 적용됩니다.

- - {/* 채번 필드는 기본적으로 읽기전용 */} -
+
+ 읽기전용 (권장) { - updateConfig("readonly", checked); - }} + onCheckedChange={(checked) => updateConfig("readonly", checked)} /> -
-

+

채번 필드는 자동으로 생성되므로 읽기전용을 권장합니다

@@ -157,327 +131,345 @@ export const V2InputConfigPanel: React.FC = ({ config, {/* 채번 타입이 아닌 경우에만 추가 설정 표시 */} {config.inputType !== "numbering" && ( <> - - - {/* 형식 (텍스트/숫자용) */} + {/* FORMAT 섹션 */} {(config.inputType === "text" || !config.inputType) && ( -
- - -
- )} - - {/* 플레이스홀더 */} -
- - updateConfig("placeholder", e.target.value)} - placeholder="입력 안내 텍스트" - className="h-8 text-xs" - /> -
- - {/* 숫자/슬라이더 전용 설정 */} - {(config.inputType === "number" || config.inputType === "slider") && ( - <> - -
-
- - updateConfig("min", e.target.value ? Number(e.target.value) : undefined)} - placeholder="0" - className="h-8 text-xs" - /> -
-
- - updateConfig("max", e.target.value ? Number(e.target.value) : undefined)} - placeholder="100" - className="h-8 text-xs" - /> -
-
- - updateConfig("step", e.target.value ? Number(e.target.value) : undefined)} - placeholder="1" - className="h-8 text-xs" - /> -
-
- - )} - - {/* 여러 줄 텍스트 전용 설정 */} - {config.inputType === "textarea" && ( -
- - updateConfig("rows", parseInt(e.target.value) || 3)} - min={2} - max={20} - className="h-8 text-xs" - /> -
- )} - - {/* 마스크 입력 (선택) */} -
- - updateConfig("mask", e.target.value)} - placeholder="예: ###-####-####" - className="h-8 text-xs" - /> -

# = 숫자, A = 문자, * = 모든 문자

-
- - - - {/* 자동생성 기능 */} -
-
- { - const currentConfig = config.autoGeneration || { type: "none", enabled: false }; - updateConfig("autoGeneration", { - ...currentConfig, - enabled: checked as boolean, - }); - }} - /> - -
- - {/* 자동생성 타입 선택 */} - {config.autoGeneration?.enabled && ( -
-
- - - - {/* 선택된 타입 설명 */} - {config.autoGeneration?.type && config.autoGeneration.type !== "none" && ( -

- {AutoGenerationUtils.getTypeDescription(config.autoGeneration.type)} -

- )} -
- - {/* 채번 규칙 선택 */} - {config.autoGeneration?.type === "numbering_rule" && ( - <> - {/* 부모 메뉴 선택 */} -
- - updateConfig("format", value)}> + + - {parentMenus.length === 0 ? ( - - 사용 가능한 메뉴가 없습니다 - - ) : ( - parentMenus.map((menu) => ( - - {menu.menu_name_kor} - - )) - )} + 제한 없음 + 이메일 + 전화번호 + URL + 통화 + 사업자번호
+
+
+ )} - {/* 채번 규칙 선택 */} - {selectedMenuObjid ? ( -
- + {/* PLACEHOLDER 섹션 */} +
+

PLACEHOLDER

+
+ 안내 텍스트 +
+ updateConfig("placeholder", e.target.value)} + placeholder="입력 안내" + className="h-7 text-xs" + /> +
+
+
+ + {/* RANGE 섹션 - 숫자/슬라이더 전용 */} + {(config.inputType === "number" || config.inputType === "slider") && ( +
+

RANGE

+
+
+ + updateConfig("min", e.target.value ? Number(e.target.value) : undefined)} + placeholder="0" + className="h-7 text-xs" + /> +
+
+ + updateConfig("max", e.target.value ? Number(e.target.value) : undefined)} + placeholder="100" + className="h-7 text-xs" + /> +
+
+ + updateConfig("step", e.target.value ? Number(e.target.value) : undefined)} + placeholder="1" + className="h-7 text-xs" + /> +
+
+
+ )} + + {/* TEXTAREA 섹션 */} + {config.inputType === "textarea" && ( +
+

TEXTAREA

+
+ 줄 수 +
+ updateConfig("rows", parseInt(e.target.value) || 3)} + min={2} + max={20} + className="h-7 text-xs" + /> +
+
+
+ )} + + {/* INPUT MASK 섹션 */} +
+

INPUT MASK

+
+ 마스크 +
+ updateConfig("mask", e.target.value)} + placeholder="###-####-####" + className="h-7 text-xs" + /> +
+
+

# = 숫자, A = 문자, * = 모든 문자

+
+ + {/* AUTO GENERATION 섹션 */} +
+

AUTO GENERATION

+
+ 자동생성 활성화 + { + const currentConfig = config.autoGeneration || { type: "none", enabled: false }; + updateConfig("autoGeneration", { + ...currentConfig, + enabled: checked as boolean, + }); + }} + /> +
+ + {config.autoGeneration?.enabled && ( +
+ {/* 자동생성 타입 */} +
+ 타입 +
- ) : ( -
- 먼저 대상 메뉴를 선택하세요 +
+ + {config.autoGeneration?.type && config.autoGeneration.type !== "none" && ( +

+ {AutoGenerationUtils.getTypeDescription(config.autoGeneration.type)} +

+ )} + + {/* 채번 규칙 선택 */} + {config.autoGeneration?.type === "numbering_rule" && ( +
+
+ + 대상 메뉴 * + +
+ +
+
+ + {selectedMenuObjid ? ( +
+ + 채번 규칙 * + +
+ +
+
+ ) : ( +
+ 먼저 대상 메뉴를 선택하세요 +
+ )}
)} - - )} - {/* 자동생성 옵션 (랜덤/순차용) */} - {config.autoGeneration?.type && - ["random_string", "random_number", "sequence"].includes(config.autoGeneration.type) && ( -
- {/* 길이 설정 */} - {["random_string", "random_number"].includes(config.autoGeneration.type) && ( -
- - { - updateConfig("autoGeneration", { - ...config.autoGeneration, - options: { - ...config.autoGeneration?.options, - length: parseInt(e.target.value) || 8, - }, - }); - }} - className="h-8 text-xs" - /> + {/* 자동생성 옵션 (랜덤/순차용) */} + {config.autoGeneration?.type && + ["random_string", "random_number", "sequence"].includes(config.autoGeneration.type) && ( +
+ {["random_string", "random_number"].includes(config.autoGeneration.type) && ( +
+ 길이 +
+ { + updateConfig("autoGeneration", { + ...config.autoGeneration, + options: { + ...config.autoGeneration?.options, + length: parseInt(e.target.value) || 8, + }, + }); + }} + className="h-7 text-xs" + /> +
+
+ )} + +
+ 접두사 +
+ { + updateConfig("autoGeneration", { + ...config.autoGeneration, + options: { + ...config.autoGeneration?.options, + prefix: e.target.value, + }, + }); + }} + placeholder="예: INV-" + className="h-7 text-xs" + /> +
+
+ +
+ 접미사 +
+ { + updateConfig("autoGeneration", { + ...config.autoGeneration, + options: { + ...config.autoGeneration?.options, + suffix: e.target.value, + }, + }); + }} + className="h-7 text-xs" + /> +
+
+ +
+ 미리보기 +
+ {AutoGenerationUtils.generatePreviewValue(config.autoGeneration)} +
+
)} - - {/* 접두사 */} -
- - { - updateConfig("autoGeneration", { - ...config.autoGeneration, - options: { - ...config.autoGeneration?.options, - prefix: e.target.value, - }, - }); - }} - placeholder="예: INV-" - className="h-8 text-xs" - /> -
- - {/* 접미사 */} -
- - { - updateConfig("autoGeneration", { - ...config.autoGeneration, - options: { - ...config.autoGeneration?.options, - suffix: e.target.value, - }, - }); - }} - className="h-8 text-xs" - /> -
- - {/* 미리보기 */} -
- -
- {AutoGenerationUtils.generatePreviewValue(config.autoGeneration)} -
-
-
- )} +
+ )}
- )} -
)}