2026-03-23 13:02:36 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 仪表盘服务
|
|
|
|
|
|
* 使用 authFetch 替代 axios,与项目其他 service 保持一致
|
|
|
|
|
|
*/
|
|
|
|
|
|
import { authFetch, baseUrl } from './authHelper'
|
2026-03-05 13:13:49 +08:00
|
|
|
|
|
2026-03-23 13:02:36 +08:00
|
|
|
|
const apiBaseUrl = baseUrl || '/api/v1'
|
2026-03-05 13:13:49 +08:00
|
|
|
|
|
2026-03-23 13:02:36 +08:00
|
|
|
|
interface ApiResponse<T> {
|
|
|
|
|
|
code: number
|
|
|
|
|
|
data: T
|
|
|
|
|
|
message?: string
|
|
|
|
|
|
}
|
2026-03-05 13:13:49 +08:00
|
|
|
|
|
|
|
|
|
|
export interface KpiData {
|
|
|
|
|
|
label: string
|
|
|
|
|
|
value: number
|
|
|
|
|
|
status: string
|
|
|
|
|
|
hint: string
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface ActivitySummary {
|
|
|
|
|
|
id: number
|
|
|
|
|
|
name: string
|
|
|
|
|
|
startTime?: string
|
|
|
|
|
|
endTime?: string
|
2026-03-23 13:02:36 +08:00
|
|
|
|
status?: string
|
2026-03-05 13:13:49 +08:00
|
|
|
|
participants: number
|
|
|
|
|
|
shares: number
|
|
|
|
|
|
conversions: number
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface Alert {
|
|
|
|
|
|
title: string
|
|
|
|
|
|
detail: string
|
|
|
|
|
|
type: string
|
|
|
|
|
|
level: string
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface Todo {
|
|
|
|
|
|
id: string
|
|
|
|
|
|
title: string
|
|
|
|
|
|
description: string
|
|
|
|
|
|
type: string
|
|
|
|
|
|
link: string
|
|
|
|
|
|
priority: string
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface DashboardData {
|
|
|
|
|
|
updatedAt: string
|
|
|
|
|
|
kpis: KpiData[]
|
|
|
|
|
|
activities: ActivitySummary[]
|
|
|
|
|
|
alerts: Alert[]
|
|
|
|
|
|
todos: Todo[]
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-23 13:02:36 +08:00
|
|
|
|
export interface RealtimeData {
|
|
|
|
|
|
currentOnline: number
|
|
|
|
|
|
todayVisits: number
|
|
|
|
|
|
realtimeConversion: number
|
|
|
|
|
|
apiRequests: number
|
|
|
|
|
|
hourlyTrend: Array<{ hour: string; visits: number }>
|
|
|
|
|
|
systemHealth: {
|
|
|
|
|
|
backend: { status: string; message: string }
|
|
|
|
|
|
database: { status: string; message: string }
|
|
|
|
|
|
redis: { status: string; message: string }
|
|
|
|
|
|
}
|
|
|
|
|
|
recentEvents: Array<{ id: string; description: string; time: string }>
|
|
|
|
|
|
timestamp: string
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface HistoryData {
|
|
|
|
|
|
timeTrend: Array<{
|
|
|
|
|
|
date: string
|
|
|
|
|
|
views: number
|
|
|
|
|
|
shares: number
|
|
|
|
|
|
conversions: number
|
|
|
|
|
|
newUsers: number
|
|
|
|
|
|
}>
|
|
|
|
|
|
comparison: {
|
|
|
|
|
|
thisWeek: { views: number; conversions: number }
|
|
|
|
|
|
lastWeek: { views: number; conversions: number }
|
|
|
|
|
|
growth: { views: number; conversions: number }
|
|
|
|
|
|
}
|
|
|
|
|
|
timestamp: string
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface KpiConfig {
|
|
|
|
|
|
kpiKey: string
|
|
|
|
|
|
threshold: number
|
|
|
|
|
|
warning: number
|
|
|
|
|
|
updatedAt?: string
|
2026-03-05 13:13:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取仪表盘数据
|
|
|
|
|
|
*/
|
|
|
|
|
|
export async function getDashboard(): Promise<DashboardData> {
|
2026-03-23 13:02:36 +08:00
|
|
|
|
const response = await authFetch(`${apiBaseUrl}/dashboard`)
|
|
|
|
|
|
const result = await response.json() as ApiResponse<DashboardData>
|
|
|
|
|
|
if (result.code !== 200) {
|
|
|
|
|
|
throw new Error(result.message || '获取仪表盘数据失败')
|
|
|
|
|
|
}
|
|
|
|
|
|
return result.data
|
2026-03-05 13:13:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取KPI数据
|
|
|
|
|
|
*/
|
|
|
|
|
|
export async function getKpis(): Promise<KpiData[]> {
|
2026-03-23 13:02:36 +08:00
|
|
|
|
const response = await authFetch(`${apiBaseUrl}/dashboard/kpis`)
|
|
|
|
|
|
const result = await response.json() as ApiResponse<KpiData[]>
|
|
|
|
|
|
if (result.code !== 200) {
|
|
|
|
|
|
throw new Error(result.message || '获取KPI数据失败')
|
|
|
|
|
|
}
|
|
|
|
|
|
return result.data
|
2026-03-05 13:13:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取活动统计
|
|
|
|
|
|
*/
|
|
|
|
|
|
export async function getActivitySummary() {
|
2026-03-23 13:02:36 +08:00
|
|
|
|
const response = await authFetch(`${apiBaseUrl}/dashboard/activities`)
|
|
|
|
|
|
const result = await response.json()
|
|
|
|
|
|
return result
|
2026-03-05 13:13:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取待办事项
|
|
|
|
|
|
*/
|
|
|
|
|
|
export async function getTodos(): Promise<Todo[]> {
|
2026-03-23 13:02:36 +08:00
|
|
|
|
const response = await authFetch(`${apiBaseUrl}/dashboard/todos`)
|
|
|
|
|
|
const result = await response.json() as ApiResponse<Todo[]>
|
|
|
|
|
|
if (result.code !== 200) {
|
|
|
|
|
|
throw new Error(result.message || '获取待办事项失败')
|
|
|
|
|
|
}
|
|
|
|
|
|
return result.data
|
2026-03-05 13:13:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-05 21:55:47 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 导出仪表盘数据
|
|
|
|
|
|
*/
|
|
|
|
|
|
export async function exportDashboard(format: string = 'csv'): Promise<Blob> {
|
2026-03-23 13:02:36 +08:00
|
|
|
|
const response = await authFetch(`${apiBaseUrl}/dashboard/export?format=${format}`)
|
|
|
|
|
|
return response.blob()
|
2026-03-05 21:55:47 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 导出KPI数据
|
|
|
|
|
|
*/
|
|
|
|
|
|
export async function exportKpis(): Promise<Blob> {
|
2026-03-23 13:02:36 +08:00
|
|
|
|
const response = await authFetch(`${apiBaseUrl}/dashboard/kpis/export`)
|
|
|
|
|
|
return response.blob()
|
2026-03-05 21:55:47 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 导出活动数据
|
|
|
|
|
|
*/
|
|
|
|
|
|
export async function exportActivities(): Promise<Blob> {
|
2026-03-23 13:02:36 +08:00
|
|
|
|
const response = await authFetch(`${apiBaseUrl}/dashboard/activities/export`)
|
|
|
|
|
|
return response.blob()
|
2026-03-05 21:55:47 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 下载文件工具函数
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function downloadBlob(blob: Blob, filename: string) {
|
|
|
|
|
|
const url = window.URL.createObjectURL(blob)
|
|
|
|
|
|
const link = document.createElement('a')
|
|
|
|
|
|
link.href = url
|
|
|
|
|
|
link.download = filename
|
|
|
|
|
|
document.body.appendChild(link)
|
|
|
|
|
|
link.click()
|
|
|
|
|
|
document.body.removeChild(link)
|
|
|
|
|
|
window.URL.revokeObjectURL(url)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-23 13:02:36 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 获取实时监控数据
|
|
|
|
|
|
*/
|
|
|
|
|
|
export async function getRealtimeData(): Promise<RealtimeData> {
|
|
|
|
|
|
const response = await authFetch(`${apiBaseUrl}/dashboard/monitor/realtime`)
|
|
|
|
|
|
const result = await response.json() as ApiResponse<RealtimeData>
|
|
|
|
|
|
if (result.code !== 200) {
|
|
|
|
|
|
throw new Error(result.message || '获取实时监控数据失败')
|
|
|
|
|
|
}
|
|
|
|
|
|
return result.data
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取历史图表数据
|
|
|
|
|
|
*/
|
|
|
|
|
|
export async function getHistoryData(days: number = 7, metric?: string): Promise<HistoryData> {
|
|
|
|
|
|
let url = `${apiBaseUrl}/dashboard/monitor/history?days=${days}`
|
|
|
|
|
|
if (metric) url += `&metric=${metric}`
|
|
|
|
|
|
const response = await authFetch(url)
|
|
|
|
|
|
const result = await response.json() as ApiResponse<HistoryData>
|
|
|
|
|
|
if (result.code !== 200) {
|
|
|
|
|
|
throw new Error(result.message || '获取历史图表数据失败')
|
|
|
|
|
|
}
|
|
|
|
|
|
return result.data
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 配置KPI阈值
|
|
|
|
|
|
*/
|
|
|
|
|
|
export async function configKpi(config: { kpiKey: string; threshold: number; warning: number }): Promise<KpiConfig> {
|
|
|
|
|
|
const response = await authFetch(`${apiBaseUrl}/dashboard/kpis/config`, {
|
|
|
|
|
|
method: 'POST',
|
|
|
|
|
|
headers: { 'Content-Type': 'application/json' },
|
|
|
|
|
|
body: JSON.stringify(config)
|
|
|
|
|
|
})
|
|
|
|
|
|
const result = await response.json() as ApiResponse<KpiConfig>
|
|
|
|
|
|
if (result.code !== 200) {
|
|
|
|
|
|
throw new Error(result.message || '配置KPI阈值失败')
|
|
|
|
|
|
}
|
|
|
|
|
|
return result.data
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 获取KPI阈值配置
|
|
|
|
|
|
*/
|
|
|
|
|
|
export async function getKpiConfig(): Promise<KpiConfig[]> {
|
|
|
|
|
|
const response = await authFetch(`${apiBaseUrl}/dashboard/kpis/config`)
|
|
|
|
|
|
const result = await response.json() as ApiResponse<KpiConfig[]>
|
|
|
|
|
|
if (result.code !== 200) {
|
|
|
|
|
|
throw new Error(result.message || '获取KPI阈值配置失败')
|
|
|
|
|
|
}
|
|
|
|
|
|
return result.data
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-05 13:13:49 +08:00
|
|
|
|
export default {
|
|
|
|
|
|
getDashboard,
|
|
|
|
|
|
getKpis,
|
|
|
|
|
|
getActivitySummary,
|
2026-03-05 21:55:47 +08:00
|
|
|
|
getTodos,
|
|
|
|
|
|
exportDashboard,
|
|
|
|
|
|
exportKpis,
|
|
|
|
|
|
exportActivities,
|
2026-03-23 13:02:36 +08:00
|
|
|
|
downloadBlob,
|
|
|
|
|
|
getRealtimeData,
|
|
|
|
|
|
getHistoryData,
|
|
|
|
|
|
configKpi,
|
|
|
|
|
|
getKpiConfig
|
2026-03-05 13:13:49 +08:00
|
|
|
|
}
|