feat: 普通用户用量统计 + 管理后台用量明细

后端
- /api/usage/stats:当前用户按日聚合统计(请求数/输入/输出/缓存 tokens/费用)
- /api/usage/logs:当前用户用量明细分页
- /api/admin/usage/logs:全量明细(分页 + 协议/状态/模型/用户筛选 + 用户名关联)
- /api/admin/usage/summary:全量汇总(按用户分组)
- dao:UsageFilter 支持筛选分页;DailyUsageDAO.ListAll
- 路由加固:新增 middleware.AdminOnly,既有 /api/admin/* 全部迁移到
  带管理员角色校验的分组(此前登录即可访问,属安全隐患)

前端
- 普通用户「用量统计」页:统计卡片 + 纯 CSS 每日请求量条形图 + 明细表格分页
- 管理后台「用量明细」页:汇总卡片 + 协议/状态/模型/用户筛选 +
  明细表格 + 原始请求/响应查看弹窗(记录开关开启时)
- stores/usage.ts 与类型定义;控制台/管理菜单挂载
This commit is contained in:
Sakurasan
2026-09-01 02:55:55 +08:00
parent f9e9a1572f
commit a259e5eb4d
9 changed files with 955 additions and 23 deletions
+35 -23
View File
@@ -113,34 +113,46 @@ func SetRouter(cfg *config.Config, db *gorm.DB, web *embed.FS) {
apiGroup.PUT("/models/:id", apiHandler.UpdateModel)
apiGroup.DELETE("/models/:id", apiHandler.DeleteModel)
// 用户自身用量统计
apiGroup.GET("/usage/stats", apiHandler.MyUsageStats)
apiGroup.GET("/usage/logs", apiHandler.MyUsageLogs)
}
// Admin API (requires admin role)
adminGroup := r.Group("/api/admin", middleware.Auth(db), middleware.AdminOnly())
{
// Admin channel management (enhanced)
apiGroup.GET("/admin/channels", apiHandler.AdminChannels)
apiGroup.POST("/admin/channels", apiHandler.AdminCreateChannel)
apiGroup.PUT("/admin/channels/:id", apiHandler.AdminUpdateChannel)
apiGroup.DELETE("/admin/channels/:id", apiHandler.AdminDeleteChannel)
apiGroup.POST("/admin/channels/:id/test", apiHandler.AdminTestChannel)
apiGroup.GET("/admin/channels/:id/models/remote", apiHandler.AdminChannelRemoteModels)
apiGroup.GET("/admin/channels/:id/models", apiHandler.AdminChannelModels)
apiGroup.POST("/admin/channels/:id/models", apiHandler.AdminChannelAddModel)
apiGroup.PATCH("/admin/channels/:id/models/:bid", apiHandler.AdminChannelUpdateModel)
apiGroup.DELETE("/admin/channels/:id/models/:bid", apiHandler.AdminChannelDeleteModel)
adminGroup.GET("/channels", apiHandler.AdminChannels)
adminGroup.POST("/channels", apiHandler.AdminCreateChannel)
adminGroup.PUT("/channels/:id", apiHandler.AdminUpdateChannel)
adminGroup.DELETE("/channels/:id", apiHandler.AdminDeleteChannel)
adminGroup.POST("/channels/:id/test", apiHandler.AdminTestChannel)
adminGroup.GET("/channels/:id/models/remote", apiHandler.AdminChannelRemoteModels)
adminGroup.GET("/channels/:id/models", apiHandler.AdminChannelModels)
adminGroup.POST("/channels/:id/models", apiHandler.AdminChannelAddModel)
adminGroup.PATCH("/channels/:id/models/:bid", apiHandler.AdminChannelUpdateModel)
adminGroup.DELETE("/channels/:id/models/:bid", apiHandler.AdminChannelDeleteModel)
// Admin model management (enhanced)
apiGroup.GET("/admin/models", apiHandler.AdminModels)
apiGroup.DELETE("/admin/models/unused", apiHandler.AdminDeleteUnusedModels)
apiGroup.POST("/admin/models", apiHandler.AdminCreateModel)
apiGroup.PUT("/admin/models/:id", apiHandler.AdminUpdateModel)
apiGroup.DELETE("/admin/models/:id", apiHandler.AdminDeleteModel)
apiGroup.POST("/admin/models/:id/bindings", apiHandler.AdminCreateModelBinding)
apiGroup.DELETE("/admin/models/:id/bindings/:bid", apiHandler.AdminDeleteModelBinding)
adminGroup.GET("/models", apiHandler.AdminModels)
adminGroup.DELETE("/models/unused", apiHandler.AdminDeleteUnusedModels)
adminGroup.POST("/models", apiHandler.AdminCreateModel)
adminGroup.PUT("/models/:id", apiHandler.AdminUpdateModel)
adminGroup.DELETE("/models/:id", apiHandler.AdminDeleteModel)
adminGroup.POST("/models/:id/bindings", apiHandler.AdminCreateModelBinding)
adminGroup.DELETE("/models/:id/bindings/:bid", apiHandler.AdminDeleteModelBinding)
// Admin system config
apiGroup.GET("/admin/config", apiHandler.AdminGetConfig)
apiGroup.PUT("/admin/config", apiHandler.AdminUpdateConfig)
apiGroup.GET("/admin/config/registration", apiHandler.AdminGetRegistration)
apiGroup.PUT("/admin/config/registration", apiHandler.AdminUpdateRegistration)
apiGroup.GET("/admin/config/password-login", apiHandler.AdminGetPasswordLogin)
apiGroup.PUT("/admin/config/password-login", apiHandler.AdminUpdatePasswordLogin)
adminGroup.GET("/config", apiHandler.AdminGetConfig)
adminGroup.PUT("/config", apiHandler.AdminUpdateConfig)
adminGroup.GET("/config/registration", apiHandler.AdminGetRegistration)
adminGroup.PUT("/config/registration", apiHandler.AdminUpdateRegistration)
adminGroup.GET("/config/password-login", apiHandler.AdminGetPasswordLogin)
adminGroup.PUT("/config/password-login", apiHandler.AdminUpdatePasswordLogin)
// Admin usage
adminGroup.GET("/usage/logs", apiHandler.AdminUsageLogs)
adminGroup.GET("/usage/summary", apiHandler.AdminUsageSummary)
}
// LLM proxy routes