diff --git a/packages/analytics/src/controllers/index.js b/packages/analytics/src/controllers/index.js
index 77e736b..8557cba 100644
--- a/packages/analytics/src/controllers/index.js
+++ b/packages/analytics/src/controllers/index.js
@@ -1,5 +1,5 @@
import { userCount } from '../models/users.js'
-import { totalQuests, totalCompleted } from '../models/profiles.js'
+import { totalQuests, totalCompleted } from '../models/quests.js'
// eslint-disable-next-line import/prefer-default-export
export async function homeController(req, res) {
diff --git a/packages/analytics/src/controllers/quests.js b/packages/analytics/src/controllers/quests.js
new file mode 100644
index 0000000..e11dc39
--- /dev/null
+++ b/packages/analytics/src/controllers/quests.js
@@ -0,0 +1,7 @@
+import { questList } from '../models/quests.js'
+
+// eslint-disable-next-line import/prefer-default-export
+export async function questListController(req, res) {
+ const quests = await questList()
+ res.render('quests', { quests })
+}
diff --git a/packages/analytics/src/models/profiles.js b/packages/analytics/src/models/profiles.js
deleted file mode 100644
index cb95ff1..0000000
--- a/packages/analytics/src/models/profiles.js
+++ /dev/null
@@ -1,62 +0,0 @@
-/* eslint-disable object-shorthand */
-/* eslint-disable func-names */
-import { UserProfile } from '@linux-odyssey/models'
-
-export function totalQuests() {
- return UserProfile.aggregate([
- {
- $project: {
- _id: 0,
- progress: { $objectToArray: '$progress' },
- },
- },
- {
- $unwind: '$progress',
- },
- {
- $group: {
- _id: null,
- totalCount: { $sum: 1 },
- },
- },
- ]).then((results) => {
- if (results.length === 0) {
- throw new Error('No documents found')
- }
- return results[0].totalCount
- })
-}
-
-export function totalCompleted() {
- return UserProfile.aggregate([
- {
- $project: {
- _id: 0,
- progress: { $objectToArray: '$progress' },
- },
- },
- {
- $unwind: '$progress',
- },
- {
- $match: {
- 'progress.v.completed': true,
- },
- },
- {
- $group: {
- _id: null,
- totalCount: { $sum: 1 },
- },
- },
- ]).then((results) => {
- if (results.length === 0) {
- throw new Error('No documents found')
- }
- return results[0].totalCount
- })
-}
-
-export function userProfileList() {
- return UserProfile.find()
-}
diff --git a/packages/analytics/src/models/quests.js b/packages/analytics/src/models/quests.js
new file mode 100644
index 0000000..9acb2cb
--- /dev/null
+++ b/packages/analytics/src/models/quests.js
@@ -0,0 +1,114 @@
+/* eslint-disable object-shorthand */
+/* eslint-disable func-names */
+import { UserProfile, Quest } from '@linux-odyssey/models'
+
+export function totalQuests() {
+ return UserProfile.aggregate([
+ {
+ $project: {
+ _id: 0,
+ progress: { $objectToArray: '$progress' },
+ },
+ },
+ {
+ $unwind: '$progress',
+ },
+ {
+ $group: {
+ _id: null,
+ totalCount: { $sum: 1 },
+ },
+ },
+ ]).then((results) => {
+ if (results.length === 0) {
+ throw new Error('No documents found')
+ }
+ return results[0].totalCount
+ })
+}
+
+export function totalCompleted() {
+ return UserProfile.aggregate([
+ {
+ $project: {
+ _id: 0,
+ progress: { $objectToArray: '$progress' },
+ },
+ },
+ {
+ $unwind: '$progress',
+ },
+ {
+ $match: {
+ 'progress.v.completed': true,
+ },
+ },
+ {
+ $group: {
+ _id: null,
+ totalCount: { $sum: 1 },
+ },
+ },
+ ]).then((results) => {
+ if (results.length === 0) {
+ throw new Error('No documents found')
+ }
+ return results[0].totalCount
+ })
+}
+
+export function questList() {
+ return UserProfile.aggregate([
+ {
+ $project: {
+ progress: {
+ $objectToArray: '$progress',
+ },
+ },
+ },
+ {
+ $unwind: '$progress',
+ },
+ {
+ $group: {
+ _id: '$progress.v.quest',
+ started: {
+ $sum: 1,
+ },
+ completed: {
+ $sum: {
+ $cond: {
+ if: { $eq: ['$progress.v.completed', true] },
+ then: 1,
+ else: 0,
+ },
+ },
+ },
+ },
+ },
+ {
+ $project: {
+ _id: 1,
+ started: 1,
+ completed: 1,
+ completedRate: {
+ $cond: {
+ if: { $eq: ['$started', 0] },
+ then: 0,
+ else: {
+ $round: [
+ { $multiply: [{ $divide: ['$completed', '$started'] }, 100] },
+ 2,
+ ],
+ },
+ },
+ },
+ },
+ },
+ {
+ $sort: {
+ _id: 1, // 按任务ID升序排序
+ },
+ },
+ ])
+}
diff --git a/packages/analytics/src/router.js b/packages/analytics/src/router.js
index f5a458b..9ef6ba6 100644
--- a/packages/analytics/src/router.js
+++ b/packages/analytics/src/router.js
@@ -2,6 +2,7 @@ import { Router } from 'express'
import { homeController } from './controllers/index.js'
import { userListController } from './controllers/users.js'
+import { questListController } from './controllers/quests.js'
import { commandListController } from './controllers/commands.js'
import {
sessionDetailController,
@@ -12,6 +13,7 @@ const router = Router()
router.get('/', homeController)
router.get('/users', userListController)
+router.get('/quests', questListController)
router.get('/commands', commandListController)
router.get('/sessions', sessionListController)
router.get('/sessions/:id', sessionDetailController)
diff --git a/packages/analytics/views/layouts/main.handlebars b/packages/analytics/views/layouts/main.handlebars
index e269d7b..6306555 100644
--- a/packages/analytics/views/layouts/main.handlebars
+++ b/packages/analytics/views/layouts/main.handlebars
@@ -8,6 +8,7 @@
diff --git a/packages/analytics/views/quests.handlebars b/packages/analytics/views/quests.handlebars
new file mode 100644
index 0000000..6107a76
--- /dev/null
+++ b/packages/analytics/views/quests.handlebars
@@ -0,0 +1,18 @@
+Quests
+
+
+
+ | Id |
+ Started |
+ Completed |
+ Completed Rate |
+
+ {{#each quests}}
+
+ | {{_id}} |
+ {{started}} |
+ {{completed}} |
+ {{completedRate}} |
+
+ {{/each}}
+
\ No newline at end of file
diff --git a/packages/analytics/views/userDetail.handlebars b/packages/analytics/views/userDetail.handlebars
new file mode 100644
index 0000000..e69de29
diff --git a/packages/analytics/views/users.handlebars b/packages/analytics/views/users.handlebars
index c2b73f2..fcbedf7 100644
--- a/packages/analytics/views/users.handlebars
+++ b/packages/analytics/views/users.handlebars
@@ -3,20 +3,20 @@
| Username |
- Email |
- Registration Method |
- Registration Time |
- Sessions Count |
Last Activity |
+ Sessions Count |
+ Email |
+ Registration Time |
+ Registration Method |
{{#each users}}
- | {{username}} |
- {{email}} |
- {{method}} |
- {{createdAt}} |
- {{sessionCount}} |
+ {{username}} |
{{lastActivityAt}} |
+ {{sessionCount}} |
+ {{email}} |
+ {{createdAt}} |
+ {{method}} |
{{/each}}