Listing_SuggestPrice/backend/app/services/notification_service.ts

85 lines
2.7 KiB
TypeScript

import Notification, { type NotificationType } from '#models/notification'
interface NotifyInput {
type: NotificationType
title: string
message?: string | null
meta?: Record<string, any> | null
}
interface ListParams {
page?: number
perPage?: number
type?: NotificationType
/** Lọc theo trạng thái đọc: true = chỉ đã đọc, false = chỉ chưa đọc. */
isRead?: boolean
}
/**
* Thông báo hướng người dùng (sản phẩm mới khi sync, import trùng, kết quả thao tác).
* Tương tự LogService nhưng có trạng thái đọc/chưa đọc và hiển thị trên UI.
*/
export default class NotificationService {
static async notify(input: NotifyInput): Promise<Notification> {
return Notification.create({
type: input.type,
title: input.title,
message: input.message ?? null,
meta: input.meta ?? null,
isRead: false,
})
}
/** Tạo nhiều thông báo một lượt. */
static async notifyMany(inputs: NotifyInput[]): Promise<void> {
if (!inputs.length) return
await Notification.createMany(
inputs.map((i) => ({
type: i.type,
title: i.title,
message: i.message ?? null,
meta: i.meta ?? null,
isRead: false,
}))
)
}
static async list(params: ListParams) {
const page = params.page ?? 1
const perPage = params.perPage ?? 25
const query = Notification.query().orderBy('created_at', 'desc')
if (params.type) query.where('type', params.type)
if (params.isRead !== undefined) query.where('is_read', params.isRead)
return query.paginate(page, perPage)
}
/** Số thông báo chưa đọc (cho badge). */
static async unreadCount(): Promise<number> {
const row = await Notification.query().where('is_read', false).count('* as total').first()
return Number((row as any)?.$extras?.total ?? 0)
}
/** Đánh dấu 1 thông báo là đã đọc. */
static async markRead(id: number): Promise<Notification> {
const notification = await Notification.findOrFail(id)
notification.isRead = true
await notification.save()
return notification
}
/** Đánh dấu tất cả (hoặc theo loại) là đã đọc. Trả về số bản ghi cập nhật. */
static async markAllRead(type?: NotificationType): Promise<number> {
const query = Notification.query().where('is_read', false)
if (type) query.where('type', type)
const result = await query.update({ is_read: true })
return Array.isArray(result) ? Number(result[0]) : Number(result)
}
static async destroy(id: number): Promise<void> {
const notification = await Notification.findOrFail(id)
await notification.delete()
}
}