v0.0.17
✨ New Features
Go backend
- New admin dashboard aggregate layer (
model/admin_dashboard.go, issue #15):GetAdminDashboardOverview(rawRange): one-shot KPI aggregation — users (total / today / 7d / 30d / active / disabled / deleted / today-ratio), resources (tokens / channels / plans / redemptions / subscriptions with enabled/active counts), quota (today / 7d / 30d / total), revenue (total / top-up / subscription / refund). Six sections in one round-trip; one SQL per section, no N+1.GetAdminTopUsers(rawRange, limit): active-user leaderboard (consumed logs in window +request_count > 0, sorted by request count desc then quota desc); current plan names batch-embedded via a singleWHERE IN.GetAdminModelDistribution(rawRange, topN)+AdminModelDistribution: whole-site top-N models by quota + 7-day series for stacked bar (later superseded by/charts; see 🔧 Refactor).GetAdminUsageDetails(rawRange, topN)+AdminUsageDetails: top-N model × per-day breakdown for the "usage details" table (later superseded by/charts).ParseAdminDashboardRange/ParseAdminChartsRange: unified range preset parsing (today/7d/30d/all); the latter emits a day-aligned window and capsallto the last 30 days to keep responses bounded.SearchAdminLogsByDayAndModel(start, end): whole-siteday × modelaggregate. Structurally identical tomodel.SearchLogsByDayAndModel(used by/api/user/dashboard) but without theuser_idfilter — the frontend can reuse the same chart-building logic.
- New
/api/admin/dashboard/chartsendpoint (controller/admin/dashboard.go::GetCharts,router/api.go, AdminAuth):- Returns
[]*model.LogStatisticwith fieldsDay / ModelName / RequestCount / Quota / PromptTokens / CompletionTokens— byte-for-byte the same shape as/api/user/dashboard. - One payload powers every chart on the admin page: requests/quota/tokens line charts, stacked model-distribution bar, and usage-details table.
- Returns
- Dashboard test suite (
model/admin_dashboard_test.go):TestParseAdminDashboardRange: covers the four range boundaries.TestParseAdminChartsRange: validates day-aligned windows and day counts.TestGetAdminDashboardOverview_Smoke: covers all six aggregate sections +active_7d.TestGetAdminTopUsers:request_count > 0filter + sorting + plan-name embedding.TestSearchAdminLogsByDayAndModel:[]LogStatisticshape + multi-user merging + field completeness.- Earlier
TestGetAdminModelDistribution/TestGetAdminUsageDetailsremoved along with the API refactor.
Frontend (web/default-pro/)
- New admin operations dashboard page
views/admin/AdminDashboard.vue(issue #15):- Top welcome bar: title "运营数据" + subtitle "全站 KPI · 趋势 · 排行 — YYYY-MM-DD" + right-aligned range radios (today / 7d / 30d / all) + last-refresh label + refresh button.
- Left column (16/24) — six panels:
- User KPIs: 8 stat cards (total / today / 7d / 30d / 7d-active / disabled / deleted / today-ratio) with arco icon + palette.
- Revenue (moved above Resources): 4 cards (total / top-up / subscription / refund) with footers.
- Resources / Usage: 5 clickable cards (tokens / channels / plans → /setting/plan / redemptions → /redemption / subscriptions).
- Token / Request Consumption + three line charts: 4 quota cards + divider + Requests / Quota / Tokens three 160px line charts (vue-echarts), Dashboard-style.
- Model Distribution (last 7 days): standalone full-width panel, stacked bar (top-8 models × 7 days) with scrollable bottom legend.
- Usage Details: table paginated 8 rows (date / model / requests / quota / tokens), dash-table styling.
- Right column (8/24):
- Ad placeholder: gradient blue→purple "AD" card.
- User Ranking: card-style (rank badge + username/email + requests/quota stats + plan tag), radio switches today/week/month.
- Announcements: 3-entry list.
- Changelog: 3-entry log.
- Resources: external links (docs + GitHub).
- Styling: all panel/grid/trend-cell/dash-table styles mirror Dashboard.vue (line-height / spacing / font-size consistent).
- New sidebar "数据" menu (
layouts/AdminLayout.vue, admin only):- Positioned above Channels, icon
icon-bar-chart, alongside Channels/Orders/Redemption/Users/Subscriptions/Settings. - Route
/admin/dashboardregistered inrouter/index.js;isAdminRouteallow-list extended withAdminDashboardso non-admins are redirected back to/dashboard.
- Positioned above Channels, icon
- New frontend API module
src/api/admin.js:adminApi.overview(range)→GET /api/admin/dashboard/overview.adminApi.topUsers(range, limit)→GET /api/admin/dashboard/top-users.adminApi.charts(range)→GET /api/admin/dashboard/charts(unified chart endpoint).adminApi.modelDistribution/adminApi.usageDetailsremoved in the refactor (replaced bycharts).
- New i18n keys (
src/i18n/locales.js,admin.*namespace, zh/en):- Page title
pageTitle: '运营数据' / 'Overview'. - 5 section titles:
sectionUsers / sectionRevenue / sectionResources / sectionQuota / sectionLeaderboard. - ~40 card labels (users / revenue / resources / quota / etc.).
- Range labels:
todayLabel: '今日' / 'Today',weekLabel: '本周' / 'This Week',monthLabel: '本月' / 'This Month', plusrangeToday/7d/30d/all. - Leaderboard:
sectionLeaderboard: '用户排行'and columnscolUsername/colRequestCount/colQuota/colBalance/colPlan. - Chart titles trimmed:
chartRequests: '请求量',chartQuota: '额度',chartTokens: 'Token',chartModelDist: '模型分布(近 7 日)'. - Announcement / changelog / resources / ad helper strings.
- Page title
- Dynamic page titles:
- Landing default title becomes
ONE-API-PRO—企业级AI API 网关(web/default-pro/index.html). - A
router.afterEachhook appends{menu}—ONE-API-PROper-route, e.g.控制台—ONE-API-PRO.
- Landing default title becomes
🐛 Bug Fixes
/api/*NoRoute no longer returns the misleading OpenAIinvalid_request_error(router/web.go):- Previously both
/v1/*and/api/*fell through toRelayNotFound, which produced an OpenAI-style 404 that looked like a relay routing issue. - Now only
/v1/*keeps the OpenAI error (relay clients rely on it); unmatched/api/*returns the standard{success:false, message:"接口不存在: METHOD PATH"}404 envelope.
- Previously both
- Fixed GORM column-inference mismatch on admin dashboard structs (
model/admin_dashboard.go):AdminDashboardUsers/AdminDashboardResources/AdminDashboardTopUserRowwere letting GORM infer the column as snake_case (New7d→new7d), which didn't match the SQL aliases (new_7d), so aggregates silently returned 0.- Explicit
gorm:"column:..."tags added; caught and fixed byTestGetAdminDashboardOverview_Smoke.
- Fixed Vue
<style scoped>not crossing component files: AdminDashboard referenced Dashboard.vue's.panel / .stat-grid / .trend-cell / .dash-tablestyles, but scoped CSS hashes are per-component. Inlined the actually-used styles into AdminDashboard's<style scoped>and removed the redundant.admin-dashboard { padding: … }, switching to.dashboard { display: flex; flex-direction: column; gap: 16px }to match Dashboard.vue. - Fixed invisible line on all-zero data:
yAxis.min = 0+max = maxV > 0 ? undefined : 1(old code hadmax = undefinedso auto-scale flattened the line);areaStyleopacity02→30;symbolSize = 6+itemStyle.borderWidth = 2to emphasize points. - Fixed
09-11label clipped at the right edge:grid.right: 16+xAxis.axisLabel.margin: 8+hideOverlap: false. - Fixed "today" missing from line charts:
AdminTrendPointusedomitempty, so days without data returned only{day}and the frontend readundefined. Replaced by a single[]LogStatisticpayload with a frontend-built N-day series that always includes today. - Fixed leftover
IconHistogram/IconRollbackreferences in AdminDashboard:npm run builddid not surface the issue (it crashed at runtime); replaced with the in-set namesIconBarChart/IconArrowFall. - Fixed UTC ↔ CST day-boundary drift: Go's
todayStart = now - (now%daySec)is UTC-aligned and SQLitestrftimeis UTC, so logs created around 00:00–08:00 CST fell into the previous UTC day. Tests now usetodayStart + 100sto align both representations on today.
🔧 Refactor
Go backend
- Chart data split out of the overview response:
- Removed
AdminTrendPoint/AdminDashboardTrends/aggregateTrends. AdminDashboardOverviewno longer carriesTrends(charts data moved to/charts).- Removed
AdminModelDistribution*/GetAdminModelDistributionandAdminUsageDetails*/GetAdminUsageDetails, plus their controller handlers and routes (/api/admin/dashboard/model-distribution,/api/admin/dashboard/usage-details). model/admin_dashboard.goshrinks by ~320 lines; unusedsort/timeimports dropped.
- Removed
- Unified response shape: a single
/chartsendpoint returns the same[]LogStatisticas/api/user/dashboard, so the frontend no longer needs three separate calls to assemble chart data.
Frontend
- AdminDashboard fully refactored: the model-distribution chart moved out of the trend row into its own full-width panel; the three line charts are now Requests / Quota / Tokens (matching Dashboard.vue).
adminApi.modelDistribution/adminApi.usageDetailsremoved;adminApi.chartsis the single source.AdminDashboard.vueadds four new computeds —chartData/daySeries/distModels/usageRows— that build the day series client-side and aggregate Top 8 models in JS.lineOptionnow reads fromchartData([{date, value}]) instead ofoverview.trends.modelBarOptionnow reads fromdistModels(client-side Top-N sort).- Usage-details table now reads from
usageRows(flat day×model rows, day desc + quota desc).
🚀 Performance / Ops
- Fixed
release-dockerworkflow arm64 emulatednpm installSIGILL (Dockerfile+.github/workflows/release-docker.yml):- Pre-build
web/build/in the release-docker job sodocker buildnever runsnpm installunder QEMU emulation (which was crashing on Node.js native binaries). - See
ci(release-docker): 预构建 web/build,避免 arm64 emulated npm install 触发 SIGILL.
- Pre-build
⚠️ Upgrade Notes
- Zero database migration: all new admin-dashboard fields are aggregate-response fields or new endpoints; no schema changes.
- Backend route changes (
router/api.go, admin route group):- Added
GET /api/admin/dashboard/charts(AdminAuth). - Removed
GET /api/admin/dashboard/model-distributionandGET /api/admin/dashboard/usage-details(replaced by/charts). - Any external monitor / script still hitting the old routes should switch to
/charts+ the frontend aggregation logic (or use/api/admin/dashboard/overviewfor KPIs).
- Added
- Backend binary must be restarted:
/chartsis a new route and only takes effect after the binary is rebuilt and the process restarted. - Frontend chunk cache: hard-refresh (Cmd+Shift+R) to load the new
AdminDashboardchunk; the old chunk may still call/usage-detailsand produce a 404. - Unmatched
/api/*error format change: after the upgrade, missing routes return{success:false, message:"接口不存在: GET /api/..."}(HTTP 404) instead of the OpenAI-style error — easier to localize. - Build & test:
go build ./...passes.go test ./model/ ./controller/ ./middleware/all green (3 new admin-dashboard tests plus existing coverage).- Frontend:
cd web/default-pro && npm run buildpasses.
- Page title changes: browser tab titles change from
One Api Pro——企业级 API 网关toONE-API-PRO—企业级AI API 网关, and admin pages show{menu}—ONE-API-PROdynamically. If any external monitor depends on the old title string, please update.