Files
sub2api/frontend/src/components/common
IanShaw027 c615a4264d refactor(frontend): 优化通用组件
- 改进ConfirmDialog对话框组件
- 增强DataTable表格组件功能和响应式布局
- 优化EmptyState空状态组件
- 完善SubscriptionProgressMini订阅进度组件
2025-12-27 16:04:16 +08:00
..
2025-12-18 14:26:55 +08:00
2025-12-18 13:50:39 +08:00
2025-12-18 14:26:55 +08:00

Common Components

This directory contains reusable Vue 3 components built with Composition API, TypeScript, and TailwindCSS.

Components

DataTable.vue

A generic data table component with sorting, loading states, and custom cell rendering.

Props:

  • columns: Column[] - Array of column definitions with key, label, sortable, and formatter
  • data: any[] - Array of data objects to display
  • loading?: boolean - Show loading skeleton

Slots:

  • empty - Custom empty state content
  • cell-{key} - Custom cell renderer for specific column (receives row and value)

Usage:

<DataTable
  :columns="[
    { key: 'name', label: 'Name', sortable: true },
    { key: 'email', label: 'Email' },
    { key: 'status', label: 'Status', formatter: (val) => val.toUpperCase() }
  ]"
  :data="users"
  :loading="isLoading"
>
  <template #cell-actions="{ row }">
    <button @click="editUser(row)">Edit</button>
  </template>
</DataTable>

Pagination.vue

Pagination component with page numbers, navigation, and page size selector.

Props:

  • total: number - Total number of items
  • page: number - Current page (1-indexed)
  • pageSize: number - Items per page
  • pageSizeOptions?: number[] - Available page size options (default: [10, 20, 50, 100])

Events:

  • update:page - Emitted when page changes
  • update:pageSize - Emitted when page size changes

Usage:

<Pagination
  :total="totalUsers"
  :page="currentPage"
  :pageSize="pageSize"
  @update:page="currentPage = $event"
  @update:pageSize="pageSize = $event"
/>

Modal.vue

Modal dialog with customizable size and close behavior.

Props:

  • show: boolean - Control modal visibility
  • title: string - Modal title
  • size?: 'sm' | 'md' | 'lg' | 'xl' | 'full' - Modal size (default: 'md')
  • closeOnEscape?: boolean - Close on Escape key (default: true)
  • closeOnClickOutside?: boolean - Close on backdrop click (default: true)

Events:

  • close - Emitted when modal should close

Slots:

  • default - Modal body content
  • footer - Modal footer content

Usage:

<Modal :show="showModal" title="Edit User" size="lg" @close="showModal = false">
  <form @submit.prevent="saveUser">
    <!-- Form content -->
  </form>

  <template #footer>
    <button @click="showModal = false">Cancel</button>
    <button @click="saveUser">Save</button>
  </template>
</Modal>

ConfirmDialog.vue

Confirmation dialog built on top of Modal component.

Props:

  • show: boolean - Control dialog visibility
  • title: string - Dialog title
  • message: string - Confirmation message
  • confirmText?: string - Confirm button text (default: 'Confirm')
  • cancelText?: string - Cancel button text (default: 'Cancel')
  • danger?: boolean - Use danger/red styling (default: false)

Events:

  • confirm - Emitted when user confirms
  • cancel - Emitted when user cancels

Usage:

<ConfirmDialog
  :show="showDeleteConfirm"
  title="Delete User"
  message="Are you sure you want to delete this user? This action cannot be undone."
  confirm-text="Delete"
  cancel-text="Cancel"
  danger
  @confirm="deleteUser"
  @cancel="showDeleteConfirm = false"
/>

StatCard.vue

Statistics card component for displaying metrics with optional change indicators.

Props:

  • title: string - Card title
  • value: number | string - Main value to display
  • icon?: Component - Icon component
  • change?: number - Percentage change value
  • changeType?: 'up' | 'down' | 'neutral' - Change direction (default: 'neutral')
  • formatValue?: (value) => string - Custom value formatter

Usage:

<StatCard title="Total Users" :value="1234" :icon="UserIcon" :change="12.5" change-type="up" />

Toast.vue

Toast notification component that automatically displays toasts from the app store.

Usage:

<!-- Add once in App.vue or layout -->
<Toast />
// Trigger toasts from anywhere using the app store
import { useAppStore } from '@/stores/app'

const appStore = useAppStore()

appStore.addToast({
  type: 'success',
  title: 'Success!',
  message: 'User created successfully',
  duration: 3000
})

appStore.addToast({
  type: 'error',
  message: 'Failed to delete user'
})

LoadingSpinner.vue

Simple animated loading spinner.

Props:

  • size?: 'sm' | 'md' | 'lg' | 'xl' - Spinner size (default: 'md')
  • color?: 'primary' | 'secondary' | 'white' | 'gray' - Spinner color (default: 'primary')

Usage:

<LoadingSpinner size="lg" color="primary" />

EmptyState.vue

Empty state placeholder with icon, message, and optional action button.

Props:

  • icon?: Component - Icon component
  • title: string - Empty state title
  • description: string - Empty state description
  • actionText?: string - Action button text
  • actionTo?: string | object - Router link destination
  • actionIcon?: boolean - Show plus icon in button (default: true)

Slots:

  • icon - Custom icon content
  • action - Custom action button/link

Usage:

<EmptyState
  title="No users found"
  description="Get started by creating your first user account."
  action-text="Add User"
  :action-to="{ name: 'users-create' }"
/>

Import

You can import components individually:

import { DataTable, Pagination, Modal } from '@/components/common'

Or import specific components:

import DataTable from '@/components/common/DataTable.vue'

Features

All components include:

  • TypeScript support with proper type definitions
  • Accessibility with ARIA attributes and keyboard navigation
  • Responsive design with mobile-friendly layouts
  • TailwindCSS styling for consistent design
  • Vue 3 Composition API with <script setup>
  • Slot support for customization