연쇄관계 자식 라벨표시

This commit is contained in:
kjs
2025-12-18 15:16:34 +09:00
parent bca6de9811
commit cf8a5a3d93
3 changed files with 226 additions and 51 deletions

View File

@@ -76,7 +76,9 @@ export const getCategoryValueCascadingGroups = async (
data: result.rows,
});
} catch (error: any) {
logger.error("카테고리 값 연쇄관계 그룹 목록 조회 실패", { error: error.message });
logger.error("카테고리 값 연쇄관계 그룹 목록 조회 실패", {
error: error.message,
});
return res.status(500).json({
success: false,
message: "카테고리 값 연쇄관계 그룹 목록 조회에 실패했습니다.",
@@ -175,7 +177,9 @@ export const getCategoryValueCascadingGroupById = async (
},
});
} catch (error: any) {
logger.error("카테고리 값 연쇄관계 그룹 상세 조회 실패", { error: error.message });
logger.error("카테고리 값 연쇄관계 그룹 상세 조회 실패", {
error: error.message,
});
return res.status(500).json({
success: false,
message: "카테고리 값 연쇄관계 그룹 조회에 실패했습니다.",
@@ -240,7 +244,9 @@ export const getCategoryValueCascadingByCode = async (
data: result.rows[0],
});
} catch (error: any) {
logger.error("카테고리 값 연쇄관계 코드 조회 실패", { error: error.message });
logger.error("카테고리 값 연쇄관계 코드 조회 실패", {
error: error.message,
});
return res.status(500).json({
success: false,
message: "카테고리 값 연쇄관계 조회에 실패했습니다.",
@@ -277,7 +283,14 @@ export const createCategoryValueCascadingGroup = async (
} = req.body;
// 필수 필드 검증
if (!relationCode || !relationName || !parentTableName || !parentColumnName || !childTableName || !childColumnName) {
if (
!relationCode ||
!relationName ||
!parentTableName ||
!parentColumnName ||
!childTableName ||
!childColumnName
) {
return res.status(400).json({
success: false,
message: "필수 필드가 누락되었습니다.",
@@ -352,7 +365,9 @@ export const createCategoryValueCascadingGroup = async (
message: "카테고리 값 연쇄관계 그룹이 생성되었습니다.",
});
} catch (error: any) {
logger.error("카테고리 값 연쇄관계 그룹 생성 실패", { error: error.message });
logger.error("카테고리 값 연쇄관계 그룹 생성 실패", {
error: error.message,
});
return res.status(500).json({
success: false,
message: "카테고리 값 연쇄관계 그룹 생성에 실패했습니다.",
@@ -403,7 +418,11 @@ export const updateCategoryValueCascadingGroup = async (
}
const existingCompanyCode = existingCheck.rows[0].company_code;
if (companyCode !== "*" && existingCompanyCode !== companyCode && existingCompanyCode !== "*") {
if (
companyCode !== "*" &&
existingCompanyCode !== companyCode &&
existingCompanyCode !== "*"
) {
return res.status(403).json({
success: false,
message: "수정 권한이 없습니다.",
@@ -440,7 +459,11 @@ export const updateCategoryValueCascadingGroup = async (
childTableName,
childColumnName,
childMenuObjid,
clearOnParentChange !== undefined ? (clearOnParentChange ? "Y" : "N") : null,
clearOnParentChange !== undefined
? clearOnParentChange
? "Y"
: "N"
: null,
showGroupLabel !== undefined ? (showGroupLabel ? "Y" : "N") : null,
emptyParentMessage,
noOptionsMessage,
@@ -461,7 +484,9 @@ export const updateCategoryValueCascadingGroup = async (
message: "카테고리 값 연쇄관계 그룹이 수정되었습니다.",
});
} catch (error: any) {
logger.error("카테고리 값 연쇄관계 그룹 수정 실패", { error: error.message });
logger.error("카테고리 값 연쇄관계 그룹 수정 실패", {
error: error.message,
});
return res.status(500).json({
success: false,
message: "카테고리 값 연쇄관계 그룹 수정에 실패했습니다.",
@@ -496,7 +521,11 @@ export const deleteCategoryValueCascadingGroup = async (
}
const existingCompanyCode = existingCheck.rows[0].company_code;
if (companyCode !== "*" && existingCompanyCode !== companyCode && existingCompanyCode !== "*") {
if (
companyCode !== "*" &&
existingCompanyCode !== companyCode &&
existingCompanyCode !== "*"
) {
return res.status(403).json({
success: false,
message: "삭제 권한이 없습니다.",
@@ -522,7 +551,9 @@ export const deleteCategoryValueCascadingGroup = async (
message: "카테고리 값 연쇄관계 그룹이 삭제되었습니다.",
});
} catch (error: any) {
logger.error("카테고리 값 연쇄관계 그룹 삭제 실패", { error: error.message });
logger.error("카테고리 값 연쇄관계 그룹 삭제 실패", {
error: error.message,
});
return res.status(500).json({
success: false,
message: "카테고리 값 연쇄관계 그룹 삭제에 실패했습니다.",
@@ -620,7 +651,9 @@ export const saveCategoryValueCascadingMappings = async (
client.release();
}
} catch (error: any) {
logger.error("카테고리 값 연쇄관계 매핑 저장 실패", { error: error.message });
logger.error("카테고리 값 연쇄관계 매핑 저장 실패", {
error: error.message,
});
return res.status(500).json({
success: false,
message: "카테고리 값 연쇄관계 매핑 저장에 실패했습니다.",
@@ -649,12 +682,15 @@ export const getCategoryValueCascadingOptions = async (
// 다중 부모값 파싱
let parentValueArray: string[] = [];
if (parentValues) {
if (Array.isArray(parentValues)) {
parentValueArray = parentValues.map(v => String(v));
parentValueArray = parentValues.map((v) => String(v));
} else {
parentValueArray = String(parentValues).split(',').map(v => v.trim()).filter(v => v);
parentValueArray = String(parentValues)
.split(",")
.map((v) => v.trim())
.filter((v) => v);
}
} else if (parentValue) {
parentValueArray = [String(parentValue)];
@@ -696,8 +732,10 @@ export const getCategoryValueCascadingOptions = async (
const group = groupResult.rows[0];
// 매핑된 자식 값 조회 (다중 부모값에 대해 IN 절 사용)
const placeholders = parentValueArray.map((_, idx) => `$${idx + 2}`).join(', ');
const placeholders = parentValueArray
.map((_, idx) => `$${idx + 2}`)
.join(", ");
const optionsQuery = `
SELECT DISTINCT
child_value_code as value,
@@ -712,7 +750,10 @@ export const getCategoryValueCascadingOptions = async (
ORDER BY parent_value_code, display_order, child_value_label
`;
const optionsResult = await pool.query(optionsQuery, [group.group_id, ...parentValueArray]);
const optionsResult = await pool.query(optionsQuery, [
group.group_id,
...parentValueArray,
]);
logger.info("카테고리 값 연쇄 옵션 조회", {
relationCode: code,
@@ -723,7 +764,7 @@ export const getCategoryValueCascadingOptions = async (
return res.json({
success: true,
data: optionsResult.rows,
showGroupLabel: group.show_group_label === 'Y',
showGroupLabel: group.show_group_label === "Y",
});
} catch (error: any) {
logger.error("카테고리 값 연쇄 옵션 조회 실패", { error: error.message });
@@ -789,7 +830,10 @@ export const getCategoryValueCascadingParentOptions = async (
AND is_active = true
`;
const optionsParams: any[] = [group.parent_table_name, group.parent_column_name];
const optionsParams: any[] = [
group.parent_table_name,
group.parent_column_name,
];
let paramIndex = 3;
// 메뉴 스코프 적용
@@ -884,7 +928,10 @@ export const getCategoryValueCascadingChildOptions = async (
AND is_active = true
`;
const optionsParams: any[] = [group.child_table_name, group.child_column_name];
const optionsParams: any[] = [
group.child_table_name,
group.child_column_name,
];
let paramIndex = 3;
// 메뉴 스코프 적용
@@ -925,3 +972,91 @@ export const getCategoryValueCascadingChildOptions = async (
}
};
/**
* 테이블명으로 해당 테이블의 모든 연쇄관계 매핑 조회
* (테이블 목록에서 코드→라벨 변환에 사용)
*/
export const getCategoryValueCascadingMappingsByTable = async (
req: AuthenticatedRequest,
res: Response
) => {
try {
const { tableName } = req.params;
const companyCode = req.user?.companyCode || "*";
if (!tableName) {
return res.status(400).json({
success: false,
message: "테이블명이 필요합니다.",
});
}
// 해당 테이블이 자식 테이블인 연쇄관계 그룹 찾기
let groupQuery = `
SELECT
group_id,
relation_code,
child_column_name
FROM category_value_cascading_group
WHERE child_table_name = $1
AND is_active = 'Y'
`;
const groupParams: any[] = [tableName];
let paramIndex = 2;
// 멀티테넌시 적용
if (companyCode !== "*") {
groupQuery += ` AND (company_code = $${paramIndex} OR company_code = '*')`;
groupParams.push(companyCode);
}
const groupResult = await pool.query(groupQuery, groupParams);
if (groupResult.rowCount === 0) {
// 연쇄관계가 없으면 빈 객체 반환
return res.json({
success: true,
data: {},
});
}
// 각 그룹의 매핑 조회
const mappings: Record<string, Array<{ code: string; label: string }>> = {};
for (const group of groupResult.rows) {
const mappingQuery = `
SELECT DISTINCT
child_value_code as code,
child_value_label as label
FROM category_value_cascading_mapping
WHERE group_id = $1
AND is_active = 'Y'
ORDER BY child_value_label
`;
const mappingResult = await pool.query(mappingQuery, [group.group_id]);
if (mappingResult.rowCount && mappingResult.rowCount > 0) {
mappings[group.child_column_name] = mappingResult.rows;
}
}
logger.info("테이블별 연쇄관계 매핑 조회", {
tableName,
groupCount: groupResult.rowCount,
columnMappings: Object.keys(mappings),
});
return res.json({
success: true,
data: mappings,
});
} catch (error: any) {
logger.error("테이블별 연쇄관계 매핑 조회 실패", { error: error.message });
return res.status(500).json({
success: false,
message: "연쇄관계 매핑 조회에 실패했습니다.",
error: error.message,
});
}
};

View File

@@ -10,6 +10,7 @@ import {
getCategoryValueCascadingOptions,
getCategoryValueCascadingParentOptions,
getCategoryValueCascadingChildOptions,
getCategoryValueCascadingMappingsByTable,
} from "../controllers/categoryValueCascadingController";
import { authenticateToken } from "../middleware/authMiddleware";
@@ -60,5 +61,14 @@ router.get("/child-options/:code", getCategoryValueCascadingChildOptions);
// 연쇄 옵션 조회 (부모 값 기반 자식 옵션)
router.get("/options/:code", getCategoryValueCascadingOptions);
export default router;
// ============================================
// 테이블별 매핑 조회 (테이블 목록 표시용)
// ============================================
// 테이블명으로 해당 테이블의 모든 연쇄관계 매핑 조회
router.get(
"/table/:tableName/mappings",
getCategoryValueCascadingMappingsByTable
);
export default router;