From 5cb225e9cd6b0ba2f52572a3afa0de6e5b2a2ece Mon Sep 17 00:00:00 2001
From: joonhoekim <26rote@gmail.com>
Date: Fri, 18 Jul 2025 16:32:22 +0900
Subject: 파일첨부 API 처리, 텍스트 변경
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
components/knox/approval/ApprovalDetail.tsx | 54 +++++++++++++++++++++++++++--
components/knox/approval/ApprovalSubmit.tsx | 46 ++++++++++++++++++++----
2 files changed, 91 insertions(+), 9 deletions(-)
(limited to 'components')
diff --git a/components/knox/approval/ApprovalDetail.tsx b/components/knox/approval/ApprovalDetail.tsx
index 034bde7d..6db43cbe 100644
--- a/components/knox/approval/ApprovalDetail.tsx
+++ b/components/knox/approval/ApprovalDetail.tsx
@@ -28,6 +28,15 @@ interface ApprovalDetailData {
content: ApprovalContentResponse['data'];
}
+// 첨부파일 타입 (가이드에 명확히 정의되어 있지 않아 필드 일부 추정)
+interface ApprovalAttachment {
+ fileName?: string;
+ fileSize?: string;
+ downloadUrl?: string;
+ fileId?: string;
+ [key: string]: unknown; // 기타 필드 허용
+}
+
export default function ApprovalDetail({
useFakeData = false,
systemId = 'EVCP_SYSTEM',
@@ -126,6 +135,43 @@ export default function ApprovalDetail({
}
};
+ // 첨부파일 다운로드 헬퍼
+ const handleDownload = async (attachment: ApprovalAttachment) => {
+ try {
+ // 1) downloadUrl 이 이미 포함된 경우
+ if (attachment.downloadUrl) {
+ window.open(attachment.downloadUrl, '_blank');
+ return;
+ }
+
+ // 2) fileId + 별도 엔드포인트 조합 (가이드에 명시되지 않았으므로 best-effort 처리)
+ if (attachment.fileId) {
+ const url = `${process.env.KNOX_API_BASE_URL}/approval/api/v2.0/attachments/${attachment.fileId}`;
+ const resp = await fetch(url, {
+ method: 'GET',
+ headers: {
+ 'System-ID': systemId,
+ },
+ });
+ if (!resp.ok) throw new Error('다운로드 실패');
+
+ // blob 생성 후 브라우저 다운로드
+ const blob = await resp.blob();
+ const link = document.createElement('a');
+ link.href = URL.createObjectURL(blob);
+ link.download = attachment.fileName || 'attachment';
+ link.click();
+ URL.revokeObjectURL(link.href);
+ return;
+ }
+
+ toast.error('다운로드 URL 정보를 찾을 수 없습니다.');
+ } catch (err) {
+ console.error('첨부파일 다운로드 오류:', err);
+ toast.error('첨부파일 다운로드 중 오류가 발생했습니다.');
+ }
+ };
+
// 초기 로딩 (initialApInfId가 있는 경우)
useEffect(() => {
if (initialApInfId) {
@@ -338,14 +384,18 @@ export default function ApprovalDetail({
첨부파일
- {approvalData.detail.attachments.map((attachment: any, index: number) => (
+ {approvalData.detail.attachments.map((attachment: ApprovalAttachment, index: number) => (
{attachment.fileName || `첨부파일 ${index + 1}`}
{attachment.fileSize || '크기 정보 없음'}
-
diff --git a/components/knox/approval/ApprovalSubmit.tsx b/components/knox/approval/ApprovalSubmit.tsx
index 37779ce3..526a87f3 100644
--- a/components/knox/approval/ApprovalSubmit.tsx
+++ b/components/knox/approval/ApprovalSubmit.tsx
@@ -17,7 +17,7 @@ import { toast } from 'sonner';
import { Loader2, Plus, Trash2, FileText, AlertCircle } from 'lucide-react';
// API 함수 및 타입
-import { submitApproval, createSubmitApprovalRequest, createApprovalLine } from '@/lib/knox-api/approval/approval';
+import { submitApproval, submitSecurityApproval, createSubmitApprovalRequest, createApprovalLine } from '@/lib/knox-api/approval/approval';
import type { ApprovalLine, SubmitApprovalRequest } from '@/lib/knox-api/approval/approval';
// Mock 데이터
@@ -40,7 +40,9 @@ const formSchema = z.object({
role: z.enum(['0', '1', '2', '3', '4', '7', '9']),
seq: z.string(),
opinion: z.string().optional()
- })).min(1, '최소 1개의 결재 경로가 필요합니다')
+ })).min(1, '최소 1개의 결재 경로가 필요합니다'),
+ // 첨부파일 (선택)
+ attachments: z.any().optional()
});
type FormData = z.infer
;
@@ -80,7 +82,8 @@ export default function ApprovalSubmit({
seq: '1',
opinion: ''
}
- ]
+ ],
+ attachments: undefined
}
});
@@ -137,6 +140,8 @@ export default function ApprovalSubmit({
);
// 상신 요청 생성
+ const attachmentsArray = data.attachments ? Array.from(data.attachments as FileList) : undefined;
+
const submitRequest: SubmitApprovalRequest = useFakeData
? {
...data,
@@ -144,7 +149,8 @@ export default function ApprovalSubmit({
importantYn: data.importantYn ? 'Y' : 'N',
sbmDt: new Date().toISOString().replace(/-|:|T/g, '').slice(0, 14),
apInfId: 'test-ap-inf-id-' + Date.now(),
- aplns: approvalLines
+ aplns: approvalLines,
+ attachments: attachmentsArray
}
: await createSubmitApprovalRequest(
data.contents,
@@ -158,14 +164,19 @@ export default function ApprovalSubmit({
notifyOption: data.notifyOption,
docMngSaveCode: data.docMngSaveCode,
sbmLang: data.sbmLang,
- timeZone: data.timeZone
+ timeZone: data.timeZone,
+ attachments: attachmentsArray
}
);
- // API 호출
+ // API 호출 (보안 등급에 따라 분기)
+ const isSecure = data.docSecuType === 'CONFIDENTIAL' || data.docSecuType === 'CONFIDENTIAL_STRICT';
+
const response = useFakeData
? await mockApprovalAPI.submitApproval(submitRequest)
- : await submitApproval(submitRequest, systemId);
+ : isSecure
+ ? await submitSecurityApproval(submitRequest, systemId)
+ : await submitApproval(submitRequest, systemId);
if (response.result === 'SUCCESS') {
setSubmitResult({ apInfId: response.data.apInfId });
@@ -333,6 +344,27 @@ export default function ApprovalSubmit({
)}
/>
+
+ {/* 첨부 파일 */}
+ (
+
+ 첨부 파일
+
+ field.onChange(e.target.files)}
+ />
+
+ 필요 시 파일을 선택하세요. (다중 선택 가능)
+
+
+ )}
+ />
+
--
cgit v1.2.3