123 lines
3.7 KiB
Markdown
123 lines
3.7 KiB
Markdown
# [계획서] 카테고리 드롭다운 - 3단계 깊이 구분 표시
|
|
|
|
> 관련 문서: [맥락노트](./CTI[맥락]-카테고리-깊이구분.md) | [체크리스트](./CTI[체크]-카테고리-깊이구분.md)
|
|
>
|
|
> 상태: **완료** (2026-03-11)
|
|
|
|
## 개요
|
|
|
|
카테고리 타입(`source="category"`) 드롭다운에서 3단계 계층(대분류 > 중분류 > 소분류)의 들여쓰기가 시각적으로 구분되지 않는 문제를 수정합니다.
|
|
|
|
---
|
|
|
|
## 변경 전 동작
|
|
|
|
- `category_values` 테이블은 `parent_value_id`, `depth` 컬럼으로 3단계 계층 구조를 지원
|
|
- 백엔드 `buildHierarchy()`가 트리 구조를 정상적으로 반환
|
|
- 프론트엔드 `flattenTree()`가 트리를 평탄화하면서 **일반 ASCII 공백(`" "`)** 으로 들여쓰기 생성
|
|
- HTML이 연속 공백을 하나로 축소(collapse)하여 depth 1과 depth 2가 동일하게 렌더링됨
|
|
|
|
### 변경 전 코드 (flattenTree)
|
|
|
|
```tsx
|
|
const prefix = depth > 0 ? " ".repeat(depth) + "└ " : "";
|
|
```
|
|
|
|
### 변경 전 렌더링 결과
|
|
|
|
```
|
|
신예철
|
|
└ 신2
|
|
└ 신22 ← depth 2인데 depth 1과 구분 불가
|
|
└ 신3
|
|
└ 신4
|
|
```
|
|
|
|
---
|
|
|
|
## 변경 후 동작
|
|
|
|
### 일반 공백을 Non-Breaking Space(`\u00A0`)로 교체
|
|
|
|
- `\u00A0`는 HTML에서 축소되지 않으므로 depth별 들여쓰기가 정확히 유지됨
|
|
- depth당 3칸(`\u00A0\u00A0\u00A0`)으로 시각적 계층 구분을 명확히 함
|
|
- 백엔드 변경 없음 (트리 구조는 이미 정상)
|
|
|
|
### 변경 후 코드 (flattenTree)
|
|
|
|
```tsx
|
|
const prefix = depth > 0 ? "\u00A0\u00A0\u00A0".repeat(depth) + "└ " : "";
|
|
```
|
|
|
|
---
|
|
|
|
## 시각적 예시
|
|
|
|
| depth | prefix | 드롭다운 표시 |
|
|
|-------|--------|-------------|
|
|
| 0 (대분류) | `""` | `신예철` |
|
|
| 1 (중분류) | `"\u00A0\u00A0\u00A0└ "` | `···└ 신2` |
|
|
| 2 (소분류) | `"\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0└ "` | `······└ 신22` |
|
|
|
|
### 변경 전후 비교
|
|
|
|
```
|
|
변경 전: 변경 후:
|
|
신예철 신예철
|
|
└ 신2 └ 신2
|
|
└ 신22 ← 구분 불가 └ 신22 ← 명확히 구분
|
|
└ 신3 └ 신3
|
|
└ 신4 └ 신4
|
|
```
|
|
|
|
---
|
|
|
|
## 아키텍처
|
|
|
|
```mermaid
|
|
flowchart TD
|
|
A[category_values 테이블] -->|parent_value_id, depth| B[백엔드 buildHierarchy]
|
|
B -->|트리 JSON 응답| C[프론트엔드 API 호출]
|
|
C --> D[flattenTree 함수]
|
|
D -->|"depth별 \u00A0 prefix 생성"| E[SelectOption 배열]
|
|
E --> F{렌더링 모드}
|
|
F -->|비검색| G[SelectItem - label 표시]
|
|
F -->|검색| H[CommandItem - displayLabel 표시]
|
|
|
|
style D fill:#f96,stroke:#333,color:#000
|
|
```
|
|
|
|
**변경 지점**: `flattenTree` 함수 내 prefix 생성 로직 (주황색 표시)
|
|
|
|
---
|
|
|
|
## 변경 대상 파일
|
|
|
|
| 파일 경로 | 변경 내용 | 변경 규모 |
|
|
|-----------|----------|----------|
|
|
| `frontend/components/v2/V2Select.tsx` (904행) | `flattenTree` prefix를 `\u00A0` 기반으로 변경 | 1줄 |
|
|
| `frontend/components/unified/UnifiedSelect.tsx` (632행) | 동일한 `flattenTree` prefix 변경 | 1줄 |
|
|
|
|
---
|
|
|
|
## 영향받는 기존 로직
|
|
|
|
V2Select.tsx의 `resolvedValue`(979행)에서 prefix를 제거하는 정규식:
|
|
|
|
```tsx
|
|
const cleanLabel = o.label.replace(/^[\s└]+/, "").trim();
|
|
```
|
|
|
|
- JavaScript `\s`는 `\u00A0`를 포함하므로 기존 정규식이 정상 동작함
|
|
- 추가 수정 불필요
|
|
|
|
---
|
|
|
|
## 설계 원칙
|
|
|
|
- 백엔드 변경 없이 프론트엔드 표시 로직만 수정
|
|
- `flattenTree` 공통 함수 수정이므로 카테고리 타입 드롭다운 전체에 자동 적용
|
|
- DB 저장값(`valueCode`)에는 영향 없음 — `label`만 변경
|
|
- 기존 prefix strip 정규식(`/^[\s└]+/`)과 호환 유지
|
|
- `V2Select`와 `UnifiedSelect` 두 곳의 동일 패턴을 일관되게 수정
|