feat: Phase 2.1 추가 Prisma 호출 전환 (25+/46)
추가 전환 완료: ✅ 조회 및 관리 함수들: - checkScreenDependencies() - 화면 의존성 확인 (JOIN 쿼리) - cleanupDeletedScreenMenuAssignments() - 메뉴 할당 정리 - permanentDeleteScreen() - 영구 삭제 (트랜잭션) - getDeletedScreens() - 휴지통 목록 조회 (페이징 + 테이블 레이블) 📊 진행률: 25+/46 (54%+) 🎯 다음: $queryRaw 함수들 전환 (테이블/컬럼 정보 조회) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
311811bc0a
commit
4637680de0
|
|
@ -315,14 +315,17 @@ export class ScreenManagementService {
|
||||||
}>;
|
}>;
|
||||||
}> {
|
}> {
|
||||||
// 권한 확인
|
// 권한 확인
|
||||||
const targetScreen = await prisma.screen_definitions.findUnique({
|
const targetScreens = await query<{ company_code: string | null }>(
|
||||||
where: { screen_id: screenId },
|
`SELECT company_code FROM screen_definitions WHERE screen_id = $1 LIMIT 1`,
|
||||||
});
|
[screenId]
|
||||||
|
);
|
||||||
|
|
||||||
if (!targetScreen) {
|
if (targetScreens.length === 0) {
|
||||||
throw new Error("화면을 찾을 수 없습니다.");
|
throw new Error("화면을 찾을 수 없습니다.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const targetScreen = targetScreens[0];
|
||||||
|
|
||||||
if (
|
if (
|
||||||
userCompanyCode !== "*" &&
|
userCompanyCode !== "*" &&
|
||||||
targetScreen.company_code !== "*" &&
|
targetScreen.company_code !== "*" &&
|
||||||
|
|
@ -332,19 +335,27 @@ export class ScreenManagementService {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 같은 회사의 모든 활성 화면에서 이 화면을 참조하는지 확인
|
// 같은 회사의 모든 활성 화면에서 이 화면을 참조하는지 확인
|
||||||
const whereClause = {
|
const whereConditions: string[] = ["sd.is_active != 'D'"];
|
||||||
is_active: { not: "D" },
|
const params: any[] = [];
|
||||||
...(userCompanyCode !== "*" && {
|
|
||||||
company_code: { in: [userCompanyCode, "*"] },
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
|
|
||||||
const allScreens = await prisma.screen_definitions.findMany({
|
if (userCompanyCode !== "*") {
|
||||||
where: whereClause,
|
whereConditions.push(`sd.company_code IN ($${params.length + 1}, $${params.length + 2})`);
|
||||||
include: {
|
params.push(userCompanyCode, "*");
|
||||||
layouts: true,
|
}
|
||||||
},
|
|
||||||
});
|
const whereSQL = whereConditions.join(" AND ");
|
||||||
|
|
||||||
|
// 화면과 레이아웃을 JOIN해서 조회
|
||||||
|
const allScreens = await query<any>(
|
||||||
|
`SELECT
|
||||||
|
sd.screen_id, sd.screen_name, sd.screen_code, sd.company_code,
|
||||||
|
sl.layout_id, sl.component_id, sl.component_type, sl.properties
|
||||||
|
FROM screen_definitions sd
|
||||||
|
LEFT JOIN screen_layouts sl ON sd.screen_id = sl.screen_id
|
||||||
|
WHERE ${whereSQL}
|
||||||
|
ORDER BY sd.screen_id, sl.layout_id`,
|
||||||
|
params
|
||||||
|
);
|
||||||
|
|
||||||
const dependencies: Array<{
|
const dependencies: Array<{
|
||||||
screenId: number;
|
screenId: number;
|
||||||
|
|
@ -660,44 +671,50 @@ export class ScreenManagementService {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 휴지통 화면들의 메뉴 할당 정리 (관리자용)
|
* 휴지통 화면들의 메뉴 할당 정리 (관리자용) (✅ Raw Query 전환 완료)
|
||||||
*/
|
*/
|
||||||
async cleanupDeletedScreenMenuAssignments(): Promise<{
|
async cleanupDeletedScreenMenuAssignments(): Promise<{
|
||||||
updatedCount: number;
|
updatedCount: number;
|
||||||
message: string;
|
message: string;
|
||||||
}> {
|
}> {
|
||||||
const result = await prisma.$executeRaw`
|
const result = await query(
|
||||||
UPDATE screen_menu_assignments
|
`UPDATE screen_menu_assignments
|
||||||
SET is_active = 'N'
|
SET is_active = 'N'
|
||||||
WHERE screen_id IN (
|
WHERE screen_id IN (
|
||||||
SELECT screen_id
|
SELECT screen_id
|
||||||
FROM screen_definitions
|
FROM screen_definitions
|
||||||
WHERE is_active = 'D'
|
WHERE is_active = 'D'
|
||||||
) AND is_active = 'Y'
|
) AND is_active = 'Y'`,
|
||||||
`;
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
|
const updatedCount = result.length;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
updatedCount: Number(result),
|
updatedCount,
|
||||||
message: `${result}개의 메뉴 할당이 정리되었습니다.`,
|
message: `${updatedCount}개의 메뉴 할당이 정리되었습니다.`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 화면 영구 삭제 (휴지통에서 완전 삭제)
|
* 화면 영구 삭제 (휴지통에서 완전 삭제) (✅ Raw Query 전환 완료)
|
||||||
*/
|
*/
|
||||||
async permanentDeleteScreen(
|
async permanentDeleteScreen(
|
||||||
screenId: number,
|
screenId: number,
|
||||||
userCompanyCode: string
|
userCompanyCode: string
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
// 권한 확인
|
// 권한 확인
|
||||||
const existingScreen = await prisma.screen_definitions.findUnique({
|
const screens = await query<{ company_code: string | null; is_active: string }>(
|
||||||
where: { screen_id: screenId },
|
`SELECT company_code, is_active FROM screen_definitions WHERE screen_id = $1 LIMIT 1`,
|
||||||
});
|
[screenId]
|
||||||
|
);
|
||||||
|
|
||||||
if (!existingScreen) {
|
if (screens.length === 0) {
|
||||||
throw new Error("화면을 찾을 수 없습니다.");
|
throw new Error("화면을 찾을 수 없습니다.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const existingScreen = screens[0];
|
||||||
|
|
||||||
if (
|
if (
|
||||||
userCompanyCode !== "*" &&
|
userCompanyCode !== "*" &&
|
||||||
existingScreen.company_code !== userCompanyCode
|
existingScreen.company_code !== userCompanyCode
|
||||||
|
|
@ -710,14 +727,16 @@ export class ScreenManagementService {
|
||||||
throw new Error("휴지통에 있는 화면만 영구 삭제할 수 있습니다.");
|
throw new Error("휴지통에 있는 화면만 영구 삭제할 수 있습니다.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 물리적 삭제 (CASCADE로 관련 레이아웃과 메뉴 할당도 함께 삭제됨)
|
// 물리적 삭제 (수동으로 관련 데이터 삭제)
|
||||||
await prisma.screen_definitions.delete({
|
await transaction(async (client) => {
|
||||||
where: { screen_id: screenId },
|
await client.query(`DELETE FROM screen_layouts WHERE screen_id = $1`, [screenId]);
|
||||||
|
await client.query(`DELETE FROM screen_menu_assignments WHERE screen_id = $1`, [screenId]);
|
||||||
|
await client.query(`DELETE FROM screen_definitions WHERE screen_id = $1`, [screenId]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 휴지통 화면 목록 조회
|
* 휴지통 화면 목록 조회 (✅ Raw Query 전환 완료)
|
||||||
*/
|
*/
|
||||||
async getDeletedScreens(
|
async getDeletedScreens(
|
||||||
companyCode: string,
|
companyCode: string,
|
||||||
|
|
@ -732,37 +751,54 @@ export class ScreenManagementService {
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
> {
|
> {
|
||||||
const whereClause: any = { is_active: "D" };
|
const offset = (page - 1) * size;
|
||||||
|
const whereConditions: string[] = ["is_active = 'D'"];
|
||||||
|
const params: any[] = [];
|
||||||
|
|
||||||
if (companyCode !== "*") {
|
if (companyCode !== "*") {
|
||||||
whereClause.company_code = companyCode;
|
whereConditions.push(`company_code = $${params.length + 1}`);
|
||||||
|
params.push(companyCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
const [screens, total] = await Promise.all([
|
const whereSQL = whereConditions.join(" AND ");
|
||||||
prisma.screen_definitions.findMany({
|
|
||||||
where: whereClause,
|
const [screens, totalResult] = await Promise.all([
|
||||||
skip: (page - 1) * size,
|
query<any>(
|
||||||
take: size,
|
`SELECT * FROM screen_definitions
|
||||||
orderBy: { deleted_date: "desc" },
|
WHERE ${whereSQL}
|
||||||
}),
|
ORDER BY deleted_date DESC NULLS LAST
|
||||||
prisma.screen_definitions.count({ where: whereClause }),
|
LIMIT $${params.length + 1} OFFSET $${params.length + 2}`,
|
||||||
|
[...params, size, offset]
|
||||||
|
),
|
||||||
|
query<{ count: string }>(
|
||||||
|
`SELECT COUNT(*)::text as count FROM screen_definitions WHERE ${whereSQL}`,
|
||||||
|
params
|
||||||
|
),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
const total = parseInt(totalResult[0]?.count || "0", 10);
|
||||||
|
|
||||||
// 테이블 라벨 정보를 한 번에 조회
|
// 테이블 라벨 정보를 한 번에 조회
|
||||||
const tableNames = [
|
const tableNames = [
|
||||||
...new Set(screens.map((s) => s.table_name).filter(Boolean)),
|
...new Set(screens.map((s: any) => s.table_name).filter(Boolean)),
|
||||||
];
|
];
|
||||||
const tableLabels = await prisma.table_labels.findMany({
|
|
||||||
where: { table_name: { in: tableNames } },
|
|
||||||
select: { table_name: true, table_label: true },
|
|
||||||
});
|
|
||||||
|
|
||||||
const tableLabelMap = new Map(
|
let tableLabelMap = new Map<string, string>();
|
||||||
tableLabels.map((tl) => [tl.table_name, tl.table_label || tl.table_name])
|
|
||||||
|
if (tableNames.length > 0) {
|
||||||
|
const placeholders = tableNames.map((_, i) => `$${i + 1}`).join(", ");
|
||||||
|
const tableLabels = await query<{ table_name: string; table_label: string | null }>(
|
||||||
|
`SELECT table_name, table_label FROM table_labels WHERE table_name IN (${placeholders})`,
|
||||||
|
tableNames
|
||||||
);
|
);
|
||||||
|
|
||||||
|
tableLabelMap = new Map(
|
||||||
|
tableLabels.map((tl: any) => [tl.table_name, tl.table_label || tl.table_name])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
data: screens.map((screen) => ({
|
data: screens.map((screen: any) => ({
|
||||||
...this.mapToScreenDefinition(screen, tableLabelMap),
|
...this.mapToScreenDefinition(screen, tableLabelMap),
|
||||||
deletedDate: screen.deleted_date || undefined,
|
deletedDate: screen.deleted_date || undefined,
|
||||||
deletedBy: screen.deleted_by || undefined,
|
deletedBy: screen.deleted_by || undefined,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue