2025-09-11 18:38:28 +09:00
|
|
|
"use client";
|
|
|
|
|
|
2025-11-04 17:35:02 +09:00
|
|
|
import React, { useState, useEffect } from "react";
|
2025-09-11 18:38:28 +09:00
|
|
|
import { Input } from "@/components/ui/input";
|
|
|
|
|
import { Label } from "@/components/ui/label";
|
|
|
|
|
import { Checkbox } from "@/components/ui/checkbox";
|
|
|
|
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
|
|
|
|
import { TextInputConfig } from "./types";
|
2025-09-19 12:19:34 +09:00
|
|
|
import { AutoGenerationType, AutoGenerationConfig } from "@/types/screen";
|
|
|
|
|
import { AutoGenerationUtils } from "@/lib/utils/autoGeneration";
|
2025-11-07 14:27:07 +09:00
|
|
|
import { getAvailableNumberingRules, getAvailableNumberingRulesForScreen } from "@/lib/api/numberingRule";
|
2025-11-04 17:35:02 +09:00
|
|
|
import { NumberingRuleConfig } from "@/types/numbering-rule";
|
2025-09-11 18:38:28 +09:00
|
|
|
|
|
|
|
|
export interface TextInputConfigPanelProps {
|
|
|
|
|
config: TextInputConfig;
|
|
|
|
|
onChange: (config: Partial<TextInputConfig>) => void;
|
2025-11-07 14:27:07 +09:00
|
|
|
screenTableName?: string; // 🆕 현재 화면의 테이블명
|
2025-09-11 18:38:28 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* TextInput 설정 패널
|
|
|
|
|
* 컴포넌트의 설정값들을 편집할 수 있는 UI 제공
|
|
|
|
|
*/
|
2025-11-07 14:27:07 +09:00
|
|
|
export const TextInputConfigPanel: React.FC<TextInputConfigPanelProps> = ({ config, onChange, screenTableName }) => {
|
2025-11-04 17:35:02 +09:00
|
|
|
// 채번 규칙 목록 상태
|
|
|
|
|
const [numberingRules, setNumberingRules] = useState<NumberingRuleConfig[]>([]);
|
|
|
|
|
const [loadingRules, setLoadingRules] = useState(false);
|
|
|
|
|
|
|
|
|
|
// 채번 규칙 목록 로드
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
const loadRules = async () => {
|
|
|
|
|
setLoadingRules(true);
|
|
|
|
|
try {
|
2025-11-07 14:27:07 +09:00
|
|
|
let response;
|
|
|
|
|
|
|
|
|
|
// 🆕 테이블명이 있으면 테이블 기반 필터링, 없으면 전체 조회
|
|
|
|
|
if (screenTableName) {
|
|
|
|
|
console.log("🔍 TextInputConfigPanel: 테이블 기반 채번 규칙 로드", { screenTableName });
|
|
|
|
|
response = await getAvailableNumberingRulesForScreen(screenTableName);
|
|
|
|
|
} else {
|
|
|
|
|
console.log("🔍 TextInputConfigPanel: 전체 채번 규칙 로드 (테이블명 없음)");
|
|
|
|
|
response = await getAvailableNumberingRules();
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-04 17:35:02 +09:00
|
|
|
if (response.success && response.data) {
|
|
|
|
|
setNumberingRules(response.data);
|
2025-11-07 14:27:07 +09:00
|
|
|
console.log("✅ 채번 규칙 로드 완료:", response.data.length, "개");
|
2025-11-04 17:35:02 +09:00
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("채번 규칙 목록 로드 실패:", error);
|
|
|
|
|
} finally {
|
|
|
|
|
setLoadingRules(false);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// autoGeneration.type이 numbering_rule일 때만 로드
|
|
|
|
|
if (config.autoGeneration?.type === "numbering_rule") {
|
|
|
|
|
loadRules();
|
|
|
|
|
}
|
2025-11-07 14:27:07 +09:00
|
|
|
}, [config.autoGeneration?.type, screenTableName]);
|
2025-11-04 17:35:02 +09:00
|
|
|
|
2025-09-11 18:38:28 +09:00
|
|
|
const handleChange = (key: keyof TextInputConfig, value: any) => {
|
|
|
|
|
onChange({ [key]: value });
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className="space-y-4">
|
2025-09-19 12:19:34 +09:00
|
|
|
<div className="text-sm font-medium">text-input 설정</div>
|
2025-09-11 18:38:28 +09:00
|
|
|
|
2025-09-19 12:19:34 +09:00
|
|
|
{/* 텍스트 관련 설정 */}
|
2025-09-11 18:38:28 +09:00
|
|
|
<div className="space-y-2">
|
|
|
|
|
<Label htmlFor="placeholder">플레이스홀더</Label>
|
|
|
|
|
<Input
|
|
|
|
|
id="placeholder"
|
|
|
|
|
value={config.placeholder || ""}
|
|
|
|
|
onChange={(e) => handleChange("placeholder", e.target.value)}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="space-y-2">
|
|
|
|
|
<Label htmlFor="maxLength">최대 길이</Label>
|
|
|
|
|
<Input
|
|
|
|
|
id="maxLength"
|
|
|
|
|
type="number"
|
|
|
|
|
value={config.maxLength || ""}
|
|
|
|
|
onChange={(e) => handleChange("maxLength", parseInt(e.target.value) || undefined)}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
|
2025-09-19 12:19:34 +09:00
|
|
|
{/* 구분선 */}
|
|
|
|
|
<div className="border-t pt-4">
|
|
|
|
|
<div className="mb-3 text-sm font-medium">고급 기능</div>
|
|
|
|
|
|
|
|
|
|
{/* 숨김 기능 */}
|
|
|
|
|
<div className="space-y-2">
|
2025-10-23 15:06:00 +09:00
|
|
|
<Label htmlFor="hidden">숨김</Label>
|
2025-09-19 12:19:34 +09:00
|
|
|
<Checkbox
|
|
|
|
|
id="hidden"
|
|
|
|
|
checked={config.hidden || false}
|
|
|
|
|
onCheckedChange={(checked) => handleChange("hidden", checked)}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* 자동생성 기능 */}
|
|
|
|
|
<div className="space-y-2">
|
|
|
|
|
<Label htmlFor="autoGeneration">자동생성 활성화</Label>
|
|
|
|
|
<Checkbox
|
|
|
|
|
id="autoGeneration"
|
|
|
|
|
checked={config.autoGeneration?.enabled || false}
|
|
|
|
|
onCheckedChange={(checked) => {
|
|
|
|
|
const currentConfig = config.autoGeneration || { type: "none", enabled: false };
|
|
|
|
|
handleChange("autoGeneration", {
|
|
|
|
|
...currentConfig,
|
|
|
|
|
enabled: checked as boolean,
|
|
|
|
|
});
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* 자동생성 타입 선택 */}
|
|
|
|
|
{config.autoGeneration?.enabled && (
|
|
|
|
|
<div className="space-y-2">
|
|
|
|
|
<Label htmlFor="autoGenerationType">자동생성 타입</Label>
|
|
|
|
|
<Select
|
|
|
|
|
value={config.autoGeneration?.type || "none"}
|
|
|
|
|
onValueChange={(value: AutoGenerationType) => {
|
|
|
|
|
const currentConfig = config.autoGeneration || { type: "none", enabled: false };
|
|
|
|
|
handleChange("autoGeneration", {
|
|
|
|
|
...currentConfig,
|
|
|
|
|
type: value,
|
|
|
|
|
});
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
<SelectTrigger>
|
|
|
|
|
<SelectValue placeholder="자동생성 타입 선택" />
|
|
|
|
|
</SelectTrigger>
|
|
|
|
|
<SelectContent>
|
|
|
|
|
<SelectItem value="none">자동생성 없음</SelectItem>
|
|
|
|
|
<SelectItem value="uuid">UUID 생성</SelectItem>
|
|
|
|
|
<SelectItem value="current_user">현재 사용자 ID</SelectItem>
|
|
|
|
|
<SelectItem value="current_time">현재 시간</SelectItem>
|
|
|
|
|
<SelectItem value="sequence">순차 번호</SelectItem>
|
2025-11-04 17:35:02 +09:00
|
|
|
<SelectItem value="numbering_rule">채번 규칙</SelectItem>
|
2025-09-19 12:19:34 +09:00
|
|
|
<SelectItem value="random_string">랜덤 문자열</SelectItem>
|
|
|
|
|
<SelectItem value="random_number">랜덤 숫자</SelectItem>
|
|
|
|
|
<SelectItem value="company_code">회사 코드</SelectItem>
|
|
|
|
|
<SelectItem value="department">부서 코드</SelectItem>
|
|
|
|
|
</SelectContent>
|
|
|
|
|
</Select>
|
|
|
|
|
|
|
|
|
|
{/* 선택된 타입 설명 */}
|
|
|
|
|
{config.autoGeneration?.type && config.autoGeneration.type !== "none" && (
|
|
|
|
|
<div className="text-xs text-gray-500">
|
|
|
|
|
{AutoGenerationUtils.getTypeDescription(config.autoGeneration.type)}
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
2025-11-04 17:35:02 +09:00
|
|
|
|
|
|
|
|
{/* 채번 규칙 선택 */}
|
|
|
|
|
{config.autoGeneration?.type === "numbering_rule" && (
|
|
|
|
|
<div className="space-y-2">
|
|
|
|
|
<Label htmlFor="numberingRuleId">
|
|
|
|
|
채번 규칙 선택 <span className="text-destructive">*</span>
|
|
|
|
|
</Label>
|
|
|
|
|
<Select
|
|
|
|
|
value={config.autoGeneration?.options?.numberingRuleId || ""}
|
|
|
|
|
onValueChange={(value) => {
|
|
|
|
|
const currentConfig = config.autoGeneration!;
|
|
|
|
|
handleChange("autoGeneration", {
|
|
|
|
|
...currentConfig,
|
|
|
|
|
options: {
|
|
|
|
|
...currentConfig.options,
|
|
|
|
|
numberingRuleId: value,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}}
|
|
|
|
|
disabled={loadingRules}
|
|
|
|
|
>
|
|
|
|
|
<SelectTrigger>
|
|
|
|
|
<SelectValue placeholder={loadingRules ? "규칙 로딩 중..." : "채번 규칙 선택"} />
|
|
|
|
|
</SelectTrigger>
|
|
|
|
|
<SelectContent>
|
|
|
|
|
{numberingRules.length === 0 ? (
|
|
|
|
|
<SelectItem value="no-rules" disabled>
|
|
|
|
|
사용 가능한 규칙이 없습니다
|
|
|
|
|
</SelectItem>
|
|
|
|
|
) : (
|
|
|
|
|
numberingRules.map((rule) => (
|
|
|
|
|
<SelectItem key={rule.ruleId} value={rule.ruleId}>
|
2025-11-07 14:27:07 +09:00
|
|
|
{rule.ruleName}
|
|
|
|
|
{rule.description && (
|
|
|
|
|
<span className="text-muted-foreground ml-2 text-xs">
|
|
|
|
|
- {rule.description}
|
|
|
|
|
</span>
|
|
|
|
|
)}
|
2025-11-04 17:35:02 +09:00
|
|
|
</SelectItem>
|
|
|
|
|
))
|
|
|
|
|
)}
|
|
|
|
|
</SelectContent>
|
|
|
|
|
</Select>
|
|
|
|
|
<p className="text-muted-foreground text-xs">
|
|
|
|
|
현재 메뉴에서 사용 가능한 채번 규칙만 표시됩니다
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
2025-09-19 12:19:34 +09:00
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{/* 자동생성 옵션 */}
|
|
|
|
|
{config.autoGeneration?.enabled &&
|
|
|
|
|
config.autoGeneration?.type &&
|
|
|
|
|
["random_string", "random_number", "sequence"].includes(config.autoGeneration.type) && (
|
|
|
|
|
<div className="space-y-2">
|
|
|
|
|
<Label>자동생성 옵션</Label>
|
|
|
|
|
|
|
|
|
|
{/* 길이 설정 (랜덤 문자열/숫자용) */}
|
|
|
|
|
{["random_string", "random_number"].includes(config.autoGeneration.type) && (
|
|
|
|
|
<div className="space-y-1">
|
|
|
|
|
<Label htmlFor="autoGenLength" className="text-xs">
|
|
|
|
|
길이
|
|
|
|
|
</Label>
|
|
|
|
|
<Input
|
|
|
|
|
id="autoGenLength"
|
|
|
|
|
type="number"
|
|
|
|
|
min="1"
|
|
|
|
|
max="50"
|
|
|
|
|
value={
|
|
|
|
|
config.autoGeneration?.options?.length || (config.autoGeneration.type === "random_string" ? 8 : 6)
|
|
|
|
|
}
|
|
|
|
|
onChange={(e) => {
|
|
|
|
|
const currentConfig = config.autoGeneration!;
|
|
|
|
|
handleChange("autoGeneration", {
|
|
|
|
|
...currentConfig,
|
|
|
|
|
options: {
|
|
|
|
|
...currentConfig.options,
|
|
|
|
|
length: parseInt(e.target.value) || 8,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{/* 접두사 */}
|
|
|
|
|
<div className="space-y-1">
|
|
|
|
|
<Label htmlFor="autoGenPrefix" className="text-xs">
|
|
|
|
|
접두사
|
|
|
|
|
</Label>
|
|
|
|
|
<Input
|
|
|
|
|
id="autoGenPrefix"
|
|
|
|
|
value={config.autoGeneration?.options?.prefix || ""}
|
|
|
|
|
onChange={(e) => {
|
|
|
|
|
const currentConfig = config.autoGeneration!;
|
|
|
|
|
handleChange("autoGeneration", {
|
|
|
|
|
...currentConfig,
|
|
|
|
|
options: {
|
|
|
|
|
...currentConfig.options,
|
|
|
|
|
prefix: e.target.value,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* 접미사 */}
|
|
|
|
|
<div className="space-y-1">
|
|
|
|
|
<Label htmlFor="autoGenSuffix" className="text-xs">
|
|
|
|
|
접미사
|
|
|
|
|
</Label>
|
|
|
|
|
<Input
|
|
|
|
|
id="autoGenSuffix"
|
|
|
|
|
value={config.autoGeneration?.options?.suffix || ""}
|
|
|
|
|
onChange={(e) => {
|
|
|
|
|
const currentConfig = config.autoGeneration!;
|
|
|
|
|
handleChange("autoGeneration", {
|
|
|
|
|
...currentConfig,
|
|
|
|
|
options: {
|
|
|
|
|
...currentConfig.options,
|
|
|
|
|
suffix: e.target.value,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* 미리보기 */}
|
|
|
|
|
<div className="space-y-1">
|
|
|
|
|
<Label className="text-xs">미리보기</Label>
|
|
|
|
|
<div className="rounded border bg-gray-100 p-2 text-xs">
|
|
|
|
|
{AutoGenerationUtils.generatePreviewValue(config.autoGeneration)}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
2025-09-11 18:38:28 +09:00
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
};
|