166 lines
5.8 KiB
TypeScript
166 lines
5.8 KiB
TypeScript
import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common';
|
|
import { Prisma } from '@prisma/client';
|
|
import { PrismaService } from '../../common/prisma/prisma.module';
|
|
import { serializeBigInt } from '../../common/decorators/current-user.decorator';
|
|
import type { AdminPartnerAccountsQueryDto, AdminPartnersQueryDto } from './dto/admin-query.dto';
|
|
import type {
|
|
CreatePartnerAccountDto,
|
|
CreatePartnerDto,
|
|
UpdatePartnerAccountDto,
|
|
UpdatePartnerDto,
|
|
} from './dto/admin-mutate.dto';
|
|
|
|
@Injectable()
|
|
export class AdminPartnersService {
|
|
constructor(private readonly prisma: PrismaService) {}
|
|
|
|
async listPartners(query: AdminPartnersQueryDto) {
|
|
const page = query.page ?? 1;
|
|
const pageSize = query.pageSize ?? 20;
|
|
const where: Prisma.PartnerWhereInput = {};
|
|
if (query.companyName) where.companyName = { contains: query.companyName };
|
|
if (query.contactPhone) where.contactPhone = { contains: query.contactPhone };
|
|
|
|
const [items, total] = await Promise.all([
|
|
this.prisma.partner.findMany({
|
|
where,
|
|
orderBy: { createdAt: 'desc' },
|
|
skip: (page - 1) * pageSize,
|
|
take: pageSize,
|
|
include: {
|
|
_count: { select: { stores: true, accounts: true, cities: true } },
|
|
},
|
|
}),
|
|
this.prisma.partner.count({ where }),
|
|
]);
|
|
return serializeBigInt({
|
|
items: items.map((p) => ({
|
|
...p,
|
|
storeCount: p._count.stores,
|
|
accountCount: p._count.accounts,
|
|
cityCount: p._count.cities,
|
|
_count: undefined,
|
|
})),
|
|
total,
|
|
page,
|
|
pageSize,
|
|
});
|
|
}
|
|
|
|
async detailPartner(id: bigint) {
|
|
const partner = await this.prisma.partner.findUnique({
|
|
where: { id },
|
|
include: {
|
|
cities: { select: { id: true, code: true, name: true, status: true } },
|
|
accounts: { select: { id: true, phone: true, name: true, isPrimary: true, status: true } },
|
|
stores: { select: { id: true, name: true, status: true }, take: 10, orderBy: { createdAt: 'desc' } },
|
|
_count: { select: { stores: true, accounts: true } },
|
|
},
|
|
});
|
|
if (!partner) throw new NotFoundException('开城合伙人不存在');
|
|
return serializeBigInt(partner);
|
|
}
|
|
|
|
async createPartner(dto: CreatePartnerDto) {
|
|
const partner = await this.prisma.partner.create({ data: dto });
|
|
return serializeBigInt(partner);
|
|
}
|
|
|
|
async updatePartner(id: bigint, dto: UpdatePartnerDto) {
|
|
const partner = await this.prisma.partner.update({ where: { id }, data: dto });
|
|
return serializeBigInt(partner);
|
|
}
|
|
|
|
async listPartnerAccounts(query: AdminPartnerAccountsQueryDto) {
|
|
const page = query.page ?? 1;
|
|
const pageSize = query.pageSize ?? 20;
|
|
const where: Prisma.PartnerAccountWhereInput = {};
|
|
if (query.phone) where.phone = { contains: query.phone };
|
|
if (query.partnerId) where.partnerId = BigInt(query.partnerId);
|
|
if (query.status) where.status = query.status as Prisma.EnumAccountStatusFilter['equals'];
|
|
|
|
const [items, total] = await Promise.all([
|
|
this.prisma.partnerAccount.findMany({
|
|
where,
|
|
orderBy: { createdAt: 'desc' },
|
|
skip: (page - 1) * pageSize,
|
|
take: pageSize,
|
|
include: {
|
|
partner: { select: { id: true, companyName: true } },
|
|
},
|
|
}),
|
|
this.prisma.partnerAccount.count({ where }),
|
|
]);
|
|
return serializeBigInt({ items, total, page, pageSize });
|
|
}
|
|
|
|
async detailPartnerAccount(id: bigint) {
|
|
const account = await this.prisma.partnerAccount.findUnique({
|
|
where: { id },
|
|
include: { partner: true },
|
|
});
|
|
if (!account) throw new NotFoundException('开城合伙人账号不存在');
|
|
|
|
const [bills, orders] = await Promise.all([
|
|
this.prisma.partnerBill.findMany({
|
|
where: { partnerId: account.partnerId },
|
|
orderBy: { createdAt: 'desc' },
|
|
take: 50,
|
|
}),
|
|
this.prisma.order.findMany({
|
|
where: { city: { partnerId: account.partnerId } },
|
|
orderBy: { createdAt: 'desc' },
|
|
take: 50,
|
|
select: {
|
|
id: true,
|
|
orderNo: true,
|
|
status: true,
|
|
payAmount: true,
|
|
createdAt: true,
|
|
user: { select: { userNo: true, phone: true } },
|
|
},
|
|
}),
|
|
]);
|
|
|
|
return serializeBigInt({ ...account, bills, orders });
|
|
}
|
|
|
|
async createPartnerAccount(dto: CreatePartnerAccountDto) {
|
|
const partner = await this.prisma.partner.findUnique({ where: { id: BigInt(dto.partnerId) } });
|
|
if (!partner) throw new BadRequestException('开城合伙人不存在');
|
|
const account = await this.prisma.partnerAccount.create({
|
|
data: {
|
|
partnerId: partner.id,
|
|
phone: dto.phone,
|
|
name: dto.name,
|
|
staffRole: dto.staffRole ? (dto.staffRole as 'PARTNER' | 'INTERNAL' | 'PROMOTER') : undefined,
|
|
isPrimary: 0,
|
|
},
|
|
});
|
|
return serializeBigInt(account);
|
|
}
|
|
|
|
async updatePartnerAccount(id: bigint, dto: UpdatePartnerAccountDto) {
|
|
const existing = await this.prisma.partnerAccount.findUnique({ where: { id } });
|
|
if (!existing) throw new NotFoundException('开城合伙人账号不存在');
|
|
|
|
const data: Prisma.PartnerAccountUpdateInput = {};
|
|
if (dto.name !== undefined) data.name = dto.name;
|
|
if (dto.status !== undefined) data.status = dto.status as 'ACTIVE' | 'DISABLED';
|
|
if (dto.phone !== undefined) {
|
|
const phone = dto.phone.trim();
|
|
if (!/^1[3-9]\d{9}$/.test(phone)) {
|
|
throw new BadRequestException('请输入正确的手机号码');
|
|
}
|
|
const phoneTaken = await this.prisma.partnerAccount.findUnique({ where: { phone } });
|
|
if (phoneTaken && phoneTaken.id !== id) {
|
|
throw new BadRequestException('该手机号已被使用');
|
|
}
|
|
data.phone = phone;
|
|
}
|
|
|
|
const account = await this.prisma.partnerAccount.update({ where: { id }, data });
|
|
return serializeBigInt(account);
|
|
}
|
|
}
|