refactor(WEB): CEO 대시보드 대규모 개선 및 문서/권한/스토어 리팩토링
- CEO 대시보드: 섹션별 API 연동 강화 (매출/매입/생산 실데이터 표시) - DashboardSettingsDialog 드래그 정렬 및 설정 UX 개선 - dashboard transformers 모듈 분리 (파일 분할) - DocumentTable/DocumentWrapper 공통 문서 컴포넌트 추출 - LineItemsTable organisms 컴포넌트 추가 - PurchaseOrderDocument/InspectionRequestDocument 문서 컴포넌트 리팩토링 - PermissionContext → permissionStore(Zustand) 전환 - useUIStore, stores/utils/userStorage 추가 - favoritesStore/useTableColumnStore 사용자별 저장 지원 - DepositDetail/WithdrawalDetail 삭제 (통합) - PurchaseDetail/SalesDetail 간소화 - amount.ts/formatters.ts 유틸 확장 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -10,16 +10,28 @@
|
||||
* - 검사대상 사전 고지 정보 테이블
|
||||
*/
|
||||
|
||||
import { ConstructionApprovalTable } from '@/components/document-system';
|
||||
import {
|
||||
ConstructionApprovalTable,
|
||||
DocumentWrapper,
|
||||
DocumentTable,
|
||||
DOC_STYLES,
|
||||
} from '@/components/document-system';
|
||||
import type { InspectionRequestDocument as InspectionRequestDocumentType } from '../types';
|
||||
|
||||
interface InspectionRequestDocumentProps {
|
||||
data: InspectionRequestDocumentType;
|
||||
}
|
||||
|
||||
/** 라벨 셀 */
|
||||
const lbl = `${DOC_STYLES.label} w-28`;
|
||||
/** 서브 라벨 셀 (bg-gray-50) */
|
||||
const subLbl = 'bg-gray-50 px-2 py-1 font-medium border-r border-gray-300 w-28';
|
||||
/** 값 셀 */
|
||||
const val = DOC_STYLES.value;
|
||||
|
||||
export function InspectionRequestDocument({ data }: InspectionRequestDocumentProps) {
|
||||
return (
|
||||
<div className="bg-white p-8 min-h-full text-[11px]">
|
||||
<DocumentWrapper fontSize="text-[11px]">
|
||||
{/* 헤더: 제목 (좌측) + 결재란 (우측) */}
|
||||
<div className="flex justify-between items-start mb-4">
|
||||
<div>
|
||||
@@ -51,47 +63,44 @@ export function InspectionRequestDocument({ data }: InspectionRequestDocumentPro
|
||||
</div>
|
||||
|
||||
{/* 기본 정보 */}
|
||||
<div className="border border-gray-400 mb-4">
|
||||
<div className="bg-gray-200 text-center py-1 font-bold border-b border-gray-400">기본 정보</div>
|
||||
<table className="w-full">
|
||||
<tbody>
|
||||
<tr className="border-b border-gray-300">
|
||||
<td className="bg-gray-100 px-2 py-1 w-28 font-medium border-r border-gray-300">수주처</td>
|
||||
<td className="px-2 py-1 border-r border-gray-300">{data.client || '-'}</td>
|
||||
<td className="bg-gray-100 px-2 py-1 w-28 font-medium border-r border-gray-300">업체명</td>
|
||||
<td className="px-2 py-1">{data.companyName || '-'}</td>
|
||||
</tr>
|
||||
<tr className="border-b border-gray-300">
|
||||
<td className="bg-gray-100 px-2 py-1 font-medium border-r border-gray-300">담당자</td>
|
||||
<td className="px-2 py-1 border-r border-gray-300">{data.manager || '-'}</td>
|
||||
<td className="bg-gray-100 px-2 py-1 font-medium border-r border-gray-300">수주번호</td>
|
||||
<td className="px-2 py-1">{data.orderNumber || '-'}</td>
|
||||
</tr>
|
||||
<tr className="border-b border-gray-300">
|
||||
<td className="bg-gray-100 px-2 py-1 font-medium border-r border-gray-300">담당자 연락처</td>
|
||||
<td className="px-2 py-1 border-r border-gray-300">{data.managerContact || '-'}</td>
|
||||
<td className="bg-gray-100 px-2 py-1 font-medium border-r border-gray-300">현장명</td>
|
||||
<td className="px-2 py-1">{data.siteName || '-'}</td>
|
||||
</tr>
|
||||
<tr className="border-b border-gray-300">
|
||||
<td className="bg-gray-100 px-2 py-1 font-medium border-r border-gray-300">납품일</td>
|
||||
<td className="px-2 py-1 border-r border-gray-300">{data.deliveryDate || '-'}</td>
|
||||
<td className="bg-gray-100 px-2 py-1 font-medium border-r border-gray-300">현장 주소</td>
|
||||
<td className="px-2 py-1">{data.siteAddress || '-'}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="bg-gray-100 px-2 py-1 font-medium border-r border-gray-300">총 개소</td>
|
||||
<td className="px-2 py-1 border-r border-gray-300">{data.totalLocations || '-'}</td>
|
||||
<td className="bg-gray-100 px-2 py-1 font-medium border-r border-gray-300">접수일</td>
|
||||
<td className="px-2 py-1">{data.receptionDate || '-'}</td>
|
||||
</tr>
|
||||
<tr className="border-t border-gray-300">
|
||||
<td className="bg-gray-100 px-2 py-1 font-medium border-r border-gray-300">검사방문요청일</td>
|
||||
<td className="px-2 py-1" colSpan={3}>{data.visitRequestDate || '-'}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<DocumentTable header="기본 정보" headerVariant="light" spacing="mb-4">
|
||||
<tbody>
|
||||
<tr className="border-b border-gray-300">
|
||||
<td className={lbl}>수주처</td>
|
||||
<td className={`${val} border-r border-gray-300`}>{data.client || '-'}</td>
|
||||
<td className={lbl}>업체명</td>
|
||||
<td className={val}>{data.companyName || '-'}</td>
|
||||
</tr>
|
||||
<tr className="border-b border-gray-300">
|
||||
<td className={lbl}>담당자</td>
|
||||
<td className={`${val} border-r border-gray-300`}>{data.manager || '-'}</td>
|
||||
<td className={lbl}>수주번호</td>
|
||||
<td className={val}>{data.orderNumber || '-'}</td>
|
||||
</tr>
|
||||
<tr className="border-b border-gray-300">
|
||||
<td className={lbl}>담당자 연락처</td>
|
||||
<td className={`${val} border-r border-gray-300`}>{data.managerContact || '-'}</td>
|
||||
<td className={lbl}>현장명</td>
|
||||
<td className={val}>{data.siteName || '-'}</td>
|
||||
</tr>
|
||||
<tr className="border-b border-gray-300">
|
||||
<td className={lbl}>납품일</td>
|
||||
<td className={`${val} border-r border-gray-300`}>{data.deliveryDate || '-'}</td>
|
||||
<td className={lbl}>현장 주소</td>
|
||||
<td className={val}>{data.siteAddress || '-'}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className={lbl}>총 개소</td>
|
||||
<td className={`${val} border-r border-gray-300`}>{data.totalLocations || '-'}</td>
|
||||
<td className={lbl}>접수일</td>
|
||||
<td className={val}>{data.receptionDate || '-'}</td>
|
||||
</tr>
|
||||
<tr className="border-t border-gray-300">
|
||||
<td className={lbl}>검사방문요청일</td>
|
||||
<td className={val} colSpan={3}>{data.visitRequestDate || '-'}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</DocumentTable>
|
||||
|
||||
{/* 입력사항: 4개 섹션 */}
|
||||
<div className="border border-gray-400 mb-4">
|
||||
@@ -103,12 +112,12 @@ export function InspectionRequestDocument({ data }: InspectionRequestDocumentPro
|
||||
<table className="w-full">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td className="bg-gray-50 px-2 py-1 w-28 font-medium border-r border-gray-300">현장명</td>
|
||||
<td className="px-2 py-1 border-r border-gray-300">{data.constructionSite.siteName || '-'}</td>
|
||||
<td className="bg-gray-50 px-2 py-1 w-28 font-medium border-r border-gray-300">대지위치</td>
|
||||
<td className="px-2 py-1 border-r border-gray-300">{data.constructionSite.landLocation || '-'}</td>
|
||||
<td className="bg-gray-50 px-2 py-1 w-20 font-medium border-r border-gray-300">지번</td>
|
||||
<td className="px-2 py-1">{data.constructionSite.lotNumber || '-'}</td>
|
||||
<td className={subLbl}>현장명</td>
|
||||
<td className={`${val} border-r border-gray-300`}>{data.constructionSite.siteName || '-'}</td>
|
||||
<td className={subLbl}>대지위치</td>
|
||||
<td className={`${val} border-r border-gray-300`}>{data.constructionSite.landLocation || '-'}</td>
|
||||
<td className={`${subLbl} w-20`}>지번</td>
|
||||
<td className={val}>{data.constructionSite.lotNumber || '-'}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -120,16 +129,16 @@ export function InspectionRequestDocument({ data }: InspectionRequestDocumentPro
|
||||
<table className="w-full">
|
||||
<tbody>
|
||||
<tr className="border-b border-gray-300">
|
||||
<td className="bg-gray-50 px-2 py-1 w-28 font-medium border-r border-gray-300">회사명</td>
|
||||
<td className="px-2 py-1 border-r border-gray-300">{data.materialDistributor.companyName || '-'}</td>
|
||||
<td className="bg-gray-50 px-2 py-1 w-28 font-medium border-r border-gray-300">회사주소</td>
|
||||
<td className="px-2 py-1">{data.materialDistributor.companyAddress || '-'}</td>
|
||||
<td className={subLbl}>회사명</td>
|
||||
<td className={`${val} border-r border-gray-300`}>{data.materialDistributor.companyName || '-'}</td>
|
||||
<td className={subLbl}>회사주소</td>
|
||||
<td className={val}>{data.materialDistributor.companyAddress || '-'}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="bg-gray-50 px-2 py-1 font-medium border-r border-gray-300">대표자명</td>
|
||||
<td className="px-2 py-1 border-r border-gray-300">{data.materialDistributor.representativeName || '-'}</td>
|
||||
<td className="bg-gray-50 px-2 py-1 font-medium border-r border-gray-300">전화번호</td>
|
||||
<td className="px-2 py-1">{data.materialDistributor.phone || '-'}</td>
|
||||
<td className={subLbl}>대표자명</td>
|
||||
<td className={`${val} border-r border-gray-300`}>{data.materialDistributor.representativeName || '-'}</td>
|
||||
<td className={subLbl}>전화번호</td>
|
||||
<td className={val}>{data.materialDistributor.phone || '-'}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -141,16 +150,16 @@ export function InspectionRequestDocument({ data }: InspectionRequestDocumentPro
|
||||
<table className="w-full">
|
||||
<tbody>
|
||||
<tr className="border-b border-gray-300">
|
||||
<td className="bg-gray-50 px-2 py-1 w-28 font-medium border-r border-gray-300">회사명</td>
|
||||
<td className="px-2 py-1 border-r border-gray-300">{data.constructorInfo.companyName || '-'}</td>
|
||||
<td className="bg-gray-50 px-2 py-1 w-28 font-medium border-r border-gray-300">회사주소</td>
|
||||
<td className="px-2 py-1">{data.constructorInfo.companyAddress || '-'}</td>
|
||||
<td className={subLbl}>회사명</td>
|
||||
<td className={`${val} border-r border-gray-300`}>{data.constructorInfo.companyName || '-'}</td>
|
||||
<td className={subLbl}>회사주소</td>
|
||||
<td className={val}>{data.constructorInfo.companyAddress || '-'}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="bg-gray-50 px-2 py-1 font-medium border-r border-gray-300">성명</td>
|
||||
<td className="px-2 py-1 border-r border-gray-300">{data.constructorInfo.name || '-'}</td>
|
||||
<td className="bg-gray-50 px-2 py-1 font-medium border-r border-gray-300">전화번호</td>
|
||||
<td className="px-2 py-1">{data.constructorInfo.phone || '-'}</td>
|
||||
<td className={subLbl}>성명</td>
|
||||
<td className={`${val} border-r border-gray-300`}>{data.constructorInfo.name || '-'}</td>
|
||||
<td className={subLbl}>전화번호</td>
|
||||
<td className={val}>{data.constructorInfo.phone || '-'}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -162,16 +171,16 @@ export function InspectionRequestDocument({ data }: InspectionRequestDocumentPro
|
||||
<table className="w-full">
|
||||
<tbody>
|
||||
<tr className="border-b border-gray-300">
|
||||
<td className="bg-gray-50 px-2 py-1 w-28 font-medium border-r border-gray-300">사무소명</td>
|
||||
<td className="px-2 py-1 border-r border-gray-300">{data.supervisor.officeName || '-'}</td>
|
||||
<td className="bg-gray-50 px-2 py-1 w-28 font-medium border-r border-gray-300">사무소주소</td>
|
||||
<td className="px-2 py-1">{data.supervisor.officeAddress || '-'}</td>
|
||||
<td className={subLbl}>사무소명</td>
|
||||
<td className={`${val} border-r border-gray-300`}>{data.supervisor.officeName || '-'}</td>
|
||||
<td className={subLbl}>사무소주소</td>
|
||||
<td className={val}>{data.supervisor.officeAddress || '-'}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="bg-gray-50 px-2 py-1 font-medium border-r border-gray-300">성명</td>
|
||||
<td className="px-2 py-1 border-r border-gray-300">{data.supervisor.name || '-'}</td>
|
||||
<td className="bg-gray-50 px-2 py-1 font-medium border-r border-gray-300">전화번호</td>
|
||||
<td className="px-2 py-1">{data.supervisor.phone || '-'}</td>
|
||||
<td className={subLbl}>성명</td>
|
||||
<td className={`${val} border-r border-gray-300`}>{data.supervisor.name || '-'}</td>
|
||||
<td className={subLbl}>전화번호</td>
|
||||
<td className={val}>{data.supervisor.phone || '-'}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -179,71 +188,71 @@ export function InspectionRequestDocument({ data }: InspectionRequestDocumentPro
|
||||
</div>
|
||||
|
||||
{/* 검사 요청 시 필독 */}
|
||||
<div className="border border-gray-400 mb-4">
|
||||
<div className="bg-gray-800 text-white text-center py-1 font-bold border-b border-gray-400">검사 요청 시 필독</div>
|
||||
<div className="px-4 py-3 text-[11px] leading-relaxed text-center">
|
||||
<p>
|
||||
발주 사이즈와 시공 완료된 사이즈가 다를 시, 일정 범위를 벗어날 경우
|
||||
<br />
|
||||
인정마크를 부착할 수 없습니다. 제품검사를 위한 방문 전 미리
|
||||
<br />
|
||||
<span className="text-red-600 font-medium">변경사항을 고지해주셔야 인정마크를 부착할 수 있습니다.</span>
|
||||
</p>
|
||||
<p className="mt-2 text-gray-600">
|
||||
(사전고지를 하지 않음으로 발생하는 문제의 귀책은 신청업체에 있습니다.)
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<DocumentTable header="검사 요청 시 필독" headerVariant="dark" spacing="mb-4">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td className="px-4 py-3 text-[11px] leading-relaxed text-center">
|
||||
<p>
|
||||
발주 사이즈와 시공 완료된 사이즈가 다를 시, 일정 범위를 벗어날 경우
|
||||
<br />
|
||||
인정마크를 부착할 수 없습니다. 제품검사를 위한 방문 전 미리
|
||||
<br />
|
||||
<span className="text-red-600 font-medium">변경사항을 고지해주셔야 인정마크를 부착할 수 있습니다.</span>
|
||||
</p>
|
||||
<p className="mt-2 text-gray-600">
|
||||
(사전고지를 하지 않음으로 발생하는 문제의 귀책은 신청업체에 있습니다.)
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</DocumentTable>
|
||||
|
||||
{/* 검사대상 사전 고지 정보 */}
|
||||
<div className="border border-gray-400 mb-4">
|
||||
<div className="bg-gray-800 text-white text-center py-1 font-bold border-b border-gray-400">검사대상 사전 고지 정보</div>
|
||||
<table className="w-full">
|
||||
<thead>
|
||||
{/* 1단: 오픈사이즈 병합 */}
|
||||
<tr className="bg-gray-100 border-b border-gray-300">
|
||||
<th className="border-r border-gray-400 px-2 py-1 w-12 text-center" rowSpan={3}>No.</th>
|
||||
<th className="border-r border-gray-400 px-2 py-1 w-16 text-center" rowSpan={3}>층수</th>
|
||||
<th className="border-r border-gray-400 px-2 py-1 w-20 text-center" rowSpan={3}>부호</th>
|
||||
<th className="border-r border-gray-400 px-2 py-1 text-center" colSpan={4}>오픈사이즈</th>
|
||||
<th className="px-2 py-1 text-center" rowSpan={3}>변경사유</th>
|
||||
<DocumentTable header="검사대상 사전 고지 정보" headerVariant="dark" spacing="mb-4">
|
||||
<thead>
|
||||
{/* 1단: 오픈사이즈 병합 */}
|
||||
<tr className="bg-gray-100 border-b border-gray-300">
|
||||
<th className={`${DOC_STYLES.th} w-12`} rowSpan={3}>No.</th>
|
||||
<th className={`${DOC_STYLES.th} w-16`} rowSpan={3}>층수</th>
|
||||
<th className={`${DOC_STYLES.th} w-20`} rowSpan={3}>부호</th>
|
||||
<th className={DOC_STYLES.th} colSpan={4}>오픈사이즈</th>
|
||||
<th className={`${DOC_STYLES.th} border-r-0`} rowSpan={3}>변경사유</th>
|
||||
</tr>
|
||||
{/* 2단: 발주 규격, 시공후 규격 */}
|
||||
<tr className="bg-gray-100 border-b border-gray-300">
|
||||
<th className={DOC_STYLES.th} colSpan={2}>발주 규격</th>
|
||||
<th className={DOC_STYLES.th} colSpan={2}>시공후 규격</th>
|
||||
</tr>
|
||||
{/* 3단: 가로, 세로 */}
|
||||
<tr className="bg-gray-100 border-b border-gray-400">
|
||||
<th className={`${DOC_STYLES.th} w-16`}>가로</th>
|
||||
<th className={`${DOC_STYLES.th} w-16`}>세로</th>
|
||||
<th className={`${DOC_STYLES.th} w-16`}>가로</th>
|
||||
<th className={`${DOC_STYLES.th} w-16`}>세로</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{data.priorNoticeItems.map((item, index) => (
|
||||
<tr key={item.id} className="border-b border-gray-300">
|
||||
<td className={DOC_STYLES.tdCenter}>{index + 1}</td>
|
||||
<td className={DOC_STYLES.tdCenter}>{item.floor}</td>
|
||||
<td className={DOC_STYLES.tdCenter}>{item.symbol}</td>
|
||||
<td className={DOC_STYLES.tdCenter}>{item.orderWidth}</td>
|
||||
<td className={DOC_STYLES.tdCenter}>{item.orderHeight}</td>
|
||||
<td className={DOC_STYLES.tdCenter}>{item.constructionWidth}</td>
|
||||
<td className={DOC_STYLES.tdCenter}>{item.constructionHeight}</td>
|
||||
<td className={DOC_STYLES.td}>{item.changeReason || '-'}</td>
|
||||
</tr>
|
||||
{/* 2단: 발주 규격, 시공후 규격 */}
|
||||
<tr className="bg-gray-100 border-b border-gray-300">
|
||||
<th className="border-r border-gray-400 px-2 py-1 text-center" colSpan={2}>발주 규격</th>
|
||||
<th className="border-r border-gray-400 px-2 py-1 text-center" colSpan={2}>시공후 규격</th>
|
||||
))}
|
||||
{data.priorNoticeItems.length === 0 && (
|
||||
<tr>
|
||||
<td colSpan={8} className="px-2 py-4 text-center text-gray-400">
|
||||
검사대상 사전 고지 정보가 없습니다.
|
||||
</td>
|
||||
</tr>
|
||||
{/* 3단: 가로, 세로 */}
|
||||
<tr className="bg-gray-100 border-b border-gray-400">
|
||||
<th className="border-r border-gray-400 px-2 py-1 w-16 text-center">가로</th>
|
||||
<th className="border-r border-gray-400 px-2 py-1 w-16 text-center">세로</th>
|
||||
<th className="border-r border-gray-400 px-2 py-1 w-16 text-center">가로</th>
|
||||
<th className="border-r border-gray-400 px-2 py-1 w-16 text-center">세로</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{data.priorNoticeItems.map((item, index) => (
|
||||
<tr key={item.id} className="border-b border-gray-300">
|
||||
<td className="border-r border-gray-300 px-2 py-1 text-center">{index + 1}</td>
|
||||
<td className="border-r border-gray-300 px-2 py-1 text-center">{item.floor}</td>
|
||||
<td className="border-r border-gray-300 px-2 py-1 text-center">{item.symbol}</td>
|
||||
<td className="border-r border-gray-300 px-2 py-1 text-center">{item.orderWidth}</td>
|
||||
<td className="border-r border-gray-300 px-2 py-1 text-center">{item.orderHeight}</td>
|
||||
<td className="border-r border-gray-300 px-2 py-1 text-center">{item.constructionWidth}</td>
|
||||
<td className="border-r border-gray-300 px-2 py-1 text-center">{item.constructionHeight}</td>
|
||||
<td className="px-2 py-1">{item.changeReason || '-'}</td>
|
||||
</tr>
|
||||
))}
|
||||
{data.priorNoticeItems.length === 0 && (
|
||||
<tr>
|
||||
<td colSpan={8} className="px-2 py-4 text-center text-gray-400">
|
||||
검사대상 사전 고지 정보가 없습니다.
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)}
|
||||
</tbody>
|
||||
</DocumentTable>
|
||||
|
||||
{/* 서명 영역 */}
|
||||
<div className="mt-8 text-center text-[10px]">
|
||||
@@ -252,6 +261,6 @@ export function InspectionRequestDocument({ data }: InspectionRequestDocumentPro
|
||||
<p>{data.createdDate}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</DocumentWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user