提交 399048a6 authored 作者: 王鹏飞's avatar 王鹏飞

chore: update

上级 78f4550b
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
"axios": "^1.13.0", "axios": "^1.13.0",
"cors": "^2.8.5", "cors": "^2.8.5",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"dayjs": "^1.11.19",
"dotenv": "^16.4.5", "dotenv": "^16.4.5",
"express": "^4.21.1", "express": "^4.21.1",
"mongoose": "^8.8.0", "mongoose": "^8.8.0",
...@@ -669,6 +670,12 @@ ...@@ -669,6 +670,12 @@
"node": "*" "node": "*"
} }
}, },
"node_modules/dayjs": {
"version": "1.11.19",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.19.tgz",
"integrity": "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==",
"license": "MIT"
},
"node_modules/debug": { "node_modules/debug": {
"version": "2.6.9", "version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
"axios": "^1.13.0", "axios": "^1.13.0",
"cors": "^2.8.5", "cors": "^2.8.5",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"dayjs": "^1.11.19",
"dotenv": "^16.4.5", "dotenv": "^16.4.5",
"express": "^4.21.1", "express": "^4.21.1",
"mongoose": "^8.8.0", "mongoose": "^8.8.0",
......
import mongoose from 'mongoose' import mongoose from 'mongoose'
import dayjs from 'dayjs'
// 最大存储大小(字符数) // 最大存储大小(字符数)
const MAX_BODY_SIZE = 2000 const MAX_BODY_SIZE = 2000
...@@ -92,9 +93,16 @@ const logSchema = new mongoose.Schema( ...@@ -92,9 +93,16 @@ const logSchema = new mongoose.Schema(
userAgent: String, userAgent: String,
ip: String, ip: String,
url: String, url: String,
createdAt: String,
updatedAt: String,
}, },
{ {
timestamps: true, timestamps: {
// 返回服务器本地时间格式的字符串:YYYY-MM-DD HH:mm:ss
currentTime: () => {
return dayjs().format('YYYY-MM-DD HH:mm:ss')
},
},
versionKey: false, versionKey: false,
} }
) )
...@@ -123,8 +131,9 @@ logSchema.pre('insertMany', function (next, docs) { ...@@ -123,8 +131,9 @@ logSchema.pre('insertMany', function (next, docs) {
next() next()
}) })
// TTL index: auto delete logs after 360 days // 注意:TTL 索引需要 Date 类型,但 createdAt 现在是字符串类型
logSchema.index({ createdAt: 1 }, { expireAfterSeconds: 360 * 24 * 60 * 60 }) // 如果需要自动删除功能,需要添加一个 Date 类型的字段用于 TTL,或者使用定时任务删除
// logSchema.index({ createdAt: 1 }, { expireAfterSeconds: 360 * 24 * 60 * 60 })
// Compound index for common queries // Compound index for common queries
logSchema.index({ type: 1, appName: 1, createdAt: -1 }) logSchema.index({ type: 1, appName: 1, createdAt: -1 })
......
import Log from './logs.model.js' import Log from './logs.model.js'
import dayjs from 'dayjs'
export const create = async (logData) => { export const create = async (logData) => {
const log = new Log(logData) const log = new Log(logData)
...@@ -21,8 +22,9 @@ export const query = async (filters = {}, options = {}) => { ...@@ -21,8 +22,9 @@ export const query = async (filters = {}, options = {}) => {
if (filters.userId) query.userId = filters.userId if (filters.userId) query.userId = filters.userId
if (filters.startTime || filters.endTime) { if (filters.startTime || filters.endTime) {
query.createdAt = {} query.createdAt = {}
if (filters.startTime) query.createdAt.$gte = new Date(filters.startTime) // createdAt 是字符串格式 YYYY-MM-DD HH:mm:ss,直接使用字符串比较
if (filters.endTime) query.createdAt.$lte = new Date(filters.endTime) if (filters.startTime) query.createdAt.$gte = filters.startTime
if (filters.endTime) query.createdAt.$lte = filters.endTime
} }
if (filters.keyword) { if (filters.keyword) {
query.message = { $regex: filters.keyword, $options: 'i' } query.message = { $regex: filters.keyword, $options: 'i' }
...@@ -44,18 +46,15 @@ export const query = async (filters = {}, options = {}) => { ...@@ -44,18 +46,15 @@ export const query = async (filters = {}, options = {}) => {
} }
} }
// 获取今日开始时间 // 获取今日开始时间(服务器本地时间,字符串格式 YYYY-MM-DD HH:mm:ss)
const getTodayStart = () => { const getTodayStart = () => {
const today = new Date() return dayjs().startOf('day').format('YYYY-MM-DD HH:mm:ss')
today.setHours(0, 0, 0, 0)
return today
} }
// 获取昨日时间范围 // 获取昨日时间范围(服务器本地时间,字符串格式)
const getYesterdayRange = () => { const getYesterdayRange = () => {
const today = getTodayStart() const today = dayjs().startOf('day').format('YYYY-MM-DD HH:mm:ss')
const yesterday = new Date(today) const yesterday = dayjs().subtract(1, 'day').startOf('day').format('YYYY-MM-DD HH:mm:ss')
yesterday.setDate(yesterday.getDate() - 1)
return { start: yesterday, end: today } return { start: yesterday, end: today }
} }
...@@ -67,7 +66,7 @@ export const getStats = async (filters = {}) => { ...@@ -67,7 +66,7 @@ export const getStats = async (filters = {}) => {
if (filters.appName) baseMatch.appName = filters.appName if (filters.appName) baseMatch.appName = filters.appName
// 并行查询所有统计数据 // 并行查询所有统计数据
const [todayTotal, yesterdayTotal, todayErrors, yesterdayErrors, todayApps, yesterdayApps, hourlyTrend, recentLogs] = const [todayTotal, yesterdayTotal, todayErrors, yesterdayErrors, todayApps, yesterdayApps, recentLogs] =
await Promise.all([ await Promise.all([
// 今日日志总数 // 今日日志总数
Log.countDocuments({ ...baseMatch, createdAt: { $gte: todayStart } }), Log.countDocuments({ ...baseMatch, createdAt: { $gte: todayStart } }),
...@@ -85,17 +84,6 @@ export const getStats = async (filters = {}) => { ...@@ -85,17 +84,6 @@ export const getStats = async (filters = {}) => {
Log.distinct('appName', { ...baseMatch, createdAt: { $gte: todayStart } }), Log.distinct('appName', { ...baseMatch, createdAt: { $gte: todayStart } }),
// 昨日活跃应用数 // 昨日活跃应用数
Log.distinct('appName', { ...baseMatch, createdAt: { $gte: yesterdayStart, $lt: yesterdayEnd } }), Log.distinct('appName', { ...baseMatch, createdAt: { $gte: yesterdayStart, $lt: yesterdayEnd } }),
// 按小时分组的趋势(今日)
Log.aggregate([
{ $match: { ...baseMatch, createdAt: { $gte: todayStart } } },
{
$group: {
_id: { $hour: '$createdAt' },
count: { $sum: 1 },
},
},
{ $sort: { _id: 1 } },
]),
// 最近日志 // 最近日志
Log.find(baseMatch).sort({ createdAt: -1 }).limit(10).lean(), Log.find(baseMatch).sort({ createdAt: -1 }).limit(10).lean(),
]) ])
...@@ -106,12 +94,6 @@ export const getStats = async (filters = {}) => { ...@@ -106,12 +94,6 @@ export const getStats = async (filters = {}) => {
return Number((((today - yesterday) / yesterday) * 100).toFixed(1)) return Number((((today - yesterday) / yesterday) * 100).toFixed(1))
} }
// 填充24小时趋势数据
const trend = Array.from({ length: 24 }, (_, hour) => {
const found = hourlyTrend.find((h) => h._id === hour)
return { hour, count: found?.count || 0 }
})
return { return {
// 今日日志 // 今日日志
todayTotal: { todayTotal: {
...@@ -128,8 +110,6 @@ export const getStats = async (filters = {}) => { ...@@ -128,8 +110,6 @@ export const getStats = async (filters = {}) => {
count: todayApps.length, count: todayApps.length,
change: todayApps.length - yesterdayApps.length, change: todayApps.length - yesterdayApps.length,
}, },
// 按小时趋势
trend,
// 最近日志 // 最近日志
recentLogs, recentLogs,
} }
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论