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:
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user