diff --git a/admin/src/views/Dashboard.vue b/admin/src/views/Dashboard.vue
index c3a193c..6b86301 100644
--- a/admin/src/views/Dashboard.vue
+++ b/admin/src/views/Dashboard.vue
@@ -40,15 +40,20 @@
{{ fmt(row.createdAt) }}
-
- {{ (row.openid || '-').slice(0, 12) }}
+
+ {{ row.userName || row.openid || '-' }}
-
+
+ {{ row.method || '-' }}
+
-
+
- {{ row.success ? '成功' : (row.failReason || '失败') }}
+
+ {{ row.success ? '成功' : (row.failReason || '失败') }}
+
+ {{ row.path || '-' }}
diff --git a/server/src/routes/admin.js b/server/src/routes/admin.js
index cc25cd6..85c2443 100755
--- a/server/src/routes/admin.js
+++ b/server/src/routes/admin.js
@@ -1193,7 +1193,7 @@ router.get('/dashboard-v2', requirePermission('dashboard:read'), async (req, res
const [
totalUsers, newUsers7d, totalKnowledge, approvedKnowledge, withQuiz,
totalTrends, trendsWithExplain, totalFeedbacks, pendingFeedbacks, totalOrders, paidOrders,
- totalLits, litUsers, recentLogins, litByDimAgg, aiStatsRaw
+ totalLits, litUsers, recentLogins, recentVisits, litByDimAgg, aiStatsRaw
] = await Promise.all([
User.countDocuments({}),
User.countDocuments({ createdAt: { $gte: new Date(Date.now() - 7 * 86400000) } }),
@@ -1208,7 +1208,8 @@ router.get('/dashboard-v2', requirePermission('dashboard:read'), async (req, res
Order.countDocuments({ status: 'paid' }),
KnowledgeLit.countDocuments({}),
KnowledgeLit.distinct('openid'),
- LoginLog.find({}).sort({ createdAt: -1 }).limit(10).lean(),
+ LoginLog.find({}).sort({ createdAt: -1 }).limit(10).populate('userId', 'nickName').lean(),
+ VisitLog.find({}).sort({ createdAt: -1 }).limit(10).lean(),
KnowledgeLit.aggregate([{ $group: { _id: '$dim', count: { $sum: 1 } } }]),
AIChatQuota.aggregate([{ $group: { _id: null, used: { $sum: '$usedQuota' }, users: { $sum: 1 } } }]),
])
@@ -1230,16 +1231,34 @@ router.get('/dashboard-v2', requirePermission('dashboard:read'), async (req, res
aiChatUsed: ai.used, aiChatUsers: ai.users,
},
litByDim: Object.entries(litByDim).map(([dim, count]) => ({ dim: Number(dim), name: DIM_NAMES[dim], count })),
- recentLogins: recentLogins.map(l => ({
- openid: l.openid,
- type: l.type,
- method: l.method,
- ip: l.ip,
- success: l.success,
- failReason: l.failReason,
- userAgent: (l.userAgent || '').slice(0, 80),
- createdAt: l.createdAt,
- })),
+ recentLogins: [
+ // 登录记录(显示昵称)
+ ...recentLogins.map(l => ({
+ kind: 'login',
+ createdAt: l.createdAt,
+ userName: l.userId?.nickName || l.openid,
+ openid: l.openid,
+ type: l.type === 'register' ? '注册' : '登录',
+ method: l.method === 'wechat_miniapp' ? '微信小程序' : (l.method || ''),
+ ip: l.ip,
+ success: l.success,
+ failReason: l.failReason,
+ })),
+ // 访问埋点(H5 / 小程序 / 直接访问)
+ ...recentVisits.map(v => ({
+ kind: 'visit',
+ createdAt: v.createdAt,
+ userName: v.source,
+ openid: '',
+ type: '访问',
+ method: [v.os, v.browser].filter(Boolean).join(' / ') || v.device || '',
+ ip: v.ip,
+ path: v.path,
+ success: true,
+ })),
+ ]
+ .sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt))
+ .slice(0, 10),
})
} catch (error) {
logger.error('获取增强看板失败:', error)