import { Injectable } from "@nestjs/common"; import { DatabaseService } from "../database/database.service"; @Injectable() export class CompaniesService { constructor(private dbService: DatabaseService) {} async findAll(page: number, limit: number, search: string) { const prisma = this.dbService.getPrisma(); const offset = (page - 1) * limit; const where = search ? { companyName: { contains: search }, } : undefined; const [companies, total] = await Promise.all([ prisma.company.findMany({ where, include: { serials: true, }, orderBy: { updatedAt: "desc" }, skip: offset, take: limit, }), prisma.company.count({ where }), ]); const totalPages = Math.ceil(total / limit); return { message: "获取企业列表成功", data: companies.map((company: any) => ({ companyName: company.companyName, firstCreated: company.createdAt, lastCreated: company.updatedAt, serialCount: company.serials.length, activeCount: company.serials.filter((s: any) => s.isActive).length, status: company.isActive ? "active" : "disabled", })), pagination: { page: parseInt(page.toString()), limit: parseInt(limit.toString()), total, totalPages, }, }; } async findOne(companyName: string, page: number, limit: number) { const prisma = this.dbService.getPrisma(); const offset = (page - 1) * limit; const company = await prisma.company.findUnique({ where: { companyName }, include: { serials: { include: { user: { select: { name: true }, }, }, orderBy: { createdAt: "desc" }, }, }, }); if (!company) { throw new Error("企业不存在"); } const now = new Date(); const serialCount = company.serials.length; const activeCount = company.serials.filter( (s) => s.isActive && (!s.validUntil || s.validUntil > now), ).length; const disabledCount = company.serials.filter((s) => !s.isActive).length; const expiredCount = company.serials.filter( (s) => s.validUntil && s.validUntil <= now, ).length; const monthlyStatsMap = new Map(); for (let i = 11; i >= 0; i--) { const date = new Date(now.getFullYear(), now.getMonth() - i, 1); const monthKey = date.toISOString().slice(0, 7); const count = company.serials.filter((s) => { const createdAt = new Date(s.createdAt); return ( createdAt.getFullYear() === date.getFullYear() && createdAt.getMonth() === date.getMonth() ); }).length; if (count > 0) { monthlyStatsMap.set(monthKey, count); } } const paginatedSerials = company.serials.slice(offset, offset + limit); return { message: "获取企业详情成功", data: { companyName: companyName, serialCount, activeCount, disabledCount, expiredCount, firstCreated: company.createdAt, lastCreated: company.updatedAt, status: company.isActive ? "active" : "disabled", serials: paginatedSerials.map((s) => ({ serialNumber: s.serialNumber, validUntil: s.validUntil, isActive: s.isActive, createdAt: s.createdAt, createdBy: s.user?.name, })), monthlyStats: Array.from(monthlyStatsMap.entries()).map( ([month, count]) => ({ month, count }), ), }, }; } async update(companyName: string, newCompanyName: string) { const prisma = this.dbService.getPrisma(); const existingCompany = await prisma.serial.count({ where: { companyName }, }); if (existingCompany === 0) { throw new Error("企业不存在"); } const duplicateCompany = await prisma.serial.count({ where: { companyName: newCompanyName }, }); if (duplicateCompany > 0) { throw new Error("企业名称已存在"); } await prisma.serial.updateMany({ where: { companyName }, data: { companyName: newCompanyName }, }); return { message: "企业名称更新成功", data: { oldCompanyName: companyName, newCompanyName, }, }; } async delete(companyName: string) { const prisma = this.dbService.getPrisma(); const existingCompany = await prisma.company.findUnique({ where: { companyName }, }); if (!existingCompany) { throw new Error("企业不存在"); } const deleteResult = await prisma.$transaction(async (tx) => { const serialDeleteCount = await tx.serial.deleteMany({ where: { companyName }, }); await tx.company.delete({ where: { companyName }, }); return serialDeleteCount.count; }); return { message: "企业已完全删除,所有相关序列号已删除", data: { companyName: companyName, deletedSerialCount: deleteResult, deletedCompanyCount: 1, }, }; } async deleteSerial(companyName: string, serialNumber: string) { const prisma = this.dbService.getPrisma(); const serial = await prisma.serial.findFirst({ where: { serialNumber: serialNumber.toUpperCase(), companyName, }, }); if (!serial) { throw new Error("序列号不存在或不属于该企业"); } await prisma.serial.delete({ where: { serialNumber: serialNumber.toUpperCase() }, }); return { message: "序列号已成功删除", data: { serialNumber: serialNumber.toUpperCase(), companyName, }, }; } async revoke(companyName: string) { const prisma = this.dbService.getPrisma(); const existingCompany = await prisma.serial.count({ where: { companyName }, }); if (existingCompany === 0) { throw new Error("企业不存在"); } await prisma.serial.updateMany({ where: { companyName }, data: { isActive: false }, }); return { message: "企业已吊销,所有序列号已失效", data: { companyName: companyName, }, }; } async getStats() { const prisma = this.dbService.getPrisma(); const now = new Date(); const [companies, serials, recentCompanies, recentSerials] = await Promise.all([ prisma.company.findMany(), prisma.serial.findMany({ include: { company: true, }, }), prisma.company.findMany({ orderBy: { updatedAt: "desc" }, take: 10, }), prisma.serial.findMany({ orderBy: { createdAt: "desc" }, take: 10, }), ]); const companyCount = companies.length; const serialCount = serials.length; const activeCount = serials.filter( (s) => s.isActive && (!s.validUntil || s.validUntil > now), ).length; const inactiveCount = serialCount - activeCount; const monthlyStats: Array<{ month: string; company_count: number; serial_count: number; }> = []; const nowYear = now.getFullYear(); const nowMonth = now.getMonth(); for (let i = 11; i >= 0; i--) { const date = new Date(nowYear, nowMonth - i, 1); const monthStr = date.toISOString().slice(0, 7); const monthSerials = serials.filter((s) => { const createdAt = new Date(s.createdAt); return ( createdAt.getFullYear() === date.getFullYear() && createdAt.getMonth() === date.getMonth() ); }); const uniqueCompanies = new Set(monthSerials.map((s) => s.companyName)); if (monthSerials.length > 0) { monthlyStats.push({ month: monthStr, company_count: uniqueCompanies.size, serial_count: monthSerials.length, }); } } return { message: "获取统计数据成功", data: { overview: { totalCompanies: companyCount, totalSerials: serialCount, activeSerials: activeCount, inactiveSerials: inactiveCount, }, monthlyStats, recentCompanies: recentCompanies.map((c) => ({ companyName: c.companyName, lastCreated: c.updatedAt, status: c.isActive ? "active" : "disabled", })), recentSerials: recentSerials.map((s) => ({ serialNumber: s.serialNumber, companyName: s.companyName, isActive: s.isActive, createdAt: s.createdAt, })), }, }; } }