## 역할 인증된 사용자 전용 업무 페이지 영역. 영업, 생산, 구매, 재고, 품질, 비용 등 70개 이상의 업무 페이지를 포함. 공통 레이아웃(Header + Sidebar + Content)으로 감싸진 대시보드 시스템. ## 공통 패턴 ### 페이지 구조 모든 페이지는 `"use client"` 클라이언트 컴포넌트. 구성: 1. 제목: `

{제목}

` 2. 검색 폼: `SearchForm` + `SearchField` + `CodeSelect`/`Input` 3. 버튼 영역: 조회, 등록, 삭제 등 4. 데이터 그리드: `DataGrid` + `Pagination` ### 데이터 조회 ```tsx const fetchData = useCallback(async () => { const res = await fetch("/api/{domain}/{resource}", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ year, category_cd, ... }), }); if (res.ok) { const json = await res.json(); setData(json.RESULTLIST || []); } }, [dependencies]); ``` ### 팝업 처리 ```tsx window.open(url, "formPopup", "width=1200,height=550,left=...,top=..."); ``` ### 행 삭제 ```tsx if (selectedRows.length === 0) { Swal.fire({ icon: "warning", title: "항목을 선택하세요." }); return; } ``` ## 연결 고리 - API: `POST /api/{domain}/{resource}` (RESULTLIST 응답) - Store: `useAuthStore()` (user, logout), `useMenuStore()` (메뉴 상태) - 컴포넌트: DataGrid, SearchForm, SearchField, CodeSelect, Input, Button, Pagination - 유틸: `numberWithCommas()`, `cn()` ## 숨겨진 스펙 - 데이터 타입: `Record[]` - DataGrid 높이: `calc(100vh - 350px)` 패턴 (페이지별 350~400px 차감) - 년도 필터: `Array.from({ length: 5 }, (_, i) => new Date().getFullYear() - i)` - 셀 클릭: `col.cellClick` 콜백으로 상세 폼 팝업 - formatter `"money"` → 통화 형식 - JSP 원본 주석: `// salesMgmt/salesMgmtContractList.jsp 대응` - 에러처리 미비: `if (res.ok)` 체크만, try-catch 없는 경우 많음 @MISTAKES.md