diff --git a/frontend/src/components/automation/ScriptCard.tsx b/frontend/src/components/automation/ScriptCard.tsx new file mode 100644 index 0000000..ea552ef --- /dev/null +++ b/frontend/src/components/automation/ScriptCard.tsx @@ -0,0 +1,72 @@ +// ScriptCard — 单个脚本卡片(含行操作按钮) // Logan.Li +import { FileCode, Eye, Play, Edit, Copy, Trash2, Loader2 } from 'lucide-react'; +import { Button } from '@/components/ui/button'; +import { Card, CardHeader, CardTitle, CardDescription, CardContent } from '@/components/ui/card'; +import { Checkbox } from '@/components/ui/checkbox'; +import { type Script, getTypeBadge } from './script-helpers'; + +interface Props { + script: Script; + selected: boolean; + executing: boolean; + onToggleSelect: () => void; + onView: () => void; + onExecute: () => void; + onEdit: () => void; + onClone: () => void; + onDelete: () => void; +} + +// 脚本卡片:复选框 + 名称 + 类型徽章 + 内容预览 + 元信息 + 行操作 // Logan.Li +export default function ScriptCard({ + script: sc, selected, executing, onToggleSelect, + onView, onExecute, onEdit, onClone, onDelete, +}: Props) { + return ( + + +
+
+ + + {sc.name} +
+ {getTypeBadge(sc.type)} +
+ {sc.description || '暂无描述'} +
+ +
+
{sc.content}
+
+
+ 执行 {sc.run_count} 次 · v{sc.version} + 超时 {sc.timeout}s +
+
+ + + + + +
+
+
+ ); +} diff --git a/frontend/src/components/automation/ScriptExecutionsTable.tsx b/frontend/src/components/automation/ScriptExecutionsTable.tsx new file mode 100644 index 0000000..d651f1e --- /dev/null +++ b/frontend/src/components/automation/ScriptExecutionsTable.tsx @@ -0,0 +1,69 @@ +// ScriptExecutionsTable — 脚本执行记录表格 // Logan.Li +import { RotateCcw, Terminal } from 'lucide-react'; +import { Button } from '@/components/ui/button'; +import { Card, CardContent } from '@/components/ui/card'; +import { type ExecutionRecord, getStatusBadge, formatDate } from './script-helpers'; + +interface Props { + executions: ExecutionRecord[]; + onRefresh: () => void; + onViewLogs: (exec: ExecutionRecord) => void; +} + +// 执行记录表格:序号/脚本/状态/开始时间/耗时/查看日志 // Logan.Li +export default function ScriptExecutionsTable({ executions, onRefresh, onViewLogs }: Props) { + return ( +
+
+ +
+ + +
+ + + + + + + + + + + + + {executions.length === 0 ? ( + + + + ) : ( + executions.map((job) => ( + + + + + + + + + )) + )} + +
#脚本状态开始时间耗时操作
+ 暂无执行记录 +
{job.id}{job.task_name}{getStatusBadge(job.status)}{formatDate(job.started_at)} + {job.duration ? `${(job.duration / 1000).toFixed(1)}s` : '-'} + + +
+
+
+
+
+ ); +} diff --git a/frontend/src/components/automation/ScriptManager.tsx b/frontend/src/components/automation/ScriptManager.tsx index 0419fb3..85bfb2d 100644 --- a/frontend/src/components/automation/ScriptManager.tsx +++ b/frontend/src/components/automation/ScriptManager.tsx @@ -1,12 +1,8 @@ // ScriptManager — 脚本库与执行记录主组件 // Logan.Li import React, { useState, useEffect } from 'react'; -import { - Play, FileCode, Clock, CheckCircle, XCircle, RotateCcw, Eye, - Plus, Search, Trash2, Edit, Copy, Terminal, Loader2, -} from 'lucide-react'; +import { Plus, Search, RotateCcw, Trash2, Loader2 } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; -import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; @@ -16,12 +12,15 @@ import { toast } from 'sonner'; import { useConfirm } from '@/components/ui/confirm-dialog'; import { scriptApi, taskExecutionApi } from '@/services/api'; import { - type Script, type ExecutionRecord, mapScript, scriptTypes, getTypeBadge, - genCode, getStatusBadge, formatDate, + type Script, type ExecutionRecord, mapScript, scriptTypes, genCode, } from './script-helpers'; -import ScriptFormDialog, { type ScriptFormData } from './ScriptFormDialog'; +import type { ScriptFormData } from './ScriptFormDialog'; +import ScriptFormDialog from './ScriptFormDialog'; import ScriptDetailDialog from './ScriptDetailDialog'; import ScriptLogsDialog from './ScriptLogsDialog'; +import ScriptStatsCards from './ScriptStatsCards'; +import ScriptCard from './ScriptCard'; +import ScriptExecutionsTable from './ScriptExecutionsTable'; export function ScriptManager() { const _confirm = useConfirm(); @@ -225,12 +224,10 @@ export function ScriptManager() { setSelectedIds(prev => prev.includes(id) ? prev.filter(i => i !== id) : [...prev, id]); }; + const allSelected = filteredScripts.length > 0 && selectedIds.length === filteredScripts.length; + const toggleSelectAll = () => { - setSelectedIds(prev => - prev.length === filteredScripts.length && filteredScripts.length > 0 - ? [] - : filteredScripts.map(sc => sc.id) - ); + setSelectedIds(allSelected ? [] : filteredScripts.map(sc => sc.id)); }; const handleBatchDelete = async () => { @@ -252,8 +249,6 @@ export function ScriptManager() { } }; - const allSelected = filteredScripts.length > 0 && selectedIds.length === filteredScripts.length; - const runningCount = executions.filter(e => e.status === 'running').length; const todaySuccess = executions.filter(e => e.status === 'success' && new Date(e.created_at).toDateString() === new Date().toDateString() @@ -265,60 +260,12 @@ export function ScriptManager() { return (
{/* 统计卡片 */} -
- - -
-
-

脚本总数

-

{scripts.length}

-
-
- -
-
-
-
- - -
-
-

执行中

-

{runningCount}

-
-
- -
-
-
-
- - -
-
-

今日成功

-

{todaySuccess}

-
-
- -
-
-
-
- - -
-
-

今日失败

-

{todayFailed}

-
-
- -
-
-
-
-
+ { setActiveTab(v); if (v === 'jobs') fetchExecutions(); }}> @@ -406,112 +353,30 @@ export function ScriptManager() {
) : ( filteredScripts.map((sc) => ( - - -
-
- toggleSelect(sc.id)} - className="border-[var(--dg-border)]" - /> - - {sc.name} -
- {getTypeBadge(sc.type)} -
- {sc.description || '暂无描述'} -
- -
-
{sc.content}
-
-
- 执行 {sc.run_count} 次 · v{sc.version} - 超时 {sc.timeout}s -
-
- - - - - -
-
-
+ toggleSelect(sc.id)} + onView={() => { setSelectedScript(sc); setDetailOpen(true); }} + onExecute={() => handleExecute(sc)} + onEdit={() => openEdit(sc)} + onClone={() => handleClone(sc)} + onDelete={() => handleDelete(sc)} + /> )) )} {/* ============ 执行记录 ============ */} - -
- -
- - -
- - - - - - - - - - - - - {executions.length === 0 ? ( - - - - ) : ( - executions.map((job) => ( - - - - - - - - - )) - )} - -
#脚本状态开始时间耗时操作
- 暂无执行记录 -
{job.id}{job.task_name}{getStatusBadge(job.status)}{formatDate(job.started_at)} - {job.duration ? `${(job.duration / 1000).toFixed(1)}s` : '-'} - - -
-
-
-
+ + { setSelectedExec(job); setLogsOpen(true); }} + /> diff --git a/frontend/src/components/automation/ScriptStatsCards.tsx b/frontend/src/components/automation/ScriptStatsCards.tsx new file mode 100644 index 0000000..5ab800f --- /dev/null +++ b/frontend/src/components/automation/ScriptStatsCards.tsx @@ -0,0 +1,70 @@ +// ScriptStatsCards — 脚本库统计卡片 // Logan.Li +import { FileCode, Loader2, CheckCircle, XCircle } from 'lucide-react'; +import { Card, CardContent } from '@/components/ui/card'; + +interface Props { + total: number; + running: number; + todaySuccess: number; + todayFailed: number; +} + +// 四个统计卡片:脚本总数 / 执行中 / 今日成功 / 今日失败 // Logan.Li +export default function ScriptStatsCards({ total, running, todaySuccess, todayFailed }: Props) { + return ( +
+ + +
+
+

脚本总数

+

{total}

+
+
+ +
+
+
+
+ + +
+
+

执行中

+

{running}

+
+
+ +
+
+
+
+ + +
+
+

今日成功

+

{todaySuccess}

+
+
+ +
+
+
+
+ + +
+
+

今日失败

+

{todayFailed}

+
+
+ +
+
+
+
+
+ ); +}