import { Response } from "express"; import { AuthenticatedRequest } from "../types/auth"; import { templateStandardService } from "../services/templateStandardService"; import { handleError } from "../utils/errorHandler"; import { checkMissingFields } from "../utils/validation"; /** * 템플릿 표준 관리 컨트롤러 */ export class TemplateStandardController { /** * 템플릿 목록 조회 */ async getTemplates(req: AuthenticatedRequest, res: Response) { try { const { active = "Y", category, search, companyCode, is_public = "Y", page = "1", limit = "50", } = req.query; const user = req.user; const userCompanyCode = user?.companyCode || "DEFAULT"; const result = await templateStandardService.getTemplates({ active: active as string, category: category as string, search: search as string, company_code: (companyCode as string) || userCompanyCode, is_public: is_public as string, page: parseInt(page as string), limit: parseInt(limit as string), }); res.json({ success: true, data: result.templates, pagination: { total: result.total, page: parseInt(page as string), limit: parseInt(limit as string), totalPages: Math.ceil(result.total / parseInt(limit as string)), }, }); } catch (error) { return handleError( res, error, "템플릿 목록 조회 중 오류가 발생했습니다." ); } } /** * 템플릿 상세 조회 */ async getTemplate(req: AuthenticatedRequest, res: Response) { try { const { templateCode } = req.params; if (!templateCode) { return res.status(400).json({ success: false, error: "템플릿 코드가 필요합니다.", }); } const template = await templateStandardService.getTemplate(templateCode); if (!template) { return res.status(404).json({ success: false, error: "템플릿을 찾을 수 없습니다.", }); } res.json({ success: true, data: template, }); } catch (error) { return handleError(res, error, "템플릿 조회 중 오류가 발생했습니다."); } } /** * 템플릿 생성 */ async createTemplate(req: AuthenticatedRequest, res: Response) { try { const user = req.user; const templateData = req.body; // 필수 필드 검증 const requiredFields = [ "template_code", "template_name", "category", "layout_config", ]; const missingFields = checkMissingFields(templateData, requiredFields); if (missingFields.length > 0) { return res.status(400).json({ success: false, error: `필수 필드가 누락되었습니다: ${missingFields.join(", ")}`, }); } // 회사 코드와 생성자 정보 추가 const templateWithMeta = { ...templateData, company_code: user?.companyCode || "DEFAULT", created_by: user?.userId || "system", updated_by: user?.userId || "system", }; const newTemplate = await templateStandardService.createTemplate(templateWithMeta); res.status(201).json({ success: true, data: newTemplate, message: "템플릿이 성공적으로 생성되었습니다.", }); } catch (error) { return handleError(res, error, "템플릿 생성 중 오류가 발생했습니다."); } } /** * 템플릿 수정 */ async updateTemplate(req: AuthenticatedRequest, res: Response) { try { const { templateCode } = req.params; const templateData = req.body; const user = req.user; if (!templateCode) { return res.status(400).json({ success: false, error: "템플릿 코드가 필요합니다.", }); } // 수정자 정보 추가 const templateWithMeta = { ...templateData, updated_by: user?.userId || "system", }; const updatedTemplate = await templateStandardService.updateTemplate( templateCode, templateWithMeta ); if (!updatedTemplate) { return res.status(404).json({ success: false, error: "템플릿을 찾을 수 없습니다.", }); } res.json({ success: true, data: updatedTemplate, message: "템플릿이 성공적으로 수정되었습니다.", }); } catch (error) { return handleError(res, error, "템플릿 수정 중 오류가 발생했습니다."); } } /** * 템플릿 삭제 */ async deleteTemplate(req: AuthenticatedRequest, res: Response) { try { const { templateCode } = req.params; if (!templateCode) { return res.status(400).json({ success: false, error: "템플릿 코드가 필요합니다.", }); } const deleted = await templateStandardService.deleteTemplate(templateCode); if (!deleted) { return res.status(404).json({ success: false, error: "템플릿을 찾을 수 없습니다.", }); } res.json({ success: true, message: "템플릿이 성공적으로 삭제되었습니다.", }); } catch (error) { return handleError(res, error, "템플릿 삭제 중 오류가 발생했습니다."); } } /** * 템플릿 정렬 순서 일괄 업데이트 */ async updateSortOrder(req: AuthenticatedRequest, res: Response) { try { const { templates } = req.body; if (!Array.isArray(templates)) { return res.status(400).json({ success: false, error: "templates는 배열이어야 합니다.", }); } await templateStandardService.updateSortOrder(templates); res.json({ success: true, message: "템플릿 정렬 순서가 성공적으로 업데이트되었습니다.", }); } catch (error) { return handleError( res, error, "템플릿 정렬 순서 업데이트 중 오류가 발생했습니다." ); } } /** * 템플릿 복제 */ async duplicateTemplate(req: AuthenticatedRequest, res: Response) { try { const { templateCode } = req.params; const { new_template_code, new_template_name } = req.body; const user = req.user; if (!templateCode || !new_template_code || !new_template_name) { return res.status(400).json({ success: false, error: "필수 필드가 누락되었습니다.", }); } const duplicatedTemplate = await templateStandardService.duplicateTemplate({ originalCode: templateCode, newCode: new_template_code, newName: new_template_name, company_code: user?.companyCode || "DEFAULT", created_by: user?.userId || "system", }); res.status(201).json({ success: true, data: duplicatedTemplate, message: "템플릿이 성공적으로 복제되었습니다.", }); } catch (error) { return handleError(res, error, "템플릿 복제 중 오류가 발생했습니다."); } } /** * 템플릿 카테고리 목록 조회 */ async getCategories(req: AuthenticatedRequest, res: Response) { try { const user = req.user; const companyCode = user?.companyCode || "DEFAULT"; const categories = await templateStandardService.getCategories(companyCode); res.json({ success: true, data: categories, }); } catch (error) { return handleError( res, error, "템플릿 카테고리 조회 중 오류가 발생했습니다." ); } } /** * 템플릿 가져오기 (JSON 파일에서) */ async importTemplate(req: AuthenticatedRequest, res: Response) { try { const user = req.user; const templateData = req.body; if (!templateData.layout_config) { return res.status(400).json({ success: false, error: "유효한 템플릿 데이터가 아닙니다.", }); } // 회사 코드와 생성자 정보 추가 const templateWithMeta = { ...templateData, company_code: user?.companyCode || "DEFAULT", created_by: user?.userId || "system", updated_by: user?.userId || "system", }; const importedTemplate = await templateStandardService.createTemplate(templateWithMeta); res.status(201).json({ success: true, data: importedTemplate, message: "템플릿이 성공적으로 가져왔습니다.", }); } catch (error) { return handleError(res, error, "템플릿 가져오기 중 오류가 발생했습니다."); } } /** * 템플릿 내보내기 (JSON 형태로) */ async exportTemplate(req: AuthenticatedRequest, res: Response) { try { const { templateCode } = req.params; if (!templateCode) { return res.status(400).json({ success: false, error: "템플릿 코드가 필요합니다.", }); } const template = await templateStandardService.getTemplate(templateCode); if (!template) { return res.status(404).json({ success: false, error: "템플릿을 찾을 수 없습니다.", }); } // 내보내기용 데이터 (메타데이터 제외) const exportData = { template_code: template.template_code, template_name: template.template_name, template_name_eng: template.template_name_eng, description: template.description, category: template.category, icon_name: template.icon_name, default_size: template.default_size, layout_config: template.layout_config, }; res.json({ success: true, data: exportData, }); } catch (error) { return handleError(res, error, "템플릿 내보내기 중 오류가 발생했습니다."); } } } export const templateStandardController = new TemplateStandardController();