- useAccountingListPage, useDateRange 공통 훅 추출 - accounting/shared/ 공통 컴포넌트 분리 - 회계 모듈(입금/출금/매출/매입/청구 등) 중복 로직 통합 - 차량관리 page.tsx 패턴 간소화 - 건설/결재/자재/출하/단가 등 날짜 관련 코드 공통화 - 코드 중복 제거 체크리스트 문서 추가 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
115 lines
3.9 KiB
TypeScript
115 lines
3.9 KiB
TypeScript
'use client';
|
|
|
|
/**
|
|
* 품의서 문서 컴포넌트
|
|
*
|
|
* 공통 컴포넌트 사용:
|
|
* - DocumentHeader: centered 레이아웃 + customApproval (ApprovalLineBox)
|
|
*/
|
|
|
|
import { ApprovalLineBox } from './ApprovalLineBox';
|
|
import type { ProposalDocumentData } from './types';
|
|
import { DocumentHeader } from '@/components/document-system';
|
|
import { formatNumber as formatCurrency } from '@/lib/utils/amount';
|
|
|
|
interface ProposalDocumentProps {
|
|
data: ProposalDocumentData;
|
|
}
|
|
|
|
export function ProposalDocument({ data }: ProposalDocumentProps) {
|
|
|
|
return (
|
|
<div className="bg-white p-8 min-h-full">
|
|
{/* 문서 헤더 (공통 컴포넌트) */}
|
|
<DocumentHeader
|
|
title="품의서"
|
|
subtitle={`문서번호: ${data.documentNo} | 작성일자: ${data.createdAt}`}
|
|
layout="centered"
|
|
customApproval={<ApprovalLineBox drafter={data.drafter} approvers={data.approvers} />}
|
|
/>
|
|
|
|
{/* 문서 내용 */}
|
|
<div className="border border-gray-300">
|
|
{/* 구매처 정보 */}
|
|
<div className="grid grid-cols-2 border-b border-gray-300">
|
|
<div className="flex border-r border-gray-300">
|
|
<div className="w-28 bg-gray-100 p-3 font-medium text-sm border-r border-gray-300">
|
|
구매처
|
|
</div>
|
|
<div className="flex-1 p-3 text-sm">{data.vendor || '-'}</div>
|
|
</div>
|
|
<div className="flex">
|
|
<div className="w-28 bg-gray-100 p-3 font-medium text-sm border-r border-gray-300">
|
|
구매처 결제일
|
|
</div>
|
|
<div className="flex-1 p-3 text-sm">{data.vendorPaymentDate || '-'}</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* 제목 */}
|
|
<div className="flex border-b border-gray-300">
|
|
<div className="w-28 bg-gray-100 p-3 font-medium text-sm border-r border-gray-300">
|
|
제목
|
|
</div>
|
|
<div className="flex-1 p-3 text-sm">{data.title || '-'}</div>
|
|
</div>
|
|
|
|
{/* 품의 내역 */}
|
|
<div className="flex border-b border-gray-300">
|
|
<div className="w-28 bg-gray-100 p-3 font-medium text-sm border-r border-gray-300">
|
|
품의 내역
|
|
</div>
|
|
<div className="flex-1 p-3 text-sm min-h-[100px] whitespace-pre-wrap">
|
|
{data.description || '-'}
|
|
</div>
|
|
</div>
|
|
|
|
{/* 품의 사유 */}
|
|
<div className="flex border-b border-gray-300">
|
|
<div className="w-28 bg-gray-100 p-3 font-medium text-sm border-r border-gray-300">
|
|
품의 사유
|
|
</div>
|
|
<div className="flex-1 p-3 text-sm min-h-[100px] whitespace-pre-wrap">
|
|
{data.reason || '-'}
|
|
</div>
|
|
</div>
|
|
|
|
{/* 예상 비용 */}
|
|
<div className="flex border-b border-gray-300">
|
|
<div className="w-28 bg-gray-100 p-3 font-medium text-sm border-r border-gray-300">
|
|
예상 비용
|
|
</div>
|
|
<div className="flex-1 p-3 text-sm font-semibold">
|
|
{formatCurrency(data.estimatedCost)}원
|
|
</div>
|
|
</div>
|
|
|
|
{/* 참고 이미지 */}
|
|
<div>
|
|
<div className="bg-gray-800 text-white p-2 text-sm font-medium text-center">
|
|
참고 이미지
|
|
</div>
|
|
<div className="min-h-[150px] p-4 bg-gray-50">
|
|
{data.attachments && data.attachments.length > 0 ? (
|
|
<div className="grid grid-cols-3 gap-4">
|
|
{data.attachments.map((url, index) => (
|
|
<img
|
|
key={index}
|
|
src={url}
|
|
alt={`첨부 이미지 ${index + 1}`}
|
|
className="w-full h-32 object-cover rounded border"
|
|
/>
|
|
))}
|
|
</div>
|
|
) : (
|
|
<div className="text-center text-gray-400 py-8">
|
|
첨부된 이미지가 없습니다
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|