4.5 KiB
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: preCSS 적용 → 기각 (SelectItem, CommandItem 양쪽 모두 수정 필요, shadcn 기본 스타일 오버라이드 부담)- CSS
padding-left사용 → 기각 (label 문자열 기반 옵션 구조에서 개별 아이템에 스타일 전달 어려움) - 트리 문자(
│,├,└) 조합 → 기각 (과도한 시각 정보, 단순 들여쓰기면 충분)
3. depth당 3칸 \u00A0
- 결정:
"\u00A0\u00A0\u00A0".repeat(depth)(depth당 3칸) - 근거: 기존 2칸은
\u00A0로 바꿔도 depth간 차이가 작음. 3칸이 시각적 구분에 적절
4. 두 파일 동시 수정
- 결정:
V2Select.tsx와UnifiedSelect.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— 화면에만 보이는 값, 들여쓰기 포함- 데이터 무결성에 영향 없음