From b09d23f97fec14ad7577fd91356d2d25aaaa9c9d Mon Sep 17 00:00:00 2001 From: RockYang Date: Wed, 2 Aug 2023 16:37:47 +0800 Subject: [PATCH] feat: the dashboard page is ready for admin console --- api/handler/admin/dashboard_handler.go | 55 ++++++++++ api/main.go | 5 + web/package-lock.json | 29 +++++- web/src/components/admin/AdminSidebar.vue | 2 +- web/src/router.js | 10 +- web/src/views/admin/Dashboard.vue | 120 ++++++++++++++++++++++ web/src/views/admin/Welcome.vue | 25 ----- 7 files changed, 214 insertions(+), 32 deletions(-) create mode 100644 api/handler/admin/dashboard_handler.go create mode 100644 web/src/views/admin/Dashboard.vue delete mode 100644 web/src/views/admin/Welcome.vue diff --git a/api/handler/admin/dashboard_handler.go b/api/handler/admin/dashboard_handler.go new file mode 100644 index 00000000..b219ca39 --- /dev/null +++ b/api/handler/admin/dashboard_handler.go @@ -0,0 +1,55 @@ +package admin + +import ( + "chatplus/core" + "chatplus/handler" + "chatplus/store/model" + "chatplus/utils/resp" + "github.com/gin-gonic/gin" + "gorm.io/gorm" + "time" +) + +type DashboardHandler struct { + handler.BaseHandler + db *gorm.DB +} + +func NewDashboardHandler(app *core.AppServer, db *gorm.DB) *DashboardHandler { + h := DashboardHandler{db: db} + h.App = app + return &h +} + +type statsVo struct { + Users int64 `json:"users"` + Chats int64 `json:"chats"` + Tokens int64 `json:"tokens"` +} + +func (h *DashboardHandler) Stats(c *gin.Context) { + stats := statsVo{} + // new users statistic + var userCount int64 + now := time.Now() + zeroTime := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()) + res := h.db.Model(&model.User{}).Where("created_at > ?", zeroTime).Count(&userCount) + if res.Error == nil { + stats.Users = userCount + } + + // new chats statistic + var chatCount int64 + res = h.db.Model(&model.ChatItem{}).Where("created_at > ?", zeroTime).Count(&chatCount) + if res.Error == nil { + stats.Chats = chatCount + } + + // tokens took stats + var tokenCount int64 + res = h.db.Model(&model.HistoryMessage{}).Select("sum(tokens) as tokens_total").Where("created_at > ?", zeroTime).Scan(&tokenCount) + if res.Error == nil { + stats.Tokens = tokenCount + } + resp.SUCCESS(c, stats) +} diff --git a/api/main.go b/api/main.go index 77f26705..cc77da2e 100644 --- a/api/main.go +++ b/api/main.go @@ -141,6 +141,7 @@ func main() { fx.Provide(admin.NewUserHandler), fx.Provide(admin.NewChatRoleHandler), fx.Provide(admin.NewRewardHandler), + fx.Provide(admin.NewDashboardHandler), // 创建服务 fx.Provide(service.NewAliYunSmsService), @@ -231,6 +232,10 @@ func main() { group := s.Engine.Group("/api/admin/reward/") group.GET("list", h.List) }), + fx.Invoke(func(s *core.AppServer, h *admin.DashboardHandler) { + group := s.Engine.Group("/api/admin/dashboard/") + group.GET("stats", h.Stats) + }), fx.Invoke(func(s *core.AppServer, db *gorm.DB) { err := s.Run(db) diff --git a/web/package-lock.json b/web/package-lock.json index e03388d5..a2ab92c4 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -25,7 +25,8 @@ "sortablejs": "^1.15.0", "vant": "^4.5.0", "vue": "^3.2.13", - "vue-router": "^4.0.15" + "vue-router": "^4.0.15", + "vue-schart": "^2.0.0" }, "devDependencies": { "@babel/core": "7.18.6", @@ -9366,6 +9367,11 @@ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "dev": true }, + "node_modules/schart.js": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/schart.js/-/schart.js-3.0.4.tgz", + "integrity": "sha512-uylb2u9rrHX1jyAuSAJUQON8XTfyDKI9kWj1J3fUlCQCkLVZ4HG4+IiV8qm//Z71dqvLI78QZ/fCBw0reB22Zw==" + }, "node_modules/schema-utils": { "version": "2.7.1", "resolved": "https://registry.npmmirror.com/schema-utils/-/schema-utils-2.7.1.tgz", @@ -10694,6 +10700,14 @@ "vue": "^3.2.0" } }, + "node_modules/vue-schart": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/vue-schart/-/vue-schart-2.0.0.tgz", + "integrity": "sha512-qAu3e5wfMcq26wK1xeHExEWfGpnjfoN1R/9QXblNi+AsU/p52X7tTwhi+Fw7H/otfEufhEY2X7z7emaoF4QO+g==", + "dependencies": { + "schart.js": "^3.0.0" + } + }, "node_modules/vue-style-loader": { "version": "4.1.3", "resolved": "https://registry.npmmirror.com/vue-style-loader/-/vue-style-loader-4.1.3.tgz", @@ -18621,6 +18635,11 @@ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "dev": true }, + "schart.js": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/schart.js/-/schart.js-3.0.4.tgz", + "integrity": "sha512-uylb2u9rrHX1jyAuSAJUQON8XTfyDKI9kWj1J3fUlCQCkLVZ4HG4+IiV8qm//Z71dqvLI78QZ/fCBw0reB22Zw==" + }, "schema-utils": { "version": "2.7.1", "resolved": "https://registry.npmmirror.com/schema-utils/-/schema-utils-2.7.1.tgz", @@ -19686,6 +19705,14 @@ "@vue/devtools-api": "^6.0.0" } }, + "vue-schart": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/vue-schart/-/vue-schart-2.0.0.tgz", + "integrity": "sha512-qAu3e5wfMcq26wK1xeHExEWfGpnjfoN1R/9QXblNi+AsU/p52X7tTwhi+Fw7H/otfEufhEY2X7z7emaoF4QO+g==", + "requires": { + "schart.js": "^3.0.0" + } + }, "vue-style-loader": { "version": "4.1.3", "resolved": "https://registry.npmmirror.com/vue-style-loader/-/vue-style-loader-4.1.3.tgz", diff --git a/web/src/components/admin/AdminSidebar.vue b/web/src/components/admin/AdminSidebar.vue index 70269953..2b14e6df 100644 --- a/web/src/components/admin/AdminSidebar.vue +++ b/web/src/components/admin/AdminSidebar.vue @@ -71,7 +71,7 @@ httpGet('/api/admin/config/get?key=system').then(res => { const items = [ { icon: 'home', - index: '/admin/welcome', + index: '/admin/dashboard', title: '仪表盘', }, { diff --git a/web/src/router.js b/web/src/router.js index 8d8b6ed0..67d150b6 100644 --- a/web/src/router.js +++ b/web/src/router.js @@ -35,15 +35,15 @@ const routes = [ { name: 'admin', path: '/admin', - redirect: '/admin/welcome', + redirect: '/admin/dashboard', component: () => import("@/views/admin/Home.vue"), meta: {title: 'ChatGPT-Plus 管理后台'}, children: [ { - path: '/admin/welcome', - name: 'admin-home', - meta: {title: '系统首页'}, - component: () => import('@/views/admin/Welcome.vue'), + path: '/admin/dashboard', + name: 'admin-dashboard', + meta: {title: '仪表盘'}, + component: () => import('@/views/admin/Dashboard.vue'), }, { path: '/admin/system', diff --git a/web/src/views/admin/Dashboard.vue b/web/src/views/admin/Dashboard.vue new file mode 100644 index 00000000..dc785a7f --- /dev/null +++ b/web/src/views/admin/Dashboard.vue @@ -0,0 +1,120 @@ + + + + + diff --git a/web/src/views/admin/Welcome.vue b/web/src/views/admin/Welcome.vue deleted file mode 100644 index 866f43e4..00000000 --- a/web/src/views/admin/Welcome.vue +++ /dev/null @@ -1,25 +0,0 @@ - - - - -