guardia-messenger/app/(tabs)/pdf_share.tsx

116 lines
4.9 KiB
TypeScript

import React, { useState, useCallback } from 'react'
import {
View, Text, ScrollView, TouchableOpacity, StyleSheet,
ActivityIndicator, Alert,
} from 'react-native'
import { useFocusEffect } from 'expo-router'
import { COLORS } from '../../constants/Config'
import { getReportData } from '../../services/api'
export default function PDFShareScreen() {
const [data, setData] = useState<any>(null)
const [loading, setLoading] = useState(false)
const [exporting, setExporting] = useState(false)
const load = useCallback(async () => {
setLoading(true)
try { const r = await getReportData(); setData(r.data) }
catch { setData(null) }
finally { setLoading(false) }
}, [])
useFocusEffect(useCallback(() => { load() }, [load]))
const exportPDF = async () => {
setExporting(true)
try {
// eslint-disable-next-line @typescript-eslint/no-var-requires
let Print: any = null; let Sharing: any = null
try { Print = require('expo-print') } catch {}
try { Sharing = require('expo-sharing') } catch {}
if (!Print || !Sharing) {
Alert.alert('알림', '현재 환경에서 PDF 내보내기가 지원되지 않습니다.')
return
}
const html = buildHTML(data)
const { uri } = await Print.printToFileAsync({ html })
if (await Sharing.isAvailableAsync()) {
await Sharing.shareAsync(uri, { mimeType: 'application/pdf', dialogTitle: 'GUARDiA 리포트 공유' })
} else {
Alert.alert('완료', `PDF가 저장됐습니다:\n${uri}`)
}
} catch { Alert.alert('오류', 'PDF 생성에 실패했습니다.') }
finally { setExporting(false) }
}
if (loading) return <ActivityIndicator style={{ flex: 1 }} color={COLORS.accent} />
if (!data) return <Text style={s.empty}> .</Text>
return (
<View style={{ flex: 1, backgroundColor: COLORS.bg }}>
<ScrollView contentContainerStyle={{ padding: 12 }}>
<Text style={s.title}> </Text>
<Text style={s.period}>{data.period ?? ''}</Text>
<View style={s.section}>
<Text style={s.sectionTitle}>SR </Text>
<Row label="전체 SR" value={data.total_sr} />
<Row label="완료" value={data.completed_sr} />
<Row label="SLA 준수율" value={`${data.sla_compliance_rate ?? 0}%`} />
<Row label="CSAP 점수" value={`${data.csap_score ?? 0}`} />
</View>
<View style={s.section}>
<Text style={s.sectionTitle}> </Text>
<Row label="성공" value={data.deploy_success ?? 0} />
<Row label="실패" value={data.deploy_failure ?? 0} />
</View>
</ScrollView>
<TouchableOpacity style={[s.exportBtn, exporting && { opacity: 0.5 }]} onPress={exportPDF} disabled={exporting}>
{exporting ? <ActivityIndicator color="#fff" /> : <Text style={s.exportText}>PDF · </Text>}
</TouchableOpacity>
</View>
)
}
function Row({ label, value }: { label: string; value: any }) {
return (
<View style={s.dataRow}>
<Text style={s.dataLabel}>{label}</Text>
<Text style={s.dataValue}>{value}</Text>
</View>
)
}
function buildHTML(data: any): string {
return `<!DOCTYPE html><html><head><meta charset="utf-8">
<style>body{font-family:sans-serif;padding:20px;}h1{color:#1e3a8a;}table{width:100%;border-collapse:collapse;}td{padding:8px;border-bottom:1px solid #eee;}</style>
</head><body>
<h1>GUARDiA 월간 리포트</h1><p>${data?.period ?? ''}</p>
<h2>SR 현황</h2><table>
<tr><td>전체 SR</td><td>${data?.total_sr ?? 0}</td></tr>
<tr><td>완료</td><td>${data?.completed_sr ?? 0}</td></tr>
<tr><td>SLA 준수율</td><td>${data?.sla_compliance_rate ?? 0}%</td></tr>
<tr><td>CSAP 점수</td><td>${data?.csap_score ?? 0}점</td></tr>
</table>
<h2>배포</h2><table>
<tr><td>성공</td><td>${data?.deploy_success ?? 0}</td></tr>
<tr><td>실패</td><td>${data?.deploy_failure ?? 0}</td></tr>
</table>
</body></html>`
}
const s = StyleSheet.create({
title: { fontSize: 20, fontWeight: '800', color: COLORS.text, marginBottom: 4 },
period: { fontSize: 13, color: COLORS.muted, marginBottom: 16 },
section: { backgroundColor: '#fff', borderRadius: 10, padding: 14, marginBottom: 10, elevation: 1 },
sectionTitle:{ fontSize: 14, fontWeight: '700', color: COLORS.text, marginBottom: 10 },
dataRow: { flexDirection: 'row', justifyContent: 'space-between', paddingVertical: 6, borderBottomWidth: 1, borderBottomColor: COLORS.light },
dataLabel: { fontSize: 13, color: COLORS.muted },
dataValue: { fontSize: 13, fontWeight: '700', color: COLORS.text },
exportBtn: { margin: 12, backgroundColor: COLORS.accent, borderRadius: 12, padding: 16, alignItems: 'center' },
exportText: { color: '#fff', fontWeight: '800', fontSize: 15 },
empty: { textAlign: 'center', color: COLORS.muted, marginTop: 40 },
})