feat(dashboard): reorganize budget and risk cards
This commit is contained in:
@@ -1,48 +1,41 @@
|
||||
<template>
|
||||
<section class="dashboard" :class="[`dashboard-${activeDashboard}`, { 'is-loading': activeDashboardLoading }]">
|
||||
<div v-if="activeDashboardLoading" class="dashboard-loading-overlay" role="status" aria-live="polite">
|
||||
<div v-if="activeDashboardLoading" class="table-state dashboard-loading-state" role="status" aria-live="polite">
|
||||
<TableLoadingState
|
||||
:title="activeDashboardLoadingText"
|
||||
message="正在同步当前看板数据"
|
||||
icon="mdi mdi-view-dashboard-outline"
|
||||
variant="overlay"
|
||||
motion="loop"
|
||||
floating
|
||||
/>
|
||||
</div>
|
||||
<div class="kpi-grid">
|
||||
<article
|
||||
v-for="metric in activeKpiMetrics"
|
||||
:key="metric.label"
|
||||
class="kpi-card panel"
|
||||
:style="{ '--accent': metric.accent, '--delay': `${metric.delay}ms` }"
|
||||
>
|
||||
<div class="kpi-head">
|
||||
<span class="kpi-icon"><i :class="metric.icon"></i></span>
|
||||
<span class="kpi-label">{{ metric.label }}</span>
|
||||
</div>
|
||||
<strong class="kpi-value">{{ metric.displayValue }}</strong>
|
||||
<div class="kpi-trend">
|
||||
<span class="kpi-badge" :class="metric.trend">
|
||||
<i :class="metric.trend === 'down' ? 'mdi mdi-arrow-down' : 'mdi mdi-arrow-up'"></i>
|
||||
{{ metric.changeText }}
|
||||
</span>
|
||||
<span class="kpi-delta">{{ metric.delta }}</span>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
<template v-else>
|
||||
<div class="kpi-grid">
|
||||
<article
|
||||
v-for="metric in activeKpiMetrics"
|
||||
:key="metric.label"
|
||||
class="kpi-card panel"
|
||||
:style="{ '--accent': metric.accent, '--delay': `${metric.delay}ms` }"
|
||||
>
|
||||
<div class="kpi-head">
|
||||
<span class="kpi-icon"><i :class="metric.icon"></i></span>
|
||||
<span class="kpi-label">{{ metric.label }}</span>
|
||||
</div>
|
||||
<strong class="kpi-value">{{ metric.displayValue }}</strong>
|
||||
<div class="kpi-trend">
|
||||
<span class="kpi-badge" :class="metric.trend">
|
||||
<i :class="metric.trend === 'down' ? 'mdi mdi-arrow-down' : 'mdi mdi-arrow-up'"></i>
|
||||
{{ metric.changeText }}
|
||||
</span>
|
||||
<span class="kpi-delta">{{ metric.delta }}</span>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<template v-if="activeDashboard === 'finance'">
|
||||
<template v-if="activeDashboard === 'finance'">
|
||||
<div class="content-grid top-grid">
|
||||
<article class="panel dashboard-card trend-panel">
|
||||
<div class="card-head">
|
||||
<h3>每日报销金额 <i class="mdi mdi-information-outline"></i></h3>
|
||||
<EnterpriseSelect
|
||||
v-model="activeTrendRange"
|
||||
class="card-select"
|
||||
:options="trendRanges"
|
||||
aria-label="趋势时间范围"
|
||||
size="small"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<TrendChart
|
||||
@@ -79,13 +72,6 @@
|
||||
<article class="panel dashboard-card rank-panel">
|
||||
<div class="card-head">
|
||||
<h3>部门报销排行 <i class="mdi mdi-information-outline"></i></h3>
|
||||
<EnterpriseSelect
|
||||
v-model="activeDepartmentRange"
|
||||
class="card-select"
|
||||
:options="departmentRangeOptions"
|
||||
aria-label="部门排行时间范围"
|
||||
size="small"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<BarChart :items="rankedDepartments" />
|
||||
@@ -94,13 +80,6 @@
|
||||
<article class="panel dashboard-card employee-rank-panel">
|
||||
<div class="card-head">
|
||||
<h3>个人报销排行 <i class="mdi mdi-information-outline"></i></h3>
|
||||
<EnterpriseSelect
|
||||
v-model="activeDepartmentRange"
|
||||
class="card-select"
|
||||
:options="departmentRangeOptions"
|
||||
aria-label="个人排行时间范围"
|
||||
size="small"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<BarChart :items="rankedEmployees" />
|
||||
@@ -109,7 +88,7 @@
|
||||
<article class="panel dashboard-card top-claim-panel">
|
||||
<div class="card-head">
|
||||
<h3>高额单据 <i class="mdi mdi-information-outline"></i></h3>
|
||||
<span class="card-range-chip">{{ activeDepartmentRange }}</span>
|
||||
<span class="card-range-chip">{{ activeRangeLabel }}</span>
|
||||
</div>
|
||||
|
||||
<div class="top-claim-split">
|
||||
@@ -145,67 +124,60 @@
|
||||
<h3>预算指标 <i class="mdi mdi-information-outline"></i></h3>
|
||||
</div>
|
||||
|
||||
<div class="budget-metric-grid">
|
||||
<div
|
||||
v-for="(item, index) in budgetMetrics"
|
||||
:key="item.label"
|
||||
class="budget-metric-item"
|
||||
:class="item.tone"
|
||||
:style="{ '--delay': `${index * 70}ms` }"
|
||||
>
|
||||
<span class="budget-metric-icon"><i :class="item.icon"></i></span>
|
||||
<div>
|
||||
<span>{{ item.label }}</span>
|
||||
<strong>{{ item.value }}</strong>
|
||||
<em>{{ item.detail }}</em>
|
||||
<div class="budget-metrics-content">
|
||||
<div class="budget-gauge-block">
|
||||
<GaugeChart
|
||||
:ratio="budgetSummary.ratio"
|
||||
:total="budgetSummary.total"
|
||||
:used="budgetSummary.used"
|
||||
:left="budgetSummary.left"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="budget-metric-grid">
|
||||
<div
|
||||
v-for="(item, index) in budgetMetrics"
|
||||
:key="item.label"
|
||||
class="budget-metric-item"
|
||||
:class="item.tone"
|
||||
:style="{ '--delay': `${index * 70}ms` }"
|
||||
>
|
||||
<span class="budget-metric-icon"><i :class="item.icon"></i></span>
|
||||
<div>
|
||||
<span>{{ item.label }}</span>
|
||||
<strong>{{ item.value }}</strong>
|
||||
<em>{{ item.detail }}</em>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="panel dashboard-card budget-panel">
|
||||
<div class="card-head">
|
||||
<h3>预算执行率(本月)<i class="mdi mdi-information-outline"></i></h3>
|
||||
</div>
|
||||
|
||||
<GaugeChart
|
||||
:ratio="budgetSummary.ratio"
|
||||
:total="budgetSummary.total"
|
||||
:used="budgetSummary.used"
|
||||
:left="budgetSummary.left"
|
||||
/>
|
||||
|
||||
<button type="button" class="text-link">查看详情 <i class="mdi mdi-chevron-right"></i></button>
|
||||
</article>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<RiskObservationDashboard
|
||||
v-else-if="activeDashboard === 'risk'"
|
||||
:dashboard="riskDashboard"
|
||||
:loading="riskDashboardLoading"
|
||||
:error="riskDashboardError"
|
||||
:last-updated-at="riskDashboardLastUpdatedAt"
|
||||
:level-legend="riskLevelLegend"
|
||||
:source-legend="riskSourceLegend"
|
||||
:signal-ranking="riskSignalRanking"
|
||||
:daily-rows="riskDailyTrendRows"
|
||||
:window-options="riskWindowOptions"
|
||||
:active-window-days="activeRiskWindowDays"
|
||||
@update:window-days="setRiskWindowDays"
|
||||
/>
|
||||
<RiskObservationDashboard
|
||||
v-else-if="activeDashboard === 'risk'"
|
||||
:dashboard="riskDashboard"
|
||||
:loading="riskDashboardLoading"
|
||||
:error="riskDashboardError"
|
||||
:last-updated-at="riskDashboardLastUpdatedAt"
|
||||
:level-legend="riskLevelLegend"
|
||||
:source-legend="riskCompositionLegend"
|
||||
:signal-ranking="riskSignalRanking"
|
||||
:daily-rows="riskDailyTrendRows"
|
||||
/>
|
||||
|
||||
<DigitalEmployeeDashboard
|
||||
v-else-if="activeDashboard === 'digitalEmployee'"
|
||||
:dashboard="digitalEmployeeDashboard"
|
||||
:loading="digitalEmployeeDashboardLoading"
|
||||
:error="digitalEmployeeDashboardError"
|
||||
:daily-rows="digitalEmployeeDailyRows"
|
||||
:task-ranking="digitalEmployeeTaskRanking"
|
||||
:category-rows="digitalEmployeeCategoryRows"
|
||||
/>
|
||||
<DigitalEmployeeDashboard
|
||||
v-else-if="activeDashboard === 'digitalEmployee'"
|
||||
:dashboard="digitalEmployeeDashboard"
|
||||
:loading="digitalEmployeeDashboardLoading"
|
||||
:error="digitalEmployeeDashboardError"
|
||||
:daily-rows="digitalEmployeeDailyRows"
|
||||
:task-ranking="digitalEmployeeTaskRanking"
|
||||
:category-rows="digitalEmployeeCategoryRows"
|
||||
/>
|
||||
|
||||
<template v-else>
|
||||
<template v-else>
|
||||
<div class="system-observability-grid">
|
||||
<article class="panel dashboard-card system-agent-ratio-panel">
|
||||
<div class="card-head">
|
||||
@@ -347,6 +319,7 @@
|
||||
</article>
|
||||
</aside>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</section>
|
||||
</template>
|
||||
@@ -365,7 +338,6 @@ import SystemTokenDailyWaveChart from '../components/charts/SystemTokenDailyWave
|
||||
import SystemUserTokenPie from '../components/charts/SystemUserTokenPie.vue'
|
||||
import DigitalEmployeeDashboard from '../components/dashboard/DigitalEmployeeDashboard.vue'
|
||||
import RiskObservationDashboard from '../components/dashboard/RiskObservationDashboard.vue'
|
||||
import EnterpriseSelect from '../components/shared/EnterpriseSelect.vue'
|
||||
import TableLoadingState from '../components/shared/TableLoadingState.vue'
|
||||
|
||||
import { useOverviewView } from '../composables/useOverviewView.js'
|
||||
@@ -381,15 +353,12 @@ const props = defineProps({
|
||||
})
|
||||
|
||||
const {
|
||||
activeDepartmentRange,
|
||||
activeRiskWindowDays,
|
||||
activeRangeLabel,
|
||||
activeTrend,
|
||||
activeTrendRange,
|
||||
budgetMetrics,
|
||||
budgetSummary,
|
||||
departmentEmployeeCenterValue,
|
||||
departmentEmployeeLegend,
|
||||
departmentRangeOptions,
|
||||
digitalEmployeeCategoryRows,
|
||||
digitalEmployeeDashboard,
|
||||
digitalEmployeeDashboardError,
|
||||
@@ -412,9 +381,7 @@ const {
|
||||
riskKpiMetrics,
|
||||
riskLevelLegend,
|
||||
riskSignalRanking,
|
||||
riskSourceLegend,
|
||||
riskWindowOptions,
|
||||
setRiskWindowDays,
|
||||
riskCompositionLegend,
|
||||
spendCenterValue,
|
||||
spendLegend,
|
||||
systemDashboardLoading,
|
||||
@@ -429,8 +396,7 @@ const {
|
||||
systemUsageDurationRows,
|
||||
systemUsageDurationSummary,
|
||||
systemUserTokenUsage,
|
||||
topClaims,
|
||||
trendRanges
|
||||
topClaims
|
||||
} = useOverviewView(props)
|
||||
|
||||
const activeDashboard = computed(() => {
|
||||
|
||||
Reference in New Issue
Block a user