v3.5.3版本更新1
CI / verify (pull_request) Has been cancelled

This commit is contained in:
2026-08-20 18:54:15 +08:00
parent ee493823bf
commit fc2e5b65de
65 changed files with 2297 additions and 875 deletions
@@ -2,6 +2,7 @@ import {
BadRequestException,
ForbiddenException,
Injectable,
Logger,
NotFoundException,
} from '@nestjs/common';
import { loadAppConfig, ClientApp, SmsScene } from '@dukang/shared-types';
@@ -22,6 +23,7 @@ import {
TestWhitelistService,
normalizeTestPhone,
} from '../../common/test-whitelist/test-whitelist.service';
import { WecomMessagePushService } from '../../integrations/wecom/wecom-message-push.service';
function haversineMeters(lat1: number, lng1: number, lat2: number, lng2: number): number {
const toRad = (d: number) => (d * Math.PI) / 180;
@@ -61,6 +63,7 @@ function parseOptionalCoord(value: unknown, kind: 'lat' | 'lng' = 'lng'): number
@Injectable()
export class StoreService {
private readonly config = loadAppConfig();
private readonly logger = new Logger(StoreService.name);
constructor(
private readonly prisma: PrismaService,
@@ -70,8 +73,33 @@ export class StoreService {
private readonly storeCategoryService: StoreCategoryService,
private readonly tencentLbs: TencentLbsProvider,
private readonly testWhitelist: TestWhitelistService,
private readonly wecomPush: WecomMessagePushService,
) {}
/** 门店进入 PENDING 时通知企微(失败不挡业务) */
private notifyStoreAuditPending(opts: {
storeName: string;
cityName?: string | null;
partnerLabel?: string | null;
submitType: '新建' | '重提';
}) {
const now = new Date().toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' });
const lines = [
`**门店审核待处理 · ${opts.submitType}**`,
`门店:${opts.storeName}`,
opts.cityName ? `城市:${opts.cityName}` : null,
opts.partnerLabel ? `合伙人:${opts.partnerLabel}` : null,
`时间:${now}`,
].filter(Boolean);
void this.wecomPush
.dispatchMarkdown('store.audit_pending', lines.join('\n'), { applyMention: false })
.catch((e) =>
this.logger.warn(
`store.audit_pending wecom push failed: ${e instanceof Error ? e.message : String(e)}`,
),
);
}
private async whitelistPhoneSet(): Promise<Set<string>> {
const rows = await this.prisma.commonTestWhitelistPhone.findMany({
select: { phone: true },
@@ -559,6 +587,19 @@ export class StoreService {
extraJson: { storeName: store.name, phone: normalizedPhone },
});
if (!this.config.autoApproveStore) {
const partner = await this.prisma.partnerAccount.findUnique({
where: { id: primaryId },
select: { name: true, phone: true },
});
this.notifyStoreAuditPending({
storeName: store.name,
cityName: store.cityName,
partnerLabel: partner?.name || partner?.phone || String(primaryId),
submitType: '新建',
});
}
return serializeBigInt({
store: mapStoreCompat({
...store,
@@ -716,6 +757,16 @@ export class StoreService {
remark: '合伙人修改资料后重新提交审核',
},
});
const partner = await this.prisma.partnerAccount.findUnique({
where: { id: primaryId },
select: { name: true, phone: true },
});
this.notifyStoreAuditPending({
storeName: updated.name,
cityName: updated.cityName,
partnerLabel: partner?.name || partner?.phone || String(primaryId),
submitType: '重提',
});
}
return this.partnerGetStore(partnerAccountId, storeId);
@@ -739,6 +790,11 @@ export class StoreService {
if (store.auditStatus === 'PENDING') {
throw new BadRequestException('门店审核中,暂不可修改资料');
}
if (store.auditStatus === 'APPROVED') {
throw new BadRequestException(
'已营业门店修改门头照/环境图须通过「提交变更」由总部审核通过后生效',
);
}
const coverUrl = body.coverUrl !== undefined ? String(body.coverUrl ?? '').trim() : undefined;
const hasEnv = body.envPhotoUrls !== undefined;
@@ -825,6 +881,16 @@ export class StoreService {
remark: '合伙人重新上传资料后重新提交审核',
},
});
const partner = await this.prisma.partnerAccount.findUnique({
where: { id: primaryId },
select: { name: true, phone: true },
});
this.notifyStoreAuditPending({
storeName: store.name,
cityName: store.cityName,
partnerLabel: partner?.name || partner?.phone || String(primaryId),
submitType: '重提',
});
}
return this.partnerGetStore(partnerAccountId, storeId);