diff --git a/frontend/src/components/analytics/RankBarList.vue b/frontend/src/components/analytics/RankBarList.vue new file mode 100644 index 0000000..b15b4e4 --- /dev/null +++ b/frontend/src/components/analytics/RankBarList.vue @@ -0,0 +1,114 @@ + + + + + {{ emptyText }} + + + {{ idx + 1 }} + + {{ it[labelKey] }} + + + + + {{ it[valueKey] }} + + + + + + diff --git a/frontend/src/components/analytics/StatCard.vue b/frontend/src/components/analytics/StatCard.vue new file mode 100644 index 0000000..6faf493 --- /dev/null +++ b/frontend/src/components/analytics/StatCard.vue @@ -0,0 +1,129 @@ + + + + + + {{ label }} + ? + + + + {{ value }} + {{ unit }} + + + {{ trendArrow(trend) }} + 环比 {{ Math.abs(trend).toFixed(1) }}% + + + + + {{ s.label }} + {{ s.value }}{{ s.unit }} + + + + + + diff --git a/frontend/src/components/analytics/TrendChart.vue b/frontend/src/components/analytics/TrendChart.vue new file mode 100644 index 0000000..04f3ce8 --- /dev/null +++ b/frontend/src/components/analytics/TrendChart.vue @@ -0,0 +1,281 @@ + + + + + + + + + + {{ t.label }} + + + {{ t.label }} + + + + + + + + + + + + + + + + {{ tooltip.label }} + + + {{ it.name }} + {{ it.value }} + + + + + + + {{ s.name }} + + + + + + diff --git a/frontend/src/composables/useAnalytics.js b/frontend/src/composables/useAnalytics.js new file mode 100644 index 0000000..e2dd894 --- /dev/null +++ b/frontend/src/composables/useAnalytics.js @@ -0,0 +1,74 @@ +import { ref } from 'vue' +import { request } from '@/api/client' + +export const RANGE_OPTIONS = [ + { code: '1h', label: '近1小时' }, + { code: '12h', label: '近12小时' }, + { code: '24h', label: '近24小时' }, + { code: '7d', label: '近7天' }, +] + +function emptyBusiness() { + return { + range: null, + kpis: { + question_count: 0, + active_user_count: 0, + prev_active_user_count: 0, + user_delta_pct: null, + avg_questions_per_user: 0, + avg_latency_ms: 0, + success_count: 0, + success_ratio: 0, + fail_count: 0, + fail_ratio: 0, + }, + trend: [], + top_questions: [], + } +} + +function emptyResources() { + return { + range: null, + kpis: { + document_count: 0, + total_tokens: 0, + total_pu: 0, + api_call_count: 0, + api_success_ratio: 0, + avg_api_latency_ms: 0, + }, + token_trend: [], + top_documents: [], + } +} + +export function useAnalytics() { + const business = ref(emptyBusiness()) + const resources = ref(emptyResources()) + const loading = ref(false) + const error = ref('') + + async function loadBusiness(rangeCode) { + business.value = await request(`/api/stats/dashboard/business?range=${encodeURIComponent(rangeCode)}`) + } + + async function loadResources(rangeCode) { + resources.value = await request(`/api/stats/dashboard/resources?range=${encodeURIComponent(rangeCode)}`) + } + + async function loadAll(rangeCode) { + loading.value = true + error.value = '' + try { + await Promise.all([loadBusiness(rangeCode), loadResources(rangeCode)]) + } catch (err) { + error.value = err?.message || String(err) + } finally { + loading.value = false + } + } + + return { business, resources, loading, error, loadAll, loadBusiness, loadResources } +} diff --git a/frontend/src/router/index.js b/frontend/src/router/index.js index a1982c1..574b446 100644 --- a/frontend/src/router/index.js +++ b/frontend/src/router/index.js @@ -42,7 +42,7 @@ const routes = [ { path: '/analytics', name: 'analytics', - component: () => import('@/views/PlaceholderView.vue'), + component: () => import('@/views/AnalyticsView.vue'), meta: { title: '数据分析', subtitle: '使用量、热门问题、命中率等数据看板。', diff --git a/frontend/src/views/AnalyticsView.vue b/frontend/src/views/AnalyticsView.vue new file mode 100644 index 0000000..bd0842e --- /dev/null +++ b/frontend/src/views/AnalyticsView.vue @@ -0,0 +1,403 @@ + + + + + + + 数据报表 + 基于问答日志和 ADP 调用留痕的实时业务与资源指标。 + + + 业务看板 + 资源看板 + + + + + + {{ opt.label }} + + + 加载中… + 加载失败 + ↻ + + + + + + + + + + + + + + 问答趋势 + + 问答次数{{ trendKpis.asked }} + 成功次数/占比{{ trendKpis.success }}/{{ trendKpis.successPct }}% + 失败次数/占比{{ trendKpis.failed }}/{{ trendKpis.failedPct }}% + + + + + + + + 高频提问 Top10 + {{ rangeLabel }} · 按问题原文聚合 + + + + + + + + + + + + + + + + Tokens / PU 消耗趋势 + {{ rangeLabel }} + + + + + + + 热门引用文档 Top10 + 按被引用次数排序 + + + + + + + + +
基于问答日志和 ADP 调用留痕的实时业务与资源指标。