83 lines
2.8 KiB
TypeScript
83 lines
2.8 KiB
TypeScript
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() } });
|
||
}
|
||
}
|