기존 HTML Blob → .doc 저장 방식을 OWPML 표준 HWPX(ZIP+XML) 포맷으로 교체. JSZip으로 HWPX 파일을 순수 브라우저에서 생성하여 한글에서 직접 열 수 있도록 구현. - hwpxExport.ts 신규: HWPX ZIP 패키징 (mimetype, header.xml, section0.xml 등) - reportUtils.ts: exportAsHWP → dynamic import로 HWPX 위임 - ReportsView.tsx, TemplateFormEditor.tsx: 구조화 데이터 직접 전달 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
89 lines
4.7 KiB
TypeScript
89 lines
4.7 KiB
TypeScript
import { sanitizeHtml } from '@common/utils/sanitize';
|
|
import type { OilSpillReportData } from './OilSpillReportTemplate';
|
|
|
|
// ─── Report Export Helpers ──────────────────────────────
|
|
export function generateReportHTML(
|
|
templateLabel: string,
|
|
meta: { writeTime: string; author: string; jurisdiction: string },
|
|
sections: { title: string; fields: { key: string; label: string }[] }[],
|
|
getVal: (key: string) => string
|
|
) {
|
|
const rows = sections.map(section => {
|
|
const fieldRows = section.fields.map(f => {
|
|
if (f.label) {
|
|
return `<tr><td style="background:#f0f4f8;padding:8px 12px;border:1px solid #d1d5db;font-weight:600;width:200px;font-size:12px;">${f.label}</td><td style="padding:8px 12px;border:1px solid #d1d5db;font-size:12px;">${getVal(f.key) || '-'}</td></tr>`
|
|
}
|
|
return `<tr><td colspan="2" style="padding:8px 12px;border:1px solid #d1d5db;font-size:12px;white-space:pre-wrap;">${getVal(f.key) || '-'}</td></tr>`
|
|
}).join('')
|
|
return `<h3 style="color:#0891b2;font-size:14px;margin:20px 0 8px;">${section.title}</h3><table style="width:100%;border-collapse:collapse;">${fieldRows}</table>`
|
|
}).join('')
|
|
|
|
return `<!DOCTYPE html><html><head><meta charset="utf-8"><title>${templateLabel}</title>
|
|
<style>@page{size:A4;margin:20mm}body{font-family:'맑은 고딕','Malgun Gothic',sans-serif;color:#1a1a1a;max-width:800px;margin:0 auto;padding:40px}</style>
|
|
</head><body>
|
|
<div style="text-align:center;margin-bottom:30px">
|
|
<h1 style="font-size:20px;margin:0">해양오염방제지원시스템</h1>
|
|
<h2 style="font-size:16px;color:#0891b2;margin:8px 0">${templateLabel}</h2>
|
|
<p style="font-size:11px;color:#666">작성일시: ${meta.writeTime} | 작성자: ${meta.author || '-'} | 관할: ${meta.jurisdiction}</p>
|
|
</div>${rows}</body></html>`
|
|
}
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
export function exportAsPDF(html: string, _filename: string) {
|
|
const sanitizedHtml = sanitizeHtml(html)
|
|
const blob = new Blob([sanitizedHtml], { type: 'text/html; charset=utf-8' })
|
|
const url = URL.createObjectURL(blob)
|
|
const win = window.open(url, '_blank')
|
|
if (win) {
|
|
win.addEventListener('afterprint', () => URL.revokeObjectURL(url))
|
|
setTimeout(() => win.print(), 500)
|
|
}
|
|
setTimeout(() => URL.revokeObjectURL(url), 30000)
|
|
}
|
|
|
|
export async function exportAsHWP(
|
|
templateLabel: string,
|
|
meta: { writeTime: string; author: string; jurisdiction: string },
|
|
sections: { title: string; fields: { key: string; label: string }[] }[],
|
|
getVal: (key: string) => string,
|
|
filename: string,
|
|
) {
|
|
const { exportAsHWPX } = await import('./hwpxExport');
|
|
await exportAsHWPX(templateLabel, meta, sections, getVal, filename);
|
|
}
|
|
|
|
export type ViewState =
|
|
| { screen: 'list' }
|
|
| { screen: 'templates' }
|
|
| { screen: 'generate' }
|
|
| { screen: 'view'; data: OilSpillReportData }
|
|
| { screen: 'edit'; data: OilSpillReportData }
|
|
|
|
export const typeColors: Record<string, { bg: string; text: string }> = {
|
|
'초기보고서': { bg: 'rgba(6,182,212,0.15)', text: '#06b6d4' },
|
|
'지휘부 보고': { bg: 'rgba(168,85,247,0.15)', text: '#a855f7' },
|
|
'예측보고서': { bg: 'rgba(59,130,246,0.15)', text: '#3b82f6' },
|
|
'종합보고서': { bg: 'rgba(249,115,22,0.15)', text: '#f97316' },
|
|
'유출유 보고': { bg: 'rgba(234,179,8,0.15)', text: '#eab308' },
|
|
}
|
|
export const statusColors: Record<string, { bg: string; text: string }> = {
|
|
'완료': { bg: 'rgba(34,197,94,0.15)', text: '#22c55e' },
|
|
'수행중': { bg: 'rgba(249,115,22,0.15)', text: '#f97316' },
|
|
'테스트': { bg: 'rgba(138,150,168,0.15)', text: '#8a96a8' },
|
|
}
|
|
export const analysisCatColors: Record<string, { bg: string; text: string; icon: string }> = {
|
|
'유출유 확산예측': { bg: 'rgba(6,182,212,0.12)', text: '#06b6d4', icon: '🛢' },
|
|
'HNS 대기확산': { bg: 'rgba(249,115,22,0.12)', text: '#f97316', icon: '🧪' },
|
|
'긴급구난': { bg: 'rgba(239,68,68,0.12)', text: '#ef4444', icon: '🚨' },
|
|
}
|
|
|
|
export function inferAnalysisCategory(report: OilSpillReportData): string {
|
|
if (report.analysisCategory) return report.analysisCategory
|
|
const t = (report.title || '').toLowerCase()
|
|
const rt = report.reportType || ''
|
|
if (t.includes('hns') || t.includes('대기확산') || t.includes('화학') || t.includes('aloha')) return 'HNS 대기확산'
|
|
if (t.includes('구난') || t.includes('구조') || t.includes('긴급') || t.includes('salvage') || t.includes('rescue')) return '긴급구난'
|
|
if (t.includes('유출유') || t.includes('확산예측') || t.includes('민감자원') || t.includes('유출사고') || t.includes('오염') || t.includes('방제') || rt === '유출유 보고' || rt === '예측보고서') return '유출유 확산예측'
|
|
return ''
|
|
}
|