✨ 首页统计条点击跳转任务列表筛选
1. Dashboard 近7日统计条形图和数字可点击 2. 点击成功/失败/待执行跳转任务列表并按对应任务ID筛选 3. 任务列表页显示筛选提示条,支持清除筛选
This commit is contained in:
@@ -173,6 +173,9 @@ export interface TaskStatisticsV2Item {
|
||||
successTask: number
|
||||
failTask: number
|
||||
pendingTask: number
|
||||
successTaskIds?: number[]
|
||||
failTaskIds?: number[]
|
||||
pendingTaskIds?: number[]
|
||||
}
|
||||
|
||||
export interface DashboardSummary {
|
||||
|
||||
@@ -27,6 +27,7 @@ import { extractPageData } from '@/types/api'
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const tableRef = ref<{ refresh: () => void } | null>(null)
|
||||
const filterIds = ref('')
|
||||
|
||||
// ---- 确认弹窗状态 ----
|
||||
const confirmOpen = ref(false)
|
||||
@@ -186,7 +187,11 @@ onMounted(() => {
|
||||
const qUsername = route.query.addUsername as string
|
||||
if (qUserId && qUsername) {
|
||||
openAddDialogWithUser(Number(qUserId), qUsername)
|
||||
// 清除 query 参数,避免刷新时重复弹窗
|
||||
router.replace({ path: route.path })
|
||||
}
|
||||
const qIds = route.query.ids as string
|
||||
if (qIds) {
|
||||
filterIds.value = qIds
|
||||
router.replace({ path: route.path })
|
||||
}
|
||||
})
|
||||
@@ -408,9 +413,17 @@ const searchFields: SearchField[] = [
|
||||
]
|
||||
|
||||
const fetchFn = async (params: PageParams): Promise<PageResponse<CpTask>> => {
|
||||
if (filterIds.value) {
|
||||
(params as any).ids = filterIds.value
|
||||
}
|
||||
const res = await cpTaskApi.getList(params)
|
||||
return extractPageData(res)
|
||||
}
|
||||
|
||||
function clearFilterIds() {
|
||||
filterIds.value = ''
|
||||
tableRef.value?.refresh()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -423,6 +436,11 @@ const fetchFn = async (params: PageParams): Promise<PageResponse<CpTask>> => {
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div v-if="filterIds" class="flex items-center gap-2 rounded-md border border-primary/30 bg-primary/5 px-3 py-2 text-sm">
|
||||
<span class="text-primary">当前按统计数据筛选中,共 {{ filterIds.split(',').length }} 条任务</span>
|
||||
<Button size="sm" variant="ghost" class="ml-auto h-7 px-2 text-xs" @click="clearFilterIds">清除筛选</Button>
|
||||
</div>
|
||||
|
||||
<DataTable
|
||||
ref="tableRef"
|
||||
:columns="columns"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, computed } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import { cpTaskApi } from '@/api/cpdaily'
|
||||
import { authApi } from '@/api/auth'
|
||||
@@ -10,6 +11,7 @@ import 'md-editor-v3/lib/preview.css'
|
||||
import type { TaskStatisticsV2Item, DashboardSummary } from '@/types/cpdaily'
|
||||
|
||||
const userStore = useUserStore()
|
||||
const router = useRouter()
|
||||
const statistics = ref<TaskStatisticsV2Item[]>([])
|
||||
const summary = ref<DashboardSummary | null>(null)
|
||||
const loading = ref(false)
|
||||
@@ -83,6 +85,11 @@ async function fetchAnnouncement() {
|
||||
}
|
||||
}
|
||||
|
||||
function goToTaskList(ids: number[] | undefined) {
|
||||
if (!ids || ids.length === 0) return
|
||||
router.push({ path: '/cpdaily/task/index', query: { ids: ids.join(',') } })
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
fetchStatistics()
|
||||
fetchSummary()
|
||||
@@ -197,25 +204,32 @@ onMounted(() => {
|
||||
<div class="flex-1 flex h-5 sm:h-6 rounded overflow-hidden bg-muted/30">
|
||||
<div
|
||||
v-if="item.successTask > 0"
|
||||
class="bg-primary transition-all"
|
||||
class="bg-primary transition-all cursor-pointer hover:opacity-80"
|
||||
:style="{ width: (item.successTask / maxTaskCount * 100) + '%' }"
|
||||
:title="`成功: ${item.successTask}`"
|
||||
:title="`成功: ${item.successTask} — 点击查看`"
|
||||
@click="goToTaskList(item.successTaskIds)"
|
||||
></div>
|
||||
<div
|
||||
v-if="item.failTask > 0"
|
||||
class="bg-destructive transition-all"
|
||||
class="bg-destructive transition-all cursor-pointer hover:opacity-80"
|
||||
:style="{ width: (item.failTask / maxTaskCount * 100) + '%' }"
|
||||
:title="`失败: ${item.failTask}`"
|
||||
:title="`失败: ${item.failTask} — 点击查看`"
|
||||
@click="goToTaskList(item.failTaskIds)"
|
||||
></div>
|
||||
<div
|
||||
v-if="item.pendingTask > 0"
|
||||
class="bg-muted-foreground/30 transition-all"
|
||||
class="bg-muted-foreground/30 transition-all cursor-pointer hover:opacity-80"
|
||||
:style="{ width: (item.pendingTask / maxTaskCount * 100) + '%' }"
|
||||
:title="`待执行: ${item.pendingTask}`"
|
||||
:title="`待执行: ${item.pendingTask} — 点击查看`"
|
||||
@click="goToTaskList(item.pendingTaskIds)"
|
||||
></div>
|
||||
</div>
|
||||
<span class="text-xs text-muted-foreground w-16 sm:w-20 shrink-0">
|
||||
{{ item.successTask }}/{{ item.failTask }}/{{ item.pendingTask }}
|
||||
<span class="text-xs text-muted-foreground w-24 sm:w-28 shrink-0 flex gap-0.5">
|
||||
<span class="cursor-pointer text-primary hover:underline" @click="goToTaskList(item.successTaskIds)">{{ item.successTask }}</span>
|
||||
<span>/</span>
|
||||
<span class="cursor-pointer text-destructive hover:underline" @click="goToTaskList(item.failTaskIds)">{{ item.failTask }}</span>
|
||||
<span>/</span>
|
||||
<span class="cursor-pointer hover:underline" @click="goToTaskList(item.pendingTaskIds)">{{ item.pendingTask }}</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user