feat: POP 회사별 자동 세팅 — 메뉴 활성화 시 레이아웃 자동 생성
- 로그인 시 POP 메뉴 발견 → 해당 회사용 POP 레이아웃 8개 자동 복제 - 템플릿: 공통(*) 우선, COMPANY_7 폴백 - 회사명 자동 치환 (탑씰 → 해당 회사명) - screen_definitions 공통(*) 화면은 모든 회사 접근 허용 - 프로필 POP 모드 메뉴: POP 메뉴 있는 회사만 표시 - getLayoutPop 개별 자동 복제 (2중 안전망)
This commit is contained in:
@@ -7,6 +7,7 @@ import { JwtUtils } from "../utils/jwtUtils";
|
||||
import { LoginRequest, UserInfo, ApiResponse, PersonBean } from "../types/auth";
|
||||
import { logger } from "../utils/logger";
|
||||
import { sendSmartFactoryLog } from "../utils/smartFactoryLog";
|
||||
import { query, queryOne } from "../database/db";
|
||||
|
||||
export class AuthController {
|
||||
/**
|
||||
@@ -104,6 +105,14 @@ export class AuthController {
|
||||
popLandingPath = "/pop";
|
||||
}
|
||||
logger.debug(`POP 랜딩 경로: ${popLandingPath}`);
|
||||
|
||||
// POP 메뉴가 존재하면 해당 회사의 POP 레이아웃 자동 초기화 (비동기)
|
||||
if (popLandingPath) {
|
||||
const companyCode = loginResult.userInfo.companyCode || "ILSHIN";
|
||||
AuthController.initPopLayoutsForCompany(companyCode).catch((err) => {
|
||||
logger.warn("POP 레이아웃 자동 초기화 중 오류 (무시):", err);
|
||||
});
|
||||
}
|
||||
} catch (popError) {
|
||||
logger.warn("POP 메뉴 조회 중 오류 (무시):", popError);
|
||||
}
|
||||
@@ -562,4 +571,78 @@ export class AuthController {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* POP 레이아웃 자동 초기화
|
||||
* 해당 회사의 screen_layouts_pop 레코드가 없으면
|
||||
* 템플릿(공통 '*' 또는 COMPANY_7)에서 복제하여 생성
|
||||
*
|
||||
* 기본 POP 화면 ID: 5, 6, 7, 8, 6526, 6527, 6528, 6529
|
||||
*/
|
||||
static async initPopLayoutsForCompany(companyCode: string): Promise<void> {
|
||||
// SUPER_ADMIN이나 공통(*)은 초기화 불필요
|
||||
if (companyCode === "*" || companyCode === "COMPANY_7") return;
|
||||
|
||||
const POP_SCREEN_IDS = [5, 6, 7, 8, 6526, 6527, 6528, 6529];
|
||||
|
||||
// 이미 해당 회사의 POP 레이아웃이 하나라도 있으면 스킵 (중복 초기화 방지)
|
||||
const existing = await query<{ cnt: string }>(
|
||||
`SELECT COUNT(*)::text AS cnt FROM screen_layouts_pop
|
||||
WHERE company_code = $1 AND screen_id = ANY($2::int[])`,
|
||||
[companyCode, POP_SCREEN_IDS],
|
||||
);
|
||||
const existingCount = parseInt(existing[0]?.cnt || "0", 10);
|
||||
if (existingCount > 0) {
|
||||
logger.debug(`POP 레이아웃 이미 존재 (${companyCode}): ${existingCount}개, 스킵`);
|
||||
return;
|
||||
}
|
||||
|
||||
logger.info(`POP 레이아웃 자동 초기화 시작: ${companyCode}`);
|
||||
|
||||
// 회사명 조회 (레이아웃 내 회사명 치환용)
|
||||
const companyInfo = await queryOne<{ company_name: string }>(
|
||||
`SELECT company_name FROM company_mng WHERE company_code = $1`,
|
||||
[companyCode],
|
||||
);
|
||||
const companyName = companyInfo?.company_name || companyCode;
|
||||
|
||||
let initCount = 0;
|
||||
for (const screenId of POP_SCREEN_IDS) {
|
||||
// 템플릿 조회: 공통(*) 우선, 없으면 COMPANY_7 폴백
|
||||
let template = await queryOne<{ layout_data: any }>(
|
||||
`SELECT layout_data FROM screen_layouts_pop
|
||||
WHERE screen_id = $1 AND company_code = '*'`,
|
||||
[screenId],
|
||||
);
|
||||
if (!template) {
|
||||
template = await queryOne<{ layout_data: any }>(
|
||||
`SELECT layout_data FROM screen_layouts_pop
|
||||
WHERE screen_id = $1 AND company_code = 'COMPANY_7'`,
|
||||
[screenId],
|
||||
);
|
||||
}
|
||||
|
||||
if (!template) {
|
||||
logger.debug(`POP 템플릿 없음 (screen_id=${screenId}), 스킵`);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 레이아웃 복제 + 회사명 치환
|
||||
const layoutStr = JSON.stringify(template.layout_data);
|
||||
const replacedStr = layoutStr
|
||||
.replace(/\(주\)탑씰/g, companyName)
|
||||
.replace(/탑씰/g, companyName)
|
||||
.replace(/TOPSEAL/gi, companyName);
|
||||
|
||||
await query(
|
||||
`INSERT INTO screen_layouts_pop (screen_id, company_code, layout_data, created_at, updated_at, created_by, updated_by)
|
||||
VALUES ($1, $2, $3, NOW(), NOW(), 'SYSTEM', 'SYSTEM')
|
||||
ON CONFLICT (screen_id, company_code) DO NOTHING`,
|
||||
[screenId, companyCode, replacedStr],
|
||||
);
|
||||
initCount++;
|
||||
}
|
||||
|
||||
logger.info(`POP 레이아웃 자동 초기화 완료: ${companyCode}, ${initCount}개 화면`);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user