host1syan's picture
Upload 212 files
5378afe verified
<script setup lang="ts">
import type { Task } from '@/types/task.d.ts'
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@/components/ui/table'
import { Button } from '@/components/ui/button'
import { Switch } from '@/components/ui/switch'
import { Badge } from '@/components/ui/badge'
import { Play, Square, Pencil, Trash2 } from 'lucide-vue-next'
interface Props {
tasks: Task[]
isLoading: boolean
stoppingIds?: Set<number>
}
const props = defineProps<Props>()
const isStopping = (id: number) => props.stoppingIds?.has(id) ?? false
const emit = defineEmits<{
(e: 'delete-task', taskId: number): void
(e: 'run-task', taskId: number): void
(e: 'stop-task', taskId: number): void
(e: 'edit-task', task: Task): void
(e: 'refresh-criteria', task: Task): void
(e: 'toggle-enabled', task: Task, enabled: boolean): void
}>()
</script>
<template>
<div class="border rounded-xl bg-slate-50/80 shadow-sm overflow-x-auto">
<Table class="min-w-full">
<TableHeader class="bg-white/70 backdrop-blur">
<TableRow class="border-b">
<TableHead class="w-[84px] text-center text-slate-600">启用</TableHead>
<TableHead class="text-slate-600">任务</TableHead>
<TableHead class="text-center text-slate-600">状态</TableHead>
<TableHead class="text-center text-slate-600">价格范围</TableHead>
<TableHead class="text-center text-slate-600">筛选条件</TableHead>
<TableHead class="text-center text-slate-600">最大页数</TableHead>
<TableHead class="text-center text-slate-600">AI 标准</TableHead>
<TableHead class="text-center text-slate-600">定时规则</TableHead>
<TableHead class="text-right text-slate-600">操作</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<template v-if="isLoading && tasks.length === 0">
<TableRow>
<TableCell :colspan="9" class="h-24 text-center text-muted-foreground">
正在加载中...
</TableCell>
</TableRow>
</template>
<template v-else-if="tasks.length === 0">
<TableRow>
<TableCell :colspan="9" class="h-24 text-center text-muted-foreground">
没有找到任何任务。
</TableCell>
</TableRow>
</template>
<template v-else>
<TableRow
v-for="task in tasks"
:key="task.id"
class="hover:bg-white transition-colors border-b last:border-b-0"
>
<TableCell class="text-center align-middle">
<Switch
:model-value="task.enabled"
@update:model-value="(val: boolean) => emit('toggle-enabled', task, val)"
/>
</TableCell>
<TableCell class="align-middle">
<div class="flex flex-col gap-2">
<div class="flex items-center gap-2">
<span class="text-base font-semibold text-slate-900">{{ task.task_name }}</span>
<Badge variant="outline" class="border-slate-200 text-xs text-slate-500">
关键词
</Badge>
<span class="rounded-full bg-slate-100 px-2 py-0.5 text-xs font-mono text-slate-700">
{{ task.keyword }}
</span>
</div>
<div class="text-xs text-slate-500" v-if="task.description">
{{ task.description }}
</div>
</div>
</TableCell>
<TableCell class="text-center align-middle">
<Badge
:variant="task.is_running ? 'default' : 'secondary'"
:class="
task.is_running
? 'bg-emerald-100 text-emerald-700 border-0 hover:bg-emerald-100'
: 'bg-amber-100 text-amber-700 border-0'
"
>
{{ task.is_running ? '运行中' : '已停止' }}
</Badge>
<div class="mt-2 text-xs text-slate-500">
{{ task.enabled ? '已启用' : '未启用' }}
</div>
</TableCell>
<TableCell class="text-center align-middle">
<div class="inline-flex flex-col items-center gap-1">
<span class="text-sm font-semibold text-slate-800">
{{ task.min_price || '不限' }} - {{ task.max_price || '不限' }}
</span>
<span class="text-xs text-slate-500">价格范围 (元)</span>
</div>
</TableCell>
<TableCell class="align-middle">
<div class="flex flex-col items-center gap-2 text-xs text-slate-600">
<div class="flex flex-wrap justify-center gap-2">
<Badge v-if="task.personal_only" variant="secondary" class="bg-slate-100 text-slate-700 border-0">
个人闲置
</Badge>
<Badge v-else variant="outline" class="border-slate-200 text-slate-500">
个人/商家不限
</Badge>
<Badge v-if="task.free_shipping" variant="secondary" class="bg-slate-100 text-slate-700 border-0">
包邮
</Badge>
<Badge v-else variant="outline" class="border-slate-200 text-slate-500">
运费不限
</Badge>
</div>
<div class="flex flex-wrap justify-center gap-2">
<Badge variant="outline" class="border-slate-200 text-slate-600 bg-white">
新发布:{{ task.new_publish_option || '不筛选' }}
</Badge>
<span class="rounded-full bg-slate-100 px-2 py-0.5 text-slate-600" :title="task.region || '—'">
区域:{{ task.region || '—' }}
</span>
</div>
</div>
</TableCell>
<TableCell class="text-center align-middle">
<div class="inline-flex items-center justify-center w-12 h-10 rounded-md bg-slate-100 text-base font-semibold text-slate-700">
{{ task.max_pages || 3 }}
</div>
</TableCell>
<TableCell class="align-middle">
<div class="flex flex-col items-center gap-2">
<span
class="px-2 py-1 rounded-md bg-slate-100 text-xs font-mono text-slate-700 truncate max-w-[170px]"
:title="task.ai_prompt_criteria_file || '暂无标准文件'"
>
{{ (task.ai_prompt_criteria_file || 'N/A').replace('prompts/', '') }}
</span>
<Button size="sm" variant="outline" class="h-8" @click="emit('refresh-criteria', task)">
重新生成
</Button>
</div>
</TableCell>
<TableCell class="text-center align-middle">
<div class="flex flex-col items-center gap-1">
<span class="text-sm font-medium text-slate-800">
{{ task.cron || '手动触发' }}
</span>
<span class="text-xs text-slate-500">定时规则</span>
</div>
</TableCell>
<TableCell class="text-right align-middle">
<div class="flex justify-end items-center gap-2">
<Button
v-if="!task.is_running"
size="sm"
variant="default"
class="min-w-[86px] shadow-sm"
:class="task.enabled
? 'bg-emerald-500 hover:bg-emerald-600 text-white'
: 'bg-slate-200 text-slate-500 hover:bg-slate-200'"
:disabled="!task.enabled"
@click="emit('run-task', task.id)"
>
<Play class="w-3 h-3 mr-1 fill-current" /> 运行
</Button>
<Button
v-else
size="sm"
variant="destructive"
class="min-w-[86px]"
:disabled="isStopping(task.id)"
@click="emit('stop-task', task.id)"
>
<template v-if="isStopping(task.id)">
停止中...
</template>
<template v-else>
<Square class="w-3 h-3 mr-1 fill-current" /> 停止
</template>
</Button>
<div class="w-px h-4 bg-slate-200 mx-1"></div>
<Button size="icon" variant="ghost" title="编辑" class="hover:bg-blue-50" @click="emit('edit-task', task)">
<Pencil class="w-4 h-4 text-blue-600" />
</Button>
<Button size="icon" variant="ghost" title="删除" class="text-red-500 hover:text-red-700 hover:bg-red-50" @click="emit('delete-task', task.id)">
<Trash2 class="w-4 h-4" />
</Button>
</div>
</TableCell>
</TableRow>
</template>
</TableBody>
</Table>
</div>
</template>