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
1 changed files with 72 additions and 63 deletions

View File

@ -1346,54 +1346,67 @@ export class ScreenManagementService {
// ========================================
/**
* 릿 ()
* 릿 () ( Raw Query )
*/
async getTemplatesByCompany(
companyCode: string,
type?: string,
isPublic?: boolean
): Promise<ScreenTemplate[]> {
const whereClause: any = {};
const whereConditions: string[] = [];
const params: any[] = [];
if (companyCode !== "*") {
whereClause.company_code = companyCode;
whereConditions.push(`company_code = $${params.length + 1}`);
params.push(companyCode);
}
if (type) {
whereClause.template_type = type;
whereConditions.push(`template_type = $${params.length + 1}`);
params.push(type);
}
if (isPublic !== undefined) {
whereClause.is_public = isPublic;
whereConditions.push(`is_public = $${params.length + 1}`);
params.push(isPublic);
}
const templates = await prisma.screen_templates.findMany({
where: whereClause,
orderBy: { created_date: "desc" },
});
const whereSQL = whereConditions.length > 0 ? `WHERE ${whereConditions.join(" AND ")}` : "";
const templates = await query<any>(
`SELECT * FROM screen_templates
${whereSQL}
ORDER BY created_date DESC`,
params
);
return templates.map(this.mapToScreenTemplate);
}
/**
* 릿
* 릿 ( Raw Query )
*/
async createTemplate(
templateData: Partial<ScreenTemplate>
): Promise<ScreenTemplate> {
const template = await prisma.screen_templates.create({
data: {
template_name: templateData.templateName!,
template_type: templateData.templateType!,
company_code: templateData.companyCode!,
description: templateData.description,
layout_data: templateData.layoutData
? JSON.parse(JSON.stringify(templateData.layoutData))
const [template] = await query<any>(
`INSERT INTO screen_templates (
template_name, template_type, company_code, description,
layout_data, is_public, created_by
) VALUES ($1, $2, $3, $4, $5, $6, $7)
RETURNING *`,
[
templateData.templateName!,
templateData.templateType!,
templateData.companyCode!,
templateData.description || null,
templateData.layoutData
? JSON.stringify(JSON.parse(JSON.stringify(templateData.layoutData)))
: null,
is_public: templateData.isPublic || false,
created_by: templateData.createdBy,
},
});
templateData.isPublic || false,
templateData.createdBy || null,
]
);
return this.mapToScreenTemplate(template);
}
@ -1403,75 +1416,71 @@ export class ScreenManagementService {
// ========================================
/**
* -
* - ( Raw Query )
*/
async assignScreenToMenu(
screenId: number,
assignmentData: MenuAssignmentRequest
): Promise<void> {
// 중복 할당 방지
const existingAssignment = await prisma.screen_menu_assignments.findFirst({
where: {
screen_id: screenId,
menu_objid: assignmentData.menuObjid,
company_code: assignmentData.companyCode,
},
});
const existing = await query<{ assignment_id: number }>(
`SELECT assignment_id FROM screen_menu_assignments
WHERE screen_id = $1 AND menu_objid = $2 AND company_code = $3
LIMIT 1`,
[screenId, assignmentData.menuObjid, assignmentData.companyCode]
);
if (existingAssignment) {
if (existing.length > 0) {
throw new Error("이미 할당된 화면입니다.");
}
await prisma.screen_menu_assignments.create({
data: {
screen_id: screenId,
menu_objid: assignmentData.menuObjid,
company_code: assignmentData.companyCode,
display_order: assignmentData.displayOrder || 0,
created_by: assignmentData.createdBy,
},
});
await query(
`INSERT INTO screen_menu_assignments (
screen_id, menu_objid, company_code, display_order, created_by
) VALUES ($1, $2, $3, $4, $5)`,
[
screenId,
assignmentData.menuObjid,
assignmentData.companyCode,
assignmentData.displayOrder || 0,
assignmentData.createdBy || null,
]
);
}
/**
*
* ( Raw Query )
*/
async getScreensByMenu(
menuObjid: number,
companyCode: string
): Promise<ScreenDefinition[]> {
const assignments = await prisma.screen_menu_assignments.findMany({
where: {
menu_objid: menuObjid,
company_code: companyCode,
is_active: "Y",
},
include: {
screen: true,
},
orderBy: { display_order: "asc" },
});
return assignments.map((assignment) =>
this.mapToScreenDefinition(assignment.screen)
const screens = await query<any>(
`SELECT sd.* FROM screen_menu_assignments sma
INNER JOIN screen_definitions sd ON sma.screen_id = sd.screen_id
WHERE sma.menu_objid = $1
AND sma.company_code = $2
AND sma.is_active = 'Y'
ORDER BY sma.display_order ASC`,
[menuObjid, companyCode]
);
return screens.map((screen) => this.mapToScreenDefinition(screen));
}
/**
* -
* - ( Raw Query )
*/
async unassignScreenFromMenu(
screenId: number,
menuObjid: number,
companyCode: string
): Promise<void> {
await prisma.screen_menu_assignments.deleteMany({
where: {
screen_id: screenId,
menu_objid: menuObjid,
company_code: companyCode,
},
});
await query(
`DELETE FROM screen_menu_assignments
WHERE screen_id = $1 AND menu_objid = $2 AND company_code = $3`,
[screenId, menuObjid, companyCode]
);
}
// ========================================