150 lines
5.0 KiB
Vue
150 lines
5.0 KiB
Vue
|
|
<template>
|
|||
|
|
<section class="dashboard">
|
|||
|
|
<div class="kpi-grid">
|
|||
|
|
<article
|
|||
|
|
v-for="metric in kpiMetrics"
|
|||
|
|
: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>
|
|||
|
|
|
|||
|
|
<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>
|
|||
|
|
<select v-model="activeTrendRange" class="card-select" aria-label="趋势时间范围">
|
|||
|
|
<option v-for="range in trendRanges" :key="range">{{ range }}</option>
|
|||
|
|
</select>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<TrendChart
|
|||
|
|
:labels="activeTrend.labels"
|
|||
|
|
:applications="activeTrend.applications"
|
|||
|
|
:approved="activeTrend.approved"
|
|||
|
|
:avg-hours="activeTrend.avgHours"
|
|||
|
|
/>
|
|||
|
|
</article>
|
|||
|
|
|
|||
|
|
<article class="panel dashboard-card donut-panel">
|
|||
|
|
<div class="card-head">
|
|||
|
|
<h3>费用结构 <i class="mdi mdi-information-outline"></i></h3>
|
|||
|
|
</div>
|
|||
|
|
<DonutChart :items="spendLegend" center-value="¥361.6K" center-label="待处理金额" />
|
|||
|
|
<p class="panel-note">* 百分比为占待处理金额比例</p>
|
|||
|
|
</article>
|
|||
|
|
|
|||
|
|
<article class="panel dashboard-card donut-panel">
|
|||
|
|
<div class="card-head">
|
|||
|
|
<h3>风险异常分布 <i class="mdi mdi-information-outline"></i></h3>
|
|||
|
|
</div>
|
|||
|
|
<DonutChart :items="riskLegend" :center-value="`${riskTotal}`" center-label="异常预警单" />
|
|||
|
|
<p class="panel-note">* 近30天数据</p>
|
|||
|
|
</article>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="content-grid bottom-grid">
|
|||
|
|
<article class="panel dashboard-card rank-panel">
|
|||
|
|
<div class="card-head">
|
|||
|
|
<h3>部门报销排行(待处理金额) <i class="mdi mdi-information-outline"></i></h3>
|
|||
|
|
<select v-model="activeDepartmentRange" class="card-select" aria-label="部门排行时间范围">
|
|||
|
|
<option v-for="range in departmentRangeOptions" :key="range">{{ range }}</option>
|
|||
|
|
</select>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<BarChart :items="rankedDepartments" />
|
|||
|
|
</article>
|
|||
|
|
|
|||
|
|
<article class="panel dashboard-card bottleneck-panel">
|
|||
|
|
<div class="card-head">
|
|||
|
|
<h3>审批瓶颈(平均处理时长) <i class="mdi mdi-information-outline"></i></h3>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="bottleneck-list">
|
|||
|
|
<div
|
|||
|
|
v-for="(item, index) in bottlenecks"
|
|||
|
|
:key="item.name"
|
|||
|
|
class="bottleneck-row"
|
|||
|
|
:style="{ '--delay': `${index * 70}ms` }"
|
|||
|
|
>
|
|||
|
|
<div class="reviewer">
|
|||
|
|
<div class="reviewer-avatar">{{ item.avatar }}</div>
|
|||
|
|
<div>
|
|||
|
|
<strong>{{ item.name }}</strong>
|
|||
|
|
<span>{{ item.role }}</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<div class="reviewer-stats">
|
|||
|
|
<strong>{{ item.duration }}</strong>
|
|||
|
|
<span class="status-tag" :class="item.tone">{{ item.status }}</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<button type="button" class="text-link">查看全部 <i class="mdi mdi-chevron-right"></i></button>
|
|||
|
|
</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>
|
|||
|
|
|
|||
|
|
</section>
|
|||
|
|
</template>
|
|||
|
|
|
|||
|
|
<script setup>
|
|||
|
|
import TrendChart from '../components/charts/TrendChart.vue'
|
|||
|
|
import DonutChart from '../components/charts/DonutChart.vue'
|
|||
|
|
import BarChart from '../components/charts/BarChart.vue'
|
|||
|
|
import GaugeChart from '../components/charts/GaugeChart.vue'
|
|||
|
|
|
|||
|
|
import { useOverviewView } from '../composables/useOverviewView.js'
|
|||
|
|
|
|||
|
|
defineProps({
|
|||
|
|
filteredRequests: { type: Array, required: true }
|
|||
|
|
})
|
|||
|
|
|
|||
|
|
const emit = defineEmits(['ask'])
|
|||
|
|
|
|||
|
|
const {
|
|||
|
|
activeDepartmentRange,
|
|||
|
|
activeTrend,
|
|||
|
|
activeTrendRange,
|
|||
|
|
bottlenecks,
|
|||
|
|
budgetSummary,
|
|||
|
|
departmentRangeOptions,
|
|||
|
|
kpiMetrics,
|
|||
|
|
rankedDepartments,
|
|||
|
|
riskLegend,
|
|||
|
|
riskTotal,
|
|||
|
|
spendLegend,
|
|||
|
|
trendRanges
|
|||
|
|
} = useOverviewView()
|
|||
|
|
</script>
|
|||
|
|
|
|||
|
|
<style scoped src="../assets/styles/views/overview-view.css"></style>
|