feat(screen): PC/POP 화면관리 데이터 분리 (excludePop 필터)
PC 화면관리에서 POP 전용 화면과 그룹이 함께 표시되어 혼동을 주는 문제를 해결하기 위해 excludePop 필터를 도입한다. [백엔드] - getScreensByCompany: NOT EXISTS 서브쿼리로 screen_layouts_pop에 레이아웃이 있는 화면 제외, 테이블 별칭 sd로 통일 - getScreenGroups: hierarchy_path 기반으로 POP 그룹 제외 (hierarchy_path IS NULL OR NOT LIKE 'POP/%') - 두 API 모두 excludePop 미전달 시 기존 동작 100% 유지 [프론트엔드] - screenApi.getScreens, getScreenGroups에 excludePop 파라미터 추가 - PC 화면관리 페이지, ScreenGroupTreeView, ScreenList에서 excludePop: true 전달
This commit is contained in:
parent
15e22ba401
commit
37d93d82b1
|
|
@ -20,7 +20,7 @@ const pool = getPool();
|
|||
export const getScreenGroups = async (req: AuthenticatedRequest, res: Response) => {
|
||||
try {
|
||||
const companyCode = req.user?.companyCode || "*";
|
||||
const { page = 1, size = 20, searchTerm } = req.query;
|
||||
const { page = 1, size = 20, searchTerm, excludePop } = req.query;
|
||||
const offset = (parseInt(page as string) - 1) * parseInt(size as string);
|
||||
|
||||
let whereClause = "WHERE 1=1";
|
||||
|
|
@ -34,6 +34,11 @@ export const getScreenGroups = async (req: AuthenticatedRequest, res: Response)
|
|||
paramIndex++;
|
||||
}
|
||||
|
||||
// POP 그룹 제외 (PC 화면관리용)
|
||||
if (excludePop === "true") {
|
||||
whereClause += ` AND (hierarchy_path IS NULL OR (hierarchy_path NOT LIKE 'POP/%' AND hierarchy_path != 'POP'))`;
|
||||
}
|
||||
|
||||
// 검색어 필터링
|
||||
if (searchTerm) {
|
||||
whereClause += ` AND (group_name ILIKE $${paramIndex} OR group_code ILIKE $${paramIndex} OR description ILIKE $${paramIndex})`;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import { AuthenticatedRequest } from "../types/auth";
|
|||
export const getScreens = async (req: AuthenticatedRequest, res: Response) => {
|
||||
try {
|
||||
const userCompanyCode = (req.user as any).companyCode;
|
||||
const { page = 1, size = 20, searchTerm, companyCode } = req.query;
|
||||
const { page = 1, size = 20, searchTerm, companyCode, excludePop } = req.query;
|
||||
|
||||
// 쿼리 파라미터로 companyCode가 전달되면 해당 회사의 화면 조회 (최고 관리자 전용)
|
||||
// 아니면 현재 사용자의 companyCode 사용
|
||||
|
|
@ -24,7 +24,8 @@ export const getScreens = async (req: AuthenticatedRequest, res: Response) => {
|
|||
targetCompanyCode,
|
||||
parseInt(page as string),
|
||||
parseInt(size as string),
|
||||
searchTerm as string // 검색어 전달
|
||||
searchTerm as string,
|
||||
{ excludePop: excludePop === "true" },
|
||||
);
|
||||
|
||||
res.json({
|
||||
|
|
|
|||
|
|
@ -108,42 +108,49 @@ export class ScreenManagementService {
|
|||
companyCode: string,
|
||||
page: number = 1,
|
||||
size: number = 20,
|
||||
searchTerm?: string, // 검색어 추가
|
||||
searchTerm?: string,
|
||||
options?: { excludePop?: boolean },
|
||||
): Promise<PaginatedResponse<ScreenDefinition>> {
|
||||
const offset = (page - 1) * size;
|
||||
|
||||
// WHERE 절 동적 생성
|
||||
const whereConditions: string[] = ["is_active != 'D'"];
|
||||
const whereConditions: string[] = ["sd.is_active != 'D'"];
|
||||
const params: any[] = [];
|
||||
|
||||
if (companyCode !== "*") {
|
||||
whereConditions.push(`company_code = $${params.length + 1}`);
|
||||
whereConditions.push(`sd.company_code = $${params.length + 1}`);
|
||||
params.push(companyCode);
|
||||
}
|
||||
|
||||
// 검색어 필터링 추가 (화면명, 화면 코드, 테이블명 검색)
|
||||
if (searchTerm && searchTerm.trim() !== "") {
|
||||
whereConditions.push(`(
|
||||
screen_name ILIKE $${params.length + 1} OR
|
||||
screen_code ILIKE $${params.length + 1} OR
|
||||
table_name ILIKE $${params.length + 1}
|
||||
sd.screen_name ILIKE $${params.length + 1} OR
|
||||
sd.screen_code ILIKE $${params.length + 1} OR
|
||||
sd.table_name ILIKE $${params.length + 1}
|
||||
)`);
|
||||
params.push(`%${searchTerm.trim()}%`);
|
||||
}
|
||||
|
||||
// POP 화면 제외 필터: screen_layouts_pop에 레이아웃이 있는 화면 제외
|
||||
if (options?.excludePop) {
|
||||
whereConditions.push(
|
||||
`NOT EXISTS (SELECT 1 FROM screen_layouts_pop slp WHERE slp.screen_id = sd.screen_id)`
|
||||
);
|
||||
}
|
||||
|
||||
const whereSQL = whereConditions.join(" AND ");
|
||||
|
||||
// 페이징 쿼리 (Raw Query)
|
||||
const [screens, totalResult] = await Promise.all([
|
||||
query<any>(
|
||||
`SELECT * FROM screen_definitions
|
||||
`SELECT sd.* FROM screen_definitions sd
|
||||
WHERE ${whereSQL}
|
||||
ORDER BY created_date DESC
|
||||
ORDER BY sd.created_date DESC
|
||||
LIMIT $${params.length + 1} OFFSET $${params.length + 2}`,
|
||||
[...params, size, offset],
|
||||
),
|
||||
query<{ count: string }>(
|
||||
`SELECT COUNT(*)::text as count FROM screen_definitions
|
||||
`SELECT COUNT(*)::text as count FROM screen_definitions sd
|
||||
WHERE ${whereSQL}`,
|
||||
params,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ export default function ScreenManagementPage() {
|
|||
const loadScreens = useCallback(async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const result = await screenApi.getScreens({ page: 1, size: 1000, searchTerm: "" });
|
||||
const result = await screenApi.getScreens({ page: 1, size: 1000, searchTerm: "", excludePop: true });
|
||||
// screenApi.getScreens는 { data: ScreenDefinition[], total, page, size, totalPages } 형태 반환
|
||||
if (result.data && result.data.length > 0) {
|
||||
setScreens(result.data);
|
||||
|
|
|
|||
|
|
@ -1011,7 +1011,7 @@ export function ScreenGroupTreeView({
|
|||
const loadGroupsData = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const response = await getScreenGroups({ size: 1000 }); // 모든 그룹 가져오기
|
||||
const response = await getScreenGroups({ size: 1000, excludePop: true });
|
||||
if (response.success && response.data) {
|
||||
setGroups(response.data);
|
||||
|
||||
|
|
|
|||
|
|
@ -223,7 +223,7 @@ export default function ScreenList({ onScreenSelect, selectedScreen, onDesignScr
|
|||
const loadGroups = async () => {
|
||||
try {
|
||||
setLoadingGroups(true);
|
||||
const response = await getScreenGroups();
|
||||
const response = await getScreenGroups({ excludePop: true });
|
||||
if (response.success && response.data) {
|
||||
setGroups(response.data);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ export const screenApi = {
|
|||
size?: number;
|
||||
companyCode?: string;
|
||||
searchTerm?: string;
|
||||
excludePop?: boolean;
|
||||
}): Promise<PaginatedResponse<ScreenDefinition>> => {
|
||||
const response = await apiClient.get("/screen-management/screens", { params });
|
||||
const raw = response.data || {};
|
||||
|
|
|
|||
|
|
@ -115,12 +115,14 @@ export async function getScreenGroups(params?: {
|
|||
page?: number;
|
||||
size?: number;
|
||||
searchTerm?: string;
|
||||
excludePop?: boolean;
|
||||
}): Promise<ApiResponse<ScreenGroup[]>> {
|
||||
try {
|
||||
const queryParams = new URLSearchParams();
|
||||
if (params?.page) queryParams.append("page", params.page.toString());
|
||||
if (params?.size) queryParams.append("size", params.size.toString());
|
||||
if (params?.searchTerm) queryParams.append("searchTerm", params.searchTerm);
|
||||
if (params?.excludePop) queryParams.append("excludePop", "true");
|
||||
|
||||
const response = await apiClient.get(`/screen-groups/groups?${queryParams.toString()}`);
|
||||
return response.data;
|
||||
|
|
|
|||
Loading…
Reference in New Issue