门店审核功能

This commit is contained in:
2026-07-14 15:25:17 +08:00
parent d61a43cc8c
commit e0f5977dd9
13 changed files with 479 additions and 40 deletions
@@ -197,6 +197,9 @@ export class StoreService {
openTime: body.openTime ? String(body.openTime) : '10:00',
closeTime: body.closeTime ? String(body.closeTime) : '22:00',
status: this.config.autoApproveStore ? 'OPEN' : 'PAUSED',
auditStatus: this.config.autoApproveStore ? 'APPROVED' : 'PENDING',
auditedAt: this.config.autoApproveStore ? new Date() : null,
rejectReason: null,
},
});
@@ -325,6 +328,18 @@ export class StoreService {
if (!['OPEN', 'PAUSED', 'CLOSED'].includes(status)) {
throw new BadRequestException('无效的门店状态');
}
if (status === 'OPEN') {
if (store.auditStatus === 'PENDING') {
throw new BadRequestException('门店尚在总部审核中,通过后方可开门');
}
if (store.auditStatus === 'REJECTED') {
throw new BadRequestException(
store.rejectReason
? `门店审核未通过:${store.rejectReason}`
: '门店审核未通过,请查看驳回原因并重新提交',
);
}
}
const updated = await this.prisma.store.update({
where: { id: storeId },
@@ -358,6 +373,9 @@ export class StoreService {
if (store.status === 'CLOSED') {
throw new BadRequestException('门店已关闭,不可编辑');
}
if (store.auditStatus === 'PENDING') {
throw new BadRequestException('门店审核中,暂不可修改资料');
}
const name = body.name !== undefined ? String(body.name).trim() : undefined;
const phone = body.phone !== undefined ? String(body.phone).trim() : undefined;
@@ -373,6 +391,7 @@ export class StoreService {
throw new BadRequestException('门店简介须为 10~500 字');
}
const resubmitAudit = store.auditStatus === 'REJECTED';
await this.prisma.store.update({
where: { id: storeId },
data: {
@@ -380,8 +399,33 @@ export class StoreService {
...(phone !== undefined ? { phone } : {}),
...(address !== undefined ? { address } : {}),
...(introRaw !== undefined ? { intro: introRaw || null } : {}),
...(resubmitAudit
? {
auditStatus: 'PENDING' as const,
rejectReason: null,
auditedAt: null,
status: store.status === 'OPEN' ? ('PAUSED' as const) : store.status,
}
: {}),
},
});
if (resubmitAudit) {
await this.prisma.commonEvent.create({
data: {
eventType: 'STORE_AUDIT',
refType: 'STORE',
refId: storeId,
actorType: 'PARTNER',
actorId: partnerAccountId,
status: 'PENDING',
param1: 'RESUBMIT',
param1Desc: 'audit_type',
remark: '合伙人修改资料后重新提交审核',
},
});
}
return this.partnerGetStore(partnerAccountId, storeId);
}
@@ -398,6 +442,13 @@ export class StoreService {
where: { storeAccountId_storeId: { storeAccountId, storeId } },
include: { store: true },
});
if (status === 'OPEN' && binding.store.auditStatus !== 'APPROVED') {
throw new BadRequestException(
binding.store.auditStatus === 'REJECTED'
? `门店审核未通过${binding.store.rejectReason ? `${binding.store.rejectReason}` : ''}`
: '门店尚在总部审核中,通过后方可营业',
);
}
const previousStatus = binding.store.status;
const store = await this.prisma.store.update({
where: { id: storeId },
@@ -423,34 +474,70 @@ export class StoreService {
select: { id: true },
});
const storeIds = partnerStoreIds.map((s) => s.id);
const [storeCount, orderCount, recentStores, pendingAuditCount] = await Promise.all([
const [storeCount, orderCount, recentStores, pendingAuditCount, recentNotices] = await Promise.all([
this.prisma.store.count({ where: { partnerAccountId: primaryId } }),
this.prisma.order.count({
where: await this.partnerCityService.buildPartnerOrderWhere(primaryId),
}),
this.prisma.store.findMany({
where: { partnerAccountId: primaryId },
select: { id: true, name: true, status: true, createdAt: true },
select: { id: true, name: true, status: true, auditStatus: true, createdAt: true },
orderBy: { createdAt: 'desc' },
take: 10,
}),
this.prisma.store.count({
where: { partnerAccountId: primaryId, auditStatus: 'PENDING' },
}),
storeIds.length === 0
? Promise.resolve(0)
: this.prisma.commonEvent.count({
? Promise.resolve([])
: this.prisma.commonEvent.findMany({
where: {
eventType: 'STORE_AUDIT',
status: 'PENDING',
refType: 'STORE',
refId: { in: storeIds },
status: { in: ['APPROVED', 'REJECTED'] },
actorType: 'HQ',
},
orderBy: { createdAt: 'desc' },
take: 20,
}),
]);
const storeNameMap = new Map(
(
await this.prisma.store.findMany({
where: { id: { in: recentNotices.map((n) => n.refId) } },
select: { id: true, name: true },
})
).map((s) => [s.id.toString(), s.name]),
);
return {
storeCount,
orderCount,
companyName: account.companyName ?? '',
recentStores: serializeBigInt(recentStores),
pendingAuditCount,
notifications: serializeBigInt(
recentNotices.map((n) => ({
id: n.id,
storeId: n.refId,
storeName: storeNameMap.get(n.refId.toString()) ?? '门店',
status: n.status,
remark: n.remark,
createdAt: n.createdAt,
title:
n.status === 'APPROVED'
? '门店审核已通过'
: n.status === 'REJECTED'
? '门店审核已驳回'
: '门店审核更新',
content:
n.status === 'APPROVED'
? `${storeNameMap.get(n.refId.toString()) ?? '门店'} 已通过总部审核,可开门营业`
: `${storeNameMap.get(n.refId.toString()) ?? '门店'} 未通过审核${n.remark ? `${n.remark}` : ''}`,
})),
),
};
}