diff --git a/backend/internal/router/admin/announcements.go b/backend/internal/router/admin/announcements.go index 98a4fc4..e971cc3 100644 --- a/backend/internal/router/admin/announcements.go +++ b/backend/internal/router/admin/announcements.go @@ -80,6 +80,11 @@ func handleGetAllAnnouncements(c *gin.Context) { } countQuery.Count(&total) + var activeCount, inactiveCount, topCount int64 + database.DB.Model(&model.Announcement{}).Where("application_id IN ? AND status = ?", appIDs, "active").Count(&activeCount) + database.DB.Model(&model.Announcement{}).Where("application_id IN ? AND status = ?", appIDs, "inactive").Count(&inactiveCount) + database.DB.Model(&model.Announcement{}).Where("application_id IN ? AND is_top = ?", appIDs, true).Count(&topCount) + query := database.DB.Where("application_id IN ?", appIDs) if applicationIDFilter != "" { query = query.Where("application_id = ?", applicationIDFilter) @@ -133,6 +138,9 @@ func handleGetAllAnnouncements(c *gin.Context) { response.Success(c, gin.H{ "announcements": result, "total": total, + "active_count": activeCount, + "inactive_count": inactiveCount, + "top_count": topCount, }) } diff --git a/backend/internal/router/admin/devices.go b/backend/internal/router/admin/devices.go index 2c71246..454c3e6 100644 --- a/backend/internal/router/admin/devices.go +++ b/backend/internal/router/admin/devices.go @@ -106,6 +106,9 @@ func handleGetDevices(c *gin.Context) { } countQuery.Count(&total) + var bannedCount int64 + database.DB.Model(&model.UserDevice{}).Where("application_id IN ? AND status = ?", appIDs, "banned").Count(&bannedCount) + query := database.DB.Preload("User").Preload("Application").Where("application_id IN ?", appIDs) if userIDFilter != "" { @@ -168,11 +171,12 @@ func handleGetDevices(c *gin.Context) { } response.Success(c, gin.H{ - "devices": devicesWithDetails, - "total": total, - "page": page, - "page_size": pageSize, - "total_page": (total + int64(pageSize) - 1) / int64(pageSize), + "devices": devicesWithDetails, + "total": total, + "page": page, + "page_size": pageSize, + "total_page": (total + int64(pageSize) - 1) / int64(pageSize), + "banned_count": bannedCount, }) } diff --git a/backend/internal/router/admin/logs.go b/backend/internal/router/admin/logs.go index 315f782..cb71bfe 100644 --- a/backend/internal/router/admin/logs.go +++ b/backend/internal/router/admin/logs.go @@ -1,4 +1,4 @@ -package admin +package admin import ( "strconv" @@ -68,6 +68,11 @@ func handleGetLogs(c *gin.Context) { query.Count(&total) + var successCount, failedCount, operationCount int64 + database.DB.Model(&model.ApiUsage{}).Where("application_id IN ? OR user_id = ?", appIDs, userID).Where("status = ?", "success").Count(&successCount) + database.DB.Model(&model.ApiUsage{}).Where("application_id IN ? OR user_id = ?", appIDs, userID).Where("status = ?", "failed").Count(&failedCount) + database.DB.Model(&model.ApiUsage{}).Where("application_id IN ? OR user_id = ?", appIDs, userID).Where("log_type = ?", "operation").Count(&operationCount) + offset := (page - 1) * pageSize if err := query.Preload("User").Preload("Application").Preload("AppUser").Order("created_at DESC").Offset(offset).Limit(pageSize).Find(&logs).Error; err != nil { response.Error(c, 500, "获取日志失败") @@ -75,10 +80,13 @@ func handleGetLogs(c *gin.Context) { } response.Success(c, gin.H{ - "logs": logs, - "total": total, - "page": page, - "page_size": pageSize, - "total_page": (total + int64(pageSize) - 1) / int64(pageSize), + "logs": logs, + "total": total, + "page": page, + "page_size": pageSize, + "total_page": (total + int64(pageSize) - 1) / int64(pageSize), + "success_count": successCount, + "failed_count": failedCount, + "operation_count": operationCount, }) } diff --git a/backend/internal/router/admin/tickets.go b/backend/internal/router/admin/tickets.go index b3558f9..a37b472 100644 --- a/backend/internal/router/admin/tickets.go +++ b/backend/internal/router/admin/tickets.go @@ -88,6 +88,11 @@ func handleGetTickets(c *gin.Context) { var total int64 query.Count(&total) + var openCount, processingCount, resolvedCount int64 + database.DB.Model(&model.Ticket{}).Where("user_id = ? OR assigned_to = ?", userID, userID).Where("status = ?", "open").Count(&openCount) + database.DB.Model(&model.Ticket{}).Where("user_id = ? OR assigned_to = ?", userID, userID).Where("status = ?", "processing").Count(&processingCount) + database.DB.Model(&model.Ticket{}).Where("user_id = ? OR assigned_to = ?", userID, userID).Where("status = ?", "resolved").Count(&resolvedCount) + offset := (page - 1) * pageSize var tickets []model.Ticket @@ -128,11 +133,14 @@ func handleGetTickets(c *gin.Context) { } response.Success(c, gin.H{ - "tickets": result, - "total": total, - "page": page, - "page_size": pageSize, - "total_page": (total + int64(pageSize) - 1) / int64(pageSize), + "tickets": result, + "total": total, + "page": page, + "page_size": pageSize, + "total_page": (total + int64(pageSize) - 1) / int64(pageSize), + "open_count": openCount, + "processing_count": processingCount, + "resolved_count": resolvedCount, }) } diff --git a/backend/internal/router/admin/versions.go b/backend/internal/router/admin/versions.go index 110ed83..e950f6c 100644 --- a/backend/internal/router/admin/versions.go +++ b/backend/internal/router/admin/versions.go @@ -95,6 +95,9 @@ func handleGetAllVersions(c *gin.Context) { } countQuery.Count(&total) + var forcedCount int64 + database.DB.Model(&model.Version{}).Where("application_id IN ? AND update_strategy = ?", appIDs, "forced").Count(&forcedCount) + query := database.DB.Where("application_id IN ?", appIDs) if applicationIDFilter != "" { query = query.Where("application_id = ?", applicationIDFilter) @@ -184,8 +187,9 @@ func handleGetAllVersions(c *gin.Context) { } response.Success(c, gin.H{ - "versions": result, - "total": total, + "versions": result, + "total": total, + "forced_count": forcedCount, }) } diff --git a/frontend/src/pages/admin/announcements/index.vue b/frontend/src/pages/admin/announcements/index.vue index 18c9fa0..ed07b5b 100644 --- a/frontend/src/pages/admin/announcements/index.vue +++ b/frontend/src/pages/admin/announcements/index.vue @@ -35,6 +35,9 @@ const searchFilter = ref('') const currentPage = ref(1) const pageSize = ref(20) const total = ref(0) +const activeCount = ref(0) +const inactiveCount = ref(0) +const topCount = ref(0) const deleteDialogOpen = ref(false) const deleteTarget = ref(null) @@ -60,10 +63,6 @@ const statusOptions = computed(() => [ { label: t('admin.announcements.statuses.inactive'), value: 'inactive' }, ]) -const activeCount = computed(() => announcements.value.filter(a => a.status === 'active').length) -const inactiveCount = computed(() => announcements.value.filter(a => a.status === 'inactive').length) -const topCount = computed(() => announcements.value.filter(a => a.is_top).length) - const serverPagination = computed(() => ({ page: currentPage.value, pageSize: pageSize.value, @@ -107,9 +106,12 @@ async function fetchAnnouncements() { params.append('search', searchFilter.value) } - const data = await api.get<{ announcements: Announcement[], total: number }>(`/dev/announcements?${params.toString()}`) + const data = await api.get(`/dev/announcements?${params.toString()}`) announcements.value = data?.announcements || [] total.value = data?.total || 0 + activeCount.value = data?.active_count || 0 + inactiveCount.value = data?.inactive_count || 0 + topCount.value = data?.top_count || 0 } catch (error) { console.error('加载公告失败:', error) diff --git a/frontend/src/pages/admin/devices/index.vue b/frontend/src/pages/admin/devices/index.vue index 5af3a52..57d51b5 100644 --- a/frontend/src/pages/admin/devices/index.vue +++ b/frontend/src/pages/admin/devices/index.vue @@ -38,6 +38,7 @@ const userIdFilter = ref('') const currentPage = ref(1) const pageSize = ref(20) const total = ref(0) +const bannedCount = ref(0) const deleteDialogOpen = ref(false) const deleteTarget = ref(null) @@ -48,7 +49,6 @@ const forceOfflineTarget = ref(null) const totalDevices = computed(() => total.value) const onlineSessionCount = computed(() => devices.value.reduce((sum, d) => sum + (d.online_sessions || 0), 0)) -const bannedCount = computed(() => devices.value.filter(device => device.status === 'banned').length) const applicationOptions = computed(() => { return applications.value.map(app => ({ @@ -115,9 +115,10 @@ async function fetchDevices() { params.append('user_id', userIdFilter.value) } - const data = await api.get<{ devices: Device[], total: number }>(`/dev/devices?${params.toString()}`) + const data = await api.get(`/dev/devices?${params.toString()}`) devices.value = Array.isArray(data?.devices) ? data.devices : [] total.value = data?.total || 0 + bannedCount.value = data?.banned_count || 0 } catch (error) { console.error('获取设备列表失败:', error) diff --git a/frontend/src/pages/admin/logs.vue b/frontend/src/pages/admin/logs.vue index c0e5a6b..789be49 100644 --- a/frontend/src/pages/admin/logs.vue +++ b/frontend/src/pages/admin/logs.vue @@ -24,6 +24,9 @@ const applications = ref([]) const currentPage = ref(1) const pageSize = ref(20) const total = ref(0) +const successCount = ref(0) +const failedCount = ref(0) +const operationCount = ref(0) const appFilter = ref('') const typeFilter = ref('') @@ -31,10 +34,6 @@ const statusFilter = ref('') const startDate = ref('') const endDate = ref('') -const successCount = computed(() => logs.value.filter(log => log.status === 'success').length) -const failedCount = computed(() => logs.value.filter(log => log.status === 'failed').length) -const operationCount = computed(() => logs.value.filter(log => log.log_type === 'operation').length) - const applicationOptions = computed(() => { return applications.value.map(app => ({ label: app.name, @@ -86,9 +85,12 @@ async function fetchLogs() { params.append('end_date', endDate.value.split('T')[0]) } - const data = await api.get<{ logs: Log[], total: number }>(`/dev/logs?${params.toString()}`) + const data = await api.get(`/dev/logs?${params.toString()}`) logs.value = data?.logs || [] total.value = data?.total || 0 + successCount.value = data?.success_count || 0 + failedCount.value = data?.failed_count || 0 + operationCount.value = data?.operation_count || 0 } catch (error) { console.error('获取日志记录失败:', error) diff --git a/frontend/src/pages/admin/tickets.vue b/frontend/src/pages/admin/tickets.vue index 3978966..a03293b 100644 --- a/frontend/src/pages/admin/tickets.vue +++ b/frontend/src/pages/admin/tickets.vue @@ -24,6 +24,9 @@ const tableRef = ref() const currentPage = ref(1) const pageSize = ref(20) const total = ref(0) +const openCount = ref(0) +const pendingCount = ref(0) +const resolvedCount = ref(0) const statusFilter = ref('') const priorityFilter = ref('') @@ -38,10 +41,6 @@ const deleteTarget = ref(null) const batchDeleteDialogOpen = ref(false) const batchDeleteIds = ref<(string | number)[]>([]) -const openCount = computed(() => tickets.value.filter(t => t.status === 'open').length) -const pendingCount = computed(() => tickets.value.filter(t => t.status === 'processing').length) -const resolvedCount = computed(() => tickets.value.filter(t => t.status === 'resolved').length) - const statusOptions = computed(() => [ { label: t('admin.tickets.status.open'), value: 'open' }, { label: t('admin.tickets.status.processing'), value: 'processing' }, @@ -90,9 +89,12 @@ async function fetchTickets() { params.append('updated_end_date', updatedEndDate.value.split('T')[0]) } - const data = await api.get<{ tickets: Ticket[], total: number }>(`/dev/tickets?${params.toString()}`) + const data = await api.get(`/dev/tickets?${params.toString()}`) tickets.value = data?.tickets || [] total.value = data?.total || 0 + openCount.value = data?.open_count || 0 + pendingCount.value = data?.processing_count || 0 + resolvedCount.value = data?.resolved_count || 0 } catch (error) { console.error('获取工单列表失败:', error) diff --git a/frontend/src/pages/admin/users/index.vue b/frontend/src/pages/admin/users/index.vue index 86c99f7..8ecec37 100644 --- a/frontend/src/pages/admin/users/index.vue +++ b/frontend/src/pages/admin/users/index.vue @@ -37,6 +37,9 @@ const createdEndDate = ref('') const currentPage = ref(1) const pageSize = ref(20) const total = ref(0) +const onlineCount = ref(0) +const offlineCount = ref(0) +const bannedCount = ref(0) const deleteDialogOpen = ref(false) const deleteTarget = ref(null) @@ -89,10 +92,6 @@ const filteredUsers = computed(() => { return result }) -const onlineCount = computed(() => users.value.filter(user => user.online_status === 'online').length) -const offlineCount = computed(() => users.value.filter(user => user.online_status === 'offline').length) -const bannedCount = computed(() => users.value.filter(user => user.status === 'banned').length) - const serverPagination = computed(() => ({ page: currentPage.value, pageSize: pageSize.value, @@ -147,9 +146,12 @@ async function fetchUsers() { params.append('status', accountStatusFilter.value) } - const data = await api.get<{ users: User[], total: number }>(`/dev/app-users?${params.toString()}`) + const data = await api.get(`/dev/app-users?${params.toString()}`) users.value = Array.isArray(data?.users) ? data.users : [] total.value = data?.total || 0 + onlineCount.value = data?.online_count || 0 + offlineCount.value = data?.offline_count || 0 + bannedCount.value = data?.banned_count || 0 } catch (error) { console.error('获取用户列表失败:', error) diff --git a/frontend/src/pages/admin/versions/index.vue b/frontend/src/pages/admin/versions/index.vue index e31ad0c..c028f72 100644 --- a/frontend/src/pages/admin/versions/index.vue +++ b/frontend/src/pages/admin/versions/index.vue @@ -36,6 +36,7 @@ const searchFilter = ref('') const currentPage = ref(1) const pageSize = ref(20) const total = ref(0) +const forcedCount = ref(0) const deleteDialogOpen = ref(false) const deleteTarget = ref(null) @@ -71,8 +72,6 @@ const totalSize = computed(() => { return versions.value.reduce((sum, v) => sum + (v.file_size || 0), 0) }) -const forcedCount = computed(() => versions.value.filter(v => v.update_strategy === 'forced').length) - const serverPagination = computed(() => ({ page: currentPage.value, pageSize: pageSize.value, @@ -128,9 +127,10 @@ async function fetchVersions() { params.append('search', searchFilter.value) } - const data = await api.get<{ versions: Version[], total: number }>(`/dev/versions?${params.toString()}`) + const data = await api.get(`/dev/versions?${params.toString()}`) versions.value = data?.versions || [] total.value = data?.total || 0 + forcedCount.value = data?.forced_count || 0 } catch (error) { console.error('加载版本列表失败:', error)