feat: Phase 2.1 Stage 3 complete - 템플릿 & 메뉴 관리 전환 (17/46)

Stage 3 완료: 템플릿 & 메뉴 관리 Raw Query 전환

 전환 완료 (5개 Prisma 호출):

**템플릿 관리 (2개):**
11. getTemplatesByCompany() - 템플릿 목록 조회 (동적 WHERE)
12. createTemplate() - 템플릿 생성 (JSON layout_data)

**메뉴 할당 관리 (3개):**
13. assignScreenToMenu() - 메뉴 할당 (중복 확인 + INSERT)
14. getScreensByMenu() - 메뉴별 화면 조회 (JOIN screen_definitions)
15. unassignScreenFromMenu() - 메뉴 할당 해제 (DELETE)

📊 진행률: 17/46 (37.0%)
🎯 다음: Stage 4 복잡한 기능 (트랜잭션, Raw Query 개선)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
kjs
2025-09-30 16:33:27 +09:00
parent 67dced74bd
commit 74351e816b
@@ -1346,54 +1346,67 @@ export class ScreenManagementService {
// ======================================== // ========================================
/** /**
* 템플릿 목록 조회 (회사별) * 템플릿 목록 조회 (회사별) (✅ Raw Query 전환 완료)
*/ */
async getTemplatesByCompany( async getTemplatesByCompany(
companyCode: string, companyCode: string,
type?: string, type?: string,
isPublic?: boolean isPublic?: boolean
): Promise<ScreenTemplate[]> { ): Promise<ScreenTemplate[]> {
const whereClause: any = {}; const whereConditions: string[] = [];
const params: any[] = [];
if (companyCode !== "*") { if (companyCode !== "*") {
whereClause.company_code = companyCode; whereConditions.push(`company_code = $${params.length + 1}`);
params.push(companyCode);
} }
if (type) { if (type) {
whereClause.template_type = type; whereConditions.push(`template_type = $${params.length + 1}`);
params.push(type);
} }
if (isPublic !== undefined) { if (isPublic !== undefined) {
whereClause.is_public = isPublic; whereConditions.push(`is_public = $${params.length + 1}`);
params.push(isPublic);
} }
const templates = await prisma.screen_templates.findMany({ const whereSQL = whereConditions.length > 0 ? `WHERE ${whereConditions.join(" AND ")}` : "";
where: whereClause,
orderBy: { created_date: "desc" }, const templates = await query<any>(
}); `SELECT * FROM screen_templates
${whereSQL}
ORDER BY created_date DESC`,
params
);
return templates.map(this.mapToScreenTemplate); return templates.map(this.mapToScreenTemplate);
} }
/** /**
* 템플릿 생성 * 템플릿 생성 (✅ Raw Query 전환 완료)
*/ */
async createTemplate( async createTemplate(
templateData: Partial<ScreenTemplate> templateData: Partial<ScreenTemplate>
): Promise<ScreenTemplate> { ): Promise<ScreenTemplate> {
const template = await prisma.screen_templates.create({ const [template] = await query<any>(
data: { `INSERT INTO screen_templates (
template_name: templateData.templateName!, template_name, template_type, company_code, description,
template_type: templateData.templateType!, layout_data, is_public, created_by
company_code: templateData.companyCode!, ) VALUES ($1, $2, $3, $4, $5, $6, $7)
description: templateData.description, RETURNING *`,
layout_data: templateData.layoutData [
? JSON.parse(JSON.stringify(templateData.layoutData)) templateData.templateName!,
templateData.templateType!,
templateData.companyCode!,
templateData.description || null,
templateData.layoutData
? JSON.stringify(JSON.parse(JSON.stringify(templateData.layoutData)))
: null, : null,
is_public: templateData.isPublic || false, templateData.isPublic || false,
created_by: templateData.createdBy, templateData.createdBy || null,
}, ]
}); );
return this.mapToScreenTemplate(template); return this.mapToScreenTemplate(template);
} }
@@ -1403,75 +1416,71 @@ export class ScreenManagementService {
// ======================================== // ========================================
/** /**
* 화면-메뉴 할당 * 화면-메뉴 할당 (✅ Raw Query 전환 완료)
*/ */
async assignScreenToMenu( async assignScreenToMenu(
screenId: number, screenId: number,
assignmentData: MenuAssignmentRequest assignmentData: MenuAssignmentRequest
): Promise<void> { ): Promise<void> {
// 중복 할당 방지 // 중복 할당 방지
const existingAssignment = await prisma.screen_menu_assignments.findFirst({ const existing = await query<{ assignment_id: number }>(
where: { `SELECT assignment_id FROM screen_menu_assignments
screen_id: screenId, WHERE screen_id = $1 AND menu_objid = $2 AND company_code = $3
menu_objid: assignmentData.menuObjid, LIMIT 1`,
company_code: assignmentData.companyCode, [screenId, assignmentData.menuObjid, assignmentData.companyCode]
}, );
});
if (existingAssignment) { if (existing.length > 0) {
throw new Error("이미 할당된 화면입니다."); throw new Error("이미 할당된 화면입니다.");
} }
await prisma.screen_menu_assignments.create({ await query(
data: { `INSERT INTO screen_menu_assignments (
screen_id: screenId, screen_id, menu_objid, company_code, display_order, created_by
menu_objid: assignmentData.menuObjid, ) VALUES ($1, $2, $3, $4, $5)`,
company_code: assignmentData.companyCode, [
display_order: assignmentData.displayOrder || 0, screenId,
created_by: assignmentData.createdBy, assignmentData.menuObjid,
}, assignmentData.companyCode,
}); assignmentData.displayOrder || 0,
assignmentData.createdBy || null,
]
);
} }
/** /**
* 메뉴별 화면 목록 조회 * 메뉴별 화면 목록 조회 (✅ Raw Query 전환 완료)
*/ */
async getScreensByMenu( async getScreensByMenu(
menuObjid: number, menuObjid: number,
companyCode: string companyCode: string
): Promise<ScreenDefinition[]> { ): Promise<ScreenDefinition[]> {
const assignments = await prisma.screen_menu_assignments.findMany({ const screens = await query<any>(
where: { `SELECT sd.* FROM screen_menu_assignments sma
menu_objid: menuObjid, INNER JOIN screen_definitions sd ON sma.screen_id = sd.screen_id
company_code: companyCode, WHERE sma.menu_objid = $1
is_active: "Y", AND sma.company_code = $2
}, AND sma.is_active = 'Y'
include: { ORDER BY sma.display_order ASC`,
screen: true, [menuObjid, companyCode]
},
orderBy: { display_order: "asc" },
});
return assignments.map((assignment) =>
this.mapToScreenDefinition(assignment.screen)
); );
return screens.map((screen) => this.mapToScreenDefinition(screen));
} }
/** /**
* 화면-메뉴 할당 해제 * 화면-메뉴 할당 해제 (✅ Raw Query 전환 완료)
*/ */
async unassignScreenFromMenu( async unassignScreenFromMenu(
screenId: number, screenId: number,
menuObjid: number, menuObjid: number,
companyCode: string companyCode: string
): Promise<void> { ): Promise<void> {
await prisma.screen_menu_assignments.deleteMany({ await query(
where: { `DELETE FROM screen_menu_assignments
screen_id: screenId, WHERE screen_id = $1 AND menu_objid = $2 AND company_code = $3`,
menu_objid: menuObjid, [screenId, menuObjid, companyCode]
company_code: companyCode, );
},
});
} }
// ======================================== // ========================================