furniture-3d-system-Wu/furniture-3d-system/src/server/repositories/store-account-management.repository.ts

198 lines
6.9 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 { prisma } from '@/lib/prisma'
import type { StoreAccountFilterKey, StoreAccountFilters, StoreAccountFieldPermissionUpdate, StoreAccountType } from '@/lib/store-account-management'
export type StoreAccountRecord = {
id: string
storeName: string
operationOwner: string
operationDepartmentHead: string
operationDirector: string
profitCenter: string
accountType: string
account: string
passwordCiphertext: string
boundPhone: string
verificationContact: string
jstOrderService: string
accountGroupName: string
createdAt: Date
updatedAt: Date
}
export type StoreAccountChangeRecord = {
id: string
storeAccountId: string | null
storeName: string
operation: string
actorId: string | null
actorName: string
changes: unknown
createdAt: Date
}
export type StoreAccountFieldPermissionRecord = {
fieldKey: string
subjectKey: string
visibility: string
}
const ACCOUNT_SELECT = {
id: true,
storeName: true,
operationOwner: true,
operationDepartmentHead: true,
operationDirector: true,
profitCenter: true,
accountType: true,
account: true,
passwordCiphertext: true,
boundPhone: true,
verificationContact: true,
jstOrderService: true,
accountGroupName: true,
createdAt: true,
updatedAt: true,
} as const
function contains(value: string) {
return { contains: value, mode: 'insensitive' as const }
}
function splitStoreNames(value: string) {
return [...new Set(value.split(/[,,;;]+/).map((item) => item.trim()).filter(Boolean))].slice(0, 500)
}
function buildWhere(filters: StoreAccountFilters) {
const and: Array<Record<string, unknown>> = []
if (filters.search) {
const searchTokens = [...new Set(filters.search.split(/[\s,,;;]+/).map((value) => value.trim()).filter(Boolean))].slice(0, 100)
and.push({ OR: searchTokens.flatMap((token) => [
{ storeName: contains(token) },
{ account: contains(token) },
{ operationOwner: contains(token) },
{ operationDepartmentHead: contains(token) },
{ operationDirector: contains(token) },
{ profitCenter: contains(token) },
{ boundPhone: contains(token) },
{ verificationContact: contains(token) },
{ jstOrderService: contains(token) },
{ accountGroupName: contains(token) },
]) })
}
const map: Partial<Record<StoreAccountFilterKey, string>> = {
accountType: 'accountType',
operationOwner: 'operationOwner',
accountGroupName: 'accountGroupName',
}
const selectedStoreNames = splitStoreNames(filters.storeName)
if (selectedStoreNames.length > 0) and.push({ storeName: { in: selectedStoreNames } })
for (const [key, field] of Object.entries(map)) {
const value = filters[key as StoreAccountFilterKey]
if (value) and.push({ [field]: contains(value) })
}
return and.length ? { AND: and } : undefined
}
export class StoreAccountManagementRepository {
async listPage(params: { skip: number; take: number; filters: StoreAccountFilters }) {
const where = buildWhere(params.filters)
const [rows, total] = await Promise.all([
prisma.storeAccount.findMany({ where, select: ACCOUNT_SELECT, orderBy: [{ storeName: 'asc' }, { account: 'asc' }], skip: params.skip, take: params.take }),
prisma.storeAccount.count({ where }),
])
return { rows, total }
}
async listStoreNames() {
const rows = await prisma.storeAccount.findMany({
select: { storeName: true },
distinct: ['storeName'],
orderBy: { storeName: 'asc' },
})
return rows.map((row) => row.storeName.trim()).filter(Boolean)
}
async findById(id: string) {
return prisma.storeAccount.findUnique({ where: { id }, select: ACCOUNT_SELECT })
}
async findByKey(params: { storeName: string; accountType: StoreAccountType; account: string }) {
return prisma.storeAccount.findUnique({
where: { storeName_accountType_account: params },
select: ACCOUNT_SELECT,
})
}
async create(data: {
storeName: string
operationOwner?: string
operationDepartmentHead?: string
operationDirector?: string
profitCenter?: string
accountType: StoreAccountType
account: string
passwordCiphertext?: string
boundPhone?: string
verificationContact?: string
jstOrderService?: string
accountGroupName?: string
actorId: string
}) {
const { actorId, ...values } = data
return prisma.storeAccount.create({ data: { ...values, passwordCiphertext: values.passwordCiphertext ?? '', createdById: actorId, updatedById: actorId }, select: ACCOUNT_SELECT })
}
async update(id: string, data: Record<string, string> & { updatedById: string }) {
return prisma.storeAccount.update({ where: { id }, data, select: ACCOUNT_SELECT })
}
async listByIds(ids: string[]) {
return prisma.storeAccount.findMany({ where: { id: { in: ids } }, select: ACCOUNT_SELECT })
}
async upsertByKey(data: {
storeName: string
accountType: StoreAccountType
account: string
values: Record<string, string>
actorId: string
}) {
return prisma.storeAccount.upsert({
where: { storeName_accountType_account: { storeName: data.storeName, accountType: data.accountType, account: data.account } },
create: { ...data.values, storeName: data.storeName, accountType: data.accountType, account: data.account, createdById: data.actorId, updatedById: data.actorId },
update: { ...data.values, updatedById: data.actorId },
select: ACCOUNT_SELECT,
})
}
async createLog(data: { storeAccountId: string | null; storeName: string; operation: string; actorId: string; actorName: string; changes: unknown }) {
return prisma.storeAccountChangeLog.create({ data: { ...data, changes: data.changes as object } })
}
async listLogs(params: { storeAccountId?: string; storeName?: string; take: number }) {
return prisma.storeAccountChangeLog.findMany({
where: params.storeAccountId ? { storeAccountId: params.storeAccountId } : params.storeName ? { storeName: params.storeName } : undefined,
orderBy: { createdAt: 'desc' },
take: params.take,
})
}
async listFieldPermissions() {
return prisma.storeAccountFieldPermission.findMany({ select: { fieldKey: true, subjectKey: true, visibility: true } })
}
async saveFieldPermissions(params: { updates: StoreAccountFieldPermissionUpdate[]; updatedById: string }) {
return prisma.$transaction(params.updates.map((item) => item.visibility === null
? prisma.storeAccountFieldPermission.deleteMany({
where: { fieldKey: item.fieldKey, subjectKey: item.subjectKey },
})
: prisma.storeAccountFieldPermission.upsert({
where: { fieldKey_subjectKey: { fieldKey: item.fieldKey, subjectKey: item.subjectKey } },
create: { ...item, visibility: item.visibility, updatedById: params.updatedById },
update: { visibility: item.visibility, updatedById: params.updatedById },
})))
}
}
export const storeAccountManagementRepository = new StoreAccountManagementRepository()