feat: [문서] 검사성적서/작업일지 저장 시 HTML 스냅샷 캡처 전송
- InspectionReportModal: contentWrapperRef로 DOM 캡처, handleSave에서 rendered_html 포함 - WorkLogModal: contentWrapperRef로 DOM 캡처, handleSave에서 rendered_html 포함 - saveInspectionDocument/saveWorkLog 타입에 rendered_html 추가 - MNG에서 스냅샷 기반 문서 출력을 위한 프론트 파이프라인 완성
This commit is contained in:
@@ -857,6 +857,7 @@ export async function saveInspectionDocument(
|
|||||||
title?: string;
|
title?: string;
|
||||||
data: Record<string, unknown>[];
|
data: Record<string, unknown>[];
|
||||||
approvers?: { role_name: string; user_id?: number }[];
|
approvers?: { role_name: string; user_id?: number }[];
|
||||||
|
rendered_html?: string;
|
||||||
}
|
}
|
||||||
): Promise<{
|
): Promise<{
|
||||||
success: boolean;
|
success: boolean;
|
||||||
|
|||||||
@@ -164,6 +164,7 @@ export function InspectionReportModal({
|
|||||||
const [isSaving, setIsSaving] = useState(false);
|
const [isSaving, setIsSaving] = useState(false);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const contentRef = useRef<InspectionContentRef>(null);
|
const contentRef = useRef<InspectionContentRef>(null);
|
||||||
|
const contentWrapperRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
// API에서 로딩된 검사 데이터 (props 없을 때 fallback)
|
// API에서 로딩된 검사 데이터 (props 없을 때 fallback)
|
||||||
const [apiWorkItems, setApiWorkItems] = useState<WorkItemData[] | null>(null);
|
const [apiWorkItems, setApiWorkItems] = useState<WorkItemData[] | null>(null);
|
||||||
@@ -341,6 +342,8 @@ export function InspectionReportModal({
|
|||||||
if (!workOrderId || !contentRef.current) return;
|
if (!workOrderId || !contentRef.current) return;
|
||||||
|
|
||||||
const data = contentRef.current.getInspectionData();
|
const data = contentRef.current.getInspectionData();
|
||||||
|
// HTML 스냅샷 캡처 (MNG 출력용)
|
||||||
|
const renderedHtml = contentWrapperRef.current?.innerHTML || undefined;
|
||||||
setIsSaving(true);
|
setIsSaving(true);
|
||||||
try {
|
try {
|
||||||
// 템플릿 모드: Document 기반 저장 (정규화 형식)
|
// 템플릿 모드: Document 기반 저장 (정규화 형식)
|
||||||
@@ -359,6 +362,7 @@ export function InspectionReportModal({
|
|||||||
step_id: activeStepId ?? undefined,
|
step_id: activeStepId ?? undefined,
|
||||||
title: activeTemplate.title || activeTemplate.name,
|
title: activeTemplate.title || activeTemplate.name,
|
||||||
data: inspData.records,
|
data: inspData.records,
|
||||||
|
rendered_html: renderedHtml,
|
||||||
});
|
});
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
toast.success('검사 문서가 저장되었습니다.');
|
toast.success('검사 문서가 저장되었습니다.');
|
||||||
@@ -530,7 +534,9 @@ export function InspectionReportModal({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{renderContent()}
|
<div ref={contentWrapperRef}>
|
||||||
|
{renderContent()}
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</DocumentViewer>
|
</DocumentViewer>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
* - 양식 미매핑 시 processType 폴백
|
* - 양식 미매핑 시 processType 폴백
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { useState, useEffect, useCallback } from 'react';
|
import { useState, useEffect, useCallback, useRef } from 'react';
|
||||||
import { Loader2, Save } from 'lucide-react';
|
import { Loader2, Save } from 'lucide-react';
|
||||||
import { DocumentViewer } from '@/components/document-system';
|
import { DocumentViewer } from '@/components/document-system';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
@@ -63,6 +63,7 @@ export function WorkLogModal({
|
|||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [isSaving, setIsSaving] = useState(false);
|
const [isSaving, setIsSaving] = useState(false);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
const contentWrapperRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
// 목업 WorkOrder 생성
|
// 목업 WorkOrder 생성
|
||||||
const createMockOrder = (id: string, pType?: ProcessType): WorkOrder => ({
|
const createMockOrder = (id: string, pType?: ProcessType): WorkOrder => ({
|
||||||
@@ -155,9 +156,13 @@ export function WorkLogModal({
|
|||||||
unit: item.unit || 'EA',
|
unit: item.unit || 'EA',
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// HTML 스냅샷 캡처 (MNG 출력용)
|
||||||
|
const renderedHtml = contentWrapperRef.current?.innerHTML || undefined;
|
||||||
|
|
||||||
const result = await saveWorkLog(workOrderId, {
|
const result = await saveWorkLog(workOrderId, {
|
||||||
table_data: tableData,
|
table_data: tableData,
|
||||||
title: workLogTemplateName || '작업일지',
|
title: workLogTemplateName || '작업일지',
|
||||||
|
rendered_html: renderedHtml,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
@@ -255,7 +260,9 @@ export function WorkLogModal({
|
|||||||
<p className="text-muted-foreground">{error || '데이터를 불러올 수 없습니다.'}</p>
|
<p className="text-muted-foreground">{error || '데이터를 불러올 수 없습니다.'}</p>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
renderContent()
|
<div ref={contentWrapperRef}>
|
||||||
|
{renderContent()}
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</DocumentViewer>
|
</DocumentViewer>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -744,6 +744,7 @@ export async function saveWorkLog(
|
|||||||
table_data?: Array<Record<string, unknown>>;
|
table_data?: Array<Record<string, unknown>>;
|
||||||
remarks?: string;
|
remarks?: string;
|
||||||
title?: string;
|
title?: string;
|
||||||
|
rendered_html?: string;
|
||||||
}
|
}
|
||||||
): Promise<{
|
): Promise<{
|
||||||
success: boolean;
|
success: boolean;
|
||||||
|
|||||||
Reference in New Issue
Block a user