85 lines
2.7 KiB
TypeScript
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()
|
|
}
|
|
}
|