Files
bill/frontend/src/components/common/LoadingSpinner.vue
Jafeng 4ea91a0f59 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

122 lines
2.6 KiB
Vue

<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>