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

@@ -26,6 +26,7 @@ import {
Tooltip,
Legend
} from 'chart.js'
import { useAnimationProgress } from '../../composables/useAnimationProgress.js'
ChartJS.register(ArcElement, Tooltip, Legend)
@@ -35,10 +36,12 @@ const props = defineProps({
centerLabel: { type: String, required: true }
})
const progress = useAnimationProgress([() => props.items], 1150)
const chartData = computed(() => ({
labels: props.items.map((i) => i.name),
datasets: [{
data: props.items.map((i) => i.value),
data: props.items.map((i) => Math.max(Number((i.value * progress.value).toFixed(1)), 0.001)),
backgroundColor: props.items.map((i) => i.color),
borderWidth: 0,
cutout: '68%',
@@ -50,6 +53,19 @@ const chartData = computed(() => ({
const chartOptions = {
responsive: true,
maintainAspectRatio: false,
animation: {
animateRotate: true,
animateScale: true,
duration: 900,
easing: 'easeOutQuart'
},
transitions: {
active: {
animation: {
duration: 180
}
}
},
plugins: {
legend: { display: false },
tooltip: {
@@ -64,7 +80,7 @@ const chartOptions = {
usePointStyle: true,
callbacks: {
label: (ctx) => {
const total = ctx.dataset.data.reduce((a, b) => a + b, 0)
const total = ctx.dataset.data.reduce((a, b) => a + b, 0) || 1
const pct = ((ctx.parsed / total) * 100).toFixed(1)
return ` ${ctx.label}: ${pct}%`
}
@@ -98,6 +114,8 @@ const chartOptions = {
place-content: center;
pointer-events: none;
text-align: center;
animation: donutCenterIn 620ms ease both;
animation-delay: 360ms;
}
.donut-center strong {
@@ -117,6 +135,8 @@ const chartOptions = {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 6px 16px;
animation: donutLegendIn 560ms ease both;
animation-delay: 480ms;
}
.legend-row {
@@ -142,4 +162,33 @@ const chartOptions = {
color: #94a3b8;
font-size: 11px;
}
@keyframes donutCenterIn {
from {
opacity: 0;
transform: scale(.92);
}
to {
opacity: 1;
transform: scale(1);
}
}
@keyframes donutLegendIn {
from {
opacity: 0;
transform: translateY(8px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@media (prefers-reduced-motion: reduce) {
.donut-center,
.donut-legend {
animation: none;
}
}
</style>

View File

@@ -3,7 +3,7 @@
<div class="gauge-body">
<Doughnut :data="chartData" :options="chartOptions" />
<div class="gauge-center">
<strong>{{ ratio }}%</strong>
<strong>{{ animatedRatio }}%</strong>
<span>已执行</span>
</div>
</div>
@@ -32,6 +32,7 @@ import {
ArcElement,
Tooltip
} from 'chart.js'
import { useAnimationProgress } from '../../composables/useAnimationProgress.js'
ChartJS.register(ArcElement, Tooltip)
@@ -43,11 +44,13 @@ const props = defineProps({
})
const ratioValue = computed(() => Number(props.ratio))
const progress = useAnimationProgress([() => props.ratio], 1150)
const animatedRatio = computed(() => Number((ratioValue.value * progress.value).toFixed(0)))
const chartData = computed(() => ({
labels: ['已执行', '剩余'],
datasets: [{
data: [ratioValue.value, 100 - ratioValue.value],
data: [animatedRatio.value, 100 - animatedRatio.value],
backgroundColor: ['#10b981', '#e2e8f0'],
borderWidth: 0
}]
@@ -59,6 +62,11 @@ const chartOptions = {
rotation: -90,
circumference: 180,
cutout: '65%',
animation: {
animateRotate: true,
duration: 900,
easing: 'easeOutQuart'
},
plugins: {
legend: { display: false },
tooltip: { enabled: false }
@@ -88,6 +96,8 @@ const chartOptions = {
transform: translateX(-50%);
text-align: center;
pointer-events: none;
animation: gaugeCenterIn 620ms ease both;
animation-delay: 360ms;
}
.gauge-center strong {
@@ -109,6 +119,8 @@ const chartOptions = {
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 8px;
text-align: center;
animation: gaugeSummaryIn 560ms ease both;
animation-delay: 500ms;
}
.gauge-summary span {
@@ -124,4 +136,33 @@ const chartOptions = {
font-size: 13px;
font-weight: 500;
}
</style>
@keyframes gaugeCenterIn {
from {
opacity: 0;
transform: translateX(-50%) translateY(8px);
}
to {
opacity: 1;
transform: translateX(-50%) translateY(0);
}
}
@keyframes gaugeSummaryIn {
from {
opacity: 0;
transform: translateY(8px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@media (prefers-reduced-motion: reduce) {
.gauge-center,
.gauge-summary {
animation: none;
}
}
</style>

View File

@@ -25,6 +25,7 @@ import {
Tooltip,
Legend
} from 'chart.js'
import { useAnimationProgress } from '../../composables/useAnimationProgress.js'
ChartJS.register(CategoryScale, LinearScale, BarElement, PointElement, LineElement, Filler, Tooltip, Legend)
@@ -35,12 +36,22 @@ const props = defineProps({
avgHours: { type: Array, required: true }
})
const progress = useAnimationProgress([
() => props.labels,
() => props.applications,
() => props.approved,
() => props.avgHours
], 1200)
const scaleSeries = (series, decimals = 0) =>
series.map((value) => Number((Number(value) * progress.value).toFixed(decimals)))
const chartData = computed(() => ({
labels: props.labels,
datasets: [
{
label: '申请量(单)',
data: props.applications,
data: scaleSeries(props.applications),
backgroundColor: '#10b981',
borderRadius: 4,
barPercentage: 0.6,
@@ -49,7 +60,7 @@ const chartData = computed(() => ({
},
{
label: '审批完成量(单)',
data: props.approved,
data: scaleSeries(props.approved),
backgroundColor: '#3b82f6',
borderRadius: 4,
barPercentage: 0.6,
@@ -58,7 +69,7 @@ const chartData = computed(() => ({
},
{
label: '平均审批时长(小时)',
data: props.avgHours,
data: scaleSeries(props.avgHours, 1),
borderColor: '#8b5cf6',
backgroundColor: 'transparent',
borderWidth: 2,
@@ -77,6 +88,10 @@ const chartData = computed(() => ({
const chartOptions = {
responsive: true,
maintainAspectRatio: false,
animation: {
duration: 900,
easing: 'easeOutQuart'
},
interaction: {
mode: 'index',
intersect: false

View File

@@ -9,7 +9,7 @@
</div>
<strong class="brand-name">星海科技</strong>
<button class="brand-toggle" type="button" aria-label="打开 AI 助手" @click="emit('openChat')">
<i class="pi pi-angle-double-left"></i>
<i class="mdi mdi-chevron-double-left"></i>
</button>
</div>
@@ -34,7 +34,7 @@
<strong>张晓明</strong>
<span>财务管理员</span>
</span>
<i class="pi pi-angle-down"></i>
<i class="mdi mdi-chevron-down"></i>
</button>
</aside>
</template>
@@ -52,8 +52,9 @@ const emit = defineEmits(['navigate', 'openChat'])
const sidebarMeta = {
overview: { label: '总览' },
requests: { label: '差旅申请/报销' },
approval: { label: '审批中心', badge: '12' },
chat: { label: 'AI助手' },
policies: { label: '政策规则' },
policies: { label: '知识管理' },
audit: { label: '审计追踪' }
}
@@ -278,7 +279,7 @@ const decoratedNavItems = computed(() =>
text-overflow: ellipsis;
}
.rail-user .pi {
.rail-user .mdi {
justify-self: end;
color: #718096;
font-size: 13px;

View File

@@ -7,8 +7,8 @@
</div>
<div class="top-actions">
<span v-if="isChat || !isOverview" class="search-wrap" :class="{ wide: isChat }">
<i class="pi pi-search search-icon"></i>
<span v-if="isChat" class="search-wrap" :class="{ wide: isChat }">
<i class="mdi mdi-magnify search-icon"></i>
<input
:value="search"
type="search"
@@ -19,7 +19,7 @@
<template v-if="isChat">
<button class="icon-btn notification" type="button" aria-label="查看通知">
<i class="pi pi-bell"></i>
<i class="mdi mdi-bell-outline"></i>
<span>1</span>
</button>
<button class="profile-btn" type="button" aria-label="打开用户菜单">
@@ -28,7 +28,7 @@
<strong>张晓明</strong>
<small>财务管理员</small>
</span>
<i class="pi pi-angle-down"></i>
<i class="mdi mdi-chevron-down"></i>
</button>
</template>
@@ -36,7 +36,7 @@
<div v-if="isOverview" class="range-combo" aria-label="首页时间范围">
<div class="range-shell">
<span class="range-meta">
<i class="pi pi-calendar"></i>
<i class="mdi mdi-calendar"></i>
<span>{{ activeDateLabel }}</span>
</span>
@@ -64,7 +64,7 @@
aria-haspopup="dialog"
@click="calendarOpen = !calendarOpen"
>
<i class="pi pi-calendar-plus"></i>
<i class="mdi mdi-calendar-plus"></i>
<span>选择时间段</span>
</button>
@@ -72,7 +72,7 @@
<header>
<strong>选择看板时间段</strong>
<button type="button" aria-label="关闭日期选择" @click="calendarOpen = false">
<i class="pi pi-times"></i>
<i class="mdi mdi-close"></i>
</button>
</header>
@@ -87,12 +87,6 @@
</label>
</div>
<div class="quick-presets" aria-label="快捷时间段">
<button type="button" @click="applyDraft('2024-07-12', '2024-07-12')">今日</button>
<button type="button" @click="applyDraft('2024-07-06', '2024-07-12')">本周</button>
<button type="button" @click="applyDraft('2024-07-01', '2024-07-31')">本月</button>
</div>
<footer>
<button class="ghost-btn" type="button" @click="calendarOpen = false">取消</button>
<button class="apply-btn" type="button" :disabled="!canApplyCustomRange" @click="applyCustomRange">
@@ -103,35 +97,30 @@
</div>
</div>
<template v-else-if="isRequests">
<button class="month-chip" type="button" aria-label="选择报销月份">
<i class="pi pi-calendar"></i>
<span>2024-07</span>
<i class="pi pi-angle-down"></i>
<template v-if="isPolicies || isRequests"></template>
<template v-else-if="isApproval">
<button class="month-chip" type="button" aria-label="筛选审批日期">
<i class="mdi mdi-calendar"></i>
<span>筛选 / 日期</span>
<i class="mdi mdi-chevron-down"></i>
</button>
<button class="icon-btn notification" type="button" aria-label="查看通知">
<i class="pi pi-bell"></i>
<span>3</span>
<i class="mdi mdi-bell-outline"></i>
<span>9</span>
</button>
<button class="profile-btn" type="button" aria-label="打开用户菜单">
<span class="profile-avatar"></span>
<span class="profile-copy">
<strong>张晓明</strong>
<small>财务管理</small>
<small>财务管理</small>
</span>
<i class="pi pi-angle-down"></i>
<i class="mdi mdi-chevron-down"></i>
</button>
</template>
<div v-else class="date-chip">
<i class="pi pi-calendar"></i>
<span>2024-07-06 ~ 2024-07-12</span>
</div>
<template v-else-if="isRequests"></template>
<button v-if="!isRequests" class="top-btn primary" type="button" @click="emit('openChat')">
<i class="pi pi-sparkles"></i>
<span>AI 助手</span>
</button>
</template>
</div>
</header>
@@ -164,6 +153,8 @@ const emit = defineEmits([
const isChat = computed(() => props.activeView === 'chat')
const isOverview = computed(() => props.activeView === 'overview')
const isRequests = computed(() => props.activeView === 'requests')
const isApproval = computed(() => props.activeView === 'approval')
const isPolicies = computed(() => props.activeView === 'policies')
const calendarOpen = ref(false)
const draftStart = ref(props.customRange.start)
const draftEnd = ref(props.customRange.end)
@@ -357,7 +348,7 @@ function formatRangeLabel(start, end) {
white-space: nowrap;
}
.range-meta .pi {
.range-meta .mdi {
color: #10b981;
}
@@ -514,28 +505,6 @@ function formatRangeLabel(start, end) {
outline: none;
}
.quick-presets {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 8px;
}
.quick-presets button {
height: 34px;
border: 1px solid #e2e8f0;
border-radius: 8px;
background: #f8fafc;
color: #334155;
font-size: 13px;
font-weight: 700;
}
.quick-presets button:hover {
border-color: rgba(16, 185, 129, .28);
background: #ecfdf5;
color: #0f9f78;
}
.ghost-btn,
.apply-btn {
height: 36px;
@@ -562,20 +531,6 @@ function formatRangeLabel(start, end) {
background: #cbd5e1;
}
.date-chip {
height: 40px;
display: inline-flex;
align-items: center;
gap: 8px;
padding: 0 32px 0 12px;
border: 1px solid #cbd5e1;
border-radius: 6px;
background: #fff;
color: var(--text);
font-size: 14px;
font-weight: 400;
}
.month-chip {
height: 42px;
display: inline-flex;
@@ -590,7 +545,7 @@ function formatRangeLabel(start, end) {
font-weight: 750;
}
.month-chip .pi:first-child {
.month-chip .mdi:first-child {
color: #64748b;
}
@@ -599,32 +554,6 @@ function formatRangeLabel(start, end) {
color: #0f9f78;
}
.date-chip .pi {
color: #94a3b8;
}
.top-btn {
height: 40px;
display: inline-flex;
align-items: center;
gap: 8px;
padding: 0 16px;
border: 0;
border-radius: 6px;
font-size: 14px;
font-weight: 650;
transition: background 160ms ease;
}
.top-btn.primary {
background: var(--primary);
color: #fff;
}
.top-btn.primary:hover {
background: #0ea672;
}
.icon-btn,
.profile-btn {
border: 0;
@@ -705,7 +634,7 @@ function formatRangeLabel(start, end) {
font-size: 12px;
}
.profile-btn .pi {
.profile-btn .mdi {
color: #64748b;
}