import { formatRiskSignalLabel } from '../utils/riskLabels.js' export const emptyFinanceTotals = { reimbursementAmount: 0, reimbursementCount: 0, pendingPaymentAmount: 0, avgClaimAmount: 0, budgetUsageRate: 0, paymentClearanceRate: 0 } export const emptyFinanceTrend = { labels: [], claimCount: [], claimAmount: [], categoryAmountSeries: [], applications: [], approved: [], avgHours: [] } export const emptyFinanceDonut = [ { name: '暂无数据', value: 0, color: '#cbd5e1' } ] export const emptyFinanceBudgetSummary = { ratio: 0, total: '¥0', used: '¥0', left: '¥0' } export const emptyFinanceBudgetMetrics = [ { label: '预算池数量', value: '0 个', detail: '年度有效预算池', tone: 'neutral', icon: 'mdi mdi-database-outline' }, { label: '总预算', value: '¥0', detail: '原始预算 + 调整', tone: 'neutral', icon: 'mdi mdi-cash-register' }, { label: '已用预算', value: '¥0', detail: '使用率 0.0%', tone: 'success', icon: 'mdi mdi-chart-arc' }, { label: '预占预算', value: '¥0', detail: '待流转单据占用', tone: 'success', icon: 'mdi mdi-lock-outline' }, { label: '可用预算', value: '¥0', detail: '可继续使用额度', tone: 'success', icon: 'mdi mdi-wallet-outline' }, { label: '预警预算池', value: '0 个', detail: '超支 0 个', tone: 'success', icon: 'mdi mdi-alert-outline' } ] export const emptySystemDashboardTotals = { toolCalls: 0, modelTokens: 0, onlineUsers: 0, avgOnlineMinutes: 0, executionSuccessRate: 0, positiveFeedback: 0, negativeFeedback: 0, failedRuns: 0, toolCallsChange: 0, modelTokensChange: 0 } export const emptySystemLoginWave = { labels: Array.from({ length: 24 }, (_, hour) => `${String(hour).padStart(2, '0')}:00`), loginUsers: Array.from({ length: 24 }, () => 0), interactions: Array.from({ length: 24 }, () => 0) } export function formatCompact(value) { if (value >= 1_000_000) return `¥${(value / 1_000_000).toFixed(1)}M` if (value >= 1_000) return `¥${(value / 1_000).toFixed(1)}K` return `¥${value}` } export function formatCurrency(value) { return formatCompact(value) } export function formatNumberCompact(value) { const number = Number(value || 0) if (number >= 1_000_000) return `${(number / 1_000_000).toFixed(1)}M` if (number >= 1_000) return `${(number / 1_000).toFixed(1)}K` return `${Math.round(number)}` } export function formatPercent(value) { return `${Math.round(Number(value || 0) * 100)}%` } export function formatMetricValue(metric, value) { if (['reimbursementAmount', 'pendingPaymentAmount', 'avgClaimAmount'].includes(metric.key)) { return formatCurrency(Math.round(value)) } if (metric.unit === '%') return `${Math.round(value)} ${metric.unit}` if (metric.unit) return `${Math.round(value)} ${metric.unit}` return `${Math.round(value)}` } export function formatSystemMetricValue(metric, value, totals = emptySystemDashboardTotals) { const numericValue = Number(value || 0) if (metric.key === 'modelTokens') return formatNumberCompact(numericValue) if (metric.key === 'avgOnlineMinutes') return `${numericValue.toFixed(1)} ${metric.unit}` if (metric.key === 'executionSuccessRate') return `${numericValue.toFixed(1)}${metric.unit}` if (metric.key === 'positiveFeedback') { const negativeFeedback = Math.round(Number(totals.negativeFeedback || 0)) return `${Math.round(numericValue)} / ${negativeFeedback}` } if (metric.unit) return `${formatNumberCompact(numericValue)} ${metric.unit}` return formatNumberCompact(numericValue) } export function resolveSystemMetricMeta(metric, totals = emptySystemDashboardTotals, realDashboardLoaded = false) { if (!realDashboardLoaded) { return { changeText: metric.change, delta: metric.delta, trend: metric.trend } } if (metric.key === 'toolCalls' || metric.key === 'modelTokens') { const changeValue = Number(totals[`${metric.key}Change`] || 0) return { changeText: `${changeValue >= 0 ? '+' : ''}${changeValue.toFixed(1)}%`, delta: '较上一周期', trend: changeValue < 0 ? 'down' : 'up' } } if (metric.key === 'executionSuccessRate') { const errorRate = Math.max(0, 100 - Number(totals.executionSuccessRate || 0)) return { changeText: '实时', delta: `错误率 ${errorRate.toFixed(1)}%`, trend: 'up' } } if (metric.key === 'positiveFeedback') { return { changeText: '实时', delta: `差评 ${Math.round(Number(totals.negativeFeedback || 0))} 次`, trend: 'up' } } return { changeText: '实时', delta: metric.key === 'onlineUsers' ? '活跃会话' : '按最近会话统计', trend: metric.trend } } export function resolveFinanceMetricMeta({ metric, meta, dashboardLoaded, loading, error }) { if (!dashboardLoaded || !meta) { return { changeText: loading ? '加载中' : '实时', delta: error ? '真实数据加载失败' : '等待真实数据', trend: metric.trend } } return { changeText: meta.changeText || metric.change, delta: meta.delta || metric.delta, trend: meta.trend || metric.trend } } export function buildRiskDistributionLegend(distribution, labels, colors, formatter = formatRiskSignalName) { const fallbackColors = ['#ef4444', '#f59e0b', 'var(--theme-primary)', '#3b82f6', '#8b5cf6', '#0f766e'] const entries = Object.entries(distribution || {}) .filter(([, value]) => Number(value || 0) > 0) if (!entries.length) { return [ { name: '暂无数据', value: 1, display: '0项', color: '#cbd5e1' } ] } return entries.map(([key, value], index) => ({ name: labels[key] || formatter(key), value: Number(value || 0), display: `${Number(value || 0)}项`, color: colors[key] || fallbackColors[index % fallbackColors.length] })) } export function formatRiskSignalName(value) { return formatRiskSignalLabel(value) } export function isMissingDimension(value) { const text = String(value || '').trim() return !text || ['待补充', '待确认', '未归属部门', '未归属', 'N/A', 'n/a', '-'].includes(text) }