feat(dashboard): polish risk and digital employee boards
This commit is contained in:
@@ -6,6 +6,10 @@ import {
|
||||
fetchSystemDashboard
|
||||
} from '../services/analytics.js'
|
||||
import { fetchRiskObservationDashboard } from '../services/riskObservations.js'
|
||||
import {
|
||||
formatRiskSignalLabel,
|
||||
formatRiskSourceLabel
|
||||
} from '../utils/riskLabels.js'
|
||||
import {
|
||||
buildDigitalEmployeeCategoryRows,
|
||||
buildDigitalEmployeeDailyRows,
|
||||
@@ -75,6 +79,13 @@ const emptyFinanceBudgetMetrics = [
|
||||
]
|
||||
|
||||
export function useOverviewView(options = {}) {
|
||||
const activeDashboardKey = computed(() => {
|
||||
const dashboard = String(options.dashboard || '').trim()
|
||||
if (dashboard === 'system') return 'system'
|
||||
if (dashboard === 'risk') return 'risk'
|
||||
if (dashboard === 'digitalEmployee') return 'digitalEmployee'
|
||||
return 'finance'
|
||||
})
|
||||
const activeTrendRange = ref(trendRanges[0])
|
||||
const activeDepartmentRange = ref(departmentRangeOptions[0])
|
||||
const riskWindowOptions = [
|
||||
@@ -86,18 +97,22 @@ export function useOverviewView(options = {}) {
|
||||
const financeDashboardPayload = ref(null)
|
||||
const financeDashboardLoading = ref(false)
|
||||
const financeDashboardError = ref(null)
|
||||
const financeDashboardLoaded = computed(() => Boolean(financeDashboardPayload.value))
|
||||
const systemDashboardPayload = ref(null)
|
||||
const systemDashboardLoading = ref(false)
|
||||
const systemDashboardError = ref(null)
|
||||
const systemDashboardLoaded = computed(() => Boolean(systemDashboardPayload.value))
|
||||
const riskDashboardPayload = ref(null)
|
||||
const riskDashboardLoading = ref(false)
|
||||
const riskDashboardError = ref(null)
|
||||
const riskDashboardLoaded = computed(() => Boolean(riskDashboardPayload.value))
|
||||
const riskDashboardLastUpdatedAt = ref('')
|
||||
let riskDashboardRefreshTimer = 0
|
||||
let riskDashboardRequestSeq = 0
|
||||
const digitalEmployeeDashboardPayload = ref(null)
|
||||
const digitalEmployeeDashboardLoading = ref(false)
|
||||
const digitalEmployeeDashboardError = ref(null)
|
||||
const digitalEmployeeDashboardLoaded = computed(() => Boolean(digitalEmployeeDashboardPayload.value))
|
||||
|
||||
const formatCompact = (value) => {
|
||||
if (value >= 1_000_000) return `¥${(value / 1_000_000).toFixed(1)}M`
|
||||
@@ -251,12 +266,29 @@ export function useOverviewView(options = {}) {
|
||||
activeRiskWindowDays.value = matched ? days : 30
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
const loadActiveDashboard = () => {
|
||||
if (activeDashboardKey.value === 'system') {
|
||||
void loadSystemDashboard()
|
||||
stopRiskDashboardRealtimeRefresh()
|
||||
return
|
||||
}
|
||||
if (activeDashboardKey.value === 'risk') {
|
||||
void loadRiskDashboard()
|
||||
startRiskDashboardRealtimeRefresh()
|
||||
return
|
||||
}
|
||||
if (activeDashboardKey.value === 'digitalEmployee') {
|
||||
void loadDigitalEmployeeDashboard()
|
||||
stopRiskDashboardRealtimeRefresh()
|
||||
return
|
||||
}
|
||||
|
||||
void loadFinanceDashboard()
|
||||
void loadSystemDashboard()
|
||||
void loadRiskDashboard()
|
||||
void loadDigitalEmployeeDashboard()
|
||||
startRiskDashboardRealtimeRefresh()
|
||||
stopRiskDashboardRealtimeRefresh()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadActiveDashboard()
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
@@ -272,12 +304,20 @@ export function useOverviewView(options = {}) {
|
||||
activeDepartmentRange.value
|
||||
],
|
||||
() => {
|
||||
void loadFinanceDashboard()
|
||||
if (activeDashboardKey.value === 'finance') {
|
||||
void loadFinanceDashboard()
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
watch(activeRiskWindowDays, () => {
|
||||
void loadRiskDashboard()
|
||||
if (activeDashboardKey.value === 'risk') {
|
||||
void loadRiskDashboard()
|
||||
}
|
||||
})
|
||||
|
||||
watch(activeDashboardKey, () => {
|
||||
loadActiveDashboard()
|
||||
})
|
||||
|
||||
const systemDashboardTotals = computed(() => (
|
||||
@@ -695,7 +735,8 @@ export function useOverviewView(options = {}) {
|
||||
financial_risk_graph: 'var(--theme-primary)',
|
||||
rule_center: '#0f766e',
|
||||
unknown: '#94a3b8'
|
||||
}
|
||||
},
|
||||
formatRiskSourceLabel
|
||||
))
|
||||
const riskSignalRanking = computed(() => {
|
||||
const rows = Array.isArray(riskDashboard.value.topRiskSignals)
|
||||
@@ -739,7 +780,7 @@ export function useOverviewView(options = {}) {
|
||||
const digitalEmployeeTaskRanking = computed(() => buildDigitalEmployeeTaskRanking(digitalEmployeeDashboard.value))
|
||||
const digitalEmployeeCategoryRows = computed(() => buildDigitalEmployeeCategoryRows(digitalEmployeeDashboard.value))
|
||||
|
||||
function buildRiskDistributionLegend(distribution, labels, colors) {
|
||||
function buildRiskDistributionLegend(distribution, labels, colors, formatter = formatRiskSignalName) {
|
||||
const entries = Object.entries(distribution || {})
|
||||
.filter(([, value]) => Number(value || 0) > 0)
|
||||
|
||||
@@ -755,7 +796,7 @@ export function useOverviewView(options = {}) {
|
||||
}
|
||||
|
||||
return entries.map(([key, value]) => ({
|
||||
name: labels[key] || formatRiskSignalName(key),
|
||||
name: labels[key] || formatter(key),
|
||||
value: Number(value || 0),
|
||||
display: `${Number(value || 0)}项`,
|
||||
color: colors[key] || 'var(--theme-primary)'
|
||||
@@ -763,16 +804,7 @@ export function useOverviewView(options = {}) {
|
||||
}
|
||||
|
||||
function formatRiskSignalName(value) {
|
||||
const text = String(value || '').trim()
|
||||
const labels = {
|
||||
duplicate_invoice: '重复发票',
|
||||
split_billing: '拆分报销',
|
||||
frequent_small_claims: '高频小额',
|
||||
location_mismatch: '地点不一致',
|
||||
amount_outlier: '金额异常',
|
||||
preapproval_absent: '缺少事前申请'
|
||||
}
|
||||
return labels[text] || text.replace(/_/g, ' ') || '未知风险'
|
||||
return formatRiskSignalLabel(value)
|
||||
}
|
||||
|
||||
function isMissingDimension(value) {
|
||||
@@ -800,12 +832,14 @@ export function useOverviewView(options = {}) {
|
||||
digitalEmployeeCategoryRows,
|
||||
digitalEmployeeDashboard,
|
||||
digitalEmployeeDashboardError,
|
||||
digitalEmployeeDashboardLoaded,
|
||||
digitalEmployeeDashboardLoading,
|
||||
digitalEmployeeDailyRows,
|
||||
digitalEmployeeKpiMetrics,
|
||||
digitalEmployeeTaskRanking,
|
||||
exceptionMix,
|
||||
financeDashboardError,
|
||||
financeDashboardLoaded,
|
||||
financeDashboardLoading,
|
||||
formatCompact,
|
||||
formatCurrency,
|
||||
@@ -818,6 +852,7 @@ export function useOverviewView(options = {}) {
|
||||
rankedEmployees,
|
||||
riskDashboard,
|
||||
riskDashboardError,
|
||||
riskDashboardLoaded,
|
||||
riskDashboardLastUpdatedAt,
|
||||
riskDashboardLoading,
|
||||
riskDailyTrendRows,
|
||||
@@ -835,6 +870,7 @@ export function useOverviewView(options = {}) {
|
||||
spendTotal,
|
||||
systemDashboardTotals,
|
||||
systemDashboardError,
|
||||
systemDashboardLoaded,
|
||||
systemDashboardLoading,
|
||||
systemAgentDailyRatio,
|
||||
systemLoginWave,
|
||||
|
||||
Reference in New Issue
Block a user