From dde179a896636ad11cdbeb2e391da71816ffaa2d Mon Sep 17 00:00:00 2001 From: admin Date: Fri, 8 May 2026 14:45:38 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=B7=A5=E5=8D=95=E3=80=81?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E3=80=81=E5=8D=A1=E5=AF=86=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E7=9A=84=E5=88=86=E9=A1=B5=E5=92=8C=E7=AD=9B?= =?UTF-8?q?=E9=80=89=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 工单管理:后端添加分页和筛选支持(status, priority, type, 日期范围) - 日志管理:前端使用服务端分页和筛选(后端已支持) - 卡密管理:前端使用服务端分页和筛选(后端已支持) - 所有页面移除前端筛选逻辑,改为服务端筛选 - 修复分页总数与筛选数据不匹配的问题 - 添加watch监听筛选条件变化,自动刷新数据 --- backend/internal/router/admin/tickets.go | 55 +++++++++++- frontend/src/pages/admin/cards/index.vue | 102 +++++++++++------------ frontend/src/pages/admin/logs.vue | 86 ++++++++++--------- frontend/src/pages/admin/tickets.vue | 100 +++++++++++----------- 4 files changed, 195 insertions(+), 148 deletions(-) diff --git a/backend/internal/router/admin/tickets.go b/backend/internal/router/admin/tickets.go index d44d723..b3558f9 100644 --- a/backend/internal/router/admin/tickets.go +++ b/backend/internal/router/admin/tickets.go @@ -1,8 +1,9 @@ -package admin +package admin import ( "fmt" "log" + "strconv" "verification-platform-backend/internal/database" "verification-platform-backend/internal/model" @@ -49,12 +50,55 @@ func handleGetTicketStats(c *gin.Context) { func handleGetTickets(c *gin.Context) { userID := c.GetUint("user_id") + + page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) + pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20")) + statusFilter := c.Query("status") + priorityFilter := c.Query("priority") + typeFilter := c.Query("type") + createdStartDate := c.Query("created_start_date") + createdEndDate := c.Query("created_end_date") + updatedStartDate := c.Query("updated_start_date") + updatedEndDate := c.Query("updated_end_date") + + query := database.DB.Model(&model.Ticket{}).Where("user_id = ? OR assigned_to = ?", userID, userID) + + if statusFilter != "" { + query = query.Where("status = ?", statusFilter) + } + if priorityFilter != "" { + query = query.Where("priority = ?", priorityFilter) + } + if typeFilter != "" { + query = query.Where("type = ?", typeFilter) + } + if createdStartDate != "" { + query = query.Where("created_at >= ?", createdStartDate+" 00:00:00") + } + if createdEndDate != "" { + query = query.Where("created_at <= ?", createdEndDate+" 23:59:59") + } + if updatedStartDate != "" { + query = query.Where("updated_at >= ?", updatedStartDate+" 00:00:00") + } + if updatedEndDate != "" { + query = query.Where("updated_at <= ?", updatedEndDate+" 23:59:59") + } + + var total int64 + query.Count(&total) + + offset := (page - 1) * pageSize + var tickets []model.Ticket - if err := database.DB.Where("user_id = ? OR assigned_to = ?", userID, userID). + if err := query. Preload("Replies"). Preload("Application"). Preload("User"). Preload("AssignedUser"). + Order("created_at DESC"). + Offset(offset). + Limit(pageSize). Find(&tickets).Error; err != nil { response.Error(c, 500, "获取工单列表失败") return @@ -84,8 +128,11 @@ func handleGetTickets(c *gin.Context) { } response.Success(c, gin.H{ - "tickets": result, - "total": len(result), + "tickets": result, + "total": total, + "page": page, + "page_size": pageSize, + "total_page": (total + int64(pageSize) - 1) / int64(pageSize), }) } diff --git a/frontend/src/pages/admin/cards/index.vue b/frontend/src/pages/admin/cards/index.vue index d14dbcf..9d08979 100644 --- a/frontend/src/pages/admin/cards/index.vue +++ b/frontend/src/pages/admin/cards/index.vue @@ -34,6 +34,9 @@ const cards = ref([]) const tableRef = ref() const applications = ref([]) const cardTypes = ref([]) +const currentPage = ref(1) +const pageSize = ref(20) +const total = ref(0) const appFilter = ref('') const cardTypeFilter = ref('') @@ -56,52 +59,9 @@ const filteredCardTypes = computed(() => { return cardTypes.value }) -const filteredCards = computed(() => { - let result = cards.value - - if (appFilter.value) { - result = result.filter(card => String(card.application_id) === appFilter.value) - } - - if (cardTypeFilter.value) { - result = result.filter(card => String(card.card_type_id) === cardTypeFilter.value) - } - - if (statusFilter.value) { - result = result.filter(card => card.status === statusFilter.value) - } - - if (startDate.value) { - const fromDateTime = startDate.value.includes('T') - ? startDate.value.replace('T', ' ') - : `${startDate.value} 00:00` - result = result.filter(card => card.created_at >= fromDateTime) - } - - if (endDate.value) { - const toDateTime = endDate.value.includes('T') - ? endDate.value.replace('T', ' ') - : `${endDate.value} 23:59` - result = result.filter(card => card.created_at <= toDateTime) - } - - if (searchFilter.value) { - const search = searchFilter.value.toLowerCase() - result = result.filter(card => - card.card_key?.toLowerCase().includes(search) - || card.application?.name?.toLowerCase().includes(search) - || card.card_type?.name?.toLowerCase().includes(search) - || card.creator?.username?.toLowerCase().includes(search) - || card.app_user?.username?.toLowerCase().includes(search), - ) - } - - return result -}) - -const unusedCount = computed(() => filteredCards.value.filter(card => card.status === 'unused').length) -const usedCount = computed(() => filteredCards.value.filter(card => card.status === 'used').length) -const bannedCount = computed(() => filteredCards.value.filter(card => card.status === 'banned').length) +const unusedCount = computed(() => cards.value.filter(card => card.status === 'unused').length) +const usedCount = computed(() => cards.value.filter(card => card.status === 'used').length) +const bannedCount = computed(() => cards.value.filter(card => card.status === 'banned').length) const applicationOptions = computed(() => { return applications.value.map(app => ({ @@ -149,16 +109,32 @@ async function fetchCardTypes() { async function fetchCards() { loading.value = true try { - const data = await api.get('/dev/cards') - if (data && typeof data === 'object' && data.cards) { - cards.value = data.cards + const params = new URLSearchParams() + params.append('page', String(currentPage.value)) + params.append('page_size', String(pageSize.value)) + + if (appFilter.value) { + params.append('application_id', appFilter.value) } - else if (Array.isArray(data)) { - cards.value = data + if (cardTypeFilter.value) { + params.append('card_type_id', cardTypeFilter.value) } - else { - cards.value = [] + if (statusFilter.value) { + params.append('status', statusFilter.value) } + if (startDate.value) { + params.append('start_date', startDate.value.split('T')[0]) + } + if (endDate.value) { + params.append('end_date', endDate.value.split('T')[0]) + } + if (searchFilter.value) { + params.append('search', searchFilter.value.trim()) + } + + const data = await api.get<{ cards: Card[], total: number }>(`/dev/cards?${params.toString()}`) + cards.value = data?.cards || [] + total.value = data?.total || 0 } catch (error) { console.error('获取卡密列表失败:', error) @@ -281,6 +257,21 @@ onMounted(() => { fetchCardTypes() fetchCards() }) + +watch([appFilter, cardTypeFilter, statusFilter, startDate, endDate, searchFilter], () => { + currentPage.value = 1 + fetchCards() +}) + +const serverPagination = computed(() => ({ + currentPage: currentPage.value, + pageSize: pageSize.value, + total: total.value, + onChange: (page: number) => { + currentPage.value = page + fetchCards() + }, +}))