카테고리 라벨 보이지 않는 문제 수정

This commit is contained in:
kjs 2026-01-12 10:32:41 +09:00
parent 6732e7d969
commit 9e7253a293
3 changed files with 79 additions and 64 deletions

View File

@ -187,71 +187,68 @@ class TableCategoryValueService {
logger.info("형제 메뉴 OBJID 목록", { menuObjid, siblingObjids }); logger.info("형제 메뉴 OBJID 목록", { menuObjid, siblingObjids });
} }
// 2. 카테고리 값 조회 (형제 메뉴 포함) // 2. 카테고리 값 조회 (메뉴 스코프 또는 형제 메뉴 포함)
let query: string; let query: string;
let params: any[]; let params: any[];
const baseSelect = `
SELECT
value_id AS "valueId",
table_name AS "tableName",
column_name AS "columnName",
value_code AS "valueCode",
value_label AS "valueLabel",
value_order AS "valueOrder",
parent_value_id AS "parentValueId",
depth,
description,
color,
icon,
is_active AS "isActive",
is_default AS "isDefault",
company_code AS "companyCode",
menu_objid AS "menuObjid",
created_at AS "createdAt",
updated_at AS "updatedAt",
created_by AS "createdBy",
updated_by AS "updatedBy"
FROM table_column_category_values
WHERE table_name = $1
AND column_name = $2
`;
if (companyCode === "*") { if (companyCode === "*") {
// 최고 관리자: 모든 카테고리 값 조회 // 최고 관리자: menuObjid가 있으면 해당 메뉴(및 형제 메뉴)의 값만 조회
// 메뉴 스코프 제거: 같은 테이블.컬럼 조합은 모든 메뉴에서 공유 if (menuObjid && siblingObjids.length > 0) {
query = ` query = baseSelect + ` AND menu_objid = ANY($3::numeric[])`;
SELECT params = [tableName, columnName, siblingObjids];
value_id AS "valueId", logger.info("최고 관리자 메뉴 스코프 카테고리 값 조회", { menuObjid, siblingObjids });
table_name AS "tableName", } else if (menuObjid) {
column_name AS "columnName", query = baseSelect + ` AND menu_objid = $3`;
value_code AS "valueCode", params = [tableName, columnName, menuObjid];
value_label AS "valueLabel", logger.info("최고 관리자 단일 메뉴 카테고리 값 조회", { menuObjid });
value_order AS "valueOrder",
parent_value_id AS "parentValueId",
depth,
description,
color,
icon,
is_active AS "isActive",
is_default AS "isDefault",
company_code AS "companyCode",
menu_objid AS "menuObjid",
created_at AS "createdAt",
updated_at AS "updatedAt",
created_by AS "createdBy",
updated_by AS "updatedBy"
FROM table_column_category_values
WHERE table_name = $1
AND column_name = $2
`;
params = [tableName, columnName];
logger.info("최고 관리자 카테고리 값 조회");
} else { } else {
// 일반 회사: 자신의 카테고리 값만 조회 // menuObjid 없으면 모든 값 조회 (중복 가능)
// 메뉴 스코프 제거: 같은 테이블.컬럼 조합은 모든 메뉴에서 공유 query = baseSelect;
query = ` params = [tableName, columnName];
SELECT logger.info("최고 관리자 전체 카테고리 값 조회 (menuObjid 없음)");
value_id AS "valueId", }
table_name AS "tableName", } else {
column_name AS "columnName", // 일반 회사: 자신의 회사 + menuObjid로 필터링
value_code AS "valueCode", if (menuObjid && siblingObjids.length > 0) {
value_label AS "valueLabel", query = baseSelect + ` AND company_code = $3 AND menu_objid = ANY($4::numeric[])`;
value_order AS "valueOrder", params = [tableName, columnName, companyCode, siblingObjids];
parent_value_id AS "parentValueId", logger.info("회사별 메뉴 스코프 카테고리 값 조회", { companyCode, menuObjid, siblingObjids });
depth, } else if (menuObjid) {
description, query = baseSelect + ` AND company_code = $3 AND menu_objid = $4`;
color, params = [tableName, columnName, companyCode, menuObjid];
icon, logger.info("회사별 단일 메뉴 카테고리 값 조회", { companyCode, menuObjid });
is_active AS "isActive", } else {
is_default AS "isDefault", // menuObjid 없으면 회사 전체 조회 (중복 가능하지만 회사별로 제한)
company_code AS "companyCode", query = baseSelect + ` AND company_code = $3`;
menu_objid AS "menuObjid",
created_at AS "createdAt",
updated_at AS "updatedAt",
created_by AS "createdBy",
updated_by AS "updatedBy"
FROM table_column_category_values
WHERE table_name = $1
AND column_name = $2
AND company_code = $3
`;
params = [tableName, columnName, companyCode]; params = [tableName, columnName, companyCode];
logger.info("회사별 카테고리 값 조회", { companyCode }); logger.info("회사별 카테고리 값 조회 (menuObjid 없음)", { companyCode });
}
} }
if (!includeInactive) { if (!includeInactive) {

View File

@ -1,6 +1,7 @@
"use client"; "use client";
import React, { useState, useEffect, useCallback, useRef } from "react"; import React, { useState, useEffect, useCallback, useRef, useMemo } from "react";
import { useSearchParams } from "next/navigation";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox"; import { Checkbox } from "@/components/ui/checkbox";
@ -188,6 +189,16 @@ export const InteractiveDataTable: React.FC<InteractiveDataTableProps> = ({
const screenContext = useScreenContextOptional(); // 화면 컨텍스트 (좌측/우측 위치 확인용) const screenContext = useScreenContextOptional(); // 화면 컨텍스트 (좌측/우측 위치 확인용)
const splitPanelPosition = screenContext?.splitPanelPosition; // 분할 패널 내 위치 const splitPanelPosition = screenContext?.splitPanelPosition; // 분할 패널 내 위치
// URL에서 menuObjid 가져오기 (카테고리 값 조회 시 필요)
const searchParams = useSearchParams();
const menuObjid = useMemo(() => {
// 1. ScreenContext에서 가져오기
if (screenContext?.menuObjid) return screenContext.menuObjid;
// 2. URL 쿼리에서 가져오기
const urlMenuObjid = searchParams.get("menuObjid");
return urlMenuObjid ? parseInt(urlMenuObjid) : undefined;
}, [screenContext?.menuObjid, searchParams]);
const [data, setData] = useState<Record<string, any>[]>([]); const [data, setData] = useState<Record<string, any>[]>([]);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [searchValues, setSearchValues] = useState<Record<string, any>>({}); const [searchValues, setSearchValues] = useState<Record<string, any>>({});
@ -365,8 +376,10 @@ export const InteractiveDataTable: React.FC<InteractiveDataTableProps> = ({
for (const col of categoryColumns) { for (const col of categoryColumns) {
try { try {
// menuObjid가 있으면 쿼리 파라미터로 전달 (메뉴별 카테고리 색상 적용)
const queryParams = menuObjid ? `?menuObjid=${menuObjid}` : "";
const response = await apiClient.get( const response = await apiClient.get(
`/table-categories/${component.tableName}/${col.columnName}/values` `/table-categories/${component.tableName}/${col.columnName}/values${queryParams}`
); );
if (response.data.success && response.data.data) { if (response.data.success && response.data.data) {
@ -379,7 +392,7 @@ export const InteractiveDataTable: React.FC<InteractiveDataTableProps> = ({
}; };
}); });
mappings[col.columnName] = mapping; mappings[col.columnName] = mapping;
console.log(`✅ 카테고리 매핑 로드 성공 [${col.columnName}]:`, mapping); console.log(`✅ 카테고리 매핑 로드 성공 [${col.columnName}]:`, mapping, { menuObjid });
} }
} catch (error) { } catch (error) {
console.error(`❌ 카테고리 값 로드 실패 [${col.columnName}]:`, error); console.error(`❌ 카테고리 값 로드 실패 [${col.columnName}]:`, error);
@ -394,7 +407,7 @@ export const InteractiveDataTable: React.FC<InteractiveDataTableProps> = ({
}; };
loadCategoryMappings(); loadCategoryMappings();
}, [component.tableName, component.columns, getColumnWebType]); }, [component.tableName, component.columns, getColumnWebType, menuObjid]);
// 파일 상태 확인 함수 // 파일 상태 확인 함수
const checkFileStatus = useCallback( const checkFileStatus = useCallback(

View File

@ -13,6 +13,7 @@ import type { SplitPanelPosition } from "@/contexts/SplitPanelContext";
interface ScreenContextValue { interface ScreenContextValue {
screenId?: number; screenId?: number;
tableName?: string; tableName?: string;
menuObjid?: number; // 메뉴 OBJID (카테고리 값 조회 시 필요)
splitPanelPosition?: SplitPanelPosition; // 🆕 분할 패널 위치 (left/right) splitPanelPosition?: SplitPanelPosition; // 🆕 분할 패널 위치 (left/right)
// 🆕 폼 데이터 (RepeaterFieldGroup 등 컴포넌트 데이터 저장) // 🆕 폼 데이터 (RepeaterFieldGroup 등 컴포넌트 데이터 저장)
@ -39,6 +40,7 @@ const ScreenContext = createContext<ScreenContextValue | null>(null);
interface ScreenContextProviderProps { interface ScreenContextProviderProps {
screenId?: number; screenId?: number;
tableName?: string; tableName?: string;
menuObjid?: number; // 메뉴 OBJID
splitPanelPosition?: SplitPanelPosition; // 🆕 분할 패널 위치 splitPanelPosition?: SplitPanelPosition; // 🆕 분할 패널 위치
children: React.ReactNode; children: React.ReactNode;
} }
@ -49,6 +51,7 @@ interface ScreenContextProviderProps {
export function ScreenContextProvider({ export function ScreenContextProvider({
screenId, screenId,
tableName, tableName,
menuObjid,
splitPanelPosition, splitPanelPosition,
children, children,
}: ScreenContextProviderProps) { }: ScreenContextProviderProps) {
@ -112,6 +115,7 @@ export function ScreenContextProvider({
() => ({ () => ({
screenId, screenId,
tableName, tableName,
menuObjid,
splitPanelPosition, splitPanelPosition,
formData, formData,
updateFormData, updateFormData,
@ -127,6 +131,7 @@ export function ScreenContextProvider({
[ [
screenId, screenId,
tableName, tableName,
menuObjid,
splitPanelPosition, splitPanelPosition,
formData, formData,
updateFormData, updateFormData,