docs: Phase 5 API 문서 추가 (사용자 초대, 알림설정, 계정관리)

- erp-api-list.md: Phase 5 섹션 추가 (12개 API)
- erp-api-detail.md: Phase 5 상세 스펙 추가
  - 13. 사용자 초대 (5개): 목록, 발송, 수락, 취소, 재발송
  - 14. 알림 설정 (3개): 조회, 수정, 일괄수정
  - 15. 계정 관리 (4개): 탈퇴, 사용중지, 약관조회, 약관수정
This commit is contained in:
2025-12-19 15:35:41 +09:00
parent 441faa8922
commit 1066ea25b2
16 changed files with 3821 additions and 19 deletions

View File

@@ -35,6 +35,7 @@ Phase 4: 견적 API 개발
docs/projects/quotation/
├── MASTER_PLAN.md # 이 문서
├── PROGRESS.md # 진행 현황
├── screenshots/ # MES 프로토타입 화면 캡쳐
├── phase-1-5130-analysis/ # 1단계: 5130 분석
│ ├── README.md
│ ├── ui-analysis.md
@@ -128,6 +129,25 @@ docs/projects/quotation/
- Phase 1 분석 결과 (js-formulas.md)
- Phase 2 분석 결과
**UI 참조 (MES 프로토타입 화면 캡쳐):**
> 📁 경로: `docs/projects/quotation/screenshots/`
| 파일명 | 설명 |
|--------|------|
| `01-formula-list-main.png` | 견적수식 목록 메인 (기본정보 카테고리, 10개 수식) |
| `02-product-dropdown.png` | 제품 선택 드롭다운 (공통/스크린/철재/슬랫) |
| `03-category-management.png` | 분류 관리 (스크린/철재/전기부품/기타부자재) |
| `04-price-formula-management.png` | 단가 수식 관리 (그룹별 품목, 적용수식 설정) |
| `05-auto-quotation-input.png` | 자동 견적 산출 입력 (오픈사이즈, 옵션 선택) |
| `06-category-guiderail.png` | 가이드레일 카테고리 수식 (조회/계산식 타입) |
| `07-formula-add-modal.png` | 수식 추가 모달 (변수, 타입, 결과출력 설정) |
**캡쳐 화면 핵심 기능:**
- 13개 카테고리 (기본정보~장수산출)
- 44개 수식 (공통)
- 수식 타입: 입력값, 계산식, 조회
- 결과 타입: 변수저장, 품목/수량 출력
**산출물:**
| 파일 | 설명 |
|------|------|
@@ -189,5 +209,6 @@ MCP: Sequential Thinking 적용
| 날짜 | 변경 내용 | 작성자 |
|------|----------|--------|
| 2025-12-19 | Phase 3에 MES 프로토타입 화면 캡쳐 참조 추가 | Claude |
| 2025-12-19 | 공통 정책 분리, 견적 특화 내용만 유지 | Claude |
| 2025-12-19 | 초기 마스터 플랜 작성 | Claude |

View File

@@ -6,11 +6,11 @@
---
## 📊 전체 진행률
## 전체 진행률
| Phase | 상태 | 진행률 | 시작일 | 완료일 |
|-------|------|--------|--------|--------|
| Phase 1: 5130 분석 | ⏳ 대기 | 0% | - | - |
| Phase 1: 5130 분석 | ✅ 완료 | 100% | 2025-12-19 | 2025-12-19 |
| Phase 2: mng 분석 | ⏳ 대기 | 0% | - | - |
| Phase 3: 구현 | ⏳ 대기 | 0% | - | - |
| Phase 4: API 개발 | ⏳ 대기 | 0% | - | - |
@@ -19,36 +19,54 @@
## 🔄 현재 작업
**현재 Phase:** 시작 전
**현재 작업:** 마스터 플랜 작성 완료
**현재 Phase:** Phase 1 완료, Phase 2 대기
**다음 작업:** mng 견적 수식 관리 현황 분석
---
## 📋 Phase 1: 5130 견적 기능 분석
## Phase 1: 5130 견적 기능 분석 (완료)
### 체크리스트
- [ ] UI/화면 분석 (list.php, form.php 등)
- [ ] JS 수식 분석 (모든 JS 파일)
- [ ] DB 구조 분석
- [ ] 비즈니스 로직 문서화
- [ ] README.md 작성
- [x] UI/화면 분석 (list.php, write_form.php 등)
- [x] JS 수식 분석 (calculation.js, fetch_unitprice.php)
- [x] PHP 계산 로직 분석 (get_screen_amount.php, get_slat_amount.php)
- [x] DB 구조 분석 (estimate, BDmodels, price_* 테이블)
- [x] 비즈니스 로직 문서화
- [x] README.md 작성
### 산출물
- [ ] phase-1-5130-analysis/README.md
- [ ] phase-1-5130-analysis/ui-analysis.md
- [ ] phase-1-5130-analysis/js-formulas.md
- [ ] phase-1-5130-analysis/db-structure.md
- [ ] phase-1-5130-analysis/business-logic.md
- [x] [README.md](./phase-1-5130-analysis/README.md) - 분석 체크리스트 및 요약
- [x] [js-formulas.md](./phase-1-5130-analysis/js-formulas.md) - **핵심** 수식 분석 (19개 항목)
- [x] [ui-analysis.md](./phase-1-5130-analysis/ui-analysis.md) - 화면별 기능 분석
- [x] [db-structure.md](./phase-1-5130-analysis/db-structure.md) - 테이블/컬럼 구조
- [x] [business-logic.md](./phase-1-5130-analysis/business-logic.md) - 비즈니스 로직 정리
### 메모
_Phase 1 진행 시 메모 기록_
### 핵심 발견 사항
#### 견적 유형 (2가지)
| 유형 | 주요 특징 |
|------|----------|
| 스크린 | 면적 기반 (높이+550), 실리카/와이어 소재 |
| 슬랫(철재) | 면적 기반 (높이+50), 방화슬랫 소재 |
#### 계산 항목 (18개)
검사비, 주자재, 조인트바, 모터, 제어기, 케이스, 케이스연기차단재, 마구리, 앵글, 가이드레일, 레일연기차단재, 하장바, L바, 보강평철, 샤프트, 무게평철, 환봉, 각파이프
#### 옵션 체크박스 (5개)
| 옵션 | 영향 항목 |
|------|----------|
| 절곡 | 케이스, 레일, 연기차단재, 하장바, L바, 보강평철 |
| 모터 | 모터 가격 |
| 보증 | 보증기간 |
| 슬랫 | 주자재(슬랫), 조인트바 |
| 부자재 | 샤프트, 각파이프, 앵글 |
---
## 📋 Phase 2: mng 견적 수식 관리 분석
### 체크리스트
- [ ] 현재 구현 상태 분석
- [ ] 현재 구현 상태 분석 (quote-formulas)
- [ ] 오류/문제점 목록화
- [ ] 개선 방향 도출
- [ ] README.md 작성
@@ -114,6 +132,8 @@ _Phase 4 진행 시 메모 기록_
|------|------|----------|------|
| 2025-12-19 | DB 작업 위치 | api 프로젝트에서만 | mng 마이그레이션 방지 |
| 2025-12-19 | 신규 테이블 정책 | options JSON 적용 | Hybrid EAV 전략 |
| 2025-12-19 | 견적 유형 | 스크린/슬랫 2가지 | 5130 기존 구조 유지 |
| 2025-12-19 | 체크박스 옵션 | JSON으로 통합 저장 | 확장성 고려 |
---
@@ -126,4 +146,6 @@ _현재 이슈 없음_
## 📚 참조 문서
- [MASTER_PLAN.md](./MASTER_PLAN.md) - 마스터 플랜
- [docs/projects/mes/v1-analysis/quotation-analysis.md](../mes/v1-analysis/quotation-analysis.md) - MES 견적 분석
- [phase-1-5130-analysis/](./phase-1-5130-analysis/) - Phase 1 분석 결과
- [docs/projects/mes/v1-analysis/quotation-analysis.md](../mes/v1-analysis/quotation-analysis.md) - MES 견적 분석
- [docs/projects/legacy-5130/03_ESTIMATE.md](../legacy-5130/03_ESTIMATE.md) - 5130 레거시 분석

View File

@@ -0,0 +1,148 @@
# Phase 1: 5130 견적 기능 분석
> **목표:** 5130 레거시 견적 시스템 완전 분석 및 문서화
> **분석 일자:** 2025-12-19
> **상태:** 🔄 진행 중
---
## 📋 분석 체크리스트
### 핵심 분석 (필수)
- [x] JS 수식 분석 (`common/calculation.js`)
- [x] PHP 단가 계산 로직 (`fetch_unitprice.php`)
- [x] 스크린 금액 계산 (`get_screen_amount.php`)
- [x] 슬랫 금액 계산 (`get_slat_amount.php`)
- [x] DB 스키마 분석 (`estimate` 테이블)
### 문서 작성
- [x] js-formulas.md - 수식 분석 (핵심!)
- [x] ui-analysis.md - 화면별 기능 분석
- [x] db-structure.md - 테이블/컬럼 구조
- [x] business-logic.md - 비즈니스 로직 정리
---
## 📁 분석 대상 파일
### 핵심 파일
| 파일 | 크기 | 설명 |
|------|------|------|
| `common/calculation.js` | 182줄 | 프론트엔드 행 계산 로직 |
| `fetch_unitprice.php` | 875줄 | **핵심** - 단가 조회 및 수식 함수 |
| `get_screen_amount.php` | 583줄 | 스크린 견적 계산 |
| `get_slat_amount.php` | 541줄 | 슬랫(철재) 견적 계산 |
| `write_form.php` | 103KB | 견적서 작성 UI |
### 디렉토리 구조
```
5130/estimate/
├── common/
│ ├── calculation.js # 행 계산 JS
│ ├── lastJS.php # 페이지 공통 JS
│ ├── common_screen.php # 스크린 공통
│ └── common_slat.php # 슬랫 공통
├── list.php # 견적 목록
├── write_form.php # 견적서 작성
├── estimate.php # 견적서 메인
├── estimateSlat.php # 슬랫 견적
├── estimateUnit.php # 단가 견적
├── fetch_unitprice.php # 단가 조회 API
├── get_estimate_amount.php # 견적 금액 라우터
├── get_screen_amount.php # 스크린 금액 계산
├── get_slat_amount.php # 슬랫 금액 계산
├── insert.php # 견적 저장
└── generate_serial_pjnum.php # 번호 생성
```
---
## 🔍 핵심 발견 사항
### 1. 견적 유형 (2가지)
| 유형 | 파일 | 주요 특징 |
|------|------|----------|
| **스크린** | `get_screen_amount.php` | 면적(m²) 기반, 실리카/와이어 소재 |
| **슬랫(철재)** | `get_slat_amount.php` | 면적 기반, 방화 슬랫 소재 |
### 2. 계산 항목 (18개 항목)
1. 검사비 (인정검사비)
2. 주자재 (스크린/슬랫)
3. 조인트바 (슬랫 전용)
4. 모터
5. 연동제어기 (매립형/노출형/뒷박스)
6. 케이스
7. 케이스용 연기차단재
8. 케이스 마구리
9. 모터 받침용 앵글
10. 가이드레일
11. 레일용 연기차단재
12. 하장바
13. L바 (스크린 전용)
14. 보강평철 (스크린 전용)
15. 감기샤프트
16. 무게평철 (스크린 전용)
17. 환봉 (스크린 전용)
18. 각파이프
19. 앵글
### 3. 체크박스 옵션 (5개)
| 옵션 | 변수명 | 영향 항목 |
|------|--------|----------|
| 절곡 | `steel` | 케이스, 가이드레일, 연기차단재, 하장바, L바, 보강평철 |
| 모터 | `motor` | 모터 가격 포함 여부 |
| 보증 | `warranty` | 보증기간 |
| 슬랫 | `slatcheck` | 주자재(슬랫), 조인트바 |
| 부자재 | `partscheck` | 샤프트, 각파이프, 앵글 |
### 4. 단가 테이블 (7개)
| 테이블 | 용도 |
|--------|------|
| `price_raw_materials` | 주자재 단가 (스크린, 슬랫) |
| `price_motor` | 모터/제어기 단가 |
| `price_shaft` | 샤프트 단가 |
| `price_pipe` | 각파이프 단가 |
| `price_angle` | 앵글 단가 |
| `BDmodels` | 케이스, 가이드레일, 부자재 단가 |
| `item_list` | 품목 마스터 |
---
## 📊 상세 문서
| 문서 | 설명 |
|------|------|
| [js-formulas.md](./js-formulas.md) | **핵심** - 모든 수식 상세 분석 |
| [ui-analysis.md](./ui-analysis.md) | 화면별 기능 분석 |
| [db-structure.md](./db-structure.md) | DB 테이블 구조 |
| [business-logic.md](./business-logic.md) | 비즈니스 로직 정리 |
---
## ⚠️ 주의 사항
### 코드 특성
1. **레거시 PHP + jQuery** - ES6 문법 없음
2. **동적 테이블명** - 일부 쿼리에서 테이블명 동적 설정
3. **JSON 기반 데이터** - `itemList` 컬럼에 JSON으로 상세 데이터 저장
4. **컬럼명 규칙** - `col1`, `col2`, ... 형태의 범용 컬럼
### SAM 이관 시 고려사항
1. 단가 테이블 구조 재설계 필요
2. `BDmodels` 테이블 → SAM 품목기준관리 연동
3. 체크박스 옵션 → 견적 옵션 테이블 설계
4. 수식 로직 → Service 클래스로 분리
---
## 📝 다음 단계
Phase 2로 이동하여 현재 mng 견적 수식 관리 상태 분석 예정
---
## 📚 참조
- [MASTER_PLAN.md](../MASTER_PLAN.md)
- [PROGRESS.md](../PROGRESS.md)
- [docs/projects/legacy-5130/03_ESTIMATE.md](../../legacy-5130/03_ESTIMATE.md)

View File

@@ -0,0 +1,472 @@
# 비즈니스 로직 분석
> **분석 대상:** 5130 레거시 견적 시스템 비즈니스 로직
> **분석 일자:** 2025-12-19
---
## 비즈니스 프로세스 개요
### 견적 생성 플로우
```
┌─────────────────────────────────────────────────────────────┐
│ 1. 견적 시작 │
│ └─ 신규 / 복사 / 수주연계 │
├─────────────────────────────────────────────────────────────┤
│ 2. 기본 정보 입력 │
│ └─ 현장명, 발주처, 담당자 │
├─────────────────────────────────────────────────────────────┤
│ 3. 제품 선택 │
│ ├─ 대분류: 스크린 / 철재 │
│ ├─ 모델: KSS01, KFS01 등 │
│ └─ 규격: 폭, 높이, 마구리윙 │
├─────────────────────────────────────────────────────────────┤
│ 4. 옵션 선택 │
│ └─ 절곡, 모터, 보증, 슬랫, 부자재 │
├─────────────────────────────────────────────────────────────┤
│ 5. 상세 항목 입력 │
│ ├─ 각 행별 위치, 폭, 높이, 수량 입력 │
│ └─ 자동 계산 트리거 │
├─────────────────────────────────────────────────────────────┤
│ 6. 금액 계산 (자동) │
│ ├─ AJAX → get_screen_amount / get_slat_amount │
│ ├─ 18개 항목별 단가 조회 및 계산 │
│ └─ 합계 산출 │
├─────────────────────────────────────────────────────────────┤
│ 7. 할인 적용 │
│ └─ 할인율 / 할인액 입력 → 최종금액 계산 │
├─────────────────────────────────────────────────────────────┤
│ 8. 저장 │
│ ├─ 견적번호 생성 (KD-PR-YYMMDD-NN) │
│ └─ DB 저장 (estimate 테이블) │
└─────────────────────────────────────────────────────────────┘
```
---
## 1. 견적 유형별 처리
### 스크린 견적 (Screen)
| 특성 | 값 |
|------|-----|
| 대분류 | 스크린 |
| 주자재 소재 | 실리카, 와이어 |
| 면적 계산 | (높이 + 550) × 폭 / 1,000,000 m² |
| 기본 제작폭 | 160mm |
| 전용 항목 | L바, 보강평철, 무게평철, 환봉 |
### 슬랫 견적 (Slat/철재)
| 특성 | 값 |
|------|-----|
| 대분류 | 철재 |
| 주자재 소재 | 방화슬랫 |
| 면적 계산 | (높이 + 50) × 폭 / 1,000,000 m² |
| 기본 제작폭 | 110mm |
| 전용 항목 | 조인트바 |
---
## 2. 옵션 체크박스 로직
### 옵션별 영향 항목
| 옵션 | 변수 | 영향받는 항목 |
|------|------|---------------|
| 절곡 | `steel` | 케이스, 케이스용 연기차단재, 마구리, 가이드레일, 레일용 연기차단재, 하장바, L바(스크린), 보강평철(스크린) |
| 모터 | `motor` | 모터 가격 포함/미포함 |
| 보증 | `warranty` | 보증기간 표시 (인정) |
| 슬랫 | `slatcheck` | 주자재(슬랫), 조인트바 |
| 부자재 | `partscheck` | 감기샤프트, 각파이프, 앵글 |
### 조건부 계산 로직
```php
// 절곡 옵션 체크 시
if ($steel == '1') {
// 케이스, 연기차단재, 레일, 하장바 등 계산
$caseAmount = calculateCase($width, $caseType, $itemList);
$smokebanAmount = calculateSmokeban($width, $itemList);
// ...
} else {
// 해당 항목 0원 처리
$caseAmount = 0;
$smokebanAmount = 0;
}
// 모터 옵션 체크 시
if ($motor == '1') {
$motorAmount = getMotorPrice($motorCapacity);
} else {
$motorAmount = 0;
}
```
---
## 3. 단가 조회 로직
### 조회 우선순위
1. **BDmodels 테이블**: 모델별 품목 단가
2. **price_* 테이블**: 품목별 세부 단가
3. **기본값**: 조회 실패 시 기본 단가 적용
### 단가 조회 함수
```php
// fetch_unitprice.php
// 1. 모터 단가 조회
function getMotorPrice($capacity) {
// price_motor 테이블에서 용량별 단가 조회
$sql = "SELECT unit_price FROM price_motor WHERE capacity = ?";
// ...
}
// 2. 샤프트 단가 조회
function getShaftPrice($length) {
// price_shaft 테이블에서 길이별 단가 조회
$sql = "SELECT unit_price FROM price_shaft WHERE ? BETWEEN min_length AND max_length";
// ...
}
// 3. BDmodels에서 품목 단가 조회
function getBDModelPrice($modelname, $itemname, $size) {
$sql = "SELECT itemList FROM BDmodels WHERE modelname = ? AND itemname = ?";
// JSON 파싱 후 사이즈에 맞는 가격 반환
}
```
---
## 4. 금액 계산 플로우
### 스크린 금액 계산 (get_screen_amount.php)
```
┌─────────────────────────────────────────────────────────────┐
│ 입력값 │
│ - 폭(col2), 높이(col3), 수량(col4), 소재(col5) │
│ - 케이스타입(col6), 레일타입(col7), 설치방식(col8) │
│ - 체크박스옵션 (steel, motor, warranty, slatcheck, partscheck)│
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ 1. 면적 계산 │
│ area = (height + 550) × width / 1,000,000 │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ 2. 중량 계산 (모터 용량 결정용) │
│ weight = area × 소재별_단위중량 │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ 3. 모터 용량 결정 │
│ motorCapacity = searchBracketSize(weight, inch) │
│ → 150K / 300K / 500K / 800K / 1000K │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ 4. 18개 항목별 금액 계산 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 1. 검사비: inspectionFee (고정) │ │
│ │ 2. 주자재: area × 소재단가 │ │
│ │ 3. 모터: getMotorPrice(capacity) × motor체크 │ │
│ │ 4. 제어기: getControllerPrice(type) × motor체크 │ │
│ │ 5. 케이스: (width+제작폭) × m당단가 × steel체크 │ │
│ │ 6. 케이스연기차단재: width × m당단가 × steel체크 │ │
│ │ 7. 마구리: 2개 × 개당단가 × steel체크 │ │
│ │ 8. 앵글: 규격별단가 × steel체크 │ │
│ │ 9. 가이드레일: (height+레일여유) × m당단가 × steel │ │
│ │ 10. 레일연기차단재: height × m당단가 × steel │ │
│ │ 11. 하장바: width × m당단가 × steel체크 │ │
│ │ 12. L바: width × m당단가 × steel체크 │ │
│ │ 13. 보강평철: width × m당단가 × steel체크 │ │
│ │ 14. 샤프트: getShaftPrice(width) × partscheck │ │
│ │ 15. 무게평철: weight계산 × 단가 │ │
│ │ 16. 환봉: 길이계산 × m당단가 │ │
│ │ 17. 각파이프: 길이계산 × m당단가 × partscheck │ │
│ │ 18. 앵글: 길이계산 × m당단가 × partscheck │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ 5. 행 합계 │
│ rowTotal = Σ(항목별금액) × 수량 │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ 6. 전체 합계 │
│ estimateTotal = Σ(모든행 rowTotal) │
│ EstimateFinalSum = estimateTotal - 할인액 │
└─────────────────────────────────────────────────────────────┘
```
---
## 5. 모터 용량 결정 로직
### 중량 + 인치 기반 판단
```php
function searchBracketSize($motorWeight, $bracketInch = null) {
$weight = floatval($motorWeight);
$inch = intval($bracketInch);
// 인치별 중량 기준
if ($inch > 0) {
// 4인치 기준
if ($inch == 4 && $weight <= 300) 300K
if ($inch == 4 && $weight <= 400) 400K
// 5인치 기준
if ($inch == 5 && $weight <= 246) 300K
if ($inch == 5 && $weight <= 327) 400K
if ($inch == 5 && $weight <= 500) 500K
if ($inch == 5 && $weight <= 600) 600K
// 6인치 기준
if ($inch == 6 && $weight <= 208) 300K
if ($inch == 6 && $weight <= 277) 400K
if ($inch == 6 && $weight <= 424) 500K
if ($inch == 6 && $weight <= 508) 600K
if ($inch == 6 && $weight <= 800) 800K
if ($inch == 6 && $weight <= 1000) 1000K
// 8인치 기준
if ($inch == 8 && $weight <= 324) 500K
if ($inch == 8 && $weight <= 388) 600K
if ($inch == 8 && $weight <= 611) 800K
if ($inch == 8 && $weight <= 1000) 1000K
} else {
// 인치 없이 중량만으로 판단
if ($weight <= 300) 300K
if ($weight <= 400) 400K
if ($weight <= 500) 500K
if ($weight <= 600) 600K
if ($weight <= 800) 800K
if ($weight <= 1000) 1000K
}
}
```
### 브라켓 사이즈 매핑
| 모터 용량 | 브라켓 사이즈 |
|-----------|---------------|
| 300K, 400K | 530×320 |
| 500K, 600K | 600×350 |
| 800K, 1000K | 690×390 |
---
## 6. 견적번호 생성
### 형식
```
KD-PR-YYMMDD-NN
KD: 경동 (회사코드)
PR: 프로젝트
YYMMDD: 날짜 (년월일 6자리)
NN: 일련번호 (01~99, 당일 기준)
```
### 생성 로직
```php
// generate_serial_pjnum.php
function generatePjnum($pdo) {
$today = date('ymd');
$prefix = "KD-PR-{$today}-";
// 오늘 날짜의 마지막 번호 조회
$sql = "SELECT pjnum FROM estimate
WHERE pjnum LIKE ?
ORDER BY pjnum DESC LIMIT 1";
$stmh = $pdo->prepare($sql);
$stmh->execute([$prefix . '%']);
$row = $stmh->fetch();
if ($row) {
// 마지막 번호 추출 후 +1
$lastNum = intval(substr($row['pjnum'], -2));
$nextNum = str_pad($lastNum + 1, 2, '0', STR_PAD_LEFT);
} else {
$nextNum = '01';
}
return $prefix . $nextNum;
}
```
---
## 7. 금액 처리 규칙
### 단위 변환
| 항목 | 입력 단위 | 계산 단위 | 비고 |
|------|----------|----------|------|
| 폭/높이 | mm | m | /1000 변환 |
| 면적 | - | m² | 폭×높이/1,000,000 |
| 중량 | - | kg | 면적×단위중량 |
| 금액 | - | 원 | 천원 단위 반올림 |
### 반올림 규칙
```javascript
// calculation.js
// 금액은 천원 단위에서 반올림
roundedAreaPrice = Math.round(areaPrice / 1000) * 1000;
// 면적은 소수점 2자리
area = Math.round(area * 100) / 100;
```
### 수동 편집 처리
```javascript
// 수동 편집된 셀은 배경색 변경
$('.manually-edited').css('background-color', '#f8d7da');
// 자동 계산 시 수동 편집 값 유지 옵션
if (!isManuallyEdited) {
cell.val(calculatedValue);
}
```
---
## 8. 데이터 저장 규칙
### 저장 전 검증
1. 필수값 확인: 현장명, 발주처, 담당자
2. 수치 변환: 콤마 제거, 정수 변환
3. 권한 확인: 레벨 5 이하
### 저장 데이터
```php
// insert.php
$data = [
'pjnum' => generatePjnum(),
'indate' => date('Y-m-d'),
'orderman' => $_SESSION['name'],
'outworkplace' => $outworkplace,
'major_category' => $major_category,
'model_name' => $model_name,
'makeWidth' => intval(str_replace(',', '', $makeWidth)),
'makeHeight' => intval(str_replace(',', '', $makeHeight)),
'maguriWing' => $maguriWing,
'inspectionFee' => intval(str_replace(',', '', $inspectionFee)),
'estimateList' => json_encode($estimateList),
'estimateList_auto' => json_encode($estimateList_auto),
'estimateSlatList' => json_encode($estimateSlatList),
'estimateSlatList_auto' => json_encode($estimateSlatList_auto),
'estimateTotal' => intval(str_replace(',', '', $estimateTotal)),
'steel' => $steel,
'motor' => $motor,
'warranty' => $warranty,
'slatcheck' => $slatcheck,
'partscheck' => $partscheck
];
```
---
## 9. SAM 이관 시 로직 변경
### Service 클래스 분리
```php
// app/Services/QuotationService.php
class QuotationService
{
// 1. 견적 생성
public function createQuote(array $data): Quote { }
// 2. 금액 계산
public function calculateAmount(Quote $quote): array { }
// 3. 스크린 계산
protected function calculateScreenAmount(array $details): array { }
// 4. 슬랫 계산
protected function calculateSlatAmount(array $details): array { }
// 5. 모터 용량 결정
protected function determineMotorCapacity(float $weight, ?int $inch): int { }
// 6. 단가 조회
protected function getUnitPrice(string $itemCode, array $params): float { }
}
```
### 계산 로직 캡슐화
```php
// app/ValueObjects/QuoteDimension.php
class QuoteDimension
{
public function __construct(
public readonly int $width,
public readonly int $height,
public readonly int $wing = 50
) {}
public function getAreaForScreen(): float
{
return ($this->height + 550) * $this->width / 1000000;
}
public function getAreaForSlat(): float
{
return ($this->height + 50) * $this->width / 1000000;
}
}
```
### 옵션 처리
```php
// app/ValueObjects/QuoteOptions.php
class QuoteOptions
{
public function __construct(
public readonly bool $steel = false,
public readonly bool $motor = false,
public readonly bool $warranty = false,
public readonly bool $slat = false,
public readonly bool $parts = false
) {}
public static function fromArray(array $data): self
{
return new self(
steel: $data['steel'] ?? false,
motor: $data['motor'] ?? false,
warranty: $data['warranty'] ?? false,
slat: $data['slat'] ?? false,
parts: $data['parts'] ?? false
);
}
public function toJson(): string
{
return json_encode([
'steel' => $this->steel,
'motor' => $this->motor,
'warranty' => $this->warranty,
'slat' => $this->slat,
'parts' => $this->parts
]);
}
}
```
---
## 참조 파일
- `5130/estimate/get_screen_amount.php` - 스크린 계산 로직
- `5130/estimate/get_slat_amount.php` - 슬랫 계산 로직
- `5130/estimate/fetch_unitprice.php` - 단가 조회 함수
- `5130/estimate/insert.php` - 저장 로직
- `5130/estimate/generate_serial_pjnum.php` - 번호 생성

View File

@@ -0,0 +1,448 @@
# DB 구조 분석
> **분석 대상:** 5130 레거시 견적 시스템 데이터베이스
> **데이터베이스:** chandj
> **분석 일자:** 2025-12-19
---
## 테이블 목록
### 핵심 테이블
| 테이블명 | 용도 | 비고 |
|----------|------|------|
| `estimate` | 견적서 마스터 | 견적 헤더 + JSON 상세 |
| `BDmodels` | 모델별 단가 | 케이스, 레일, 부자재 단가 |
| `BDparts` | 부품 단가 | 부품별 가격 계수 |
### 단가 테이블
| 테이블명 | 용도 | 비고 |
|----------|------|------|
| `price_raw_materials` | 주자재 단가 | 스크린, 슬랫 소재 |
| `price_motor` | 모터 단가 | 용량별 모터 가격 |
| `price_shaft` | 샤프트 단가 | 길이별 샤프트 가격 |
| `price_pipe` | 각파이프 단가 | 규격별 파이프 가격 |
| `price_angle` | 앵글 단가 | 규격별 앵글 가격 |
| `price_bend` | 절곡비 단가 | 절곡 가공비 |
| `price_smokeban` | 연기차단재 단가 | 연기차단재 가격 |
| `price_etc` | 기타 단가 | 기타 부자재 |
| `price_pole` | 폴 단가 | 폴 관련 가격 |
### 참조 테이블
| 테이블명 | 용도 |
|----------|------|
| `item_list` | 품목 마스터 |
| `output` | 발주서 (수주→발주 연계) |
---
## 1. estimate 테이블 (견적 마스터)
### 스키마
```sql
CREATE TABLE estimate (
num INT AUTO_INCREMENT PRIMARY KEY,
-- 기본 정보
pjnum VARCHAR(50), -- 프로젝트 번호 (KD-PR-YYMMDD-NN)
indate DATE, -- 등록일
orderman VARCHAR(50), -- 담당자
outworkplace VARCHAR(200), -- 현장명/거래처
-- 분류 정보
major_category VARCHAR(50), -- 대분류 (스크린/철재)
model_name VARCHAR(100), -- 모델명 (KSS01, KFS01 등)
position VARCHAR(50), -- 위치
-- 규격 정보
makeWidth INT DEFAULT 160, -- 제작 폭 (스크린:160, 슬랫:110)
makeHeight INT DEFAULT 350, -- 제작 높이
maguriWing VARCHAR(20) DEFAULT '50', -- 마구리 윙
-- 발주처 정보
con_num VARCHAR(50), -- 계약번호
secondord VARCHAR(100), -- 2차 발주처
secondordman VARCHAR(50), -- 2차 담당자
secondordmantel VARCHAR(20), -- 2차 담당자 연락처
secondordnum VARCHAR(50), -- 2차 발주번호
-- 견적 상세 (JSON)
estimateList TEXT, -- 스크린 견적 리스트 (JSON)
estimateList_auto TEXT, -- 스크린 자동계산 리스트 (JSON)
estimateSlatList TEXT, -- 슬랫 견적 리스트 (JSON)
estimateSlatList_auto TEXT, -- 슬랫 자동계산 리스트 (JSON)
-- 금액 정보
estimateTotal INT DEFAULT 0, -- 견적 총액
EstimateFirstSum INT DEFAULT 0, -- 최초 견적 합계
EstimateUpdatetSum INT DEFAULT 0, -- 수정 견적 합계
EstimateDiffer INT DEFAULT 0, -- 차액
estimateSurang INT DEFAULT 0, -- 수량
-- 할인 정보
EstimateDiscountRate INT DEFAULT 0,-- 할인율 (%)
EstimateDiscount INT DEFAULT 0, -- 할인금액
EstimateFinalSum INT DEFAULT 0, -- 최종 금액
-- 검사비/옵션
inspectionFee INT DEFAULT 50000, -- 인정검사비
steel VARCHAR(50), -- 절곡 옵션 (1/0)
motor VARCHAR(100), -- 모터 옵션 (1/0)
warranty VARCHAR(100), -- 보증 (인정/빈값)
slatcheck VARCHAR(10), -- 슬랫 체크 (1/0)
partscheck VARCHAR(10), -- 부자재 체크 (1/0)
-- 시스템 필드
comment TEXT, -- 비고
update_log TEXT, -- 수정이력
is_deleted TINYINT DEFAULT 0, -- 삭제플래그
INDEX idx_pjnum (pjnum),
INDEX idx_outworkplace (outworkplace),
INDEX idx_indate (indate)
);
```
### 주요 컬럼 설명
#### 프로젝트 번호 (pjnum)
```
형식: KD-PR-YYMMDD-NN
- KD: 경동
- PR: 프로젝트
- YYMMDD: 날짜 (6자리)
- NN: 일련번호 (01~99)
예시: KD-PR-251219-01
```
#### 대분류 (major_category)
| 값 | 설명 |
|----|------|
| 스크린 | 스크린 방화셔터 |
| 철재 | 철재 슬랫 방화셔터 |
#### 체크박스 옵션
| 컬럼 | 값 | 의미 |
|------|-----|------|
| steel | '1' / '0' | 절곡 포함/미포함 |
| motor | '1' / '0' | 모터 포함/미포함 |
| warranty | '인정' / '' | 보증 포함/미포함 |
| slatcheck | '1' / '0' | 슬랫 포함/미포함 |
| partscheck | '1' / '0' | 부자재 포함/미포함 |
---
## 2. estimateList JSON 구조
### 수동 입력 항목 (estimateList, estimateSlatList)
```json
[
{
"item_name": "가이드레일",
"specification": "A형 65×80",
"unit": "EA",
"quantity": 2,
"unit_price": 150000,
"amount": 300000,
"remark": ""
},
{
"item_name": "스크린 판넬",
"specification": "1.0T × 1200W",
"unit": "m²",
"quantity": 24.5,
"unit_price": 45000,
"amount": 1102500,
"remark": "SUS304"
}
]
```
### 자동 계산 항목 (estimateList_auto, estimateSlatList_auto)
```json
[
{
"item_code": "AUTO001",
"item_name": "벤딩 가공비",
"calc_type": "per_meter",
"base_value": 120.5,
"unit_price": 2500,
"amount": 301250
}
]
```
---
## 3. BDmodels 테이블 (모델별 단가)
### 스키마
```sql
CREATE TABLE IF NOT EXISTS BDmodels (
id INT AUTO_INCREMENT PRIMARY KEY,
modelname VARCHAR(50), -- 모델명
itemname VARCHAR(100), -- 품목명
itemsecond VARCHAR(100), -- 품목 세부
itemList TEXT, -- 상세 가격 JSON
is_deleted TINYINT DEFAULT 0,
INDEX idx_modelname (modelname),
INDEX idx_itemname (itemname)
);
```
### itemList JSON 구조
```json
{
"prices": [
{"size": "530*320", "price": 150000},
{"size": "600*350", "price": 180000},
{"size": "690*390", "price": 210000}
],
"unit": "EA",
"description": "모터 브라켓"
}
```
### 주요 품목
| modelname | itemname | 용도 |
|-----------|----------|------|
| 공통 | 케이스 | 케이스 단가 |
| 공통 | 가이드레일 | 레일 단가 |
| 공통 | 연기차단재 | 연기차단재 단가 |
| 공통 | 하장바 | 하장바 단가 |
| 공통 | 마구리 | 마구리 단가 |
| 스크린 | L바 | L바 단가 (스크린 전용) |
| 스크린 | 보강평철 | 보강평철 단가 (스크린 전용) |
| 슬랫 | 조인트바 | 조인트바 단가 (슬랫 전용) |
---
## 4. 단가 테이블
### price_raw_materials (주자재)
```sql
CREATE TABLE price_raw_materials (
id INT AUTO_INCREMENT PRIMARY KEY,
material_type VARCHAR(50), -- 소재 유형 (실리카, 와이어, 방화슬랫)
specification VARCHAR(100), -- 규격
unit VARCHAR(20), -- 단위 (m², kg)
unit_price DECIMAL(10,0), -- 단가
itemList TEXT, -- 상세 JSON
is_deleted TINYINT DEFAULT 0
);
```
### price_motor (모터)
```sql
CREATE TABLE price_motor (
id INT AUTO_INCREMENT PRIMARY KEY,
capacity VARCHAR(20), -- 용량 (150K, 300K, 500K, 800K, 1000K)
type VARCHAR(50), -- 유형
unit_price DECIMAL(10,0), -- 단가
is_deleted TINYINT DEFAULT 0
);
```
### price_shaft (샤프트)
```sql
CREATE TABLE price_shaft (
id INT AUTO_INCREMENT PRIMARY KEY,
length_range VARCHAR(50), -- 길이 범위
unit_price DECIMAL(10,0), -- 단가
weight_per_meter DECIMAL(5,2), -- m당 중량
is_deleted TINYINT DEFAULT 0
);
```
### price_pipe (각파이프)
```sql
CREATE TABLE price_pipe (
id INT AUTO_INCREMENT PRIMARY KEY,
specification VARCHAR(50), -- 규격 (50×50, 75×75 등)
unit_price DECIMAL(10,0), -- m당 단가
weight_per_meter DECIMAL(5,2), -- m당 중량
is_deleted TINYINT DEFAULT 0
);
```
### price_angle (앵글)
```sql
CREATE TABLE price_angle (
id INT AUTO_INCREMENT PRIMARY KEY,
specification VARCHAR(50), -- 규격 (50×50×5 등)
unit_price DECIMAL(10,0), -- m당 단가
weight_per_meter DECIMAL(5,2), -- m당 중량
is_deleted TINYINT DEFAULT 0
);
```
---
## 5. 컬럼 매핑 (스크린 vs 슬랫)
### get_screen_amount.php 컬럼
| 항목 | 컬럼 | 설명 |
|------|------|------|
| 위치 | col1 | 설치 위치 |
| 폭 | col2 | 오픈사이즈 폭 (mm) |
| 높이 | col3 | 오픈사이즈 높이 (mm) |
| 수량 | col4 | 수량 |
| 소재 | col5 | 실리카/와이어 |
| 케이스 타입 | col6 | 절곡/롤 |
| 레일 타입 | col7 | A형/B형 |
| 설치방식 | col8 | 매립/노출 |
| 면적 | col9 | 계산된 면적 (m²) |
| 케이스 길이 | col10 | mm |
| 레일 길이 | col11 | mm |
| 하장바 길이 | col12 | mm |
| 중량 | col13 | kg |
| 검사비 | col14 | 원 |
| 주자재 | col15 | 원 |
| 모터 | col16 | 원 |
| 제어기 | col17 | 원 |
| 케이스 | col18 | 원 |
| 레일 | col19 | 원 |
| 앵글 | col20 | 원 |
| 샤프트 | col21 | 원 |
| 인치 | col22 | 샤프트 인치 |
### get_slat_amount.php 컬럼
| 항목 | 컬럼 | 설명 |
|------|------|------|
| 위치 | col1 | 설치 위치 |
| 폭 | col2 | 오픈사이즈 폭 (mm) |
| 높이 | col3 | 오픈사이즈 높이 (mm) |
| 수량 | col4 | 수량 |
| 소재 | col5 | 방화슬랫 |
| 케이스 타입 | col6 | 절곡/롤 |
| 레일 타입 | col7 | A형/B형 |
| 설치방식 | col8 | 매립/노출 |
| 면적 | col9 | 계산된 면적 (m²) |
| 케이스 길이 | col10 | mm |
| 레일 길이 | col11 | mm |
| 하장바 길이 | col12 | mm |
| 중량 | col13 | kg |
| 검사비 | col14 | 원 |
| 주자재 (슬랫) | col15 | 원 |
| 조인트바 | col16 | 원 (슬랫 전용) |
| 모터 | col17 | 원 |
| 제어기 | col18 | 원 |
| 케이스 | col19 | 원 |
| 레일 | col20 | 원 |
| 앵글 | col21 | 원 |
| 샤프트 | col22 | 원 |
| 인치 | col23 | 샤프트 인치 |
---
## 6. 데이터 관계도
```
┌─────────────────────────────────────────────────────────┐
│ estimate │
│ (견적 마스터) │
├─────────────────────────────────────────────────────────┤
│ num (PK) │
│ pjnum (견적번호) │
│ major_category → '스크린' / '철재' │
│ model_name → item_list.model_name │
│ estimateList (JSON) ────┐ │
│ estimateSlatList (JSON) │ │
└──────────────────────────┼───────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ JSON 상세 항목 │
├─────────────────────────────────────────────────────────┤
│ item_name → BDmodels.itemname │
│ unit_price ← price_* 테이블 조회 │
└──────────────────────────────────────────────────────────┘
┌─────────────────┼─────────────────┐
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ BDmodels │ │ price_motor │ │ price_shaft │
│ (모델 단가) │ │ (모터 단가) │ │ (샤프트 단가)│
└──────────────┘ └──────────────┘ └──────────────┘
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│price_raw_mat │ │ price_pipe │ │ price_angle │
│ (주자재) │ │ (각파이프) │ │ (앵글) │
└──────────────┘ └──────────────┘ └──────────────┘
```
---
## 7. SAM 이관 매핑
### 테이블 매핑
| 5130 테이블 | SAM 테이블 | 비고 |
|-------------|------------|------|
| estimate | quotes + quote_items | 헤더/상세 분리 |
| BDmodels | products + prices | 품목기준관리 연동 |
| price_* | prices | 통합 단가 테이블 |
### 주요 변환 포인트
1. **JSON → 정규화**: estimateList JSON을 quote_items 테이블로 분리
2. **동적 컬럼 → 고정 컬럼**: col1~col23을 명시적 컬럼명으로 변경
3. **체크박스 → options JSON**: steel, motor 등을 options JSON으로 통합
4. **단가 테이블 통합**: 7개 단가 테이블을 prices 테이블로 통합
### SAM 스키마 (제안)
```sql
-- 견적 헤더
CREATE TABLE quotes (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
tenant_id BIGINT UNSIGNED NOT NULL,
quote_number VARCHAR(50) NOT NULL,
quote_date DATE NOT NULL,
customer_id BIGINT UNSIGNED,
project_name VARCHAR(200),
category ENUM('screen', 'slat') NOT NULL,
model_id BIGINT UNSIGNED,
options JSON, -- {steel: true, motor: true, warranty: true, ...}
dimensions JSON, -- {width: 160, height: 350, wing: 50}
inspection_fee DECIMAL(10,0) DEFAULT 50000,
subtotal DECIMAL(12,0) DEFAULT 0,
discount_rate DECIMAL(5,2) DEFAULT 0,
discount_amount DECIMAL(12,0) DEFAULT 0,
total_amount DECIMAL(12,0) DEFAULT 0,
status ENUM('draft', 'sent', 'accepted', 'rejected') DEFAULT 'draft',
created_by BIGINT UNSIGNED,
created_at TIMESTAMP,
updated_at TIMESTAMP,
deleted_at TIMESTAMP NULL,
INDEX idx_tenant_quote (tenant_id, quote_number),
INDEX idx_tenant_date (tenant_id, quote_date)
);
-- 견적 상세
CREATE TABLE quote_items (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
quote_id BIGINT UNSIGNED NOT NULL,
item_type ENUM('manual', 'auto') DEFAULT 'manual',
item_code VARCHAR(50),
item_name VARCHAR(100) NOT NULL,
specification VARCHAR(200),
unit VARCHAR(20),
quantity DECIMAL(10,2) DEFAULT 1,
unit_price DECIMAL(12,0) DEFAULT 0,
amount DECIMAL(12,0) DEFAULT 0,
sort_order INT DEFAULT 0,
remark TEXT,
FOREIGN KEY (quote_id) REFERENCES quotes(id) ON DELETE CASCADE,
INDEX idx_quote (quote_id)
);
```
---
## 참조 파일
- `5130/estimate/insert.php` - 견적 저장 로직
- `5130/estimate/fetch_unitprice.php` - 단가 조회
- `5130/bendingfee_backup/sql.php` - BDmodels 스키마
- `docs/projects/legacy-5130/03_ESTIMATE.md` - 이전 분석

View File

@@ -0,0 +1,471 @@
# 5130 견적 수식 분석
> **핵심 문서** - 모든 견적 계산 수식 상세 분석
> **분석 일자:** 2025-12-19
---
## 📋 수식 개요
### 수식 파일 위치
| 파일 | 용도 | 핵심 함수 |
|------|------|----------|
| `common/calculation.js` | 프론트엔드 행 계산 | `calculateRowTotal()` |
| `fetch_unitprice.php` | 단가 조회/계산 헬퍼 | 30+ 함수 |
| `get_screen_amount.php` | 스크린 견적 계산 | `calculateScreenAmount()` |
| `get_slat_amount.php` | 슬랫 견적 계산 | `calculateSlatAmount()` |
---
## 🔢 기본 계산 수식
### 1. 행별 합계 계산 (calculation.js)
```javascript
// 기본 수식
totalPrice = 수량(su) × 단가(unitPrice)
// 면적 기반 수식
if (면적단가 > 0) {
단가 = 면적(areaLength) × 면적단가(areaPrice)
totalPrice = 수량 × 단가
}
```
### 2. 면적 계산
```php
// 스크린 면적 (m²)
// 기본 높이 350에 +550 추가 = 900 기준
$calculateHeight = $height + 550;
$area = $width * $calculateHeight / 1000000;
// 슬랫 면적 (m²)
// 기본 높이 350에 +50 추가 = 400 기준
$calculateHeight = $height + 50;
$area = $width * $calculateHeight / 1000000;
```
---
## 💰 항목별 수식 상세
### 1. 검사비 (인정검사비)
```php
$inspectionFee = 기본값(50000);
$검사비 = $inspectionFee × $수량;
```
| 입력 | 출력 | 단위 |
|------|------|------|
| 검사비 단가 | 검사비 총액 | 원 |
---
### 2. 주자재 (스크린/슬랫)
```php
// 스크린 (실리카/와이어)
$screen_price = $price_raw_materials × round($area, 2);
$주자재_스크린 = $screen_price × $수량;
// 슬랫 (방화)
$slat_price = $price_raw_materials × round($area, 2);
$주자재_슬랫 = $slat_price × $수량;
```
| 입력 | 계산 | 출력 |
|------|------|------|
| 폭(W), 높이(H), 단가 | 면적 × 단가 × 수량 | 주자재 금액 |
**조건:** `slatcheck == '1'` 일 때만 슬랫 주자재 계산
---
### 3. 조인트바 (슬랫 전용)
```php
$jointbar_price = $price_jointbar × $item['col76'];
```
| 입력 | 출력 |
|------|------|
| 조인트바 개수(col76) × 단가 | 조인트바 금액 |
**조건:** `slatcheck == '1'` 일 때만 계산
---
### 4. 모터
```php
// 모터 용량 추출 (숫자만)
$motorSpec = preg_replace('/[a-zA-Z]/', '', $item['col19']);
$motorUnit_price = getPriceForMotor($motorSpec, $itemList);
$모터 = $motorUnit_price × $수량;
```
| 입력 | 조건 | 출력 |
|------|------|------|
| 모터 용량, 수량 | 모터공급처='경동(견적가포함)' AND motor='1' | 모터 금액 |
**모터 용량 판별 로직:**
```php
function calculateMotorSpec($item, $weight, $BracketInch) {
// 스크린/철재 구분
$ItemSel = (substr($item['col4'], 0, 2) === 'KS') ? '스크린' : '철재';
// 중량 + 인치 조합으로 용량 결정
// 스크린: 150K, 300K, 400K, 500K, 600K
// 철재: 300K, 400K, 500K, 600K, 800K, 1000K
// 예시 조건 (스크린 150K)
if ($ItemSel === '스크린' && $BracketInch == 4 && $weight <= 150) {
return 150;
}
// ... 기타 조건들
}
```
**모터 용량 매핑표:**
| 인치 | 중량 범위 | 스크린 용량 | 철재 용량 |
|------|----------|------------|----------|
| 4" | ≤150kg | 150K | - |
| 4" | ≤300kg | 300K | 300K |
| 4" | ≤400kg | 400K | 400K |
| 5" | ≤500kg | 500K | 500K |
| 5" | ≤600kg | 600K | 600K |
| 6" | ≤800kg | - | 800K |
| 8" | ≤1000kg | - | 1000K |
---
### 5. 연동제어기
```php
$price1 = calculateControllerSpec($item['col15'], $itemList, '매립형');
$price2 = calculateControllerSpec($item['col16'], $itemList, '노출형');
$price3 = calculateControllerSpec($item['col17'], $itemList, '뒷박스');
$controller_price =
$price1 × $매립형_수량 +
$price2 × $노출형_수량 +
$price3 × $뒷박스_수량;
```
| 유형 | 입력 컬럼 | 설명 |
|------|----------|------|
| 매립형 | col15 (스크린) / col16 (슬랫) | 벽 매립 타입 |
| 노출형 | col16 (스크린) / col17 (슬랫) | 외부 노출 타입 |
| 뒷박스 | col17 (스크린) / col18 (슬랫) | 뒷면 박스 타입 |
---
### 6. 케이스
```php
// 규격별 단가 조회 (BDmodels 테이블)
if ($item['col36'] === 'custom') {
$dimension = $item['col36_custom']; // 커스텀 규격
} else {
$dimension = $item['col36']; // 표준 규격
}
// 표준 규격이면 단가표에서 조회
if (array_key_exists($dimension, $shutterBoxprices)) {
$shutter_price = $shutterBoxprices[$dimension] / 1000;
} else {
// 비표준 규격은 기본 단가 기준 면적비로 계산
$basicbox_price = $shutterBoxprices['500*380']; // 스크린 기본
// 또는 '650*550' (슬랫 기본)
$basicbox_pricePermeter = $basicbox_price / (500 * 380 / 1000);
$shutter_price = $basicbox_pricePermeter × $boxwidth × $boxheight / 1000;
}
$케이스 = round($shutter_price × $total_length × 1000) × $수량;
```
| 조건 | 계산 |
|------|------|
| steel='1' (절곡 체크) | 단가 × 길이(m) × 수량 |
---
### 7. 케이스용 연기차단재
```php
$boxSmokeBanPrices = BDmodels에서 '케이스용 연기차단재' 단가 조회;
$total_length = $item['col37'] / 1000; // mm → m 변환
$케이스용_연기차단재 = round($boxSmokeBanPrices × $total_length) × $수량;
```
| 조건 | 계산 |
|------|------|
| steel='1' AND 케이스규격 있음 | 단가 × 길이(m) × 수량 |
---
### 8. 케이스 마구리
```php
$maguriCol = $item['col45']; // 마구리 규격
$maguriPrices = BDmodels에서 seconditem='마구리' AND spec=$maguriCol 조회;
$케이스_마구리 = round($maguriPrices × $수량);
```
| 조건 | 계산 |
|------|------|
| steel='1' | 단가 × 수량 |
---
### 9. 모터 받침용 앵글
```php
// 스크린
$price_angle = calculateAngle($item['col14'], $itemList, '스크린용');
// 슬랫 (브라켓 크기 기반)
if (empty($item['col21'])) {
$bracket_size = searchBracketSize($item['col13'], $item['col22']);
} else {
$bracket_size = $item['col21'];
}
$price_angle = calculateAngleBracket_slat($item['col15'], $itemList, $bracket_size);
$모터받침용_앵글 = round($price_angle × $수량 × 4); // 4개 세트
```
**브라켓 사이즈 결정 로직:**
```php
function searchBracketSize($motorWeight, $bracketInch) {
// 모터 용량 판별
$motorCapacity = calculateMotorKG($weight, $inch);
// 용량별 브라켓 사이즈 매핑
if (in_array($motorCapacity, [300, 400])) return '530*320';
if (in_array($motorCapacity, [500, 600])) return '600*350';
if (in_array($motorCapacity, [800, 1000])) return '690*390';
return '530*320'; // 기본값
}
```
---
### 10. 가이드레일
```php
// 레일 유형에 따른 가격 계산
if (strpos($guideType, '혼합') !== false) {
// 혼합형: 벽면 + 측면 각각 다른 규격
$wallPrice = $guidrailPrices[$wallKey];
$sidePrice = $guidrailPrices[$sideKey];
$guidrail_price = $wallPrice + $sidePrice; // 1개 세트
} else {
// 단일형: 벽면 또는 측면
$guidrail_price = $guidrailPrices[$guideKey] × 2; // 2개 세트
}
$total_length = $item['col23'] / 1000; // mm → m
$가이드레일 = round($guidrail_price × $total_length) × $수량;
```
**가이드레일 키 구성:**
```
$key = $modelCode|$finishingType|$spec
예: KS-100|도장|65*80
```
---
### 11. 레일용 연기차단재
```php
$guiderailSmokeBanPrices = BDmodels에서 '가이드레일용 연기차단재' 조회;
$total_length = $item['col23'] / 1000;
$레일용_연기차단재 = round($guiderailSmokeBanPrices × $total_length) × 2 × $수량;
```
| 조건 | 계산 |
|------|------|
| steel='1' AND 연기차단재 옵션 있음 | 단가 × 길이 × 2(양쪽) × 수량 |
---
### 12. 하장바
```php
$bottomBarPrices = BDmodels에서
model_name=$modelCode AND
seconditem='하단마감재' AND
finishing_type=$finishingType 조회;
$total_length = $item['col48'] / 1000 × $수량; // 스크린
// 또는 $item['col49'] (슬랫)
$하장바 = round($bottomBarPrices × $total_length);
```
| 조건 | 계산 |
|------|------|
| steel='1' AND 하장바 옵션 있음 | 단가 × 길이 × 수량 |
---
### 13. L바 (스크린 전용)
```php
$LBarPrices = BDmodels에서 seconditem='L-BAR' 조회;
$total_length = $item['col51'] / 1000 × $수량;
$L바 = round($LBarPrices × $total_length);
```
| 조건 | 계산 |
|------|------|
| steel='1' AND L바 옵션 있음 | 단가 × 길이 × 수량 |
---
### 14. 보강평철 (스크린 전용)
```php
$bottomPlatePrices = BDmodels에서 seconditem='보강평철' 조회;
$total_length = $item['col54'] / 1000 × $수량;
$보강평철 = round($bottomPlatePrices × $total_length);
```
| 조건 | 계산 |
|------|------|
| steel='1' AND 보강평철 옵션 있음 | 단가 × 길이 × 수량 |
---
### 15. 감기샤프트
```php
function calculateShaftPrice($item, $pdo) {
// 샤프트 규격별 가격 합산
// 컬럼: col59~col65 (스크린), col61~col71 (슬랫)
addShaftPrice($item['col59'], $itemList, '3', '300', $sum); // 3인치 300mm
addShaftPrice($item['col60'], $itemList, '4', '3000', $sum); // 4인치 3000mm
addShaftPrice($item['col61'], $itemList, '4', '4500', $sum); // 4인치 4500mm
// ... 기타 규격
return $sum_shaft_price;
}
function addShaftPrice($column, $itemList, $size, $length, &$sum) {
$shaft_price = calculateShaft($column, $itemList, $size, $length);
if ($shaft_price > 0) {
$sum += $shaft_price;
}
}
```
**샤프트 규격표:**
| 인치 | 길이 | 스크린 컬럼 | 슬랫 컬럼 |
|------|------|------------|----------|
| 3" | 300mm | col59 | - |
| 4" | 3000mm | col60 | col61 |
| 4" | 4500mm | col61 | col62 |
| 4" | 6000mm | col62 | col63 |
| 5" | 6000mm | col63 | col64 |
| 5" | 7000mm | col64 | col65 |
| 5" | 8200mm | col65 | col66 |
| 6" | 3000mm | - | col67 |
| 6" | 6000mm | - | col68 |
| 6" | 7000mm | - | col69 |
| 6" | 8000mm | - | col70 |
| 8" | 8200mm | - | col71 |
---
### 16. 무게평철 12T (스크린 전용)
```php
$baseWeightPlatePrice = 12000; // 고정 단가
$무게평철 = $baseWeightPlatePrice × $item['col57'];
```
| 조건 | 계산 |
|------|------|
| steel='1' | 12,000원 × 개수 |
---
### 17. 환봉 (스크린 전용)
```php
$round_bar_price = 2000; // 고정 단가
$round_bar_surang = $item['col70'];
$환봉 = round($round_bar_price × $round_bar_surang);
```
| 조건 | 계산 |
|------|------|
| steel='1' | 2,000원 × 개수 |
---
### 18. 각파이프
```php
$pipe_price_3000 = calculatePipe($itemList, '1.4', '3000'); // 1.4T 3000mm
$pipe_price_6000 = calculatePipe($itemList, '1.4', '6000'); // 1.4T 6000mm
$pipe_surang_3000 = $item['col68']; // 스크린
$pipe_surang_6000 = $item['col69'];
// 또는 col74, col75 (슬랫)
$각파이프_총액 =
($pipe_price_3000 × $pipe_surang_3000) +
($pipe_price_6000 × $pipe_surang_6000);
```
| 조건 | 계산 |
|------|------|
| partscheck='1' | (3000mm 단가 × 수량) + (6000mm 단가 × 수량) |
---
### 19. 앵글
```php
$mainangle_price = calculateMainAngle(1, $itemList, '앵글3T', '2.5'); // 스크린
// 또는 '앵글4T' (슬랫)
$mainangle_surang = $item['col71']; // 스크린
// 또는 col77 (슬랫)
$앵글 = round($mainangle_price × $mainangle_surang);
```
| 조건 | 계산 |
|------|------|
| partscheck='1' | 단가 × 수량 |
---
## 📊 전체 금액 계산
```php
$totalRowAmount = 0;
foreach ($rowItemDetails as $key => $value) {
if (!in_array($key, ['TotalAmount', 'slatcheck', 'partscheck', 'steel', 'motor', 'warranty'])) {
$totalRowAmount += $value;
}
}
$rowItemDetails['TotalAmount'] = round($totalRowAmount);
```
**반환 데이터 구조:**
```php
return [
'total_amount' => $total_amount, // 전체 합계
'details' => $sums, // 행별 소계 배열
'itemDetails' => $itemDetails, // 항목별 상세 금액
'surangSum' => $surangSum // 총 수량
];
```
---
## 🏷️ 테스트 케이스
### 스크린 견적 예시
| 입력 | 값 |
|------|-----|
| 폭(W) | 3,000mm |
| 높이(H) | 2,500mm |
| 수량 | 2 |
| 모터공급 | 경동(견적가포함) |
| 모터용량 | 300K |
| 케이스 | 500*380 |
| 검사비 | 50,000원 |
| 항목 | 계산식 | 금액 |
|------|--------|------|
| 검사비 | 50,000 × 2 | 100,000 |
| 주자재 | 면적 × 단가 × 2 | (계산 필요) |
| 모터 | 300K 단가 × 2 | (단가표 참조) |
| ... | ... | ... |
---
## ⚠️ 주의사항
1. **컬럼 번호 차이**: 스크린과 슬랫에서 같은 항목이 다른 컬럼 사용
2. **단위 변환**: mm → m 변환 필수 (/ 1000)
3. **반올림 처리**: 대부분 `round()` 사용
4. **조건부 계산**: 체크박스 옵션에 따라 계산 여부 결정
5. **JSON 데이터**: 단가 테이블의 `itemList` 컬럼은 JSON 형식
---
## 📚 참조
- [fetch_unitprice.php](../../../../5130/estimate/fetch_unitprice.php) - 헬퍼 함수
- [get_screen_amount.php](../../../../5130/estimate/get_screen_amount.php) - 스크린 계산
- [get_slat_amount.php](../../../../5130/estimate/get_slat_amount.php) - 슬랫 계산

View File

@@ -0,0 +1,382 @@
# UI/화면 분석
> **분석 대상:** 5130 레거시 견적 시스템 화면
> **분석 일자:** 2025-12-19
---
## 화면 목록
### 메인 화면
| 파일 | 화면명 | 설명 |
|------|--------|------|
| `list.php` | 견적 목록 | 견적서 리스트, 검색, 필터링 |
| `write_form.php` | 견적 작성 | 견적서 작성/수정 폼 (103KB, 핵심 파일) |
| `viewEstimate.php` | 견적서 보기 | 견적서 조회/출력 |
| `statistics.php` | 견적 통계 | 통계 대시보드 |
### 견적 유형별 화면
| 파일 | 화면명 | 설명 |
|------|--------|------|
| `estimate.php` | 스크린 견적 | 스크린 견적서 메인 |
| `estimateSlat.php` | 슬랫 견적 | 슬랫(철재) 견적서 메인 |
| `estimateUnit.php` | 단가 견적 | 단가 기반 견적서 |
| `screen_view_original.php` | 스크린 상세 | 스크린 견적 상세 뷰 |
| `slat_view_original.php` | 슬랫 상세 | 슬랫 견적 상세 뷰 |
### 상세/수정 화면
| 파일 | 화면명 | 설명 |
|------|--------|------|
| `edit.php` | 견적 수정 | 스크린 견적 수정 |
| `edit_slat.php` | 슬랫 수정 | 슬랫 견적 수정 |
| `viewEstimateDetail.php` | 상세 보기 | 견적 상세 정보 |
| `EsDetail_screen.php` | 스크린 상세 | 스크린 항목 상세 |
| `EsDetail_slat.php` | 슬랫 상세 | 슬랫 항목 상세 |
| `compare.php` | 견적 비교 | 견적 버전 비교 |
### 출력/다운로드
| 파일 | 화면명 | 설명 |
|------|--------|------|
| `print_list.php` | 목록 인쇄 | 견적 목록 인쇄용 |
| `downloadExcel.php` | 엑셀 다운로드 | 견적서 엑셀 내보내기 |
| `saveExcel.php` | 엑셀 저장 | 엑셀 파일 저장 |
---
## 1. 견적 목록 (list.php)
### 화면 구조
```
┌─────────────────────────────────────────────────────────────┐
│ 견적 List [새로고침] │
├─────────────────────────────────────────────────────────────┤
│ ▷ 123건 접수일 [2025-02-19] ~ [2025-12-19] │
│ [전체] [스크린] [철재] 제품모델▼ 검색[______] [검색] │
│ [신규] │
├─────────────────────────────────────────────────────────────┤
│ 번호│접수일 │견적번호 │구분 │제품│수량│금액 │발주처...│
│─────│────────│────────────│──────│────│────│──────│─────────│
│ 123 │25-12-19│KD-PR-251219│스크린│KSS01│ 5 │5,000K│(주)ABC │
│ 122 │25-12-18│KD-PR-251218│철재 │KFS01│ 3 │3,200K│(주)DEF │
│ ... │ │ │ │ │ │ │ │
└─────────────────────────────────────────────────────────────┘
```
### 필터/검색 조건
| 항목 | 타입 | 설명 |
|------|------|------|
| `fromdate` | date | 시작일 (기본: -10개월) |
| `todate` | date | 종료일 (기본: +1개월) |
| `major_category` | radio | 전체/스크린/철재 |
| `model_name` | select | 제품 모델 선택 |
| `search` | text | 전체 컬럼 검색 |
### 테이블 컬럼
| 컬럼 | 폭 | 설명 |
|------|-----|------|
| 번호 | 30px | 일련번호 (역순) |
| 접수일 | 100px | indate |
| 견적번호 | 100px | pjnum |
| 구분 | 80px | major_category (스크린/철재) |
| 제품코드 | 80px | model_name |
| 수량 | 80px | estimateSurang |
| 금액 | 80px | estimateTotal |
| 발주처 | 150px | secondord |
| 담당자 | 80px | secondordman |
| 연락처 | 120px | secondordmantel |
| 현장명 | 200px | outworkplace |
| 작성자 | 80px | orderman |
| 비고 | 300px | comment |
### 기능 버튼
- **새로고침**: `location.reload()`
- **검색**: 필터 조건으로 목록 갱신
- **신규**: `write_form.php` 이동
---
## 2. 견적 작성 폼 (write_form.php)
### 화면 모드
| 모드 | 설명 |
|------|------|
| 신규 (`mode=''`) | 새 견적 작성 |
| 수정 (`mode=modify`) | 기존 견적 수정 |
| 복사 (`mode=copy`) | 기존 견적 복사하여 신규 생성 |
| 발주 (`header=header`) | 수주에서 발주 산출 |
| 스크린 수정 (`itemoption=screen`) | 스크린 발주서 수정 |
| 슬랫 수정 (`itemoption=slat`) | 철재스라트 발주서 수정 |
### 화면 구조 (추정)
```
┌─────────────────────────────────────────────────────────────┐
│ 견적 산출 │
├─────────────────────────────────────────────────────────────┤
│ ┌──────────── 기본 정보 ────────────┐ │
│ │ 접수일: [2025-12-19] │ │
│ │ 견적번호: KD-PR-251219-01 │ │
│ │ 담당자: 홍길동 │ │
│ │ 현장명: (주)ABC 빌딩 │ │
│ └───────────────────────────────────┘ │
│ │
│ ┌──────────── 발주처 정보 ──────────┐ │
│ │ 발주처: ____________ │ │
│ │ 담당자: ____________ 연락처: ____│ │
│ └───────────────────────────────────┘ │
│ │
│ ┌──────────── 제품 정보 ────────────┐ │
│ │ 대분류: (●)스크린 (○)철재 │ │
│ │ 모델명: [KSS01 ▼] │ │
│ │ 제작폭: [160] 제작높이: [350] │ │
│ │ 마구리윙: [50] │ │
│ └───────────────────────────────────┘ │
│ │
│ ┌──────────── 옵션 체크 ────────────┐ │
│ │ [✓] 절곡 [✓] 모터 [✓] 보증 │ │
│ │ [✓] 슬랫 [✓] 부자재 │ │
│ └───────────────────────────────────┘ │
│ │
│ ┌──────────── 견적 항목 ────────────┐ │
│ │ 검사비: [50,000] │ │
│ │ │ │
│ │ [스크린 견적 테이블] │ │
│ │ [슬랫 견적 테이블] │ │
│ └───────────────────────────────────┘ │
│ │
│ ┌──────────── 금액 합계 ────────────┐ │
│ │ 수량: 5 합계: 5,000,000 │ │
│ │ 할인율: 10% 할인액: 500,000 │ │
│ │ 최종금액: 4,500,000 │ │
│ └───────────────────────────────────┘ │
│ │
│ [저장] [취소] [삭제] │
└─────────────────────────────────────────────────────────────┘
```
### 주요 입력 필드
#### 기본 정보
| 필드 | 변수명 | 타입 | 기본값 |
|------|--------|------|--------|
| 접수일 | `indate` | date | 오늘 |
| 견적번호 | `pjnum` | text | 자동생성 |
| 담당자 | `orderman` | text | 로그인 사용자 |
| 현장명 | `outworkplace` | text | - |
#### 발주처 정보
| 필드 | 변수명 | 타입 |
|------|--------|------|
| 발주처 | `secondord` | text |
| 담당자 | `secondordman` | text |
| 연락처 | `secondordmantel` | text |
#### 제품 정보
| 필드 | 변수명 | 타입 | 기본값 |
|------|--------|------|--------|
| 대분류 | `major_category` | radio | 스크린 |
| 모델명 | `model_name` | select | - |
| 제작폭 | `makeWidth` | number | 160 (스크린), 110 (슬랫) |
| 제작높이 | `makeHeight` | number | 350 |
| 마구리윙 | `maguriWing` | number | 50 |
#### 옵션 체크박스
| 필드 | 변수명 | 영향 |
|------|--------|------|
| 절곡 | `steel` | 케이스, 레일, 연기차단재, 하장바, L바, 보강평철 |
| 모터 | `motor` | 모터 가격 포함 |
| 보증 | `warranty` | 보증기간 표시 |
| 슬랫 | `slatcheck` | 주자재(슬랫), 조인트바 |
| 부자재 | `partscheck` | 샤프트, 각파이프, 앵글 |
#### 금액 정보
| 필드 | 변수명 | 설명 |
|------|--------|------|
| 검사비 | `inspectionFee` | 인정검사비 (기본: 50,000) |
| 수량 | `estimateSurang` | 총 수량 |
| 합계 | `estimateTotal` | 견적 총액 |
| 최초합계 | `EstimateFirstSum` | 최초 견적 합계 |
| 수정합계 | `EstimateUpdatetSum` | 수정 견적 합계 |
| 차액 | `EstimateDiffer` | 최초-수정 차액 |
| 할인율 | `EstimateDiscountRate` | % |
| 할인액 | `EstimateDiscount` | 원 |
| 최종금액 | `EstimateFinalSum` | 최종 결정 금액 |
### CSS 클래스
```css
/* 수동 편집된 셀 강조 */
.manually-edited {
background-color: #f8d7da !important;
}
/* readonly 체크박스 */
.readonly-checkbox,
.readonly-radio {
pointer-events: none;
opacity: 1;
}
/* 커스텀 너비 */
.w-40, .w-50, .w-60, .w-85 { ... }
```
---
## 3. 견적 항목 테이블
### 스크린 견적 테이블 (estimateList)
| 열 | 필드명 | 설명 |
|----|--------|------|
| 항목명 | `item_name` | 품목 이름 |
| 규격 | `specification` | 규격/사양 |
| 단위 | `unit` | EA, m², m, kg |
| 수량 | `quantity` | 수량 |
| 단가 | `unit_price` | 단가 |
| 금액 | `amount` | quantity × unit_price |
| 비고 | `remark` | 메모 |
### 슬랫 견적 테이블 (estimateSlatList)
스크린과 동일 구조
### 자동계산 테이블 (estimateList_auto, estimateSlatList_auto)
| 열 | 필드명 | 설명 |
|----|--------|------|
| 항목코드 | `item_code` | 자동계산 항목 코드 |
| 항목명 | `item_name` | 품목 이름 |
| 계산타입 | `calc_type` | per_meter, per_area 등 |
| 기준값 | `base_value` | 계산 기준 수치 |
| 단가 | `unit_price` | 단가 |
| 금액 | `amount` | 계산 결과 |
---
## 4. API 엔드포인트 (AJAX 호출)
### 데이터 조회
| 엔드포인트 | 용도 |
|------------|------|
| `fetch_unitprice.php` | 단가 조회 |
| `fetch_date.php` | 날짜 정보 |
| `fetch_receiver.php` | 수신자 정보 |
| `fetch_outworkplace.php` | 현장 목록 |
| `fetch_length_data.php` | 길이 데이터 |
| `fetch_price.php` | 가격 정보 |
### 금액 계산
| 엔드포인트 | 용도 |
|------------|------|
| `get_estimate_amount.php` | 견적 금액 라우터 |
| `get_screen_amount.php` | 스크린 금액 계산 |
| `get_slat_amount.php` | 슬랫 금액 계산 |
| `recalc_row.php` | 행 재계산 |
### 데이터 저장
| 엔드포인트 | 용도 |
|------------|------|
| `insert.php` | 견적 저장 (신규) |
| `update.php` | 견적 수정 |
| `delete.php` | 견적 삭제 |
| `insert_estimate.php` | 견적 등록 |
| `insert_detail.php` | 상세 저장 |
### 기타
| 엔드포인트 | 용도 |
|------------|------|
| `generate_serial_pjnum.php` | 견적번호 생성 |
| `get_initial_pjnum.php` | 초기 견적번호 |
| `insert_logmenu.php` | 로그 기록 |
---
## 5. JavaScript 처리
### 공통 스크립트 (common/)
| 파일 | 용도 |
|------|------|
| `calculation.js` | 행 계산 로직 |
| `lastJS.php` | 페이지 공통 JS |
| `common_screen.php` | 스크린 공통 |
| `common_slat.php` | 슬랫 공통 |
### 주요 이벤트 처리
```javascript
// 수량/단가 변경 시 금액 재계산
function calculateRowTotal(row) { ... }
// 옵션 체크박스 변경 시 항목 재계산
$('input[name="steel"]').change(function() { ... });
// 모델 변경 시 단가 조회
$('#model_name').change(function() {
// AJAX: fetch_unitprice.php
});
// 크기 변경 시 전체 재계산
$('#makeWidth, #makeHeight').change(function() {
// AJAX: get_estimate_amount.php
});
```
---
## 6. 사용자 권한
### 접근 레벨
```php
// 레벨 5 이하만 접근 가능
if(!isset($_SESSION["level"]) || $_SESSION["level"]>5) {
header("Location:" . $WebSite . "login/login_form.php");
exit;
}
```
### 작성 권한자
```php
$authorities = [
"개발자", "전진", "노완호", "이세희",
"함신옥", "손금주", "이은진", "이경호"
];
```
---
## SAM 이관 시 UI 고려사항
### 1. Livewire + Blade 전환
| 5130 | SAM |
|------|-----|
| jQuery AJAX | Livewire wire:click |
| PHP 직접 렌더링 | Blade 컴포넌트 |
| 전역 변수 | Livewire 프로퍼티 |
| form submit | wire:submit |
### 2. 컴포넌트 분리
```
resources/views/livewire/quotation/
├── quote-list.blade.php # 목록
├── quote-form.blade.php # 작성/수정
├── quote-detail.blade.php # 상세
├── components/
│ ├── quote-table.blade.php # 견적 테이블
│ ├── option-checkboxes.blade.php # 옵션 체크박스
│ └── amount-summary.blade.php # 금액 요약
```
### 3. 반응형 개선
- 현재: 고정 너비 테이블
- 개선: Tailwind 반응형 그리드
### 4. UX 개선점
- 실시간 금액 계산 (debounce 적용)
- 자동저장 (draft 기능)
- 견적 버전 비교 UI
- 모바일 최적화
---
## 참조 파일
- `list.php:111-192` - 목록 테이블 구조
- `write_form.php:1-300` - 폼 초기화 로직
- `common/calculation.js` - 행 계산 로직
- `_row.php` - 행 렌더링 공통
- `_request.php` - 요청 파라미터 처리

Binary file not shown.

After

Width:  |  Height:  |  Size: 359 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 368 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 245 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 290 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 384 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 373 KiB