ERP-node/docs/ycshin-node/CTI[맥락]-카테고리-깊이구분.md

4.5 KiB

[맥락노트] 카테고리 드롭다운 - 3단계 깊이 구분 표시

관련 문서: 계획서 | 체크리스트


왜 이 작업을 하는가

  • 품목정보 등록 모달의 "재고단위" 등 카테고리 드롭다운에서 3단계 계층이 시각적으로 구분되지 않음
  • 예: "신22"가 "신2"의 하위인데, "신3", "신4"와 같은 레벨로 보임
  • 사용자가 대분류/중분류/소분류 관계를 파악할 수 없어 잘못된 항목을 선택할 위험

핵심 결정 사항과 근거

1. 원인: HTML 공백 축소(collapse)

  • 현상: flattenTree에서 " ".repeat(depth)로 들여쓰기를 만들지만, HTML이 연속 공백을 하나로 합침
  • 결과: depth 1(" └ ")과 depth 2(" └ ")가 동일하게 렌더링됨
  • 확인: SelectItem, CommandItem 모두 white-space: pre 미적용 상태

2. 해결: Non-Breaking Space(\u00A0) 사용

  • 결정: 일반 공백 " ""\u00A0"로 교체
  • 근거: \u00A0는 HTML에서 축소되지 않아 depth별 들여쓰기가 정확히 유지됨
  • 대안 검토:
    • white-space: pre CSS 적용 → 기각 (SelectItem, CommandItem 양쪽 모두 수정 필요, shadcn 기본 스타일 오버라이드 부담)
    • CSS padding-left 사용 → 기각 (label 문자열 기반 옵션 구조에서 개별 아이템에 스타일 전달 어려움)
    • 트리 문자(, , ) 조합 → 기각 (과도한 시각 정보, 단순 들여쓰기면 충분)

3. depth당 3칸 \u00A0

  • 결정: "\u00A0\u00A0\u00A0".repeat(depth) (depth당 3칸)
  • 근거: 기존 2칸은 \u00A0로 바꿔도 depth간 차이가 작음. 3칸이 시각적 구분에 적절

4. 두 파일 동시 수정

  • 결정: V2Select.tsxUnifiedSelect.tsx 모두 수정
  • 근거: 동일한 flattenTree 패턴이 두 컴포넌트에 존재. 하나만 수정하면 불일치 발생

5. 기존 prefix strip 정규식 호환

  • 확인: V2Select.tsx 979행의 o.label.replace(/^[\s└]+/, "").trim()
  • 근거: JavaScript \s\u00A0를 포함하므로 추가 수정 불필요

구현 중 발견한 사항

CAT_ vs CATEGORY_ 접두사 불일치

테스트 과정에서 최고 관리자 계정으로 리스트 조회 시 CAT_MMLL6U02_QH2V 같은 코드가 그대로 표시되는 현상 발견.

  • 원인: 카테고리 값 생성 함수가 두 곳에 존재하며 접두사가 다름
    • CategoryValueAddDialog.tsx: CATEGORY_ 접두사
    • CategoryValueManagerTree.tsx: CAT_ 접두사
  • 영향: 리스트 해석 로직(V2Repeater, InteractiveDataTable, UnifiedRepeater)이 CATEGORY_ 접두사만 인식하여 CAT_ 코드는 라벨 변환 실패
  • 판단: 일반 회사 계정에서는 정상 동작 확인. 본 작업(들여쓰기 표시) 범위 외로 별도 이슈로 분리

관련 파일 위치

구분 파일 경로 설명
수정 완료 frontend/components/v2/V2Select.tsx flattenTree 함수 (904행)
수정 완료 frontend/components/unified/UnifiedSelect.tsx flattenTree 함수 (632행)
백엔드 (변경 없음) backend-node/src/services/tableCategoryValueService.ts buildHierarchy 메서드
UI 컴포넌트 (변경 없음) frontend/components/ui/select.tsx SelectItem 렌더링
UI 컴포넌트 (변경 없음) frontend/components/ui/command.tsx CommandItem 렌더링

기술 참고

flattenTree 동작 흐름

백엔드 API 응답 (트리 구조):
{
  valueCode: "CAT_001", valueLabel: "신예철", children: [
    { valueCode: "CAT_002", valueLabel: "신2", children: [
      { valueCode: "CAT_003", valueLabel: "신22", children: [] }
    ]},
    { valueCode: "CAT_004", valueLabel: "신3", children: [] },
    { valueCode: "CAT_005", valueLabel: "신4", children: [] }
  ]
}

→ flattenTree 변환 후 (SelectOption 배열):
[
  { value: "CAT_001", label: "신예철" },
  { value: "CAT_002", label: "\u00A0\u00A0\u00A0└ 신2" },
  { value: "CAT_003", label: "\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0└ 신22" },
  { value: "CAT_004", label: "\u00A0\u00A0\u00A0└ 신3" },
  { value: "CAT_005", label: "\u00A0\u00A0\u00A0└ 신4" }
]

value vs label 분리

  • value (저장값): valueCode — DB에 저장되는 값, 들여쓰기 없음
  • label (표시값): prefix + valueLabel — 화면에만 보이는 값, 들여쓰기 포함
  • 데이터 무결성에 영향 없음