feat: 기안함/결재함 상세 모달 버튼 분기 및 수정 기능 추가
- 기안함 임시저장 상세: 복제, 상신, 인쇄 버튼 표시 - 기안함 결재대기 이후 상세: 인쇄만 표시 - 결재함 상세: 수정, 반려, 승인, 인쇄 버튼 표시 - 결재함 리스트 작업컬럼 수정 버튼 → 기안함 수정 페이지 이동 - DocumentDetailModal mode/documentStatus 기반 조건부 렌더링 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -13,6 +13,7 @@ import { toast } from 'sonner';
|
||||
import {
|
||||
getDrafts,
|
||||
getDraftsSummary,
|
||||
getDraftById,
|
||||
deleteDraft,
|
||||
deleteDrafts,
|
||||
submitDraft,
|
||||
@@ -238,14 +239,21 @@ export function DraftBox() {
|
||||
|
||||
// ===== 문서 클릭/수정 핸들러 (조건부 로직) =====
|
||||
// 임시저장 → 문서 작성 페이지 (수정 모드)
|
||||
// 그 외 → 문서 상세 모달
|
||||
const handleDocumentClick = useCallback((item: DraftRecord) => {
|
||||
// 그 외 → 문서 상세 모달 (상세 API 호출하여 content 포함된 데이터 가져옴)
|
||||
const handleDocumentClick = useCallback(async (item: DraftRecord) => {
|
||||
if (item.status === 'draft') {
|
||||
// 임시저장 상태 → 문서 작성 페이지로 이동 (수정 모드)
|
||||
router.push(`/ko/approval/draft/new?id=${item.id}&mode=edit`);
|
||||
} else {
|
||||
// 그 외 상태 → 문서 상세 모달 열기
|
||||
setSelectedDocument(item);
|
||||
// 그 외 상태 → 문서 상세 API 호출 후 모달 열기
|
||||
// 목록 API에서는 content가 포함되지 않을 수 있으므로 상세 조회 필요
|
||||
const detailData = await getDraftById(item.id);
|
||||
if (detailData) {
|
||||
setSelectedDocument(detailData);
|
||||
} else {
|
||||
// 상세 조회 실패 시 기존 데이터 사용
|
||||
setSelectedDocument(item);
|
||||
}
|
||||
setIsModalOpen(true);
|
||||
}
|
||||
}, [router]);
|
||||
@@ -258,9 +266,14 @@ export function DraftBox() {
|
||||
}, [selectedDocument, router]);
|
||||
|
||||
const handleModalCopy = useCallback(() => {
|
||||
console.log('[DraftBox] handleModalCopy 호출됨, selectedDocument:', selectedDocument);
|
||||
if (selectedDocument) {
|
||||
router.push(`/ko/approval/draft/new?copyFrom=${selectedDocument.id}`);
|
||||
const copyUrl = `/ko/approval/draft/new?copyFrom=${selectedDocument.id}`;
|
||||
console.log('[DraftBox] 복제 URL로 이동:', copyUrl);
|
||||
router.push(copyUrl);
|
||||
setIsModalOpen(false);
|
||||
} else {
|
||||
console.log('[DraftBox] selectedDocument가 없음');
|
||||
}
|
||||
}, [selectedDocument, router]);
|
||||
|
||||
@@ -276,6 +289,29 @@ export function DraftBox() {
|
||||
setIsModalOpen(false);
|
||||
}, []);
|
||||
|
||||
// ===== 모달에서 상신 핸들러 =====
|
||||
const handleModalSubmit = useCallback(async () => {
|
||||
if (!selectedDocument) return;
|
||||
|
||||
startTransition(async () => {
|
||||
try {
|
||||
const result = await submitDraft(selectedDocument.id);
|
||||
if (result.success) {
|
||||
toast.success('문서를 상신했습니다.');
|
||||
setIsModalOpen(false);
|
||||
setSelectedDocument(null);
|
||||
loadData();
|
||||
loadSummary();
|
||||
} else {
|
||||
toast.error(result.error || '상신에 실패했습니다.');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Submit error:', error);
|
||||
toast.error('상신 중 오류가 발생했습니다.');
|
||||
}
|
||||
});
|
||||
}, [selectedDocument, loadData, loadSummary]);
|
||||
|
||||
// ===== DraftRecord → 모달용 데이터 변환 =====
|
||||
const getDocumentType = (item: DraftRecord): DocumentType => {
|
||||
// documentTypeCode 우선 사용, 없으면 documentType(양식명)으로 추론
|
||||
@@ -371,7 +407,11 @@ export function DraftBox() {
|
||||
}
|
||||
default: {
|
||||
// proposal (품의서)
|
||||
// API content 구조: { vendor, vendorPaymentDate, title, description, reason, estimatedCost }
|
||||
// API content 구조: { vendor, vendorPaymentDate, title, description, reason, estimatedCost, files }
|
||||
const files = (content.files as Array<{ id: number; name: string; url?: string }>) || [];
|
||||
// Next.js 프록시 URL 사용 (인증된 요청 프록시)
|
||||
const attachmentUrls = files.map(f => `/api/files/${f.id}/download`);
|
||||
|
||||
return {
|
||||
documentNo: item.documentNo,
|
||||
createdAt: item.draftDate,
|
||||
@@ -381,7 +421,7 @@ export function DraftBox() {
|
||||
description: (content.description as string) || '',
|
||||
reason: (content.reason as string) || '',
|
||||
estimatedCost: (content.estimatedCost as number) || 0,
|
||||
attachments: [],
|
||||
attachments: attachmentUrls,
|
||||
approvers,
|
||||
drafter,
|
||||
};
|
||||
@@ -451,7 +491,8 @@ export function DraftBox() {
|
||||
</Badge>
|
||||
</TableCell>
|
||||
<TableCell className="text-center" onClick={(e) => e.stopPropagation()}>
|
||||
{isSelected && (
|
||||
{/* 임시저장 상태일 때만 수정/삭제 버튼 표시 */}
|
||||
{isSelected && item.status === 'draft' && (
|
||||
<div className="flex items-center justify-center gap-1">
|
||||
<Button
|
||||
variant="ghost"
|
||||
@@ -510,7 +551,8 @@ export function DraftBox() {
|
||||
</div>
|
||||
}
|
||||
actions={
|
||||
isSelected ? (
|
||||
/* 임시저장 상태일 때만 수정/삭제 버튼 표시 */
|
||||
isSelected && item.status === 'draft' ? (
|
||||
<div className="flex gap-2">
|
||||
<Button variant="outline" className="flex-1" onClick={() => handleDocumentClick(item)}>
|
||||
<Pencil className="w-4 h-4 mr-2" /> 수정
|
||||
@@ -628,10 +670,11 @@ export function DraftBox() {
|
||||
onOpenChange={setIsModalOpen}
|
||||
documentType={getDocumentType(selectedDocument)}
|
||||
data={convertToModalData(selectedDocument)}
|
||||
mode="draft"
|
||||
documentStatus={selectedDocument.status}
|
||||
onEdit={handleModalEdit}
|
||||
onCopy={handleModalCopy}
|
||||
onApprove={handleModalApprove}
|
||||
onReject={handleModalReject}
|
||||
onSubmit={handleModalSubmit}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
|
||||
Reference in New Issue
Block a user