78 lines
2.7 KiB
JavaScript
78 lines
2.7 KiB
JavaScript
const db = require('../db/models');
|
|
const Sequelize = db.Sequelize;
|
|
const Op = Sequelize.Op;
|
|
|
|
module.exports = class AnalyticsService {
|
|
static async recordView(data, req) {
|
|
return await db.page_views.create({
|
|
productId: data.productId || null,
|
|
categoryId: data.categoryId || null,
|
|
userId: req.user ? req.user.id : null,
|
|
ipAddress: req.ip,
|
|
userAgent: req.headers['user-agent']
|
|
});
|
|
}
|
|
|
|
static async getTopProducts(limit = 5) {
|
|
// Use a simpler query to avoid complex group by issues with nested includes
|
|
const topViewedIds = await db.page_views.findAll({
|
|
attributes: [
|
|
'productId',
|
|
[Sequelize.fn('COUNT', Sequelize.col('productId')), 'viewCount']
|
|
],
|
|
where: {
|
|
productId: { [Op.ne]: null }
|
|
},
|
|
group: ['productId'],
|
|
order: [[Sequelize.literal('"viewCount"'), 'DESC']],
|
|
limit: Number(limit),
|
|
raw: true
|
|
});
|
|
|
|
if (topViewedIds.length === 0) return [];
|
|
|
|
const productIds = topViewedIds.map(v => v.productId);
|
|
const products = await db.products.findAll({
|
|
where: { id: { [Op.in]: productIds } },
|
|
include: [{ model: db.file, as: 'images' }]
|
|
});
|
|
|
|
// Map counts back to products
|
|
return products.map(p => {
|
|
const viewData = topViewedIds.find(v => v.productId === p.id);
|
|
return {
|
|
...p.get({ plain: true }),
|
|
viewCount: viewData ? parseInt(viewData.viewCount) : 0
|
|
};
|
|
}).sort((a, b) => b.viewCount - a.viewCount);
|
|
}
|
|
|
|
static async getViewStats() {
|
|
const totalViews = await db.page_views.count();
|
|
const productViews = await db.page_views.count({ where: { productId: { [Op.ne]: null } } });
|
|
const categoryViews = await db.page_views.count({ where: { categoryId: { [Op.ne]: null } } });
|
|
|
|
// Last 7 days views
|
|
const sevenDaysAgo = new Date();
|
|
sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7);
|
|
|
|
const dailyViews = await db.page_views.findAll({
|
|
attributes: [
|
|
[Sequelize.fn('DATE', Sequelize.col('createdAt')), 'date'],
|
|
[Sequelize.fn('COUNT', Sequelize.col('id')), 'count']
|
|
],
|
|
where: {
|
|
createdAt: { [Op.gte]: sevenDaysAgo }
|
|
},
|
|
group: [Sequelize.fn('DATE', Sequelize.col('createdAt'))],
|
|
order: [[Sequelize.fn('DATE', Sequelize.col('createdAt')), 'ASC']]
|
|
});
|
|
|
|
return {
|
|
totalViews,
|
|
productViews,
|
|
categoryViews,
|
|
dailyViews
|
|
};
|
|
}
|
|
}; |