389 lines
9.5 KiB
Markdown
389 lines
9.5 KiB
Markdown
# 리포트 페이지 관리 시스템 설계
|
|
|
|
## 1. 개요
|
|
|
|
리포트 디자이너에 다중 페이지 관리 기능을 추가하여 여러 페이지에 걸친 복잡한 문서를 작성할 수 있도록 합니다.
|
|
|
|
## 2. 주요 기능
|
|
|
|
### 2.1 페이지 관리
|
|
|
|
- 페이지 추가/삭제
|
|
- 페이지 복사
|
|
- 페이지 순서 변경 (드래그 앤 드롭)
|
|
- 페이지 이름 지정
|
|
|
|
### 2.2 페이지 네비게이션
|
|
|
|
- 좌측 페이지 썸네일 패널
|
|
- 페이지 간 전환 (클릭)
|
|
- 이전/다음 페이지 이동
|
|
- 페이지 번호 표시
|
|
|
|
### 2.3 페이지별 설정
|
|
|
|
- 페이지 크기 (A4, A3, Letter, 사용자 정의)
|
|
- 페이지 방향 (세로/가로)
|
|
- 여백 설정
|
|
- 배경색
|
|
|
|
### 2.4 컴포넌트 관리
|
|
|
|
- 컴포넌트는 특정 페이지에 속함
|
|
- 페이지 간 컴포넌트 복사/이동
|
|
- 현재 페이지의 컴포넌트만 표시
|
|
|
|
## 3. 데이터베이스 스키마
|
|
|
|
### 3.1 기존 구조 활용 (변경 없음)
|
|
|
|
**report_layout 테이블의 layout_config (JSONB) 활용**
|
|
|
|
기존:
|
|
|
|
```json
|
|
{
|
|
"width": 210,
|
|
"height": 297,
|
|
"orientation": "portrait",
|
|
"components": [...]
|
|
}
|
|
```
|
|
|
|
변경 후:
|
|
|
|
```json
|
|
{
|
|
"pages": [
|
|
{
|
|
"page_id": "page-uuid-1",
|
|
"page_name": "표지",
|
|
"page_order": 0,
|
|
"width": 210,
|
|
"height": 297,
|
|
"orientation": "portrait",
|
|
"margins": {
|
|
"top": 20,
|
|
"bottom": 20,
|
|
"left": 20,
|
|
"right": 20
|
|
},
|
|
"background_color": "#ffffff",
|
|
"components": [
|
|
{
|
|
"id": "comp-1",
|
|
"type": "text",
|
|
"x": 100,
|
|
"y": 50,
|
|
...
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"page_id": "page-uuid-2",
|
|
"page_name": "본문",
|
|
"page_order": 1,
|
|
"width": 210,
|
|
"height": 297,
|
|
"orientation": "portrait",
|
|
"margins": { "top": 20, "bottom": 20, "left": 20, "right": 20 },
|
|
"background_color": "#ffffff",
|
|
"components": [...]
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### 3.2 마이그레이션 전략
|
|
|
|
기존 단일 페이지 리포트 자동 변환:
|
|
|
|
```typescript
|
|
// 기존 구조 감지 시
|
|
if (layoutConfig.components && !layoutConfig.pages) {
|
|
// 자동으로 pages 구조로 변환
|
|
layoutConfig = {
|
|
pages: [
|
|
{
|
|
page_id: uuidv4(),
|
|
page_name: "페이지 1",
|
|
page_order: 0,
|
|
width: layoutConfig.width || 210,
|
|
height: layoutConfig.height || 297,
|
|
orientation: layoutConfig.orientation || "portrait",
|
|
margins: { top: 20, bottom: 20, left: 20, right: 20 },
|
|
background_color: "#ffffff",
|
|
components: layoutConfig.components,
|
|
},
|
|
],
|
|
};
|
|
}
|
|
```
|
|
|
|
## 4. 프론트엔드 구조
|
|
|
|
### 4.1 타입 정의 (types/report.ts)
|
|
|
|
```typescript
|
|
export interface ReportPage {
|
|
page_id: string;
|
|
report_id: string;
|
|
page_order: number;
|
|
page_name: string;
|
|
|
|
// 페이지 설정
|
|
width: number;
|
|
height: number;
|
|
orientation: 'portrait' | 'landscape';
|
|
|
|
// 여백
|
|
margin_top: number;
|
|
margin_bottom: number;
|
|
margin_left: number;
|
|
margin_right: number;
|
|
|
|
// 배경
|
|
background_color: string;
|
|
|
|
created_at?: string;
|
|
updated_at?: string;
|
|
}
|
|
|
|
export interface ComponentConfig {
|
|
id: string;
|
|
// page_id 불필요 (페이지의 components 배열에 포함됨)
|
|
type: 'text' | 'label' | 'image' | 'table' | ...;
|
|
x: number;
|
|
y: number;
|
|
width: number;
|
|
height: number;
|
|
// ... 기타 속성
|
|
}
|
|
|
|
export interface ReportLayoutConfig {
|
|
pages: ReportPage[];
|
|
}
|
|
```
|
|
|
|
### 4.2 Context 구조 변경
|
|
|
|
```typescript
|
|
interface ReportDesignerContextType {
|
|
// 페이지 관리
|
|
pages: ReportPage[];
|
|
currentPageId: string | null;
|
|
currentPage: ReportPage | null;
|
|
|
|
addPage: () => void;
|
|
deletePage: (pageId: string) => void;
|
|
duplicatePage: (pageId: string) => void;
|
|
reorderPages: (sourceIndex: number, targetIndex: number) => void;
|
|
selectPage: (pageId: string) => void;
|
|
updatePage: (pageId: string, updates: Partial<ReportPage>) => void;
|
|
|
|
// 컴포넌트 (현재 페이지만)
|
|
currentPageComponents: ComponentConfig[];
|
|
|
|
// ... 기존 기능들
|
|
}
|
|
```
|
|
|
|
### 4.3 UI 구조
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ ReportDesignerToolbar (저장, 미리보기, 페이지 추가 등) │
|
|
├──────────┬────────────────────────────────────┬─────────────┤
|
|
│ │ │ │
|
|
│ PageList │ ReportDesignerCanvas │ Right │
|
|
│ (좌측) │ (현재 페이지만 표시) │ Panel │
|
|
│ │ │ (속성) │
|
|
│ - Page 1 │ ┌──────────────────────────┐ │ │
|
|
│ - Page 2 │ │ │ │ │
|
|
│ * Page 3 │ │ [컴포넌트들] │ │ │
|
|
│ (현재) │ │ │ │ │
|
|
│ │ └──────────────────────────┘ │ │
|
|
│ [+ 추가] │ │ │
|
|
│ │ 이전 | 다음 (페이지 네비게이션) │ │
|
|
└──────────┴────────────────────────────────────┴─────────────┘
|
|
```
|
|
|
|
## 5. 컴포넌트 구조
|
|
|
|
### 5.1 새 컴포넌트
|
|
|
|
#### PageListPanel.tsx
|
|
|
|
```typescript
|
|
- 좌측 페이지 목록 패널
|
|
- 페이지 썸네일 표시
|
|
- 드래그 앤 드롭으로 순서 변경
|
|
- 페이지 추가/삭제/복사 버튼
|
|
- 현재 페이지 하이라이트
|
|
```
|
|
|
|
#### PageNavigator.tsx
|
|
|
|
```typescript
|
|
- 캔버스 하단의 페이지 네비게이션
|
|
- 이전/다음 버튼
|
|
- 현재 페이지 번호 표시
|
|
- 페이지 점프 (1/5 형식)
|
|
```
|
|
|
|
#### PageSettingsPanel.tsx
|
|
|
|
```typescript
|
|
- 우측 패널 내 페이지 설정 섹션
|
|
- 페이지 크기, 방향
|
|
- 여백 설정
|
|
- 배경색
|
|
```
|
|
|
|
### 5.2 수정할 컴포넌트
|
|
|
|
#### ReportDesignerContext.tsx
|
|
|
|
- pages 상태 추가
|
|
- currentPageId 상태 추가
|
|
- 페이지 관리 함수들 추가
|
|
- components를 currentPageComponents로 필터링
|
|
|
|
#### ReportDesignerCanvas.tsx
|
|
|
|
- currentPageComponents만 렌더링
|
|
- 캔버스 크기를 currentPage 기준으로 설정
|
|
- 컴포넌트 추가 시 page_id 포함
|
|
|
|
#### ReportDesignerToolbar.tsx
|
|
|
|
- "페이지 추가" 버튼 추가
|
|
- 저장 시 pages도 함께 저장
|
|
|
|
#### ReportPreviewModal.tsx
|
|
|
|
- 모든 페이지 순서대로 미리보기
|
|
- 페이지 구분선 표시
|
|
- PDF 저장 시 모든 페이지 포함
|
|
|
|
## 6. API 엔드포인트
|
|
|
|
### 6.1 페이지 관리
|
|
|
|
```typescript
|
|
// 페이지 목록 조회
|
|
GET /api/report/:reportId/pages
|
|
Response: { pages: ReportPage[] }
|
|
|
|
// 페이지 생성
|
|
POST /api/report/:reportId/pages
|
|
Body: { page_name, width, height, orientation, margins }
|
|
Response: { page: ReportPage }
|
|
|
|
// 페이지 수정
|
|
PUT /api/report/pages/:pageId
|
|
Body: Partial<ReportPage>
|
|
Response: { page: ReportPage }
|
|
|
|
// 페이지 삭제
|
|
DELETE /api/report/pages/:pageId
|
|
Response: { success: boolean }
|
|
|
|
// 페이지 순서 변경
|
|
PUT /api/report/:reportId/pages/reorder
|
|
Body: { pageOrders: Array<{ page_id, page_order }> }
|
|
Response: { success: boolean }
|
|
|
|
// 페이지 복사
|
|
POST /api/report/pages/:pageId/duplicate
|
|
Response: { page: ReportPage }
|
|
```
|
|
|
|
### 6.2 레이아웃 (기존 수정)
|
|
|
|
```typescript
|
|
// 레이아웃 저장 (페이지별)
|
|
PUT /api/report/:reportId/layout
|
|
Body: {
|
|
pages: ReportPage[],
|
|
components: ComponentConfig[] // page_id 포함
|
|
}
|
|
```
|
|
|
|
## 7. 구현 단계
|
|
|
|
### Phase 1: DB 및 백엔드 (0.5일)
|
|
|
|
1. ✅ DB 스키마 생성
|
|
2. ✅ API 엔드포인트 구현
|
|
3. ✅ 기존 리포트 마이그레이션 (단일 페이지 생성)
|
|
|
|
### Phase 2: 타입 및 Context (0.5일)
|
|
|
|
1. ✅ 타입 정의 업데이트
|
|
2. ✅ Context에 페이지 상태/함수 추가
|
|
3. ✅ API 연동
|
|
|
|
### Phase 3: UI 컴포넌트 (1일)
|
|
|
|
1. ✅ PageListPanel 구현
|
|
2. ✅ PageNavigator 구현
|
|
3. ✅ PageSettingsPanel 구현
|
|
|
|
### Phase 4: 통합 및 수정 (1일)
|
|
|
|
1. ✅ Canvas에서 현재 페이지만 표시
|
|
2. ✅ 컴포넌트 추가/수정 시 page_id 처리
|
|
3. ✅ 미리보기에서 모든 페이지 표시
|
|
4. ✅ PDF/WORD 저장에서 모든 페이지 처리
|
|
|
|
### Phase 5: 테스트 및 최적화 (0.5일)
|
|
|
|
1. ✅ 페이지 전환 성능 확인
|
|
2. ✅ 썸네일 렌더링 최적화
|
|
3. ✅ 버그 수정
|
|
|
|
**총 예상 기간: 3-4일**
|
|
|
|
## 8. 주의사항
|
|
|
|
### 8.1 성능 최적화
|
|
|
|
- 페이지 썸네일은 저해상도로 렌더링
|
|
- 현재 페이지 컴포넌트만 DOM에 유지
|
|
- 페이지 전환 시 애니메이션 최소화
|
|
|
|
### 8.2 호환성
|
|
|
|
- 기존 리포트는 자동으로 단일 페이지로 마이그레이션
|
|
- 템플릿도 페이지 구조 포함
|
|
|
|
### 8.3 사용자 경험
|
|
|
|
- 페이지 삭제 시 확인 다이얼로그
|
|
- 컴포넌트가 있는 페이지 삭제 시 경고
|
|
- 페이지 순서 변경 시 즉시 반영
|
|
|
|
## 9. 추후 확장 기능
|
|
|
|
### 9.1 페이지 템플릿
|
|
|
|
- 자주 사용하는 페이지 레이아웃 저장
|
|
- 페이지 추가 시 템플릿 선택
|
|
|
|
### 9.2 마스터 페이지
|
|
|
|
- 모든 페이지에 공통으로 적용되는 헤더/푸터
|
|
- 페이지 번호 자동 삽입
|
|
|
|
### 9.3 페이지 연결
|
|
|
|
- 테이블 데이터가 여러 페이지에 자동 분할
|
|
- 페이지 오버플로우 처리
|
|
|
|
## 10. 참고 자료
|
|
|
|
- 오즈리포트 메뉴얼
|
|
- Crystal Reports 페이지 관리
|
|
- Adobe InDesign 페이지 시스템
|