| 1 | /** |
| 2 | * PublishListTab - 发布列表 Tab 组件 |
| 3 | * 显示插件发布任务列表 |
| 4 | */ |
| 5 | |
| 6 | 'use client' |
| 7 | |
| 8 | import type { PluginPlatformType, PublishTask } from '@/store/plugin/types/baseTypes' |
| 9 | import dayjs from 'dayjs' |
| 10 | import { FileText } from 'lucide-react' |
| 11 | import { useTranslation } from 'react-i18next' |
| 12 | import { Badge } from '@/components/ui/badge' |
| 13 | |
| 14 | import { getPlatformInfoSync } from '@/store/platformMetadata' |
| 15 | import { usePluginStore } from '@/store/plugin' |
| 16 | import { PlatformTaskStatus } from '@/store/plugin/types/baseTypes' |
| 17 | import { cn } from '@/utils/className' |
| 18 | |
| 19 | interface PublishListTabProps { |
| 20 | /** 点击任务回调 */ |
| 21 | onViewDetail?: (task: PublishTask) => void |
| 22 | } |
| 23 | |
| 24 | /** |
| 25 | * 获取平台显示名称 |
| 26 | */ |
| 27 | function getPlatformName(platform: PluginPlatformType): string { |
| 28 | const platInfo = getPlatformInfoSync(platform) |
| 29 | return platInfo?.name || platform |
| 30 | } |
| 31 | |
| 32 | /** |
| 33 | * 获取状态 Badge 自定义类名 |
| 34 | */ |
| 35 | function getStatusClassName(status: PlatformTaskStatus): string { |
| 36 | switch (status) { |
| 37 | case PlatformTaskStatus.COMPLETED: |
| 38 | return 'bg-green-100 text-green-700 hover:bg-green-100' |
| 39 | case PlatformTaskStatus.PUBLISHING: |
| 40 | return 'bg-blue-100 text-blue-700 hover:bg-blue-100' |
| 41 | case PlatformTaskStatus.ERROR: |
| 42 | return 'bg-red-100 text-red-700 hover:bg-red-100' |
| 43 | case PlatformTaskStatus.CANCELED: |
| 44 | return 'bg-muted text-muted-foreground hover:bg-muted' |
| 45 | default: |
| 46 | return 'bg-muted text-foreground hover:bg-muted' |
| 47 | } |
| 48 | } |
| 49 | |
| 50 | /** |
| 51 | * 发布列表 Tab 组件 |
| 52 | */ |
| 53 | export function PublishListTab({ onViewDetail }: PublishListTabProps) { |
| 54 | const { t } = useTranslation('plugin') |
| 55 | const publishTasks = usePluginStore(state => state.publishTasks) || [] |
| 56 | |
| 57 | // 空状态 |
| 58 | if (publishTasks.length === 0) { |
| 59 | return ( |
| 60 | <div className="flex flex-1 flex-col items-center justify-center py-16"> |
| 61 | <div className="mb-4 flex h-16 w-16 items-center justify-center rounded-full bg-muted"> |
| 62 | <FileText className="h-8 w-8 text-muted-foreground" /> |
| 63 | </div> |
| 64 | <p className="text-sm text-muted-foreground">{t('publishList.empty')}</p> |
| 65 | </div> |
| 66 | ) |
| 67 | } |
| 68 | |
| 69 | return ( |
| 70 | <div className="flex flex-col gap-2"> |
| 71 | {publishTasks.map(task => ( |
| 72 | <div |
| 73 | key={task.id} |
| 74 | className="flex cursor-pointer items-center justify-between rounded-lg border border-border bg-background p-4 transition-all hover:border-border hover:shadow-sm" |
| 75 | onClick={() => onViewDetail?.(task)} |
| 76 | > |
| 77 | {/* 左侧:任务信息 */} |
| 78 | <div className="flex flex-1 flex-col gap-1.5 overflow-hidden"> |
| 79 | <span className="truncate font-medium text-foreground"> |
| 80 | {task.title || t('publishList.untitled' as any)} |
| 81 | </span> |
| 82 | <div className="flex items-center gap-2"> |
| 83 | {/* 平台标签 */} |
| 84 | <div className="flex gap-1"> |
| 85 | {task.platformTasks.slice(0, 3).map(pt => ( |
| 86 | <Badge key={pt.platform} variant="outline" className="text-xs"> |
| 87 | {getPlatformName(pt.platform as PluginPlatformType)} |
| 88 | </Badge> |
| 89 | ))} |
| 90 | {task.platformTasks.length > 3 && ( |
| 91 | <Badge variant="outline" className="text-xs"> |
| 92 | + |
| 93 | {task.platformTasks.length - 3} |
| 94 | </Badge> |
| 95 | )} |
| 96 | </div> |
| 97 | {/* 时间 */} |
| 98 | <span className="text-xs text-muted-foreground"> |
| 99 | {dayjs(task.createdAt).format('MM-DD HH:mm')} |
| 100 | </span> |
| 101 | </div> |
| 102 | </div> |
| 103 | |
| 104 | {/* 右侧:状态 */} |
| 105 | <Badge |
| 106 | variant="secondary" |
| 107 | className={cn('ml-3 shrink-0', getStatusClassName(task.overallStatus))} |
| 108 | > |
| 109 | {t(`common.${task.overallStatus}`)} |
| 110 | </Badge> |
| 111 | </div> |
| 112 | ))} |
| 113 | </div> |
| 114 | ) |
| 115 | } |
| 116 |