fix: 看板最近访问记录合并登录+访问埋点(显示昵称/来源/终端/路径),修复只显示登录日志看不到最新访问的问题
This commit is contained in:
@@ -40,15 +40,20 @@
|
|||||||
<el-table-column prop="createdAt" label="时间" width="160">
|
<el-table-column prop="createdAt" label="时间" width="160">
|
||||||
<template #default="{ row }">{{ fmt(row.createdAt) }}</template>
|
<template #default="{ row }">{{ fmt(row.createdAt) }}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="openid" label="用户" width="150">
|
<el-table-column label="用户/来源" width="130">
|
||||||
<template #default="{ row }">{{ (row.openid || '-').slice(0, 12) }}</template>
|
<template #default="{ row }">{{ row.userName || row.openid || '-' }}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="type" label="类型" width="70" />
|
<el-table-column prop="type" label="类型" width="70" />
|
||||||
<el-table-column prop="method" label="方式" width="110" />
|
<el-table-column label="方式/终端" width="120">
|
||||||
|
<template #default="{ row }">{{ row.method || '-' }}</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column prop="ip" label="IP" width="120" />
|
<el-table-column prop="ip" label="IP" width="120" />
|
||||||
<el-table-column label="结果">
|
<el-table-column label="结果 / 路径" min-width="150" show-overflow-tooltip>
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-tag :type="row.success ? 'success' : 'danger'" size="small">{{ row.success ? '成功' : (row.failReason || '失败') }}</el-tag>
|
<template v-if="row.kind === 'login'">
|
||||||
|
<el-tag :type="row.success ? 'success' : 'danger'" size="small">{{ row.success ? '成功' : (row.failReason || '失败') }}</el-tag>
|
||||||
|
</template>
|
||||||
|
<template v-else>{{ row.path || '-' }}</template>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|||||||
+31
-12
@@ -1193,7 +1193,7 @@ router.get('/dashboard-v2', requirePermission('dashboard:read'), async (req, res
|
|||||||
const [
|
const [
|
||||||
totalUsers, newUsers7d, totalKnowledge, approvedKnowledge, withQuiz,
|
totalUsers, newUsers7d, totalKnowledge, approvedKnowledge, withQuiz,
|
||||||
totalTrends, trendsWithExplain, totalFeedbacks, pendingFeedbacks, totalOrders, paidOrders,
|
totalTrends, trendsWithExplain, totalFeedbacks, pendingFeedbacks, totalOrders, paidOrders,
|
||||||
totalLits, litUsers, recentLogins, litByDimAgg, aiStatsRaw
|
totalLits, litUsers, recentLogins, recentVisits, litByDimAgg, aiStatsRaw
|
||||||
] = await Promise.all([
|
] = await Promise.all([
|
||||||
User.countDocuments({}),
|
User.countDocuments({}),
|
||||||
User.countDocuments({ createdAt: { $gte: new Date(Date.now() - 7 * 86400000) } }),
|
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' }),
|
Order.countDocuments({ status: 'paid' }),
|
||||||
KnowledgeLit.countDocuments({}),
|
KnowledgeLit.countDocuments({}),
|
||||||
KnowledgeLit.distinct('openid'),
|
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 } } }]),
|
KnowledgeLit.aggregate([{ $group: { _id: '$dim', count: { $sum: 1 } } }]),
|
||||||
AIChatQuota.aggregate([{ $group: { _id: null, used: { $sum: '$usedQuota' }, users: { $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,
|
aiChatUsed: ai.used, aiChatUsers: ai.users,
|
||||||
},
|
},
|
||||||
litByDim: Object.entries(litByDim).map(([dim, count]) => ({ dim: Number(dim), name: DIM_NAMES[dim], count })),
|
litByDim: Object.entries(litByDim).map(([dim, count]) => ({ dim: Number(dim), name: DIM_NAMES[dim], count })),
|
||||||
recentLogins: recentLogins.map(l => ({
|
recentLogins: [
|
||||||
openid: l.openid,
|
// 登录记录(显示昵称)
|
||||||
type: l.type,
|
...recentLogins.map(l => ({
|
||||||
method: l.method,
|
kind: 'login',
|
||||||
ip: l.ip,
|
createdAt: l.createdAt,
|
||||||
success: l.success,
|
userName: l.userId?.nickName || l.openid,
|
||||||
failReason: l.failReason,
|
openid: l.openid,
|
||||||
userAgent: (l.userAgent || '').slice(0, 80),
|
type: l.type === 'register' ? '注册' : '登录',
|
||||||
createdAt: l.createdAt,
|
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) {
|
} catch (error) {
|
||||||
logger.error('获取增强看板失败:', error)
|
logger.error('获取增强看板失败:', error)
|
||||||
|
|||||||
Reference in New Issue
Block a user