ec-nest/src/common/base-crud.service.ts
liuyun 5c1f2992b5 fix: created_by 注入 + 登出审计记录真实 username
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-11 16:43:31 +08:00

83 lines
2.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { PrismaService } from '../prisma/prisma.service.js';
import { getRequestContext } from './context/request-context.js';
/**
* 软删时需「改名回收」唯一键的模型映射:modelName → 唯一字段及其列长。
* 目的:软删只置 deletedAt 不释放 @@unique,重建同名会 P2002;删除时把唯一字段改名
* 成「原值(截断) + #id」释放唯一键,展示名字段(name/label)保持不变。
*/
const RECYCLE_FIELDS: Record<string, { field: string; maxLen: number }> = {
user: { field: 'username', maxLen: 64 },
role: { field: 'code', maxLen: 64 },
resource: { field: 'code', maxLen: 128 },
org: { field: 'code', maxLen: 64 },
dictType: { field: 'code', maxLen: 64 },
dictItem: { field: 'value', maxLen: 64 },
config: { field: 'key', maxLen: 128 },
};
/**
* 通用 CRUD 基类:封装分页/创建/更新/软删。
* 创建时自动注入 tenantCode(Tenant 模型除外);软删由子类按需调用 softRemove。
*/
export class BaseCrudService {
constructor(
protected readonly prisma: PrismaService,
private readonly modelName: string,
) {}
protected db(): any {
return (this.prisma.client as any)[this.modelName];
}
async paginate(
page = 1,
pageSize = 20,
where: Record<string, unknown> = {},
orderBy: Record<string, unknown> = { createdAt: 'desc' },
) {
const [list, total] = await Promise.all([
this.db().findMany({ where, skip: (page - 1) * pageSize, take: pageSize, orderBy }),
this.db().count({ where }),
]);
return { list, total, page, pageSize };
}
async list(where: Record<string, unknown> = {}, orderBy?: Record<string, unknown>) {
return this.db().findMany({ where, orderBy });
}
async findById(id: string) {
return this.db().findUnique({ where: { id } });
}
async create(data: Record<string, unknown>) {
const ctx = getRequestContext();
if (ctx && this.modelName !== 'tenant') {
data.tenantCode = ctx.tenantCode;
data.createdBy = ctx.userId;
}
return this.db().create({ data });
}
async update(id: string, data: Record<string, unknown>) {
return this.db().update({ where: { id }, data });
}
async softRemove(id: string) {
const recycle = RECYCLE_FIELDS[this.modelName];
if (!recycle) {
return this.db().update({ where: { id }, data: { deletedAt: new Date() } });
}
// 先读原值,改名回收唯一键,再软删
const record = await this.findById(id);
const original = record?.[recycle.field];
if (original == null) {
return this.db().update({ where: { id }, data: { deletedAt: new Date() } });
}
const suffix = `#${id}`;
const recycled = `${String(original).slice(0, recycle.maxLen - suffix.length)}${suffix}`;
return this.db().update({ where: { id }, data: { [recycle.field]: recycled, deletedAt: new Date() } });
}
}