Files
bill/frontend/src/components/common/LoadingSpinner.vue

122 lines
2.6 KiB
Vue
Raw Normal View History

feat: 完成任务3 - 开发核心交易管理界面 任务3.1 实现基础 UI 组件库 - 创建 BaseIcon 组件,支持 emoji 和 SVG 图标 - 实现 CategoryIcon 组件,用于分类图标显示 - 开发 AmountInput 组件,支持金额输入和类型切换 - 创建 DatePicker 组件,支持日期选择和快捷日期 - 实现 BaseSelect 组件,支持搜索和自定义选项 - 添加 LoadingSpinner 和 EmptyState 组件 - 扩展 Tailwind 配置,完善设计系统色彩 任务3.2 创建交易列表和卡片组件 - 实现 TransactionCard 组件,展示交易详情 - 创建 TransactionList 组件,支持分组显示和批量操作 - 添加日期分组和汇总功能 - 实现无限滚动和加载更多功能 - 支持选择模式和批量删除 - 更新 TransactionsView 使用新组件 任务3.3 开发交易添加和编辑表单 - 创建 TransactionForm 组件,支持添加和编辑交易 - 集成所有输入组件(金额、分类、账户、日期等) - 实现表单验证和数据清理 - 添加重复交易检测功能 - 创建 AddTransactionView 页面 - 配置路由支持添加和编辑交易 任务3.4 实现搜索和筛选功能 - 创建 TransactionSearch 组件,支持智能搜索 - 实现搜索建议和搜索历史功能 - 开发 TransactionFilter 组件,支持多维度筛选 - 添加快速筛选标签和日期预设 - 集成搜索和筛选到 TransactionsView - 实现实时筛选和结果统计 核心特性: - 完整的交易管理界面(列表、添加、编辑、搜索、筛选) - 现代化的 neumorphic 设计风格 - 响应式布局和移动端优化 - 智能搜索和多维度筛选 - 用户友好的交互体验 - 完整的表单验证和错误处理
2025-08-14 16:03:02 +08:00
<template>
<div :class="containerClasses">
<!-- 旋转加载器 -->
<div
v-if="type === 'spinner'"
:class="[
'animate-spin rounded-full border-2 border-current border-t-transparent',
sizeClasses,
colorClasses
]"
/>
<!-- 脉冲加载器 -->
<div
v-else-if="type === 'pulse'"
:class="[
'animate-pulse rounded-full bg-current',
sizeClasses,
colorClasses
]"
/>
<!-- 点状加载器 -->
<div v-else-if="type === 'dots'" :class="['flex space-x-1', colorClasses]">
<div
v-for="i in 3"
:key="i"
:class="[
'rounded-full bg-current animate-bounce',
dotSizeClasses
]"
:style="{ animationDelay: `${(i - 1) * 0.1}s` }"
/>
</div>
<!-- 骨架屏加载器 -->
<div v-else-if="type === 'skeleton'" class="animate-pulse space-y-3">
<div class="h-4 bg-gray-200 rounded w-3/4"></div>
<div class="h-4 bg-gray-200 rounded w-1/2"></div>
<div class="h-4 bg-gray-200 rounded w-5/6"></div>
</div>
<!-- 加载文本 -->
<div v-if="text" :class="['mt-2 text-sm', colorClasses]">
{{ text }}
</div>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue'
interface Props {
type?: 'spinner' | 'pulse' | 'dots' | 'skeleton'
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl'
color?: 'primary' | 'secondary' | 'gray' | 'white'
text?: string
center?: boolean
overlay?: boolean
}
const props = withDefaults(defineProps<Props>(), {
type: 'spinner',
size: 'md',
color: 'primary',
center: false,
overlay: false
})
// 容器类
const containerClasses = computed(() => {
const classes = []
if (props.center) {
classes.push('flex flex-col items-center justify-center')
}
if (props.overlay) {
classes.push(
'fixed inset-0 bg-black bg-opacity-50 z-50',
'flex items-center justify-center'
)
}
return classes
})
// 尺寸类
const sizeClasses = computed(() => {
const sizes = {
xs: 'w-3 h-3',
sm: 'w-4 h-4',
md: 'w-6 h-6',
lg: 'w-8 h-8',
xl: 'w-12 h-12'
}
return sizes[props.size]
})
// 点状加载器尺寸
const dotSizeClasses = computed(() => {
const sizes = {
xs: 'w-1 h-1',
sm: 'w-1.5 h-1.5',
md: 'w-2 h-2',
lg: 'w-3 h-3',
xl: 'w-4 h-4'
}
return sizes[props.size]
})
// 颜色类
const colorClasses = computed(() => {
const colors = {
primary: 'text-primary',
secondary: 'text-text-secondary',
gray: 'text-gray-400',
white: 'text-white'
}
return colors[props.color]
})
</script>