웹타입 컴포넌트 분리작업

This commit is contained in:
kjs
2025-09-09 14:29:04 +09:00
parent 540d82e7e4
commit a17602c643
76 changed files with 16660 additions and 1735 deletions

View File

@@ -19,6 +19,9 @@ import commonCodeRoutes from "./routes/commonCodeRoutes";
import dynamicFormRoutes from "./routes/dynamicFormRoutes";
import fileRoutes from "./routes/fileRoutes";
import companyManagementRoutes from "./routes/companyManagementRoutes";
import webTypeStandardRoutes from "./routes/webTypeStandardRoutes";
import buttonActionStandardRoutes from "./routes/buttonActionStandardRoutes";
import screenStandardRoutes from "./routes/screenStandardRoutes";
// import userRoutes from './routes/userRoutes';
// import menuRoutes from './routes/menuRoutes';
@@ -101,6 +104,9 @@ app.use("/api/common-codes", commonCodeRoutes);
app.use("/api/dynamic-form", dynamicFormRoutes);
app.use("/api/files", fileRoutes);
app.use("/api/company-management", companyManagementRoutes);
app.use("/api/admin/web-types", webTypeStandardRoutes);
app.use("/api/admin/button-actions", buttonActionStandardRoutes);
app.use("/api/screen", screenStandardRoutes);
// app.use('/api/users', userRoutes);
// app.use('/api/menus', menuRoutes);

View File

@@ -0,0 +1,349 @@
import { Request, Response } from "express";
import { PrismaClient } from "@prisma/client";
import { AuthenticatedRequest } from "../types/auth";
const prisma = new PrismaClient();
export class ButtonActionStandardController {
// 버튼 액션 목록 조회
static async getButtonActions(req: Request, res: Response) {
try {
const { active, category, search } = req.query;
const where: any = {};
if (active) {
where.is_active = active as string;
}
if (category) {
where.category = category as string;
}
if (search) {
where.OR = [
{ action_name: { contains: search as string, mode: "insensitive" } },
{
action_name_eng: {
contains: search as string,
mode: "insensitive",
},
},
{ description: { contains: search as string, mode: "insensitive" } },
];
}
const buttonActions = await prisma.button_action_standards.findMany({
where,
orderBy: [{ sort_order: "asc" }, { action_type: "asc" }],
});
return res.json({
success: true,
data: buttonActions,
message: "버튼 액션 목록을 성공적으로 조회했습니다.",
});
} catch (error) {
console.error("버튼 액션 목록 조회 오류:", error);
return res.status(500).json({
success: false,
message: "버튼 액션 목록 조회 중 오류가 발생했습니다.",
error: error instanceof Error ? error.message : "알 수 없는 오류",
});
}
}
// 버튼 액션 상세 조회
static async getButtonAction(req: Request, res: Response) {
try {
const { actionType } = req.params;
const buttonAction = await prisma.button_action_standards.findUnique({
where: { action_type: actionType },
});
if (!buttonAction) {
return res.status(404).json({
success: false,
message: "해당 버튼 액션을 찾을 수 없습니다.",
});
}
return res.json({
success: true,
data: buttonAction,
message: "버튼 액션 정보를 성공적으로 조회했습니다.",
});
} catch (error) {
console.error("버튼 액션 상세 조회 오류:", error);
return res.status(500).json({
success: false,
message: "버튼 액션 조회 중 오류가 발생했습니다.",
error: error instanceof Error ? error.message : "알 수 없는 오류",
});
}
}
// 버튼 액션 생성
static async createButtonAction(req: AuthenticatedRequest, res: Response) {
try {
const {
action_type,
action_name,
action_name_eng,
description,
category = "general",
default_text,
default_text_eng,
default_icon,
default_color,
default_variant = "default",
confirmation_required = false,
confirmation_message,
validation_rules,
action_config,
sort_order = 0,
is_active = "Y",
} = req.body;
// 필수 필드 검증
if (!action_type || !action_name) {
return res.status(400).json({
success: false,
message: "액션 타입과 이름은 필수입니다.",
});
}
// 중복 체크
const existingAction = await prisma.button_action_standards.findUnique({
where: { action_type },
});
if (existingAction) {
return res.status(409).json({
success: false,
message: "이미 존재하는 액션 타입입니다.",
});
}
const newButtonAction = await prisma.button_action_standards.create({
data: {
action_type,
action_name,
action_name_eng,
description,
category,
default_text,
default_text_eng,
default_icon,
default_color,
default_variant,
confirmation_required,
confirmation_message,
validation_rules,
action_config,
sort_order,
is_active,
created_by: req.user?.userId || "system",
updated_by: req.user?.userId || "system",
},
});
return res.status(201).json({
success: true,
data: newButtonAction,
message: "버튼 액션이 성공적으로 생성되었습니다.",
});
} catch (error) {
console.error("버튼 액션 생성 오류:", error);
return res.status(500).json({
success: false,
message: "버튼 액션 생성 중 오류가 발생했습니다.",
error: error instanceof Error ? error.message : "알 수 없는 오류",
});
}
}
// 버튼 액션 수정
static async updateButtonAction(req: AuthenticatedRequest, res: Response) {
try {
const { actionType } = req.params;
const {
action_name,
action_name_eng,
description,
category,
default_text,
default_text_eng,
default_icon,
default_color,
default_variant,
confirmation_required,
confirmation_message,
validation_rules,
action_config,
sort_order,
is_active,
} = req.body;
// 존재 여부 확인
const existingAction = await prisma.button_action_standards.findUnique({
where: { action_type: actionType },
});
if (!existingAction) {
return res.status(404).json({
success: false,
message: "해당 버튼 액션을 찾을 수 없습니다.",
});
}
const updatedButtonAction = await prisma.button_action_standards.update({
where: { action_type: actionType },
data: {
action_name,
action_name_eng,
description,
category,
default_text,
default_text_eng,
default_icon,
default_color,
default_variant,
confirmation_required,
confirmation_message,
validation_rules,
action_config,
sort_order,
is_active,
updated_by: req.user?.userId || "system",
updated_date: new Date(),
},
});
return res.json({
success: true,
data: updatedButtonAction,
message: "버튼 액션이 성공적으로 수정되었습니다.",
});
} catch (error) {
console.error("버튼 액션 수정 오류:", error);
return res.status(500).json({
success: false,
message: "버튼 액션 수정 중 오류가 발생했습니다.",
error: error instanceof Error ? error.message : "알 수 없는 오류",
});
}
}
// 버튼 액션 삭제
static async deleteButtonAction(req: Request, res: Response) {
try {
const { actionType } = req.params;
// 존재 여부 확인
const existingAction = await prisma.button_action_standards.findUnique({
where: { action_type: actionType },
});
if (!existingAction) {
return res.status(404).json({
success: false,
message: "해당 버튼 액션을 찾을 수 없습니다.",
});
}
await prisma.button_action_standards.delete({
where: { action_type: actionType },
});
return res.json({
success: true,
message: "버튼 액션이 성공적으로 삭제되었습니다.",
});
} catch (error) {
console.error("버튼 액션 삭제 오류:", error);
return res.status(500).json({
success: false,
message: "버튼 액션 삭제 중 오류가 발생했습니다.",
error: error instanceof Error ? error.message : "알 수 없는 오류",
});
}
}
// 버튼 액션 정렬 순서 업데이트
static async updateButtonActionSortOrder(
req: AuthenticatedRequest,
res: Response
) {
try {
const { buttonActions } = req.body; // [{ action_type: 'save', sort_order: 1 }, ...]
if (!Array.isArray(buttonActions)) {
return res.status(400).json({
success: false,
message: "유효하지 않은 데이터 형식입니다.",
});
}
// 트랜잭션으로 일괄 업데이트
await prisma.$transaction(
buttonActions.map((item) =>
prisma.button_action_standards.update({
where: { action_type: item.action_type },
data: {
sort_order: item.sort_order,
updated_by: req.user?.userId || "system",
updated_date: new Date(),
},
})
)
);
return res.json({
success: true,
message: "버튼 액션 정렬 순서가 성공적으로 업데이트되었습니다.",
});
} catch (error) {
console.error("버튼 액션 정렬 순서 업데이트 오류:", error);
return res.status(500).json({
success: false,
message: "정렬 순서 업데이트 중 오류가 발생했습니다.",
error: error instanceof Error ? error.message : "알 수 없는 오류",
});
}
}
// 버튼 액션 카테고리 목록 조회
static async getButtonActionCategories(req: Request, res: Response) {
try {
const categories = await prisma.button_action_standards.groupBy({
by: ["category"],
where: {
is_active: "Y",
},
_count: {
category: true,
},
});
const categoryList = categories.map((item) => ({
category: item.category,
count: item._count.category,
}));
return res.json({
success: true,
data: categoryList,
message: "버튼 액션 카테고리 목록을 성공적으로 조회했습니다.",
});
} catch (error) {
console.error("버튼 액션 카테고리 조회 오류:", error);
return res.status(500).json({
success: false,
message: "카테고리 조회 중 오류가 발생했습니다.",
error: error instanceof Error ? error.message : "알 수 없는 오류",
});
}
}
}

View File

@@ -0,0 +1,330 @@
import { Request, Response } from "express";
import { PrismaClient } from "@prisma/client";
import { AuthenticatedRequest } from "../types/auth";
const prisma = new PrismaClient();
export class WebTypeStandardController {
// 웹타입 목록 조회
static async getWebTypes(req: Request, res: Response) {
try {
const { active, category, search } = req.query;
const where: any = {};
if (active) {
where.is_active = active as string;
}
if (category) {
where.category = category as string;
}
if (search) {
where.OR = [
{ type_name: { contains: search as string, mode: "insensitive" } },
{
type_name_eng: { contains: search as string, mode: "insensitive" },
},
{ description: { contains: search as string, mode: "insensitive" } },
];
}
const webTypes = await prisma.web_type_standards.findMany({
where,
orderBy: [{ sort_order: "asc" }, { web_type: "asc" }],
});
return res.json({
success: true,
data: webTypes,
message: "웹타입 목록을 성공적으로 조회했습니다.",
});
} catch (error) {
console.error("웹타입 목록 조회 오류:", error);
return res.status(500).json({
success: false,
message: "웹타입 목록 조회 중 오류가 발생했습니다.",
error: error instanceof Error ? error.message : "알 수 없는 오류",
});
}
}
// 웹타입 상세 조회
static async getWebType(req: Request, res: Response) {
try {
const { webType } = req.params;
const webTypeData = await prisma.web_type_standards.findUnique({
where: { web_type: webType },
});
if (!webTypeData) {
return res.status(404).json({
success: false,
message: "해당 웹타입을 찾을 수 없습니다.",
});
}
return res.json({
success: true,
data: webTypeData,
message: "웹타입 정보를 성공적으로 조회했습니다.",
});
} catch (error) {
console.error("웹타입 상세 조회 오류:", error);
return res.status(500).json({
success: false,
message: "웹타입 조회 중 오류가 발생했습니다.",
error: error instanceof Error ? error.message : "알 수 없는 오류",
});
}
}
// 웹타입 생성
static async createWebType(req: AuthenticatedRequest, res: Response) {
try {
const {
web_type,
type_name,
type_name_eng,
description,
category = "input",
component_name = "TextWidget",
default_config,
validation_rules,
default_style,
input_properties,
sort_order = 0,
is_active = "Y",
} = req.body;
// 필수 필드 검증
if (!web_type || !type_name) {
return res.status(400).json({
success: false,
message: "웹타입 코드와 이름은 필수입니다.",
});
}
// 중복 체크
const existingWebType = await prisma.web_type_standards.findUnique({
where: { web_type },
});
if (existingWebType) {
return res.status(409).json({
success: false,
message: "이미 존재하는 웹타입 코드입니다.",
});
}
const newWebType = await prisma.web_type_standards.create({
data: {
web_type,
type_name,
type_name_eng,
description,
category,
component_name,
default_config,
validation_rules,
default_style,
input_properties,
sort_order,
is_active,
created_by: req.user?.userId || "system",
updated_by: req.user?.userId || "system",
},
});
return res.status(201).json({
success: true,
data: newWebType,
message: "웹타입이 성공적으로 생성되었습니다.",
});
} catch (error) {
console.error("웹타입 생성 오류:", error);
return res.status(500).json({
success: false,
message: "웹타입 생성 중 오류가 발생했습니다.",
error: error instanceof Error ? error.message : "알 수 없는 오류",
});
}
}
// 웹타입 수정
static async updateWebType(req: AuthenticatedRequest, res: Response) {
try {
const { webType } = req.params;
const {
type_name,
type_name_eng,
description,
category,
component_name,
default_config,
validation_rules,
default_style,
input_properties,
sort_order,
is_active,
} = req.body;
// 존재 여부 확인
const existingWebType = await prisma.web_type_standards.findUnique({
where: { web_type: webType },
});
if (!existingWebType) {
return res.status(404).json({
success: false,
message: "해당 웹타입을 찾을 수 없습니다.",
});
}
const updatedWebType = await prisma.web_type_standards.update({
where: { web_type: webType },
data: {
type_name,
type_name_eng,
description,
category,
component_name,
default_config,
validation_rules,
default_style,
input_properties,
sort_order,
is_active,
updated_by: req.user?.userId || "system",
updated_date: new Date(),
},
});
return res.json({
success: true,
data: updatedWebType,
message: "웹타입이 성공적으로 수정되었습니다.",
});
} catch (error) {
console.error("웹타입 수정 오류:", error);
return res.status(500).json({
success: false,
message: "웹타입 수정 중 오류가 발생했습니다.",
error: error instanceof Error ? error.message : "알 수 없는 오류",
});
}
}
// 웹타입 삭제
static async deleteWebType(req: Request, res: Response) {
try {
const { webType } = req.params;
// 존재 여부 확인
const existingWebType = await prisma.web_type_standards.findUnique({
where: { web_type: webType },
});
if (!existingWebType) {
return res.status(404).json({
success: false,
message: "해당 웹타입을 찾을 수 없습니다.",
});
}
await prisma.web_type_standards.delete({
where: { web_type: webType },
});
return res.json({
success: true,
message: "웹타입이 성공적으로 삭제되었습니다.",
});
} catch (error) {
console.error("웹타입 삭제 오류:", error);
return res.status(500).json({
success: false,
message: "웹타입 삭제 중 오류가 발생했습니다.",
error: error instanceof Error ? error.message : "알 수 없는 오류",
});
}
}
// 웹타입 정렬 순서 업데이트
static async updateWebTypeSortOrder(
req: AuthenticatedRequest,
res: Response
) {
try {
const { webTypes } = req.body; // [{ web_type: 'text', sort_order: 1 }, ...]
if (!Array.isArray(webTypes)) {
return res.status(400).json({
success: false,
message: "유효하지 않은 데이터 형식입니다.",
});
}
// 트랜잭션으로 일괄 업데이트
await prisma.$transaction(
webTypes.map((item) =>
prisma.web_type_standards.update({
where: { web_type: item.web_type },
data: {
sort_order: item.sort_order,
updated_by: req.user?.userId || "system",
updated_date: new Date(),
},
})
)
);
return res.json({
success: true,
message: "웹타입 정렬 순서가 성공적으로 업데이트되었습니다.",
});
} catch (error) {
console.error("웹타입 정렬 순서 업데이트 오류:", error);
return res.status(500).json({
success: false,
message: "정렬 순서 업데이트 중 오류가 발생했습니다.",
error: error instanceof Error ? error.message : "알 수 없는 오류",
});
}
}
// 웹타입 카테고리 목록 조회
static async getWebTypeCategories(req: Request, res: Response) {
try {
const categories = await prisma.web_type_standards.groupBy({
by: ["category"],
where: {
is_active: "Y",
},
_count: {
category: true,
},
});
const categoryList = categories.map((item) => ({
category: item.category,
count: item._count.category,
}));
return res.json({
success: true,
data: categoryList,
message: "웹타입 카테고리 목록을 성공적으로 조회했습니다.",
});
} catch (error) {
console.error("웹타입 카테고리 조회 오류:", error);
return res.status(500).json({
success: false,
message: "카테고리 조회 중 오류가 발생했습니다.",
error: error instanceof Error ? error.message : "알 수 없는 오류",
});
}
}
}

View File

@@ -0,0 +1,30 @@
import express from "express";
import { ButtonActionStandardController } from "../controllers/buttonActionStandardController";
import { authenticateToken } from "../middleware/authMiddleware";
const router = express.Router();
// 모든 라우트에 인증 미들웨어 적용
router.use(authenticateToken);
// 버튼 액션 표준 관리 라우트
router.get("/", ButtonActionStandardController.getButtonActions);
router.get(
"/categories",
ButtonActionStandardController.getButtonActionCategories
);
router.get("/:actionType", ButtonActionStandardController.getButtonAction);
router.post("/", ButtonActionStandardController.createButtonAction);
router.put("/:actionType", ButtonActionStandardController.updateButtonAction);
router.delete(
"/:actionType",
ButtonActionStandardController.deleteButtonAction
);
router.put(
"/sort-order/bulk",
ButtonActionStandardController.updateButtonActionSortOrder
);
export default router;

View File

@@ -0,0 +1,25 @@
import express from "express";
import { WebTypeStandardController } from "../controllers/webTypeStandardController";
import { ButtonActionStandardController } from "../controllers/buttonActionStandardController";
import { authenticateToken } from "../middleware/authMiddleware";
const router = express.Router();
// 모든 라우트에 인증 미들웨어 적용
router.use(authenticateToken);
// 화면관리에서 사용할 조회 전용 API
router.get("/web-types", WebTypeStandardController.getWebTypes);
router.get(
"/web-types/categories",
WebTypeStandardController.getWebTypeCategories
);
router.get("/button-actions", ButtonActionStandardController.getButtonActions);
router.get(
"/button-actions/categories",
ButtonActionStandardController.getButtonActionCategories
);
export default router;

View File

@@ -0,0 +1,24 @@
import express from "express";
import { WebTypeStandardController } from "../controllers/webTypeStandardController";
import { authenticateToken } from "../middleware/authMiddleware";
const router = express.Router();
// 모든 라우트에 인증 미들웨어 적용
router.use(authenticateToken);
// 웹타입 표준 관리 라우트
router.get("/", WebTypeStandardController.getWebTypes);
router.get("/categories", WebTypeStandardController.getWebTypeCategories);
router.get("/:webType", WebTypeStandardController.getWebType);
router.post("/", WebTypeStandardController.createWebType);
router.put("/:webType", WebTypeStandardController.updateWebType);
router.delete("/:webType", WebTypeStandardController.deleteWebType);
router.put(
"/sort-order/bulk",
WebTypeStandardController.updateWebTypeSortOrder
);
export default router;