返回 AiToEarn
PublishListTab.tsx
根目录 / project / aitoearn-web / src / components / Plugin / PluginReady / PublishListTab.tsx
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
116 lines Plain Text