chore: remove prototype files and unused UI assets

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
2026-05-01 00:39:24 +08:00
parent 64537119e0
commit 7d6dbc4ac0
21 changed files with 772 additions and 2544 deletions

View File

@@ -5,23 +5,19 @@
v-for="metric in kpiMetrics"
:key="metric.label"
class="kpi-card panel"
:style="{ '--accent': metric.accent }"
:style="{ '--accent': metric.accent, '--delay': `${metric.delay}ms` }"
>
<div class="kpi-top">
<div class="kpi-icon">
<i :class="metric.icon"></i>
</div>
<div>
<p>{{ metric.label }}</p>
<strong>{{ metric.displayValue }}</strong>
</div>
<div class="kpi-head">
<span class="kpi-icon"><i :class="metric.icon"></i></span>
<span class="kpi-label">{{ metric.label }}</span>
</div>
<div class="kpi-bottom" :class="metric.trend">
<span>
<i :class="metric.trend === 'down' ? 'pi pi-arrow-down' : 'pi pi-arrow-up'"></i>
<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>
<small>{{ metric.delta }}</small>
<span class="kpi-delta">{{ metric.delta }}</span>
</div>
</article>
</div>
@@ -29,7 +25,7 @@
<div class="content-grid top-grid">
<article class="panel dashboard-card trend-panel">
<div class="card-head">
<h3>报销申请与审批趋势 <i class="pi pi-info-circle"></i></h3>
<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>
@@ -45,7 +41,7 @@
<article class="panel dashboard-card donut-panel">
<div class="card-head">
<h3>费用结构 <i class="pi pi-info-circle"></i></h3>
<h3>费用结构 <i class="mdi mdi-information-outline"></i></h3>
</div>
<DonutChart :items="spendLegend" center-value="¥361.6K" center-label="待处理金额" />
<p class="panel-note">* 百分比为占待处理金额比例</p>
@@ -53,7 +49,7 @@
<article class="panel dashboard-card donut-panel">
<div class="card-head">
<h3>风险异常分布 <i class="pi pi-info-circle"></i></h3>
<h3>风险异常分布 <i class="mdi mdi-information-outline"></i></h3>
</div>
<DonutChart :items="riskLegend" :center-value="`${riskTotal}`" center-label="异常预警单" />
<p class="panel-note">* 近30天数据</p>
@@ -63,7 +59,7 @@
<div class="content-grid bottom-grid">
<article class="panel dashboard-card rank-panel">
<div class="card-head">
<h3>部门报销排行待处理金额 <i class="pi pi-info-circle"></i></h3>
<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>
@@ -74,11 +70,16 @@
<article class="panel dashboard-card bottleneck-panel">
<div class="card-head">
<h3>审批瓶颈平均处理时长 <i class="pi pi-info-circle"></i></h3>
<h3>审批瓶颈平均处理时长 <i class="mdi mdi-information-outline"></i></h3>
</div>
<div class="bottleneck-list">
<div v-for="item in bottlenecks" :key="item.name" class="bottleneck-row">
<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>
@@ -93,12 +94,12 @@
</div>
</div>
<button type="button" class="text-link">查看全部 <i class="pi pi-angle-right"></i></button>
<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="pi pi-info-circle"></i></h3>
<h3>预算执行率本月 <i class="mdi mdi-information-outline"></i></h3>
</div>
<GaugeChart
@@ -108,7 +109,7 @@
:left="budgetSummary.left"
/>
<button type="button" class="text-link">查看详情 <i class="pi pi-angle-right"></i></button>
<button type="button" class="text-link">查看详情 <i class="mdi mdi-chevron-right"></i></button>
</article>
</div>
</section>
@@ -163,18 +164,23 @@ const formatCompact = (value) => {
const formatCurrency = (value) => formatCompact(value)
const kpiMetrics = computed(() => metricBlueprints.map((metric) => {
const formatMetricValue = (metric, value) => {
if (metric.key === 'pendingAmount') return formatCurrency(Math.round(value))
if (metric.key === 'avgSla') return `${value.toFixed(1)} ${metric.unit}`
if (metric.unit === '%') return `${Math.round(value)} ${metric.unit}`
if (metric.unit) return `${Math.round(value)} ${metric.unit}`
return `${Math.round(value)}`
}
const kpiMetrics = computed(() => metricBlueprints.map((metric, index) => {
const rawValue = demoTotals[metric.key]
const displayValue = metric.key === 'pendingAmount'
? formatCurrency(rawValue)
: metric.unit && !String(rawValue).endsWith(metric.unit)
? `${rawValue} ${metric.unit}`
: `${rawValue}`
const displayValue = formatMetricValue(metric, rawValue)
return {
...metric,
displayValue,
changeText: metric.change
changeText: metric.change,
delay: index * 55
}
}))
@@ -222,86 +228,104 @@ const rankedDepartments = computed(() => {
}
.kpi-card {
padding: 20px;
position: relative;
padding: 20px 20px 16px;
display: flex;
flex-direction: column;
gap: 0;
border-left: 3px solid var(--accent);
animation: dashboardItemIn 520ms var(--ease) both;
animation-delay: var(--delay, 0ms);
transition: box-shadow 200ms ease, transform 200ms ease;
}
.kpi-top {
flex: 1;
.kpi-card:hover {
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.06);
transform: translateY(-1px);
}
.kpi-head {
display: flex;
align-items: flex-start;
justify-content: space-between;
align-items: center;
gap: 10px;
margin-bottom: 16px;
}
.kpi-top > div {
min-width: 0;
overflow: hidden;
.kpi-icon {
width: 36px;
height: 36px;
display: grid;
place-items: center;
border-radius: 8px;
background: color-mix(in srgb, var(--accent) 10%, white);
color: var(--accent);
font-size: 18px;
flex: 0 0 auto;
animation: iconPop 560ms var(--ease) both;
animation-delay: calc(var(--delay, 0ms) + 100ms);
}
.kpi-top p {
margin: 0 0 6px;
.kpi-label {
color: #64748b;
font-size: 13px;
font-weight: 500;
line-height: 1.3;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.kpi-top strong {
.kpi-value {
display: block;
color: #1e293b;
font-size: clamp(18px, 1.6vw, 22px);
line-height: 1.2;
font-weight: 700;
height: 32px;
line-height: 32px;
color: #0f172a;
font-size: clamp(20px, 1.6vw, 26px);
line-height: 1;
font-weight: 800;
font-variant-numeric: tabular-nums;
white-space: nowrap;
margin-bottom: 16px;
letter-spacing: 0;
}
.kpi-icon {
width: 44px;
height: 44px;
display: grid;
place-items: center;
border-radius: 10px;
background: color-mix(in srgb, var(--accent) 10%, white);
color: var(--accent);
font-size: 20px;
flex: 0 0 auto;
}
.kpi-bottom {
.kpi-trend {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
margin-top: 12px;
padding-top: 12px;
border-top: 1px solid #f1f5f9;
}
.kpi-bottom span {
.kpi-badge {
display: inline-flex;
align-items: center;
gap: 4px;
font-size: 13px;
font-weight: 600;
gap: 3px;
padding: 2px 8px;
border-radius: 4px;
font-size: 12px;
font-weight: 700;
line-height: 1.6;
}
.kpi-bottom.up span {
.kpi-badge.up {
background: rgba(239, 68, 68, 0.08);
color: #dc2626;
}
.kpi-bottom.down span {
.kpi-badge.down {
background: rgba(22, 163, 74, 0.08);
color: #16a34a;
}
.kpi-bottom small {
.kpi-badge .mdi {
font-size: 13px;
}
.kpi-delta {
color: #94a3b8;
font-size: 12px;
text-align: right;
white-space: nowrap;
}
.content-grid {
@@ -313,8 +337,16 @@ const rankedDepartments = computed(() => {
.dashboard-card {
padding: 20px;
transition: box-shadow 200ms ease, transform 200ms ease;
animation: dashboardItemIn 560ms var(--ease) both;
}
.top-grid .dashboard-card:nth-child(1) { animation-delay: 80ms; }
.top-grid .dashboard-card:nth-child(2) { animation-delay: 150ms; }
.top-grid .dashboard-card:nth-child(3) { animation-delay: 220ms; }
.bottom-grid .dashboard-card:nth-child(1) { animation-delay: 290ms; }
.bottom-grid .dashboard-card:nth-child(2) { animation-delay: 360ms; }
.bottom-grid .dashboard-card:nth-child(3) { animation-delay: 430ms; }
.dashboard-card:hover {
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.06);
transform: translateY(-1px);
@@ -346,7 +378,7 @@ const rankedDepartments = computed(() => {
line-height: 1.35;
}
.card-head .pi {
.card-head .mdi {
color: #94a3b8;
font-size: 12px;
vertical-align: 1px;
@@ -393,6 +425,8 @@ const rankedDepartments = computed(() => {
align-items: center;
justify-content: space-between;
gap: 12px;
animation: listRowIn 460ms var(--ease) both;
animation-delay: var(--delay, 0ms);
}
.reviewer {
@@ -472,6 +506,51 @@ const rankedDepartments = computed(() => {
font-size: 14px;
}
@keyframes dashboardItemIn {
from {
opacity: 0;
transform: translateY(12px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes listRowIn {
from {
opacity: 0;
transform: translateX(-10px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes iconPop {
0% {
opacity: 0;
transform: scale(.82);
}
70% {
opacity: 1;
transform: scale(1.04);
}
100% {
opacity: 1;
transform: scale(1);
}
}
@media (prefers-reduced-motion: reduce) {
.kpi-card,
.dashboard-card,
.bottleneck-row {
animation: none;
}
}
@media (max-width: 1320px) {
.kpi-grid {
grid-template-columns: repeat(3, minmax(0, 1fr));