269 lines
7.0 KiB
TypeScript
269 lines
7.0 KiB
TypeScript
// 統計服務 - 替代 MySQL 觸發器功能
|
|
import { PrismaClient } from '@prisma/client'
|
|
|
|
const prisma = new PrismaClient()
|
|
|
|
// 統計更新服務
|
|
export class StatisticsService {
|
|
// 更新困擾案例統計
|
|
static async updateWishStats(wishId: number, action: 'create' | 'update' | 'delete', isPublic?: boolean) {
|
|
try {
|
|
const today = new Date()
|
|
today.setHours(0, 0, 0, 0)
|
|
|
|
if (action === 'create') {
|
|
// 創建困擾案例
|
|
await prisma.systemStat.upsert({
|
|
where: { statDate: today },
|
|
update: {
|
|
totalWishes: { increment: 1 },
|
|
publicWishes: { increment: isPublic ? 1 : 0 },
|
|
privateWishes: { increment: isPublic ? 0 : 1 }
|
|
},
|
|
create: {
|
|
statDate: today,
|
|
totalWishes: 1,
|
|
publicWishes: isPublic ? 1 : 0,
|
|
privateWishes: isPublic ? 0 : 1,
|
|
totalLikes: 0,
|
|
activeUsers: 0,
|
|
storageUsedMb: 0
|
|
}
|
|
})
|
|
} else if (action === 'delete') {
|
|
// 刪除困擾案例
|
|
const existing = await prisma.systemStat.findUnique({
|
|
where: { statDate: today }
|
|
})
|
|
|
|
if (existing) {
|
|
await prisma.systemStat.update({
|
|
where: { statDate: today },
|
|
data: {
|
|
totalWishes: Math.max(existing.totalWishes - 1, 0),
|
|
publicWishes: Math.max(existing.publicWishes - (isPublic ? 1 : 0), 0),
|
|
privateWishes: Math.max(existing.privateWishes - (isPublic ? 0 : 1), 0)
|
|
}
|
|
})
|
|
}
|
|
} else if (action === 'update') {
|
|
// 更新困擾案例(公開狀態變更)
|
|
const existing = await prisma.systemStat.findUnique({
|
|
where: { statDate: today }
|
|
})
|
|
|
|
if (existing) {
|
|
await prisma.systemStat.update({
|
|
where: { statDate: today },
|
|
data: {
|
|
publicWishes: { increment: isPublic ? 1 : -1 },
|
|
privateWishes: { increment: isPublic ? -1 : 1 }
|
|
}
|
|
})
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('更新困擾案例統計失敗:', error)
|
|
}
|
|
}
|
|
|
|
// 更新點讚統計
|
|
static async updateLikeStats(wishId: number, action: 'create' | 'delete') {
|
|
try {
|
|
const today = new Date()
|
|
today.setHours(0, 0, 0, 0)
|
|
|
|
if (action === 'create') {
|
|
await prisma.systemStat.upsert({
|
|
where: { statDate: today },
|
|
update: {
|
|
totalLikes: { increment: 1 }
|
|
},
|
|
create: {
|
|
statDate: today,
|
|
totalWishes: 0,
|
|
publicWishes: 0,
|
|
privateWishes: 0,
|
|
totalLikes: 1,
|
|
activeUsers: 0,
|
|
storageUsedMb: 0
|
|
}
|
|
})
|
|
} else if (action === 'delete') {
|
|
const existing = await prisma.systemStat.findUnique({
|
|
where: { statDate: today }
|
|
})
|
|
|
|
if (existing) {
|
|
await prisma.systemStat.update({
|
|
where: { statDate: today },
|
|
data: {
|
|
totalLikes: Math.max(existing.totalLikes - 1, 0)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('更新點讚統計失敗:', error)
|
|
}
|
|
}
|
|
|
|
// 更新活躍用戶統計
|
|
static async updateActiveUserStats(userSession: string) {
|
|
try {
|
|
const today = new Date()
|
|
today.setHours(0, 0, 0, 0)
|
|
|
|
// 檢查今天是否已經統計過這個用戶
|
|
const existing = await prisma.systemStat.findUnique({
|
|
where: { statDate: today }
|
|
})
|
|
|
|
if (existing) {
|
|
// 簡單的活躍用戶計數(實際應用中可能需要更複雜的邏輯)
|
|
await prisma.systemStat.update({
|
|
where: { statDate: today },
|
|
data: {
|
|
activeUsers: { increment: 1 }
|
|
}
|
|
})
|
|
} else {
|
|
await prisma.systemStat.create({
|
|
data: {
|
|
statDate: today,
|
|
totalWishes: 0,
|
|
publicWishes: 0,
|
|
privateWishes: 0,
|
|
totalLikes: 0,
|
|
activeUsers: 1,
|
|
storageUsedMb: 0
|
|
}
|
|
})
|
|
}
|
|
} catch (error) {
|
|
console.error('更新活躍用戶統計失敗:', error)
|
|
}
|
|
}
|
|
|
|
// 獲取統計數據
|
|
static async getStatistics() {
|
|
try {
|
|
const today = new Date()
|
|
today.setHours(0, 0, 0, 0)
|
|
|
|
const stats = await prisma.systemStat.findUnique({
|
|
where: { statDate: today }
|
|
})
|
|
|
|
if (!stats) {
|
|
return {
|
|
totalWishes: 0,
|
|
publicWishes: 0,
|
|
privateWishes: 0,
|
|
totalLikes: 0,
|
|
activeUsers: 0,
|
|
storageUsedMb: 0
|
|
}
|
|
}
|
|
|
|
return stats
|
|
} catch (error) {
|
|
console.error('獲取統計數據失敗:', error)
|
|
return null
|
|
}
|
|
}
|
|
|
|
// 重新計算所有統計數據
|
|
static async recalculateAllStats() {
|
|
try {
|
|
const today = new Date()
|
|
today.setHours(0, 0, 0, 0)
|
|
|
|
// 計算總困擾數
|
|
const totalWishes = await prisma.wish.count({
|
|
where: { status: 'active' }
|
|
})
|
|
|
|
// 計算公開困擾數
|
|
const publicWishes = await prisma.wish.count({
|
|
where: {
|
|
status: 'active',
|
|
isPublic: true
|
|
}
|
|
})
|
|
|
|
// 計算私密困擾數
|
|
const privateWishes = await prisma.wish.count({
|
|
where: {
|
|
status: 'active',
|
|
isPublic: false
|
|
}
|
|
})
|
|
|
|
// 計算總點讚數
|
|
const totalLikes = await prisma.wishLike.count()
|
|
|
|
// 計算本週新增困擾數
|
|
const thisWeek = new Date()
|
|
thisWeek.setDate(thisWeek.getDate() - 7)
|
|
const thisWeekWishes = await prisma.wish.count({
|
|
where: {
|
|
status: 'active',
|
|
createdAt: { gte: thisWeek }
|
|
}
|
|
})
|
|
|
|
// 計算上週新增困擾數
|
|
const lastWeekStart = new Date()
|
|
lastWeekStart.setDate(lastWeekStart.getDate() - 14)
|
|
const lastWeekEnd = new Date()
|
|
lastWeekEnd.setDate(lastWeekEnd.getDate() - 7)
|
|
const lastWeekWishes = await prisma.wish.count({
|
|
where: {
|
|
status: 'active',
|
|
createdAt: {
|
|
gte: lastWeekStart,
|
|
lt: lastWeekEnd
|
|
}
|
|
}
|
|
})
|
|
|
|
// 更新或創建統計記錄
|
|
await prisma.systemStat.upsert({
|
|
where: { statDate: today },
|
|
update: {
|
|
totalWishes,
|
|
publicWishes,
|
|
privateWishes,
|
|
totalLikes,
|
|
activeUsers: 0, // 需要更複雜的邏輯來計算活躍用戶
|
|
storageUsedMb: 0 // 需要計算實際儲存使用量
|
|
},
|
|
create: {
|
|
statDate: today,
|
|
totalWishes,
|
|
publicWishes,
|
|
privateWishes,
|
|
totalLikes,
|
|
activeUsers: 0,
|
|
storageUsedMb: 0
|
|
}
|
|
})
|
|
|
|
return {
|
|
totalWishes,
|
|
publicWishes,
|
|
privateWishes,
|
|
totalLikes,
|
|
thisWeekWishes,
|
|
lastWeekWishes
|
|
}
|
|
} catch (error) {
|
|
console.error('重新計算統計數據失敗:', error)
|
|
return null
|
|
}
|
|
}
|
|
}
|
|
|
|
export default StatisticsService
|