import { Injectable } from '@nestjs/common'; import { BaseCrudService } from '../common/base-crud.service.js'; import { PrismaService } from '../prisma/prisma.service.js'; import { getRequestContext } from '../common/context/request-context.js'; import { CreateNoticeDto, ListNoticeQuery, UpdateNoticeDto } from './dto.js'; @Injectable() export class NoticesService extends BaseCrudService { constructor(prisma: PrismaService) { super(prisma, 'notice'); } listNotices(q: ListNoticeQuery) { const where: Record = {}; if (q.title) where.title = { contains: q.title }; if (q.status) where.status = q.status; return this.paginate(q.page, q.pageSize, where); } createNotice(dto: CreateNoticeDto) { return this.create({ ...dto }); } updateNotice(id: string, dto: UpdateNoticeDto) { return this.update(id, { ...dto }); } /** 当前用户可见通知(enabled)+ 已读状态。 */ async mine(q: ListNoticeQuery) { const ctx = getRequestContext()!; const [rows, total] = await Promise.all([ this.prisma.client.notice.findMany({ where: { status: 'enabled' }, skip: (q.page - 1) * q.pageSize, take: q.pageSize, orderBy: { createdAt: 'desc' }, select: { id: true, title: true, content: true, status: true, createdAt: true }, }), this.prisma.client.notice.count({ where: { status: 'enabled' } }), ]); const ids = rows.map((r) => r.id); const readRows = ids.length ? await this.prisma.client.noticeRead.findMany({ where: { userId: ctx.userId, noticeId: { in: ids } }, select: { noticeId: true, readAt: true }, }) : []; const readMap = new Map(readRows.map((r) => [r.noticeId, r.readAt])); const list = rows.map((r) => ({ ...r, readAt: readMap.get(r.id) ?? null })); return { list, total, page: q.page, pageSize: q.pageSize }; } /** 未读数 = enabled 通知数 − 当前用户已读数(O(enabled 通知数),公告量小可接受)。 */ async unreadCount(): Promise { const ctx = getRequestContext()!; const enabled = await this.prisma.client.notice.findMany({ where: { status: 'enabled' }, select: { id: true } }); const enabledIds = enabled.map((n) => n.id); const readCount = enabledIds.length ? await this.prisma.client.noticeRead.count({ where: { userId: ctx.userId, noticeId: { in: enabledIds } } }) : 0; return Math.max(0, enabled.length - readCount); } async read(id: string): Promise { const ctx = getRequestContext()!; await this.prisma.client.noticeRead.upsert({ where: { tenantCode_noticeId_userId: { tenantCode: ctx.tenantCode, noticeId: id, userId: ctx.userId } }, update: {}, create: { tenantCode: ctx.tenantCode, noticeId: id, userId: ctx.userId }, }); return null; } async readAll(): Promise { const ctx = getRequestContext()!; const enabled = await this.prisma.client.notice.findMany({ where: { status: 'enabled' }, select: { id: true } }); if (enabled.length === 0) return null; await this.prisma.client.noticeRead.createMany({ data: enabled.map((n) => ({ tenantCode: ctx.tenantCode, noticeId: n.id, userId: ctx.userId })), skipDuplicates: true, }); return null; } }