import React, { useState, useCallback } from 'react' import { View, Text, ScrollView, StyleSheet, RefreshControl, ActivityIndicator } from 'react-native' import { useFocusEffect } from 'expo-router' import { COLORS } from '../../constants/Config' import client from '../../services/api' function GaugeBar({ value, max, color }: { value: number; max: number; color: string }) { const pct = Math.min(100, Math.round((value / max) * 100)) return ( ) } const g = StyleSheet.create({ wrap: { height: 8, backgroundColor: COLORS.border, borderRadius: 4, overflow: 'hidden' }, fill: { height: '100%', borderRadius: 4 }, }) export default function HealthScorecardScreen() { const [data, setData] = useState(null) const [loading, setLoading] = useState(false) const load = useCallback(async () => { setLoading(true) try { const r = await client.get('/api/dashboard'); setData(r.data) } catch { setData(null) } finally { setLoading(false) } }, []) useFocusEffect(useCallback(() => { load() }, [load])) if (loading && !data) return if (!data) return 건강 점수를 불러올 수 없습니다. const metrics = [ { label: 'SR 처리율', value: data.sr_completion_rate ?? 0, max: 100, unit: '%', color: COLORS.success }, { label: 'SLA 준수율', value: data.sla_compliance ?? data.sla_rate ?? 0, max: 100, unit: '%', color: COLORS.blue }, { label: '서버 가용률', value: data.server_availability ?? 0, max: 100, unit: '%', color: COLORS.accent }, { label: '미해결 SR', value: data.open_tasks ?? 0, max: Math.max(data.open_tasks ?? 1, 50), unit: '건', color: COLORS.warning }, { label: 'CSAP 준수율', value: data.csap_score ?? data.compliance_score ?? 0, max: 100, unit: '%', color: '#8b5cf6' }, ] const overall = Math.round(metrics.filter(m => m.unit === '%').reduce((a, m) => a + m.value, 0) / metrics.filter(m => m.unit === '%').length) const overallColor = overall >= 90 ? COLORS.success : overall >= 70 ? COLORS.warning : COLORS.danger return ( } contentContainerStyle={{ padding: 16 }}> 종합 건강 점수 {overall} {overall >= 90 ? '우수' : overall >= 70 ? '보통' : '위험'} {metrics.map(m => ( {m.label} {m.value}{m.unit} ))} ) } const s = StyleSheet.create({ container: { flex: 1, backgroundColor: COLORS.bg }, empty: { textAlign: 'center', color: COLORS.muted, marginTop: 40 }, overallCard: { alignItems: 'center', borderWidth: 2, borderRadius: 16, padding: 24, marginBottom: 16, backgroundColor: '#fff', elevation: 2 }, overallLabel: { fontSize: 13, color: COLORS.muted, marginBottom: 8 }, overallScore: { fontSize: 60, fontWeight: '900', lineHeight: 68 }, overallGrade: { fontSize: 16, fontWeight: '700', marginTop: 4 }, card: { backgroundColor: '#fff', borderRadius: 12, padding: 14, marginBottom: 8, elevation: 1 }, row: { flexDirection: 'row', justifyContent: 'space-between', marginBottom: 8 }, label: { fontSize: 13, color: COLORS.text, fontWeight: '600' }, value: { fontSize: 14, fontWeight: '800' }, })