템플릿관리, 컴포넌트 관리
This commit is contained in:
52
backend-node/scripts/add-button-webtype.js
Normal file
52
backend-node/scripts/add-button-webtype.js
Normal file
@@ -0,0 +1,52 @@
|
||||
const { PrismaClient } = require("@prisma/client");
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
async function addButtonWebType() {
|
||||
try {
|
||||
console.log("🔍 버튼 웹타입 확인 중...");
|
||||
|
||||
// 기존 button 웹타입 확인
|
||||
const existingButton = await prisma.web_type_standards.findUnique({
|
||||
where: { web_type: "button" },
|
||||
});
|
||||
|
||||
if (existingButton) {
|
||||
console.log("✅ 버튼 웹타입이 이미 존재합니다.");
|
||||
console.log("📄 기존 설정:", JSON.stringify(existingButton, null, 2));
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("➕ 버튼 웹타입 추가 중...");
|
||||
|
||||
// 버튼 웹타입 추가
|
||||
const buttonWebType = await prisma.web_type_standards.create({
|
||||
data: {
|
||||
web_type: "button",
|
||||
type_name: "버튼",
|
||||
type_name_eng: "Button",
|
||||
description: "클릭 가능한 버튼 컴포넌트",
|
||||
category: "action",
|
||||
component_name: "ButtonWidget",
|
||||
config_panel: "ButtonConfigPanel",
|
||||
default_config: {
|
||||
actionType: "custom",
|
||||
variant: "default",
|
||||
},
|
||||
sort_order: 100,
|
||||
is_active: "Y",
|
||||
created_by: "system",
|
||||
updated_by: "system",
|
||||
},
|
||||
});
|
||||
|
||||
console.log("✅ 버튼 웹타입이 성공적으로 추가되었습니다!");
|
||||
console.log("📄 추가된 설정:", JSON.stringify(buttonWebType, null, 2));
|
||||
} catch (error) {
|
||||
console.error("❌ 버튼 웹타입 추가 실패:", error);
|
||||
} finally {
|
||||
await prisma.$disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
addButtonWebType();
|
||||
74
backend-node/scripts/create-component-table.js
Normal file
74
backend-node/scripts/create-component-table.js
Normal file
@@ -0,0 +1,74 @@
|
||||
const { PrismaClient } = require("@prisma/client");
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
async function createComponentTable() {
|
||||
try {
|
||||
console.log("🔧 component_standards 테이블 생성 중...");
|
||||
|
||||
// 테이블 생성 SQL
|
||||
await prisma.$executeRaw`
|
||||
CREATE TABLE IF NOT EXISTS component_standards (
|
||||
component_code VARCHAR(50) PRIMARY KEY,
|
||||
component_name VARCHAR(100) NOT NULL,
|
||||
component_name_eng VARCHAR(100),
|
||||
description TEXT,
|
||||
category VARCHAR(50) NOT NULL,
|
||||
icon_name VARCHAR(50),
|
||||
default_size JSON,
|
||||
component_config JSON NOT NULL,
|
||||
preview_image VARCHAR(255),
|
||||
sort_order INTEGER DEFAULT 0,
|
||||
is_active CHAR(1) DEFAULT 'Y',
|
||||
is_public CHAR(1) DEFAULT 'Y',
|
||||
company_code VARCHAR(50) NOT NULL,
|
||||
created_date TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP,
|
||||
created_by VARCHAR(50),
|
||||
updated_date TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_by VARCHAR(50)
|
||||
)
|
||||
`;
|
||||
|
||||
console.log("✅ component_standards 테이블 생성 완료");
|
||||
|
||||
// 인덱스 생성
|
||||
await prisma.$executeRaw`
|
||||
CREATE INDEX IF NOT EXISTS idx_component_standards_category
|
||||
ON component_standards (category)
|
||||
`;
|
||||
|
||||
await prisma.$executeRaw`
|
||||
CREATE INDEX IF NOT EXISTS idx_component_standards_company
|
||||
ON component_standards (company_code)
|
||||
`;
|
||||
|
||||
console.log("✅ 인덱스 생성 완료");
|
||||
|
||||
// 테이블 코멘트 추가
|
||||
await prisma.$executeRaw`
|
||||
COMMENT ON TABLE component_standards IS 'UI 컴포넌트 표준 정보를 저장하는 테이블'
|
||||
`;
|
||||
|
||||
console.log("✅ 테이블 코멘트 추가 완료");
|
||||
} catch (error) {
|
||||
console.error("❌ 테이블 생성 실패:", error);
|
||||
throw error;
|
||||
} finally {
|
||||
await prisma.$disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
// 실행
|
||||
if (require.main === module) {
|
||||
createComponentTable()
|
||||
.then(() => {
|
||||
console.log("🎉 테이블 생성 완료!");
|
||||
process.exit(0);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("💥 테이블 생성 실패:", error);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = { createComponentTable };
|
||||
294
backend-node/scripts/seed-templates.js
Normal file
294
backend-node/scripts/seed-templates.js
Normal file
@@ -0,0 +1,294 @@
|
||||
const { PrismaClient } = require("@prisma/client");
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
// 기본 템플릿 데이터 정의
|
||||
const defaultTemplates = [
|
||||
{
|
||||
template_code: "advanced-data-table-v2",
|
||||
template_name: "고급 데이터 테이블 v2",
|
||||
template_name_eng: "Advanced Data Table v2",
|
||||
description:
|
||||
"검색, 필터링, 페이징, CRUD 기능이 포함된 완전한 데이터 테이블 컴포넌트",
|
||||
category: "table",
|
||||
icon_name: "table",
|
||||
default_size: {
|
||||
width: 1000,
|
||||
height: 680,
|
||||
},
|
||||
layout_config: {
|
||||
components: [
|
||||
{
|
||||
type: "datatable",
|
||||
label: "고급 데이터 테이블",
|
||||
position: { x: 0, y: 0 },
|
||||
size: { width: 1000, height: 680 },
|
||||
style: {
|
||||
border: "1px solid #e5e7eb",
|
||||
borderRadius: "8px",
|
||||
backgroundColor: "#ffffff",
|
||||
padding: "0",
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
id: "id",
|
||||
label: "ID",
|
||||
type: "number",
|
||||
visible: true,
|
||||
sortable: true,
|
||||
filterable: false,
|
||||
width: 80,
|
||||
},
|
||||
{
|
||||
id: "name",
|
||||
label: "이름",
|
||||
type: "text",
|
||||
visible: true,
|
||||
sortable: true,
|
||||
filterable: true,
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
id: "email",
|
||||
label: "이메일",
|
||||
type: "email",
|
||||
visible: true,
|
||||
sortable: true,
|
||||
filterable: true,
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
id: "status",
|
||||
label: "상태",
|
||||
type: "select",
|
||||
visible: true,
|
||||
sortable: true,
|
||||
filterable: true,
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
id: "created_date",
|
||||
label: "생성일",
|
||||
type: "date",
|
||||
visible: true,
|
||||
sortable: true,
|
||||
filterable: true,
|
||||
width: 120,
|
||||
},
|
||||
],
|
||||
filters: [
|
||||
{
|
||||
id: "status",
|
||||
label: "상태",
|
||||
type: "select",
|
||||
options: [
|
||||
{ label: "전체", value: "" },
|
||||
{ label: "활성", value: "active" },
|
||||
{ label: "비활성", value: "inactive" },
|
||||
],
|
||||
},
|
||||
{ id: "name", label: "이름", type: "text" },
|
||||
{ id: "email", label: "이메일", type: "text" },
|
||||
],
|
||||
pagination: {
|
||||
enabled: true,
|
||||
pageSize: 10,
|
||||
pageSizeOptions: [5, 10, 20, 50, 100],
|
||||
showPageSizeSelector: true,
|
||||
showPageInfo: true,
|
||||
showFirstLast: true,
|
||||
},
|
||||
actions: {
|
||||
showSearchButton: true,
|
||||
searchButtonText: "검색",
|
||||
enableExport: true,
|
||||
enableRefresh: true,
|
||||
enableAdd: true,
|
||||
enableEdit: true,
|
||||
enableDelete: true,
|
||||
addButtonText: "추가",
|
||||
editButtonText: "수정",
|
||||
deleteButtonText: "삭제",
|
||||
},
|
||||
addModalConfig: {
|
||||
title: "새 데이터 추가",
|
||||
description: "테이블에 새로운 데이터를 추가합니다.",
|
||||
width: "lg",
|
||||
layout: "two-column",
|
||||
gridColumns: 2,
|
||||
fieldOrder: ["name", "email", "status"],
|
||||
requiredFields: ["name", "email"],
|
||||
hiddenFields: ["id", "created_date"],
|
||||
advancedFieldConfigs: {
|
||||
status: {
|
||||
type: "select",
|
||||
options: [
|
||||
{ label: "활성", value: "active" },
|
||||
{ label: "비활성", value: "inactive" },
|
||||
],
|
||||
},
|
||||
},
|
||||
submitButtonText: "추가",
|
||||
cancelButtonText: "취소",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
sort_order: 1,
|
||||
is_active: "Y",
|
||||
is_public: "Y",
|
||||
company_code: "*",
|
||||
created_by: "system",
|
||||
updated_by: "system",
|
||||
},
|
||||
{
|
||||
template_code: "universal-button",
|
||||
template_name: "범용 버튼",
|
||||
template_name_eng: "Universal Button",
|
||||
description:
|
||||
"다양한 기능을 설정할 수 있는 범용 버튼. 상세설정에서 기능을 선택하세요.",
|
||||
category: "button",
|
||||
icon_name: "mouse-pointer",
|
||||
default_size: {
|
||||
width: 80,
|
||||
height: 36,
|
||||
},
|
||||
layout_config: {
|
||||
components: [
|
||||
{
|
||||
type: "widget",
|
||||
widgetType: "button",
|
||||
label: "버튼",
|
||||
position: { x: 0, y: 0 },
|
||||
size: { width: 80, height: 36 },
|
||||
style: {
|
||||
backgroundColor: "#3b82f6",
|
||||
color: "#ffffff",
|
||||
border: "none",
|
||||
borderRadius: "6px",
|
||||
fontSize: "14px",
|
||||
fontWeight: "500",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
sort_order: 2,
|
||||
is_active: "Y",
|
||||
is_public: "Y",
|
||||
company_code: "*",
|
||||
created_by: "system",
|
||||
updated_by: "system",
|
||||
},
|
||||
{
|
||||
template_code: "file-upload",
|
||||
template_name: "파일 첨부",
|
||||
template_name_eng: "File Upload",
|
||||
description: "드래그앤드롭 파일 업로드 영역",
|
||||
category: "file",
|
||||
icon_name: "upload",
|
||||
default_size: {
|
||||
width: 300,
|
||||
height: 120,
|
||||
},
|
||||
layout_config: {
|
||||
components: [
|
||||
{
|
||||
type: "widget",
|
||||
widgetType: "file",
|
||||
label: "파일 첨부",
|
||||
position: { x: 0, y: 0 },
|
||||
size: { width: 300, height: 120 },
|
||||
style: {
|
||||
border: "2px dashed #d1d5db",
|
||||
borderRadius: "8px",
|
||||
backgroundColor: "#f9fafb",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
fontSize: "14px",
|
||||
color: "#6b7280",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
sort_order: 3,
|
||||
is_active: "Y",
|
||||
is_public: "Y",
|
||||
company_code: "*",
|
||||
created_by: "system",
|
||||
updated_by: "system",
|
||||
},
|
||||
{
|
||||
template_code: "form-container",
|
||||
template_name: "폼 컨테이너",
|
||||
template_name_eng: "Form Container",
|
||||
description: "입력 폼을 위한 기본 컨테이너 레이아웃",
|
||||
category: "form",
|
||||
icon_name: "form",
|
||||
default_size: {
|
||||
width: 400,
|
||||
height: 300,
|
||||
},
|
||||
layout_config: {
|
||||
components: [
|
||||
{
|
||||
type: "container",
|
||||
label: "폼 컨테이너",
|
||||
position: { x: 0, y: 0 },
|
||||
size: { width: 400, height: 300 },
|
||||
style: {
|
||||
border: "1px solid #e5e7eb",
|
||||
borderRadius: "8px",
|
||||
backgroundColor: "#ffffff",
|
||||
padding: "16px",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
sort_order: 4,
|
||||
is_active: "Y",
|
||||
is_public: "Y",
|
||||
company_code: "*",
|
||||
created_by: "system",
|
||||
updated_by: "system",
|
||||
},
|
||||
];
|
||||
|
||||
async function seedTemplates() {
|
||||
console.log("🌱 템플릿 시드 데이터 삽입 시작...");
|
||||
|
||||
try {
|
||||
// 기존 템플릿이 있는지 확인하고 없는 경우에만 삽입
|
||||
for (const template of defaultTemplates) {
|
||||
const existing = await prisma.template_standards.findUnique({
|
||||
where: { template_code: template.template_code },
|
||||
});
|
||||
|
||||
if (!existing) {
|
||||
await prisma.template_standards.create({
|
||||
data: template,
|
||||
});
|
||||
console.log(`✅ 템플릿 '${template.template_name}' 생성됨`);
|
||||
} else {
|
||||
console.log(`⏭️ 템플릿 '${template.template_name}' 이미 존재함`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log("🎉 템플릿 시드 데이터 삽입 완료!");
|
||||
} catch (error) {
|
||||
console.error("❌ 템플릿 시드 데이터 삽입 실패:", error);
|
||||
throw error;
|
||||
} finally {
|
||||
await prisma.$disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
// 스크립트가 직접 실행될 때만 시드 함수 실행
|
||||
if (require.main === module) {
|
||||
seedTemplates().catch((error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = { seedTemplates };
|
||||
411
backend-node/scripts/seed-ui-components.js
Normal file
411
backend-node/scripts/seed-ui-components.js
Normal file
@@ -0,0 +1,411 @@
|
||||
const { PrismaClient } = require("@prisma/client");
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
// 실제 UI 구성에 필요한 컴포넌트들
|
||||
const uiComponents = [
|
||||
// === 액션 컴포넌트 ===
|
||||
{
|
||||
component_code: "button-primary",
|
||||
component_name: "기본 버튼",
|
||||
component_name_eng: "Primary Button",
|
||||
description: "일반적인 액션을 위한 기본 버튼 컴포넌트",
|
||||
category: "action",
|
||||
icon_name: "MousePointer",
|
||||
default_size: { width: 100, height: 36 },
|
||||
component_config: {
|
||||
type: "button",
|
||||
variant: "primary",
|
||||
text: "버튼",
|
||||
action: "custom",
|
||||
style: {
|
||||
backgroundColor: "#3b82f6",
|
||||
color: "#ffffff",
|
||||
borderRadius: "6px",
|
||||
fontSize: "14px",
|
||||
fontWeight: "500",
|
||||
},
|
||||
},
|
||||
sort_order: 10,
|
||||
},
|
||||
{
|
||||
component_code: "button-secondary",
|
||||
component_name: "보조 버튼",
|
||||
component_name_eng: "Secondary Button",
|
||||
description: "보조 액션을 위한 버튼 컴포넌트",
|
||||
category: "action",
|
||||
icon_name: "MousePointer",
|
||||
default_size: { width: 100, height: 36 },
|
||||
component_config: {
|
||||
type: "button",
|
||||
variant: "secondary",
|
||||
text: "취소",
|
||||
action: "cancel",
|
||||
style: {
|
||||
backgroundColor: "#f1f5f9",
|
||||
color: "#475569",
|
||||
borderRadius: "6px",
|
||||
fontSize: "14px",
|
||||
},
|
||||
},
|
||||
sort_order: 11,
|
||||
},
|
||||
|
||||
// === 레이아웃 컴포넌트 ===
|
||||
{
|
||||
component_code: "card-basic",
|
||||
component_name: "기본 카드",
|
||||
component_name_eng: "Basic Card",
|
||||
description: "정보를 그룹화하는 기본 카드 컴포넌트",
|
||||
category: "layout",
|
||||
icon_name: "Square",
|
||||
default_size: { width: 400, height: 300 },
|
||||
component_config: {
|
||||
type: "card",
|
||||
title: "카드 제목",
|
||||
showHeader: true,
|
||||
showFooter: false,
|
||||
style: {
|
||||
backgroundColor: "#ffffff",
|
||||
border: "1px solid #e5e7eb",
|
||||
borderRadius: "8px",
|
||||
padding: "16px",
|
||||
boxShadow: "0 1px 3px rgba(0, 0, 0, 0.1)",
|
||||
},
|
||||
},
|
||||
sort_order: 20,
|
||||
},
|
||||
{
|
||||
component_code: "dashboard-grid",
|
||||
component_name: "대시보드 그리드",
|
||||
component_name_eng: "Dashboard Grid",
|
||||
description: "대시보드를 위한 그리드 레이아웃 컴포넌트",
|
||||
category: "layout",
|
||||
icon_name: "LayoutGrid",
|
||||
default_size: { width: 800, height: 600 },
|
||||
component_config: {
|
||||
type: "dashboard",
|
||||
columns: 3,
|
||||
gap: 16,
|
||||
items: [],
|
||||
style: {
|
||||
backgroundColor: "#f8fafc",
|
||||
padding: "20px",
|
||||
borderRadius: "8px",
|
||||
},
|
||||
},
|
||||
sort_order: 21,
|
||||
},
|
||||
{
|
||||
component_code: "panel-collapsible",
|
||||
component_name: "접을 수 있는 패널",
|
||||
component_name_eng: "Collapsible Panel",
|
||||
description: "접고 펼칠 수 있는 패널 컴포넌트",
|
||||
category: "layout",
|
||||
icon_name: "ChevronDown",
|
||||
default_size: { width: 500, height: 200 },
|
||||
component_config: {
|
||||
type: "panel",
|
||||
title: "패널 제목",
|
||||
collapsible: true,
|
||||
defaultExpanded: true,
|
||||
style: {
|
||||
backgroundColor: "#ffffff",
|
||||
border: "1px solid #e5e7eb",
|
||||
borderRadius: "8px",
|
||||
},
|
||||
},
|
||||
sort_order: 22,
|
||||
},
|
||||
|
||||
// === 데이터 표시 컴포넌트 ===
|
||||
{
|
||||
component_code: "stats-card",
|
||||
component_name: "통계 카드",
|
||||
component_name_eng: "Statistics Card",
|
||||
description: "수치와 통계를 표시하는 카드 컴포넌트",
|
||||
category: "data",
|
||||
icon_name: "BarChart3",
|
||||
default_size: { width: 250, height: 120 },
|
||||
component_config: {
|
||||
type: "stats",
|
||||
title: "총 판매량",
|
||||
value: "1,234",
|
||||
unit: "개",
|
||||
trend: "up",
|
||||
percentage: "+12.5%",
|
||||
style: {
|
||||
backgroundColor: "#ffffff",
|
||||
border: "1px solid #e5e7eb",
|
||||
borderRadius: "8px",
|
||||
padding: "20px",
|
||||
},
|
||||
},
|
||||
sort_order: 30,
|
||||
},
|
||||
{
|
||||
component_code: "progress-bar",
|
||||
component_name: "진행률 표시",
|
||||
component_name_eng: "Progress Bar",
|
||||
description: "작업 진행률을 표시하는 컴포넌트",
|
||||
category: "data",
|
||||
icon_name: "BarChart2",
|
||||
default_size: { width: 300, height: 60 },
|
||||
component_config: {
|
||||
type: "progress",
|
||||
label: "진행률",
|
||||
value: 65,
|
||||
max: 100,
|
||||
showPercentage: true,
|
||||
style: {
|
||||
backgroundColor: "#f1f5f9",
|
||||
borderRadius: "4px",
|
||||
height: "8px",
|
||||
},
|
||||
},
|
||||
sort_order: 31,
|
||||
},
|
||||
{
|
||||
component_code: "chart-basic",
|
||||
component_name: "기본 차트",
|
||||
component_name_eng: "Basic Chart",
|
||||
description: "데이터를 시각화하는 기본 차트 컴포넌트",
|
||||
category: "data",
|
||||
icon_name: "TrendingUp",
|
||||
default_size: { width: 500, height: 300 },
|
||||
component_config: {
|
||||
type: "chart",
|
||||
chartType: "line",
|
||||
title: "차트 제목",
|
||||
data: [],
|
||||
options: {
|
||||
responsive: true,
|
||||
plugins: {
|
||||
legend: { position: "top" },
|
||||
},
|
||||
},
|
||||
},
|
||||
sort_order: 32,
|
||||
},
|
||||
|
||||
// === 네비게이션 컴포넌트 ===
|
||||
{
|
||||
component_code: "breadcrumb",
|
||||
component_name: "브레드크럼",
|
||||
component_name_eng: "Breadcrumb",
|
||||
description: "현재 위치를 표시하는 네비게이션 컴포넌트",
|
||||
category: "navigation",
|
||||
icon_name: "ChevronRight",
|
||||
default_size: { width: 400, height: 32 },
|
||||
component_config: {
|
||||
type: "breadcrumb",
|
||||
items: [
|
||||
{ label: "홈", href: "/" },
|
||||
{ label: "관리자", href: "/admin" },
|
||||
{ label: "현재 페이지" },
|
||||
],
|
||||
separator: ">",
|
||||
},
|
||||
sort_order: 40,
|
||||
},
|
||||
{
|
||||
component_code: "tabs-horizontal",
|
||||
component_name: "가로 탭",
|
||||
component_name_eng: "Horizontal Tabs",
|
||||
description: "컨텐츠를 탭으로 구분하는 네비게이션 컴포넌트",
|
||||
category: "navigation",
|
||||
icon_name: "Tabs",
|
||||
default_size: { width: 500, height: 300 },
|
||||
component_config: {
|
||||
type: "tabs",
|
||||
orientation: "horizontal",
|
||||
tabs: [
|
||||
{ id: "tab1", label: "탭 1", content: "첫 번째 탭 내용" },
|
||||
{ id: "tab2", label: "탭 2", content: "두 번째 탭 내용" },
|
||||
],
|
||||
defaultTab: "tab1",
|
||||
},
|
||||
sort_order: 41,
|
||||
},
|
||||
{
|
||||
component_code: "pagination",
|
||||
component_name: "페이지네이션",
|
||||
component_name_eng: "Pagination",
|
||||
description: "페이지를 나눠서 표시하는 네비게이션 컴포넌트",
|
||||
category: "navigation",
|
||||
icon_name: "ChevronLeft",
|
||||
default_size: { width: 300, height: 40 },
|
||||
component_config: {
|
||||
type: "pagination",
|
||||
currentPage: 1,
|
||||
totalPages: 10,
|
||||
showFirst: true,
|
||||
showLast: true,
|
||||
showPrevNext: true,
|
||||
},
|
||||
sort_order: 42,
|
||||
},
|
||||
|
||||
// === 피드백 컴포넌트 ===
|
||||
{
|
||||
component_code: "alert-info",
|
||||
component_name: "정보 알림",
|
||||
component_name_eng: "Info Alert",
|
||||
description: "정보를 사용자에게 알리는 컴포넌트",
|
||||
category: "feedback",
|
||||
icon_name: "Info",
|
||||
default_size: { width: 400, height: 60 },
|
||||
component_config: {
|
||||
type: "alert",
|
||||
variant: "info",
|
||||
title: "알림",
|
||||
message: "중요한 정보를 확인해주세요.",
|
||||
dismissible: true,
|
||||
icon: true,
|
||||
},
|
||||
sort_order: 50,
|
||||
},
|
||||
{
|
||||
component_code: "badge-status",
|
||||
component_name: "상태 뱃지",
|
||||
component_name_eng: "Status Badge",
|
||||
description: "상태나 카테고리를 표시하는 뱃지 컴포넌트",
|
||||
category: "feedback",
|
||||
icon_name: "Tag",
|
||||
default_size: { width: 80, height: 24 },
|
||||
component_config: {
|
||||
type: "badge",
|
||||
text: "활성",
|
||||
variant: "success",
|
||||
size: "sm",
|
||||
style: {
|
||||
backgroundColor: "#10b981",
|
||||
color: "#ffffff",
|
||||
borderRadius: "12px",
|
||||
fontSize: "12px",
|
||||
},
|
||||
},
|
||||
sort_order: 51,
|
||||
},
|
||||
{
|
||||
component_code: "loading-spinner",
|
||||
component_name: "로딩 스피너",
|
||||
component_name_eng: "Loading Spinner",
|
||||
description: "로딩 상태를 표시하는 스피너 컴포넌트",
|
||||
category: "feedback",
|
||||
icon_name: "RefreshCw",
|
||||
default_size: { width: 100, height: 100 },
|
||||
component_config: {
|
||||
type: "loading",
|
||||
variant: "spinner",
|
||||
size: "md",
|
||||
message: "로딩 중...",
|
||||
overlay: false,
|
||||
},
|
||||
sort_order: 52,
|
||||
},
|
||||
|
||||
// === 입력 컴포넌트 ===
|
||||
{
|
||||
component_code: "search-box",
|
||||
component_name: "검색 박스",
|
||||
component_name_eng: "Search Box",
|
||||
description: "검색 기능이 있는 입력 컴포넌트",
|
||||
category: "input",
|
||||
icon_name: "Search",
|
||||
default_size: { width: 300, height: 40 },
|
||||
component_config: {
|
||||
type: "search",
|
||||
placeholder: "검색어를 입력하세요...",
|
||||
showButton: true,
|
||||
debounce: 500,
|
||||
style: {
|
||||
borderRadius: "20px",
|
||||
border: "1px solid #d1d5db",
|
||||
},
|
||||
},
|
||||
sort_order: 60,
|
||||
},
|
||||
{
|
||||
component_code: "filter-dropdown",
|
||||
component_name: "필터 드롭다운",
|
||||
component_name_eng: "Filter Dropdown",
|
||||
description: "데이터 필터링을 위한 드롭다운 컴포넌트",
|
||||
category: "input",
|
||||
icon_name: "Filter",
|
||||
default_size: { width: 200, height: 40 },
|
||||
component_config: {
|
||||
type: "filter",
|
||||
label: "필터",
|
||||
options: [
|
||||
{ value: "all", label: "전체" },
|
||||
{ value: "active", label: "활성" },
|
||||
{ value: "inactive", label: "비활성" },
|
||||
],
|
||||
defaultValue: "all",
|
||||
multiple: false,
|
||||
},
|
||||
sort_order: 61,
|
||||
},
|
||||
];
|
||||
|
||||
async function seedUIComponents() {
|
||||
try {
|
||||
console.log("🚀 UI 컴포넌트 시딩 시작...");
|
||||
|
||||
// 기존 데이터 삭제
|
||||
console.log("📝 기존 컴포넌트 데이터 삭제 중...");
|
||||
await prisma.$executeRaw`DELETE FROM component_standards`;
|
||||
|
||||
// 새 컴포넌트 데이터 삽입
|
||||
console.log("📦 새로운 UI 컴포넌트 삽입 중...");
|
||||
|
||||
for (const component of uiComponents) {
|
||||
await prisma.component_standards.create({
|
||||
data: {
|
||||
...component,
|
||||
company_code: "DEFAULT",
|
||||
created_by: "system",
|
||||
updated_by: "system",
|
||||
},
|
||||
});
|
||||
console.log(`✅ ${component.component_name} 컴포넌트 생성됨`);
|
||||
}
|
||||
|
||||
console.log(
|
||||
`\n🎉 총 ${uiComponents.length}개의 UI 컴포넌트가 성공적으로 생성되었습니다!`
|
||||
);
|
||||
|
||||
// 카테고리별 통계
|
||||
const categoryCounts = {};
|
||||
uiComponents.forEach((component) => {
|
||||
categoryCounts[component.category] =
|
||||
(categoryCounts[component.category] || 0) + 1;
|
||||
});
|
||||
|
||||
console.log("\n📊 카테고리별 컴포넌트 수:");
|
||||
Object.entries(categoryCounts).forEach(([category, count]) => {
|
||||
console.log(` ${category}: ${count}개`);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("❌ UI 컴포넌트 시딩 실패:", error);
|
||||
throw error;
|
||||
} finally {
|
||||
await prisma.$disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
// 실행
|
||||
if (require.main === module) {
|
||||
seedUIComponents()
|
||||
.then(() => {
|
||||
console.log("✨ UI 컴포넌트 시딩 완료!");
|
||||
process.exit(0);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("💥 시딩 실패:", error);
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = { seedUIComponents, uiComponents };
|
||||
121
backend-node/scripts/test-template-creation.js
Normal file
121
backend-node/scripts/test-template-creation.js
Normal file
@@ -0,0 +1,121 @@
|
||||
const { PrismaClient } = require("@prisma/client");
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
async function testTemplateCreation() {
|
||||
console.log("🧪 템플릿 생성 테스트 시작...");
|
||||
|
||||
try {
|
||||
// 1. 테이블 존재 여부 확인
|
||||
console.log("1. 템플릿 테이블 존재 여부 확인 중...");
|
||||
|
||||
try {
|
||||
const count = await prisma.template_standards.count();
|
||||
console.log(`✅ template_standards 테이블 발견 (현재 ${count}개 레코드)`);
|
||||
} catch (error) {
|
||||
if (error.code === "P2021") {
|
||||
console.log("❌ template_standards 테이블이 존재하지 않습니다.");
|
||||
console.log("👉 데이터베이스 마이그레이션이 필요합니다.");
|
||||
return;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
|
||||
// 2. 샘플 템플릿 생성 테스트
|
||||
console.log("2. 샘플 템플릿 생성 중...");
|
||||
|
||||
const sampleTemplate = {
|
||||
template_code: "test-button-" + Date.now(),
|
||||
template_name: "테스트 버튼",
|
||||
template_name_eng: "Test Button",
|
||||
description: "테스트용 버튼 템플릿",
|
||||
category: "button",
|
||||
icon_name: "mouse-pointer",
|
||||
default_size: {
|
||||
width: 80,
|
||||
height: 36,
|
||||
},
|
||||
layout_config: {
|
||||
components: [
|
||||
{
|
||||
type: "widget",
|
||||
widgetType: "button",
|
||||
label: "테스트 버튼",
|
||||
position: { x: 0, y: 0 },
|
||||
size: { width: 80, height: 36 },
|
||||
style: {
|
||||
backgroundColor: "#3b82f6",
|
||||
color: "#ffffff",
|
||||
border: "none",
|
||||
borderRadius: "6px",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
sort_order: 999,
|
||||
is_active: "Y",
|
||||
is_public: "Y",
|
||||
company_code: "*",
|
||||
created_by: "test",
|
||||
updated_by: "test",
|
||||
};
|
||||
|
||||
const created = await prisma.template_standards.create({
|
||||
data: sampleTemplate,
|
||||
});
|
||||
|
||||
console.log("✅ 샘플 템플릿 생성 성공:", created.template_code);
|
||||
|
||||
// 3. 생성된 템플릿 조회 테스트
|
||||
console.log("3. 템플릿 조회 테스트 중...");
|
||||
|
||||
const retrieved = await prisma.template_standards.findUnique({
|
||||
where: { template_code: created.template_code },
|
||||
});
|
||||
|
||||
if (retrieved) {
|
||||
console.log("✅ 템플릿 조회 성공:", retrieved.template_name);
|
||||
console.log(
|
||||
"📄 Layout Config:",
|
||||
JSON.stringify(retrieved.layout_config, null, 2)
|
||||
);
|
||||
}
|
||||
|
||||
// 4. 카테고리 목록 조회 테스트
|
||||
console.log("4. 카테고리 목록 조회 테스트 중...");
|
||||
|
||||
const categories = await prisma.template_standards.findMany({
|
||||
where: { is_active: "Y" },
|
||||
select: { category: true },
|
||||
distinct: ["category"],
|
||||
});
|
||||
|
||||
console.log(
|
||||
"✅ 발견된 카테고리:",
|
||||
categories.map((c) => c.category)
|
||||
);
|
||||
|
||||
// 5. 테스트 데이터 정리
|
||||
console.log("5. 테스트 데이터 정리 중...");
|
||||
|
||||
await prisma.template_standards.delete({
|
||||
where: { template_code: created.template_code },
|
||||
});
|
||||
|
||||
console.log("✅ 테스트 데이터 정리 완료");
|
||||
|
||||
console.log("🎉 모든 테스트 통과!");
|
||||
} catch (error) {
|
||||
console.error("❌ 테스트 실패:", error);
|
||||
console.error("📋 상세 정보:", {
|
||||
message: error.message,
|
||||
code: error.code,
|
||||
stack: error.stack?.split("\n").slice(0, 5),
|
||||
});
|
||||
} finally {
|
||||
await prisma.$disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
// 스크립트 실행
|
||||
testTemplateCreation();
|
||||
Reference in New Issue
Block a user