web_type에 따른 input 변화 구현

This commit is contained in:
hyeonsu 2025-09-21 12:31:37 +09:00
parent c3cb1a0033
commit 0bad11686e
2 changed files with 87 additions and 114 deletions

View File

@ -49,65 +49,46 @@ export class EntityReferenceController {
if (!columnInfo) { if (!columnInfo) {
return res.status(404).json({ return res.status(404).json({
success: false, success: false,
message: `컬럼 '${tableName}.${columnName}'을 찾을 수 없습니다.`, message: `컬럼 정보를 찾을 수 없습니다: ${tableName}.${columnName}`,
}); });
} }
// column_labels에서 참조 테이블 정보 가져오기 // webType 확인
let referenceTable = columnInfo.reference_table || ""; if (columnInfo.web_type !== "entity") {
let referenceColumn = columnInfo.reference_column || "";
let displayColumn = "name"; // 기본 표시 컬럼
// detailSettings에서 displayColumn 정보 추출
try {
if (columnInfo.detail_settings) {
const detailSettings = JSON.parse(columnInfo.detail_settings);
displayColumn = detailSettings.displayColumn || displayColumn;
}
} catch (error) {
logger.warn("detailSettings 파싱 실패:", error);
}
// reference_table이 없는 경우 컬럼명 기반으로 추론
if (!referenceTable) {
if (columnName.endsWith("_code")) {
// dept_code -> dept_info
const baseTableName = columnName.replace("_code", "_info");
referenceTable = baseTableName;
referenceColumn = columnName; // dept_code
logger.info(`참조 테이블 추론: ${columnName} -> ${referenceTable}`);
} else if (columnName.endsWith("_id")) {
// user_id -> user_info
const baseTableName = columnName.replace("_id", "_info");
referenceTable = baseTableName;
referenceColumn = columnName; // user_id
logger.info(`참조 테이블 추론: ${columnName} -> ${referenceTable}`);
}
}
if (!referenceTable) {
return res.status(400).json({ return res.status(400).json({
success: false, success: false,
message: `컬럼 '${tableName}.${columnName}'에 참조 테이블이 설정되지 않았습니다.`, message: `컬럼 '${tableName}.${columnName}'은 entity 타입이 아닙니다. webType: ${columnInfo.web_type}`,
}); });
} }
// 테이블별 적절한 표시 컬럼 설정 // column_labels에서 직접 참조 정보 가져오기
if (referenceTable === "dept_info") { const referenceTable = columnInfo.reference_table;
displayColumn = "dept_name"; const referenceColumn = columnInfo.reference_column;
} else if (referenceTable === "user_info") { const displayColumn = columnInfo.display_column || "name";
displayColumn = "user_name";
// entity 타입인데 참조 테이블 정보가 없으면 오류
if (!referenceTable || !referenceColumn) {
return res.status(400).json({
success: false,
message: `Entity 타입 컬럼 '${tableName}.${columnName}'에 참조 테이블 정보가 설정되지 않았습니다. column_labels에서 reference_table과 reference_column을 확인해주세요.`,
});
} }
// referenceColumn이 없으면 테이블별 Primary Key로 설정 // 참조 테이블이 실제로 존재하는지 확인
if (!referenceColumn) { try {
if (referenceTable === "dept_info") { await prisma.$queryRawUnsafe(`SELECT 1 FROM ${referenceTable} LIMIT 1`);
referenceColumn = "dept_code"; logger.info(
} else if (referenceTable === "user_info") { `Entity 참조 설정: ${tableName}.${columnName} -> ${referenceTable}.${referenceColumn} (display: ${displayColumn})`
referenceColumn = "user_id"; );
} else { } catch (error) {
referenceColumn = "id"; // 기본값 logger.error(
} `참조 테이블 '${referenceTable}'이 존재하지 않습니다:`,
error
);
return res.status(400).json({
success: false,
message: `참조 테이블 '${referenceTable}'이 존재하지 않습니다. column_labels의 reference_table 설정을 확인해주세요.`,
});
} }
// 동적 쿼리로 참조 데이터 조회 // 동적 쿼리로 참조 데이터 조회
@ -140,28 +121,24 @@ export class EntityReferenceController {
}) })
); );
const result: EntityReferenceData = {
options,
referenceInfo: {
referenceTable,
referenceColumn: "id",
displayColumn,
},
};
logger.info(`엔티티 참조 데이터 조회 완료: ${options.length}개 항목`); logger.info(`엔티티 참조 데이터 조회 완료: ${options.length}개 항목`);
return res.json({ return res.json({
success: true, success: true,
message: "엔티티 참조 데이터 조회 성공", data: {
data: result, options,
referenceInfo: {
referenceTable,
referenceColumn,
displayColumn,
},
},
}); });
} catch (error) { } catch (error) {
logger.error("엔티티 참조 데이터 조회 실패:", error); logger.error("엔티티 참조 데이터 조회 실패:", error);
return res.status(500).json({ return res.status(500).json({
success: false, success: false,
message: "엔티티 참조 데이터 조회 중 오류가 발생했습니다.", message: "엔티티 참조 데이터 조회 중 오류가 발생했습니다.",
error: error instanceof Error ? error.message : "Unknown error",
}); });
} }
} }
@ -180,54 +157,51 @@ export class EntityReferenceController {
search, search,
}); });
// code_info 테이블에서 공통 코드 조회 // code_info 테이블에서 코드 데이터 조회
let whereClause: any = { let whereCondition: any = {
code_category: codeCategory, code_category: codeCategory,
is_active: "Y", is_active: "Y",
}; };
// 검색 조건 추가
if (search) { if (search) {
whereClause.OR = [ whereCondition.code_name = {
{ code_value: { contains: String(search), mode: "insensitive" } }, contains: String(search),
{ code_name: { contains: String(search), mode: "insensitive" } }, mode: "insensitive",
]; };
} }
const codes = await prisma.code_info.findMany({ const codeData = await prisma.code_info.findMany({
where: whereClause, where: whereCondition,
orderBy: { sort_order: "asc" },
take: Number(limit),
select: { select: {
code_value: true, code_value: true,
code_name: true, code_name: true,
}, },
orderBy: {
code_name: "asc",
},
take: Number(limit),
}); });
// 옵션 형태로 변환 // 옵션 형태로 변환
const options: EntityReferenceOption[] = codes.map((code: any) => ({ const options: EntityReferenceOption[] = codeData.map((code) => ({
value: code.code_value || "", value: code.code_value,
label: code.code_name || "", label: code.code_name,
})); }));
const result: CodeReferenceData = {
options,
codeCategory,
};
logger.info(`공통 코드 데이터 조회 완료: ${options.length}개 항목`); logger.info(`공통 코드 데이터 조회 완료: ${options.length}개 항목`);
return res.json({ return res.json({
success: true, success: true,
message: "공통 코드 데이터 조회 성공", data: {
data: result, options,
codeCategory,
},
}); });
} catch (error) { } catch (error) {
logger.error("공통 코드 데이터 조회 실패:", error); logger.error("공통 코드 데이터 조회 실패:", error);
return res.status(500).json({ return res.status(500).json({
success: false, success: false,
message: "공통 코드 데이터 조회 중 오류가 발생했습니다.", message: "공통 코드 데이터 조회 중 오류가 발생했습니다.",
error: error instanceof Error ? error.message : "Unknown error",
}); });
} }
} }

View File

@ -33,6 +33,8 @@ export const WebTypeInput: React.FC<WebTypeInputProps> = ({
placeholder, placeholder,
tableName, tableName,
}) => { }) => {
// tableName은 props 또는 column.tableName에서 가져옴
const effectiveTableName = tableName || (column as ColumnInfo & { tableName?: string }).tableName;
const webType = column.webType || "text"; const webType = column.webType || "text";
const [entityOptions, setEntityOptions] = useState<EntityReferenceOption[]>([]); const [entityOptions, setEntityOptions] = useState<EntityReferenceOption[]>([]);
const [codeOptions, setCodeOptions] = useState<EntityReferenceOption[]>([]); const [codeOptions, setCodeOptions] = useState<EntityReferenceOption[]>([]);
@ -79,20 +81,12 @@ export const WebTypeInput: React.FC<WebTypeInputProps> = ({
const loadEntityData = useCallback(async () => { const loadEntityData = useCallback(async () => {
try { try {
setLoading(true); setLoading(true);
// tableName이 없으면 referenceTable에서 추론 (dept_code -> dept_info)
const effectiveTableName =
tableName ||
(() => {
if (column.columnName?.endsWith("_code")) {
return column.columnName.replace("_code", "_info");
}
if (column.columnName?.endsWith("_id")) {
return column.columnName.replace("_id", "_info");
}
return "unknown_table";
})();
console.log(`🔍 Entity API 호출: ${effectiveTableName}.${column.columnName}`); // entity 타입은 반드시 effectiveTableName과 columnName이 있어야 함
if (!effectiveTableName || !column.columnName) {
throw new Error("Entity 타입에는 tableName과 columnName이 필요합니다.");
}
const data = await EntityReferenceAPI.getEntityReferenceData(effectiveTableName, column.columnName, { const data = await EntityReferenceAPI.getEntityReferenceData(effectiveTableName, column.columnName, {
limit: 100, limit: 100,
}); });
@ -102,7 +96,7 @@ export const WebTypeInput: React.FC<WebTypeInputProps> = ({
} finally { } finally {
setLoading(false); setLoading(false);
} }
}, [tableName, column.columnName]); }, [effectiveTableName, column.columnName]);
const loadCodeData = useCallback(async () => { const loadCodeData = useCallback(async () => {
try { try {
@ -119,36 +113,41 @@ export const WebTypeInput: React.FC<WebTypeInputProps> = ({
} }
}, [column.codeCategory, detailSettings.codeCategory, fallbackCodeCategory]); }, [column.codeCategory, detailSettings.codeCategory, fallbackCodeCategory]);
// Entity 타입일 때 참조 데이터 로드 // webType에 따른 데이터 로드
useEffect(() => { useEffect(() => {
// 디버깅: dept_code 필드의 정보 확인 // 디버깅: entity 타입 필드 정보 확인
if (column.columnName === "dept_code") { if (column.columnName === "manager_name" || webType === "entity") {
console.log("🔍 dept_code 필드 디버깅:", { console.log("🔍 Entity 필드 디버깅:", {
columnName: column.columnName, columnName: column.columnName,
webType: webType, webType: webType,
referenceTable: column.referenceTable,
tableName: tableName, tableName: tableName,
shouldLoadEntity: (webType === "entity" || column.referenceTable) && tableName && column.columnName, effectiveTableName: effectiveTableName,
fullColumn: column, referenceTable: column.referenceTable,
referenceColumn: column.referenceColumn,
displayColumn: (column as any).displayColumn,
shouldLoadEntity: webType === "entity" && effectiveTableName && column.columnName,
}); });
} }
// webType이 entity이거나, referenceTable이 있으면 entity로 처리 if (webType === "entity" && effectiveTableName && column.columnName) {
if ((webType === "entity" || column.referenceTable) && column.columnName) { // entity 타입: 다른 테이블 참조
// tableName이 없으면 referenceTable에서 추론 console.log("🚀 Entity 데이터 로드 시작:", effectiveTableName, column.columnName);
const effectiveTableName = tableName || (column.referenceTable ? "unknown" : null); loadEntityData();
if (effectiveTableName) {
loadEntityData();
}
} else if (webType === "code" && (column.codeCategory || detailSettings.codeCategory || fallbackCodeCategory)) { } else if (webType === "code" && (column.codeCategory || detailSettings.codeCategory || fallbackCodeCategory)) {
// code 타입: code_info 테이블에서 공통 코드 조회
loadCodeData(); loadCodeData();
} }
// text 타입: 일반 텍스트 입력
// file 타입: 파일 업로드
}, [ }, [
webType, webType,
tableName, effectiveTableName,
column.columnName, column.columnName,
column.codeCategory, column.codeCategory,
column.referenceTable, column.referenceTable,
column.referenceColumn,
(column as any).displayColumn,
tableName,
fallbackCodeCategory, fallbackCodeCategory,
detailSettings.codeCategory, detailSettings.codeCategory,
loadEntityData, loadEntityData,
@ -201,8 +200,8 @@ export const WebTypeInput: React.FC<WebTypeInputProps> = ({
className, className,
}; };
// WebType별 렌더링 (referenceTable이 있으면 entity로 처리) // WebType별 렌더링 (column_labels의 webType을 정확히 따름)
const actualWebType = webType === "entity" || column.referenceTable ? "entity" : webType; const actualWebType = webType;
switch (actualWebType) { switch (actualWebType) {
case "text": case "text":