422 lines
13 KiB
TypeScript
422 lines
13 KiB
TypeScript
import { Request, Response } from "express";
|
|
import { AuthenticatedRequest } from "../types/auth";
|
|
import { query, queryOne, transaction } from "../database/db";
|
|
|
|
export class ButtonActionStandardController {
|
|
// 버튼 액션 목록 조회
|
|
static async getButtonActions(req: Request, res: Response) {
|
|
try {
|
|
const { active, category, search } = req.query;
|
|
|
|
const whereConditions: string[] = [];
|
|
const queryParams: any[] = [];
|
|
let paramIndex = 1;
|
|
|
|
if (active) {
|
|
whereConditions.push(`is_active = $${paramIndex}`);
|
|
queryParams.push(active as string);
|
|
paramIndex++;
|
|
}
|
|
|
|
if (category) {
|
|
whereConditions.push(`category = $${paramIndex}`);
|
|
queryParams.push(category as string);
|
|
paramIndex++;
|
|
}
|
|
|
|
if (search) {
|
|
whereConditions.push(`(action_name ILIKE $${paramIndex} OR action_name_eng ILIKE $${paramIndex} OR description ILIKE $${paramIndex})`);
|
|
queryParams.push(`%${search}%`);
|
|
paramIndex++;
|
|
}
|
|
|
|
const whereClause = whereConditions.length > 0
|
|
? `WHERE ${whereConditions.join(" AND ")}`
|
|
: "";
|
|
|
|
const buttonActions = await query<any>(
|
|
`SELECT * FROM button_action_standards ${whereClause} ORDER BY sort_order ASC, action_type ASC`,
|
|
queryParams
|
|
);
|
|
|
|
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 queryOne<any>(
|
|
"SELECT * FROM button_action_standards WHERE action_type = $1 LIMIT 1",
|
|
[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 queryOne<any>(
|
|
"SELECT * FROM button_action_standards WHERE action_type = $1 LIMIT 1",
|
|
[action_type]
|
|
);
|
|
|
|
if (existingAction) {
|
|
return res.status(409).json({
|
|
success: false,
|
|
message: "이미 존재하는 액션 타입입니다.",
|
|
});
|
|
}
|
|
|
|
const [newButtonAction] = await query<any>(
|
|
`INSERT INTO button_action_standards (
|
|
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, updated_by, created_date, updated_date
|
|
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, NOW(), NOW())
|
|
RETURNING *`,
|
|
[
|
|
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 ? JSON.stringify(validation_rules) : null,
|
|
action_config ? JSON.stringify(action_config) : null,
|
|
sort_order, is_active,
|
|
req.user?.userId || "system",
|
|
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 queryOne<any>(
|
|
"SELECT * FROM button_action_standards WHERE action_type = $1 LIMIT 1",
|
|
[actionType]
|
|
);
|
|
|
|
if (!existingAction) {
|
|
return res.status(404).json({
|
|
success: false,
|
|
message: "해당 버튼 액션을 찾을 수 없습니다.",
|
|
});
|
|
}
|
|
|
|
const updateFields: string[] = [];
|
|
const updateParams: any[] = [];
|
|
let paramIndex = 1;
|
|
|
|
if (action_name !== undefined) {
|
|
updateFields.push(`action_name = $${paramIndex}`);
|
|
updateParams.push(action_name);
|
|
paramIndex++;
|
|
}
|
|
if (action_name_eng !== undefined) {
|
|
updateFields.push(`action_name_eng = $${paramIndex}`);
|
|
updateParams.push(action_name_eng);
|
|
paramIndex++;
|
|
}
|
|
if (description !== undefined) {
|
|
updateFields.push(`description = $${paramIndex}`);
|
|
updateParams.push(description);
|
|
paramIndex++;
|
|
}
|
|
if (category !== undefined) {
|
|
updateFields.push(`category = $${paramIndex}`);
|
|
updateParams.push(category);
|
|
paramIndex++;
|
|
}
|
|
if (default_text !== undefined) {
|
|
updateFields.push(`default_text = $${paramIndex}`);
|
|
updateParams.push(default_text);
|
|
paramIndex++;
|
|
}
|
|
if (default_text_eng !== undefined) {
|
|
updateFields.push(`default_text_eng = $${paramIndex}`);
|
|
updateParams.push(default_text_eng);
|
|
paramIndex++;
|
|
}
|
|
if (default_icon !== undefined) {
|
|
updateFields.push(`default_icon = $${paramIndex}`);
|
|
updateParams.push(default_icon);
|
|
paramIndex++;
|
|
}
|
|
if (default_color !== undefined) {
|
|
updateFields.push(`default_color = $${paramIndex}`);
|
|
updateParams.push(default_color);
|
|
paramIndex++;
|
|
}
|
|
if (default_variant !== undefined) {
|
|
updateFields.push(`default_variant = $${paramIndex}`);
|
|
updateParams.push(default_variant);
|
|
paramIndex++;
|
|
}
|
|
if (confirmation_required !== undefined) {
|
|
updateFields.push(`confirmation_required = $${paramIndex}`);
|
|
updateParams.push(confirmation_required);
|
|
paramIndex++;
|
|
}
|
|
if (confirmation_message !== undefined) {
|
|
updateFields.push(`confirmation_message = $${paramIndex}`);
|
|
updateParams.push(confirmation_message);
|
|
paramIndex++;
|
|
}
|
|
if (validation_rules !== undefined) {
|
|
updateFields.push(`validation_rules = $${paramIndex}`);
|
|
updateParams.push(validation_rules ? JSON.stringify(validation_rules) : null);
|
|
paramIndex++;
|
|
}
|
|
if (action_config !== undefined) {
|
|
updateFields.push(`action_config = $${paramIndex}`);
|
|
updateParams.push(action_config ? JSON.stringify(action_config) : null);
|
|
paramIndex++;
|
|
}
|
|
if (sort_order !== undefined) {
|
|
updateFields.push(`sort_order = $${paramIndex}`);
|
|
updateParams.push(sort_order);
|
|
paramIndex++;
|
|
}
|
|
if (is_active !== undefined) {
|
|
updateFields.push(`is_active = $${paramIndex}`);
|
|
updateParams.push(is_active);
|
|
paramIndex++;
|
|
}
|
|
|
|
updateFields.push(`updated_by = $${paramIndex}`);
|
|
updateParams.push(req.user?.userId || "system");
|
|
paramIndex++;
|
|
|
|
updateFields.push(`updated_date = $${paramIndex}`);
|
|
updateParams.push(new Date());
|
|
paramIndex++;
|
|
|
|
updateParams.push(actionType);
|
|
|
|
const [updatedButtonAction] = await query<any>(
|
|
`UPDATE button_action_standards SET ${updateFields.join(", ")}
|
|
WHERE action_type = $${paramIndex} RETURNING *`,
|
|
updateParams
|
|
);
|
|
|
|
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 queryOne<any>(
|
|
"SELECT * FROM button_action_standards WHERE action_type = $1 LIMIT 1",
|
|
[actionType]
|
|
);
|
|
|
|
if (!existingAction) {
|
|
return res.status(404).json({
|
|
success: false,
|
|
message: "해당 버튼 액션을 찾을 수 없습니다.",
|
|
});
|
|
}
|
|
|
|
await query<any>(
|
|
"DELETE FROM button_action_standards WHERE action_type = $1",
|
|
[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 transaction(async (client) => {
|
|
for (const item of buttonActions) {
|
|
await client.query(
|
|
`UPDATE button_action_standards
|
|
SET sort_order = $1, updated_by = $2, updated_date = NOW()
|
|
WHERE action_type = $3`,
|
|
[item.sort_order, req.user?.userId || "system", item.action_type]
|
|
);
|
|
}
|
|
});
|
|
|
|
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 query<{ category: string; count: string }>(
|
|
`SELECT category, COUNT(*) as count
|
|
FROM button_action_standards
|
|
WHERE is_active = $1
|
|
GROUP BY category`,
|
|
["Y"]
|
|
);
|
|
|
|
const categoryList = categories.map((item) => ({
|
|
category: item.category,
|
|
count: parseInt(item.count),
|
|
}));
|
|
|
|
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 : "알 수 없는 오류",
|
|
});
|
|
}
|
|
}
|
|
}
|