feat: 채번규칙 메뉴 스코프 전환 완료

 주요 변경사항:
- 백엔드: menuService.ts 추가 (형제 메뉴 조회 유틸리티)
- 백엔드: numberingRuleService.getAvailableRulesForMenu() 메뉴 스코프 적용
- 백엔드: tableCategoryValueService 메뉴 스코프 준비 (menuObjid 파라미터 추가)
- 프론트엔드: TextInputConfigPanel에 부모 메뉴 선택 UI 추가
- 프론트엔드: 메뉴별 채번규칙 필터링 (형제 메뉴 공유)

🔧 기술 세부사항:
- getSiblingMenuObjids(): 같은 부모를 가진 형제 메뉴 OBJID 조회
- 채번규칙 우선순위: menu (형제) > table > global
- 사용자 메뉴(menu_type='1') 레벨 2만 부모 메뉴로 선택 가능

📝 다음 단계:
- 카테고리 컴포넌트도 메뉴 스코프로 전환 예정
This commit is contained in:
kjs
2025-11-11 14:32:00 +09:00
parent 532c80a86b
commit 668b45d4ea
16 changed files with 1838 additions and 268 deletions

View File

@@ -27,12 +27,24 @@ router.get("/available/:menuObjid?", authenticateToken, async (req: Authenticate
const companyCode = req.user!.companyCode;
const menuObjid = req.params.menuObjid ? parseInt(req.params.menuObjid) : undefined;
logger.info("📥 메뉴별 채번 규칙 조회 요청", { companyCode, menuObjid });
try {
const rules = await numberingRuleService.getAvailableRulesForMenu(companyCode, menuObjid);
logger.info("✅ 메뉴별 채번 규칙 조회 성공 (컨트롤러)", {
companyCode,
menuObjid,
rulesCount: rules.length
});
return res.json({ success: true, data: rules });
} catch (error: any) {
logger.error("메뉴별 사용 가능한 규칙 조회 실패", {
logger.error("메뉴별 사용 가능한 규칙 조회 실패 (컨트롤러)", {
error: error.message,
errorCode: error.code,
errorStack: error.stack,
companyCode,
menuObjid,
});
return res.status(500).json({ success: false, error: error.message });

View File

@@ -32,18 +32,31 @@ export const getCategoryColumns = async (req: AuthenticatedRequest, res: Respons
/**
* 카테고리 값 목록 조회 (메뉴 스코프 적용)
*
* Query Parameters:
* - menuObjid: 메뉴 OBJID (선택사항, 제공 시 형제 메뉴의 카테고리 값 포함)
* - includeInactive: 비활성 값 포함 여부
*/
export const getCategoryValues = async (req: AuthenticatedRequest, res: Response) => {
try {
const companyCode = req.user!.companyCode;
const { tableName, columnName } = req.params;
const includeInactive = req.query.includeInactive === "true";
const menuObjid = req.query.menuObjid ? Number(req.query.menuObjid) : undefined;
logger.info("카테고리 값 조회 요청", {
tableName,
columnName,
menuObjid,
companyCode,
});
const values = await tableCategoryValueService.getCategoryValues(
tableName,
columnName,
companyCode,
includeInactive
includeInactive,
menuObjid // ← menuObjid 전달
);
return res.json({
@@ -61,18 +74,37 @@ export const getCategoryValues = async (req: AuthenticatedRequest, res: Response
};
/**
* 카테고리 값 추가
* 카테고리 값 추가 (메뉴 스코프)
*
* Body:
* - menuObjid: 메뉴 OBJID (필수)
* - 나머지 카테고리 값 정보
*/
export const addCategoryValue = async (req: AuthenticatedRequest, res: Response) => {
try {
const companyCode = req.user!.companyCode;
const userId = req.user!.userId;
const value = req.body;
const { menuObjid, ...value } = req.body;
if (!menuObjid) {
return res.status(400).json({
success: false,
message: "menuObjid는 필수입니다",
});
}
logger.info("카테고리 값 추가 요청", {
tableName: value.tableName,
columnName: value.columnName,
menuObjid,
companyCode,
});
const newValue = await tableCategoryValueService.addCategoryValue(
value,
companyCode,
userId
userId,
Number(menuObjid) // ← menuObjid 전달
);
return res.status(201).json({