feat: add delete log
This commit is contained in:
@@ -97,3 +97,41 @@ func (lc *LogController) GetLogDetail(c *gin.Context) {
|
|||||||
|
|
||||||
utils.Success(c, vo.ToTaskLogVO(&log))
|
utils.Success(c, vo.ToTaskLogVO(&log))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (lc *LogController) ClearLogs(c *gin.Context) {
|
||||||
|
var req struct {
|
||||||
|
TaskID *int `json:"task_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
utils.BadRequest(c, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
query := database.DB.Model(&models.TaskLog{})
|
||||||
|
if req.TaskID != nil && *req.TaskID > 0 {
|
||||||
|
query = query.Where("task_id = ?", *req.TaskID)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := query.Delete(&models.TaskLog{}).Error; err != nil {
|
||||||
|
utils.ServerError(c, "清空日志失败")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
utils.SuccessMsg(c, "日志清空成功")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (lc *LogController) DeleteLog(c *gin.Context) {
|
||||||
|
id, err := strconv.Atoi(c.Param("id"))
|
||||||
|
if err != nil {
|
||||||
|
utils.BadRequest(c, "无效的日志ID")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := database.DB.Delete(&models.TaskLog{}, id).Error; err != nil {
|
||||||
|
utils.ServerError(c, "删除日志失败")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
utils.SuccessMsg(c, "日志已删除")
|
||||||
|
}
|
||||||
|
|||||||
@@ -109,6 +109,7 @@ func (tc *TaskController) GetTasks(c *gin.Context) {
|
|||||||
agentIDStr := c.DefaultQuery("agent_id", "")
|
agentIDStr := c.DefaultQuery("agent_id", "")
|
||||||
|
|
||||||
tags := c.DefaultQuery("tags", "")
|
tags := c.DefaultQuery("tags", "")
|
||||||
|
taskType := c.DefaultQuery("type", "")
|
||||||
|
|
||||||
var agentID *uint
|
var agentID *uint
|
||||||
if agentIDStr != "" {
|
if agentIDStr != "" {
|
||||||
@@ -118,7 +119,7 @@ func (tc *TaskController) GetTasks(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks, total := tc.taskService.GetTasksWithPagination(p.Page, p.PageSize, name, agentID, tags)
|
tasks, total := tc.taskService.GetTasksWithPagination(p.Page, p.PageSize, name, agentID, tags, taskType)
|
||||||
utils.PaginatedResponse(c, vo.ToTaskVOListFromModels(tasks), total, p)
|
utils.PaginatedResponse(c, vo.ToTaskVOListFromModels(tasks), total, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -172,8 +172,10 @@ func Setup(c *Controllers) *gin.Engine {
|
|||||||
logs := authorized.Group("/logs")
|
logs := authorized.Group("/logs")
|
||||||
{
|
{
|
||||||
logs.GET("", c.Log.GetLogs)
|
logs.GET("", c.Log.GetLogs)
|
||||||
|
logs.POST("/clear", c.Log.ClearLogs)
|
||||||
logs.GET("/ws", c.LogWS.StreamLog)
|
logs.GET("/ws", c.LogWS.StreamLog)
|
||||||
logs.GET("/:id", c.Log.GetLogDetail)
|
logs.GET("/:id", c.Log.GetLogDetail)
|
||||||
|
logs.DELETE("/:id", c.Log.DeleteLog)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 终端模块
|
// 终端模块
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ func (ts *TaskService) GetTasks() []models.Task {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetTasksWithPagination 分页获取任务列表
|
// GetTasksWithPagination 分页获取任务列表
|
||||||
func (ts *TaskService) GetTasksWithPagination(page, pageSize int, name string, agentID *uint, tags string) ([]models.Task, int64) {
|
func (ts *TaskService) GetTasksWithPagination(page, pageSize int, name string, agentID *uint, tags string, taskType string) ([]models.Task, int64) {
|
||||||
var tasks []models.Task
|
var tasks []models.Task
|
||||||
var total int64
|
var total int64
|
||||||
|
|
||||||
@@ -60,6 +60,9 @@ func (ts *TaskService) GetTasksWithPagination(page, pageSize int, name string, a
|
|||||||
if tags != "" {
|
if tags != "" {
|
||||||
query = query.Where("tags LIKE ?", "%"+tags+"%")
|
query = query.Where("tags LIKE ?", "%"+tags+"%")
|
||||||
}
|
}
|
||||||
|
if taskType != "" {
|
||||||
|
query = query.Where("type = ?", taskType)
|
||||||
|
}
|
||||||
if agentID != nil {
|
if agentID != nil {
|
||||||
query = query.Where("agent_id = ?", *agentID)
|
query = query.Where("agent_id = ?", *agentID)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,13 +58,14 @@ export const api = {
|
|||||||
request('/auth/register', { method: 'POST', body: JSON.stringify(data) })
|
request('/auth/register', { method: 'POST', body: JSON.stringify(data) })
|
||||||
},
|
},
|
||||||
tasks: {
|
tasks: {
|
||||||
list: (params?: { page?: number; page_size?: number; name?: string; agent_id?: number; tags?: string }) => {
|
list: (params?: { page?: number; page_size?: number; name?: string; agent_id?: number; tags?: string; type?: string }) => {
|
||||||
const query = new URLSearchParams()
|
const query = new URLSearchParams()
|
||||||
if (params?.page) query.set('page', String(params.page))
|
if (params?.page) query.set('page', String(params.page))
|
||||||
if (params?.page_size) query.set('page_size', String(params.page_size))
|
if (params?.page_size) query.set('page_size', String(params.page_size))
|
||||||
if (params?.name) query.set('name', params.name)
|
if (params?.name) query.set('name', params.name)
|
||||||
if (params?.tags) query.set('tags', params.tags)
|
if (params?.tags) query.set('tags', params.tags)
|
||||||
if (params?.agent_id) query.set('agent_id', String(params.agent_id))
|
if (params?.agent_id) query.set('agent_id', String(params.agent_id))
|
||||||
|
if (params?.type) query.set('type', params.type)
|
||||||
return request<TaskListResponse>(`/tasks?${query}`)
|
return request<TaskListResponse>(`/tasks?${query}`)
|
||||||
},
|
},
|
||||||
create: (data: Partial<Task>) => request<Task>('/tasks', { method: 'POST', body: JSON.stringify(data) }),
|
create: (data: Partial<Task>) => request<Task>('/tasks', { method: 'POST', body: JSON.stringify(data) }),
|
||||||
@@ -106,7 +107,9 @@ export const api = {
|
|||||||
return request<LogListResponse>(`/logs?${query}`)
|
return request<LogListResponse>(`/logs?${query}`)
|
||||||
},
|
},
|
||||||
get: (id: number) => request<LogDetail>(`/logs/${id}`),
|
get: (id: number) => request<LogDetail>(`/logs/${id}`),
|
||||||
detail: (id: number) => request<LogDetail>(`/logs/${id}`)
|
detail: (id: number) => request<LogDetail>(`/logs/${id}`),
|
||||||
|
delete: (id: number) => request(`/logs/${id}`, { method: 'DELETE' }),
|
||||||
|
clear: (taskId?: number) => request('/logs/clear', { method: 'POST', body: JSON.stringify({ task_id: taskId }) })
|
||||||
},
|
},
|
||||||
dashboard: {
|
dashboard: {
|
||||||
stats: () => request<Stats>('/stats'),
|
stats: () => request<Stats>('/stats'),
|
||||||
|
|||||||
@@ -8,10 +8,20 @@ import Pagination from '@/components/Pagination.vue'
|
|||||||
import LogViewer from './LogViewer.vue'
|
import LogViewer from './LogViewer.vue'
|
||||||
import {
|
import {
|
||||||
RefreshCw, X, Search, Maximize2, GitBranch, Terminal,
|
RefreshCw, X, Search, Maximize2, GitBranch, Terminal,
|
||||||
CheckCircle2, XCircle, AlertCircle, Ban, Clock, Zap as ZapIcon, Check
|
CheckCircle2, XCircle, AlertCircle, Ban, Clock, Zap as ZapIcon, Check, Trash2
|
||||||
} from 'lucide-vue-next'
|
} from 'lucide-vue-next'
|
||||||
import { api, type TaskLog } from '@/api'
|
import { api, type TaskLog } from '@/api'
|
||||||
import { Badge } from '@/components/ui/badge'
|
import { Badge } from '@/components/ui/badge'
|
||||||
|
import {
|
||||||
|
AlertDialog,
|
||||||
|
AlertDialogAction,
|
||||||
|
AlertDialogCancel,
|
||||||
|
AlertDialogContent,
|
||||||
|
AlertDialogDescription,
|
||||||
|
AlertDialogFooter,
|
||||||
|
AlertDialogHeader,
|
||||||
|
AlertDialogTitle,
|
||||||
|
} from '@/components/ui/alert-dialog'
|
||||||
import { toast } from 'vue-sonner'
|
import { toast } from 'vue-sonner'
|
||||||
import { useSiteSettings } from '@/composables/useSiteSettings'
|
import { useSiteSettings } from '@/composables/useSiteSettings'
|
||||||
import TextOverflow from '@/components/TextOverflow.vue'
|
import TextOverflow from '@/components/TextOverflow.vue'
|
||||||
@@ -32,6 +42,13 @@ let durationTimer: ReturnType<typeof setInterval> | null = null
|
|||||||
// 全屏查看
|
// 全屏查看
|
||||||
const showFullscreen = ref(false)
|
const showFullscreen = ref(false)
|
||||||
|
|
||||||
|
// 清除所有日志弹窗
|
||||||
|
const showClearDialog = ref(false)
|
||||||
|
|
||||||
|
// 删除单条日志弹窗
|
||||||
|
const showDeleteDialog = ref(false)
|
||||||
|
const deleteLogId = ref<number | null>(null)
|
||||||
|
|
||||||
const wsContent = ref('')
|
const wsContent = ref('')
|
||||||
const isWsLoading = ref(false)
|
const isWsLoading = ref(false)
|
||||||
let logSocket: WebSocket | null = null
|
let logSocket: WebSocket | null = null
|
||||||
@@ -203,6 +220,40 @@ function formatDuration(ms: number): string {
|
|||||||
return `${(ms / 60000).toFixed(1)}分钟`
|
return `${(ms / 60000).toFixed(1)}分钟`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function handleClearLogs() {
|
||||||
|
try {
|
||||||
|
await api.logs.clear(filterTaskId.value)
|
||||||
|
toast.success('相关日志已清空')
|
||||||
|
showClearDialog.value = false
|
||||||
|
loadLogs()
|
||||||
|
} catch (error: any) {
|
||||||
|
toast.error(error.message || '清空失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function confirmDeleteLog(id: number) {
|
||||||
|
deleteLogId.value = id
|
||||||
|
showDeleteDialog.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleDeleteLog() {
|
||||||
|
if (!deleteLogId.value) return
|
||||||
|
try {
|
||||||
|
await api.logs.delete(deleteLogId.value)
|
||||||
|
toast.success('该日志已删除')
|
||||||
|
|
||||||
|
// 如果当前选中的是这条日志,关闭详情页
|
||||||
|
if (selectedLog.value?.id === deleteLogId.value) {
|
||||||
|
closeDetail()
|
||||||
|
}
|
||||||
|
|
||||||
|
showDeleteDialog.value = false
|
||||||
|
loadLogs()
|
||||||
|
} catch (err: any) {
|
||||||
|
toast.error(err.message || '删除失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function getStatusBadgeClass(status: string) {
|
function getStatusBadgeClass(status: string) {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case TASK_STATUS.SUCCESS:
|
case TASK_STATUS.SUCCESS:
|
||||||
@@ -256,9 +307,12 @@ watch(() => route.query.task_id, (newTaskId) => {
|
|||||||
<Input v-model="filterKeyword" placeholder="搜索任务..." class="h-9 pl-9 w-full sm:w-56 text-sm"
|
<Input v-model="filterKeyword" placeholder="搜索任务..." class="h-9 pl-9 w-full sm:w-56 text-sm"
|
||||||
@input="handleSearch" />
|
@input="handleSearch" />
|
||||||
</div>
|
</div>
|
||||||
<Button variant="outline" size="icon" class="h-9 w-9 shrink-0" @click="loadLogs">
|
<Button variant="outline" size="icon" class="h-9 w-9 shrink-0" @click="loadLogs" title="刷新">
|
||||||
<RefreshCw class="h-4 w-4" />
|
<RefreshCw class="h-4 w-4" />
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button variant="outline" class="h-9 px-4 shrink-0 text-sm text-destructive hover:bg-destructive/10 hover:text-destructive border-destructive/20" @click="showClearDialog = true">
|
||||||
|
<Trash2 class="h-4 w-4 sm:mr-2" /> <span class="hidden sm:inline" style="padding-left: 2px;">清空日志</span>
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -273,6 +327,7 @@ watch(() => route.query.task_id, (newTaskId) => {
|
|||||||
<span class="flex-1 min-w-0">任务名称</span>
|
<span class="flex-1 min-w-0">任务名称</span>
|
||||||
<span class="w-8 shrink-0 text-center">状态</span>
|
<span class="w-8 shrink-0 text-center">状态</span>
|
||||||
<span class="w-12 text-right shrink-0">耗时</span>
|
<span class="w-12 text-right shrink-0">耗时</span>
|
||||||
|
<span class="w-8 text-center shrink-0"></span>
|
||||||
</div>
|
</div>
|
||||||
<!-- 大屏表头 -->
|
<!-- 大屏表头 -->
|
||||||
<div
|
<div
|
||||||
@@ -284,6 +339,7 @@ watch(() => route.query.task_id, (newTaskId) => {
|
|||||||
<span class="w-12 shrink-0 text-center">状态</span>
|
<span class="w-12 shrink-0 text-center">状态</span>
|
||||||
<span class="w-16 text-right shrink-0">耗时</span>
|
<span class="w-16 text-right shrink-0">耗时</span>
|
||||||
<span v-if="!selectedLog" class="w-40 text-right shrink-0 hidden md:block">执行时间</span>
|
<span v-if="!selectedLog" class="w-40 text-right shrink-0 hidden md:block">执行时间</span>
|
||||||
|
<span class="w-10 shrink-0 text-center"></span>
|
||||||
</div>
|
</div>
|
||||||
<!-- 列表 -->
|
<!-- 列表 -->
|
||||||
<div class="divide-y flex-1">
|
<div class="divide-y flex-1">
|
||||||
@@ -291,7 +347,7 @@ watch(() => route.query.task_id, (newTaskId) => {
|
|||||||
暂无日志
|
暂无日志
|
||||||
</div>
|
</div>
|
||||||
<div v-for="log in logs" :key="log.id" :class="[
|
<div v-for="log in logs" :key="log.id" :class="[
|
||||||
'cursor-pointer hover:bg-muted/30 transition-colors',
|
'cursor-pointer hover:bg-muted/30 transition-colors group',
|
||||||
selectedLog?.id === log.id && 'bg-accent/50'
|
selectedLog?.id === log.id && 'bg-accent/50'
|
||||||
]" @click="selectLog(log)">
|
]" @click="selectLog(log)">
|
||||||
<!-- 小屏行 -->
|
<!-- 小屏行 -->
|
||||||
@@ -330,6 +386,11 @@ watch(() => route.query.task_id, (newTaskId) => {
|
|||||||
</span>
|
</span>
|
||||||
<span class="w-12 text-right shrink-0 text-muted-foreground text-xs">{{ formatDuration(log.duration)
|
<span class="w-12 text-right shrink-0 text-muted-foreground text-xs">{{ formatDuration(log.duration)
|
||||||
}}</span>
|
}}</span>
|
||||||
|
<span class="w-8 shrink-0 flex justify-center opacity-100">
|
||||||
|
<Button variant="ghost" size="icon" class="h-6 w-6 text-muted-foreground hover:text-destructive shrink-0" @click.stop="confirmDeleteLog(log.id)" title="删除该日志">
|
||||||
|
<Trash2 class="h-3.5 w-3.5" />
|
||||||
|
</Button>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<!-- 大屏行 -->
|
<!-- 大屏行 -->
|
||||||
<div class="hidden sm:flex items-center gap-4 px-4 py-2">
|
<div class="hidden sm:flex items-center gap-4 px-4 py-2">
|
||||||
@@ -373,6 +434,11 @@ watch(() => route.query.task_id, (newTaskId) => {
|
|||||||
<span v-if="!selectedLog"
|
<span v-if="!selectedLog"
|
||||||
class="w-40 text-right shrink-0 text-muted-foreground text-xs hidden md:block">{{ log.start_time ||
|
class="w-40 text-right shrink-0 text-muted-foreground text-xs hidden md:block">{{ log.start_time ||
|
||||||
log.created_at }}</span>
|
log.created_at }}</span>
|
||||||
|
<span class="w-10 shrink-0 flex justify-center opacity-100">
|
||||||
|
<Button variant="ghost" size="icon" class="h-6 w-6 text-muted-foreground hover:text-destructive shrink-0" @click.stop="confirmDeleteLog(log.id)" title="删除该日志">
|
||||||
|
<Trash2 class="h-3.5 w-3.5" />
|
||||||
|
</Button>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -390,10 +456,18 @@ watch(() => route.query.task_id, (newTaskId) => {
|
|||||||
class="h-6 px-2 text-[10px]" :disabled="isStopping" @click="stopTask">
|
class="h-6 px-2 text-[10px]" :disabled="isStopping" @click="stopTask">
|
||||||
{{ isStopping ? '停止中...' : '停止任务' }}
|
{{ isStopping ? '停止中...' : '停止任务' }}
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button v-else variant="outline" size="sm" class="h-7 px-3 text-xs text-destructive hover:text-destructive hover:bg-destructive/10 border-destructive/30" @click="confirmDeleteLog(selectedLog.id)">
|
||||||
|
<Trash2 class="h-3.5 w-3.5 mr-1" /> 删除日志
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
<Button variant="ghost" size="icon" class="h-7 w-7 text-muted-foreground hover:text-destructive" title="删除该日志" @click="confirmDeleteLog(selectedLog.id)">
|
||||||
|
<Trash2 class="h-3.5 w-3.5" />
|
||||||
|
</Button>
|
||||||
|
<Button variant="ghost" size="icon" class="h-7 w-7" @click="closeDetail" title="关闭">
|
||||||
|
<X class="h-3.5 w-3.5" />
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<Button variant="ghost" size="icon" class="h-7 w-7" @click="closeDetail">
|
|
||||||
<X class="h-3.5 w-3.5" />
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="px-4 py-3 border-b space-y-2 text-sm">
|
<div class="px-4 py-3 border-b space-y-2 text-sm">
|
||||||
<div class="flex justify-between items-center h-6">
|
<div class="flex justify-between items-center h-6">
|
||||||
@@ -466,5 +540,41 @@ watch(() => route.query.task_id, (newTaskId) => {
|
|||||||
<!-- 全屏查看日志 -->
|
<!-- 全屏查看日志 -->
|
||||||
<LogViewer v-model:open="showFullscreen" :title="`日志输出 - ${selectedLog?.task_name || ''}`"
|
<LogViewer v-model:open="showFullscreen" :title="`日志输出 - ${selectedLog?.task_name || ''}`"
|
||||||
:content="decompressedOutput" :status="selectedLog?.status" />
|
:content="decompressedOutput" :status="selectedLog?.status" />
|
||||||
|
|
||||||
|
<!-- 清空日志确认弹窗 -->
|
||||||
|
<AlertDialog :open="showClearDialog" @update:open="showClearDialog = $event">
|
||||||
|
<AlertDialogContent>
|
||||||
|
<AlertDialogHeader>
|
||||||
|
<AlertDialogTitle>确认清空日志?</AlertDialogTitle>
|
||||||
|
<AlertDialogDescription>
|
||||||
|
此操作将永久删除{{ filterTaskId ? '当前任务的' : '所有' }}任务历史记录,包括控制台输出,并且无法撤销。
|
||||||
|
</AlertDialogDescription>
|
||||||
|
</AlertDialogHeader>
|
||||||
|
<AlertDialogFooter>
|
||||||
|
<AlertDialogCancel>取消</AlertDialogCancel>
|
||||||
|
<AlertDialogAction @click="handleClearLogs" class="bg-red-500 text-white hover:bg-red-600 dark:bg-red-600 dark:text-white dark:hover:bg-red-700">
|
||||||
|
清空
|
||||||
|
</AlertDialogAction>
|
||||||
|
</AlertDialogFooter>
|
||||||
|
</AlertDialogContent>
|
||||||
|
</AlertDialog>
|
||||||
|
|
||||||
|
<!-- 单条删除确认弹窗 -->
|
||||||
|
<AlertDialog :open="showDeleteDialog" @update:open="showDeleteDialog = $event">
|
||||||
|
<AlertDialogContent>
|
||||||
|
<AlertDialogHeader>
|
||||||
|
<AlertDialogTitle>确认删除这条日志?</AlertDialogTitle>
|
||||||
|
<AlertDialogDescription>
|
||||||
|
此操作将永久删除该次运行记录和日志文件,且不可恢复。
|
||||||
|
</AlertDialogDescription>
|
||||||
|
</AlertDialogHeader>
|
||||||
|
<AlertDialogFooter>
|
||||||
|
<AlertDialogCancel>取消</AlertDialogCancel>
|
||||||
|
<AlertDialogAction @click="handleDeleteLog" class="bg-red-500 text-white hover:bg-red-600 dark:bg-red-600 dark:text-white dark:hover:bg-red-700">
|
||||||
|
删除
|
||||||
|
</AlertDialogAction>
|
||||||
|
</AlertDialogFooter>
|
||||||
|
</AlertDialogContent>
|
||||||
|
</AlertDialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import Pagination from '@/components/Pagination.vue'
|
|||||||
import TaskDialog from './TaskDialog.vue'
|
import TaskDialog from './TaskDialog.vue'
|
||||||
import RepoDialog from './RepoDialog.vue'
|
import RepoDialog from './RepoDialog.vue'
|
||||||
import { Plus, Play, Pencil, Trash2, Search, ScrollText, GitBranch, Terminal, Server, Monitor, X, Loader2, Wifi, WifiOff, Zap, ZapOff, Copy, Tag } from 'lucide-vue-next'
|
import { Plus, Play, Pencil, Trash2, Search, ScrollText, GitBranch, Terminal, Server, Monitor, X, Loader2, Wifi, WifiOff, Zap, ZapOff, Copy, Tag } from 'lucide-vue-next'
|
||||||
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'
|
||||||
import { api, type Agent, type Task } from '@/api'
|
import { api, type Agent, type Task } from '@/api'
|
||||||
import { toast } from 'vue-sonner'
|
import { toast } from 'vue-sonner'
|
||||||
import { useSiteSettings } from '@/composables/useSiteSettings'
|
import { useSiteSettings } from '@/composables/useSiteSettings'
|
||||||
@@ -29,6 +30,7 @@ const deleteTaskId = ref<number | null>(null)
|
|||||||
|
|
||||||
const filterName = ref('')
|
const filterName = ref('')
|
||||||
const filterTags = ref('')
|
const filterTags = ref('')
|
||||||
|
const filterType = ref('all')
|
||||||
const filterAgentId = ref<number | null>(null)
|
const filterAgentId = ref<number | null>(null)
|
||||||
const currentPage = ref(1)
|
const currentPage = ref(1)
|
||||||
const total = ref(0)
|
const total = ref(0)
|
||||||
@@ -69,6 +71,7 @@ async function loadTasks() {
|
|||||||
page_size: pageSize.value,
|
page_size: pageSize.value,
|
||||||
name: filterName.value || undefined,
|
name: filterName.value || undefined,
|
||||||
tags: filterTags.value || undefined,
|
tags: filterTags.value || undefined,
|
||||||
|
type: filterType.value === 'all' ? undefined : filterType.value,
|
||||||
agent_id: filterAgentId.value || undefined
|
agent_id: filterAgentId.value || undefined
|
||||||
})
|
})
|
||||||
tasks.value = res.data
|
tasks.value = res.data
|
||||||
@@ -90,6 +93,11 @@ function handleSearch() {
|
|||||||
}, 300)
|
}, 300)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleTypeChange() {
|
||||||
|
currentPage.value = 1
|
||||||
|
loadTasks()
|
||||||
|
}
|
||||||
|
|
||||||
function handlePageChange(page: number) {
|
function handlePageChange(page: number) {
|
||||||
currentPage.value = page
|
currentPage.value = page
|
||||||
loadTasks()
|
loadTasks()
|
||||||
@@ -228,6 +236,18 @@ watch(() => route.query.agent_id, (newVal) => {
|
|||||||
<Input v-model="filterTags" placeholder="搜索标签..." class="h-9 pl-9 w-full sm:w-32 text-sm"
|
<Input v-model="filterTags" placeholder="搜索标签..." class="h-9 pl-9 w-full sm:w-32 text-sm"
|
||||||
@input="handleSearch" />
|
@input="handleSearch" />
|
||||||
</div>
|
</div>
|
||||||
|
<div class="relative flex-1 sm:flex-none">
|
||||||
|
<Select v-model="filterType" @update:model-value="handleTypeChange">
|
||||||
|
<SelectTrigger class="h-9 w-full sm:w-28 text-sm">
|
||||||
|
<SelectValue placeholder="所有类型" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="all">所有类型</SelectItem>
|
||||||
|
<SelectItem :value="TASK_TYPE.NORMAL">定时任务</SelectItem>
|
||||||
|
<SelectItem :value="TASK_TYPE.REPO">仓库同步</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
<div v-if="filterAgentId"
|
<div v-if="filterAgentId"
|
||||||
class="flex items-center gap-1 px-2 py-1 bg-primary/10 text-primary rounded-md text-sm">
|
class="flex items-center gap-1 px-2 py-1 bg-primary/10 text-primary rounded-md text-sm">
|
||||||
<Server class="h-3.5 w-3.5" />
|
<Server class="h-3.5 w-3.5" />
|
||||||
|
|||||||
Reference in New Issue
Block a user