v3.5.11企业微信通知调整
CI / verify (pull_request) Waiting to run

This commit is contained in:
2026-08-26 09:55:19 +08:00
parent 632539e8dc
commit 3afbdfe6b9
17 changed files with 775 additions and 83 deletions
@@ -21,6 +21,7 @@ import { serializeBigInt } from '../../common/decorators/current-user.decorator'
import { StoreService } from './store.service';
import { PartnerCityService } from '../city-scope/partner-city.service';
import { WecomMessagePushService } from '../../integrations/wecom/wecom-message-push.service';
import { formatHqWecomLabel, formatPartnerWecomLabel, formatShopWecomLabel } from './wecom-submitter-label';
import { HqPermissionsResolver, hqStoreCityWhere } from '../../common/guards/hq-permission.guard';
type ChangeableField = (typeof STORE_INFO_CHANGEABLE_FIELDS)[number];
@@ -335,13 +336,18 @@ export class StoreInfoChangeService {
`Store info change submitted storeId=${input.storeId} fields=${changedFields.join(',')}`,
);
const submitterLabel = input.submitterType === 'PARTNER' ? '合伙人' : '门店';
const submitter =
input.submitterType === 'PARTNER'
? await formatPartnerWecomLabel(this.prisma, input.submitterId)
: input.submitterType === 'HQ_DIRECT_ADMIN'
? await formatHqWecomLabel(this.prisma, input.submitterId)
: await formatShopWecomLabel(this.prisma, input.submitterId);
void this.wecomPush.dispatchEvent(
'store.info_change_pending',
{
storeName: String(store.name ?? input.storeId),
cityName: String(store.cityName ?? '—'),
submitter: submitterLabel,
submitter,
changedFields: formatStoreInfoChangeFieldLabels(changedFields),
requestId: created.id.toString(),
},
@@ -15,6 +15,7 @@ import { PrismaService } from '../../common/prisma/prisma.module';
import { serializeBigInt } from '../../common/decorators/current-user.decorator';
import { StoreService } from './store.service';
import { WecomMessagePushService } from '../../integrations/wecom/wecom-message-push.service';
import { formatPartnerWecomLabel, formatShopWecomLabel } from './wecom-submitter-label';
import { HqPermissionsResolver, hqStoreCityWhere } from '../../common/guards/hq-permission.guard';
type PackageInput = Record<string, unknown>;
@@ -193,13 +194,16 @@ export class StorePackageService {
where: { id: storeId },
select: { name: true, cityName: true },
});
const submitterLabel = submitterType === 'PARTNER' ? '合伙人' : '门店';
const submitter =
submitterType === 'PARTNER'
? await formatPartnerWecomLabel(this.prisma, submitterId)
: await formatShopWecomLabel(this.prisma, submitterId);
void this.wecomPush.dispatchEvent(
'store.package_audit_pending',
{
storeName: store?.name ?? String(storeId),
cityName: store?.cityName || '—',
submitter: submitterLabel,
submitter,
packageCount: String(packages.length),
requestId: req.id.toString(),
},
@@ -24,6 +24,7 @@ import {
normalizeTestPhone,
} from '../../common/test-whitelist/test-whitelist.service';
import { WecomMessagePushService } from '../../integrations/wecom/wecom-message-push.service';
import { formatPartnerWecomLabel } from './wecom-submitter-label';
function haversineMeters(lat1: number, lng1: number, lat2: number, lng2: number): number {
const toRad = (d: number) => (d * Math.PI) / 180;
@@ -76,25 +77,29 @@ export class StoreService {
private readonly wecomPush: WecomMessagePushService,
) {}
/** 门店进入 PENDING 时通知企微(失败不挡业务) */
/** 门店进入 PENDING 或 HQ 新建时通知企微(失败不挡业务) */
private notifyStoreAuditPending(opts: {
storeId: bigint;
storeName: string;
cityName?: string | null;
partnerLabel?: string | null;
submitter?: string | null;
submitType: '新建' | '重提';
handlePath?: string;
}) {
void this.wecomPush.dispatchEvent(
'store.audit_pending',
{
storeName: opts.storeName,
cityName: opts.cityName || '—',
submitter: opts.submitter || opts.partnerLabel || '—',
partnerLabel: opts.partnerLabel || '—',
action: opts.submitType,
storeId: opts.storeId.toString(),
},
{
handlePath: `/stores?auditStatus=PENDING&storeId=${opts.storeId.toString()}`,
handlePath:
opts.handlePath || `/stores?auditStatus=PENDING&storeId=${opts.storeId.toString()}`,
},
);
}
@@ -587,15 +592,16 @@ export class StoreService {
});
if (!this.config.autoApproveStore) {
const partner = await this.prisma.partnerAccount.findUnique({
where: { id: primaryId },
select: { name: true, phone: true },
});
const [submitter, partnerLabel] = await Promise.all([
formatPartnerWecomLabel(this.prisma, partnerAccountId),
formatPartnerWecomLabel(this.prisma, primaryId),
]);
this.notifyStoreAuditPending({
storeId: store.id,
storeName: store.name,
cityName: store.cityName,
partnerLabel: partner?.name || partner?.phone || String(primaryId),
submitter,
partnerLabel,
submitType: '新建',
});
}
@@ -757,15 +763,16 @@ export class StoreService {
remark: '合伙人修改资料后重新提交审核',
},
});
const partner = await this.prisma.partnerAccount.findUnique({
where: { id: primaryId },
select: { name: true, phone: true },
});
const [submitter, partnerLabel] = await Promise.all([
formatPartnerWecomLabel(this.prisma, partnerAccountId),
formatPartnerWecomLabel(this.prisma, primaryId),
]);
this.notifyStoreAuditPending({
storeId: updated.id,
storeName: updated.name,
cityName: updated.cityName,
partnerLabel: partner?.name || partner?.phone || String(primaryId),
submitter,
partnerLabel,
submitType: '重提',
});
}
@@ -882,15 +889,16 @@ export class StoreService {
remark: '合伙人重新上传资料后重新提交审核',
},
});
const partner = await this.prisma.partnerAccount.findUnique({
where: { id: primaryId },
select: { name: true, phone: true },
});
const [submitter, partnerLabel] = await Promise.all([
formatPartnerWecomLabel(this.prisma, partnerAccountId),
formatPartnerWecomLabel(this.prisma, primaryId),
]);
this.notifyStoreAuditPending({
storeId: store.id,
storeName: store.name,
cityName: store.cityName,
partnerLabel: partner?.name || partner?.phone || String(primaryId),
submitter,
partnerLabel,
submitType: '重提',
});
}
@@ -0,0 +1,58 @@
import type { PrismaClient } from '@prisma/client';
export function joinCompanyAndName(
company?: string | null,
name?: string | null,
fallback = '—',
): string {
const person = (name || '').trim() || fallback;
const org = (company || '').trim();
return org ? `${org} · ${person}` : person;
}
export async function formatPartnerWecomLabel(
prisma: PrismaClient,
accountId: bigint,
): Promise<string> {
const acc = await prisma.partnerAccount.findUnique({
where: { id: accountId },
select: {
name: true,
phone: true,
companyName: true,
isPrimary: true,
parentAccountId: true,
},
});
if (!acc) return '—';
let company = acc.companyName?.trim() || '';
if (!company && acc.isPrimary !== 1 && acc.parentAccountId) {
const primary = await prisma.partnerAccount.findUnique({
where: { id: acc.parentAccountId },
select: { companyName: true },
});
company = primary?.companyName?.trim() || '';
}
const name = acc.name?.trim() || acc.phone || String(accountId);
return joinCompanyAndName(company, name, String(accountId));
}
export async function formatHqWecomLabel(prisma: PrismaClient, hqAccountId: bigint): Promise<string> {
const hq = await prisma.hqAccount.findUnique({
where: { id: hqAccountId },
select: { name: true },
});
return hq?.name?.trim() || 'HQ';
}
export async function formatShopWecomLabel(
prisma: PrismaClient,
storeAccountId: bigint,
): Promise<string> {
const acc = await prisma.storeAccount.findUnique({
where: { id: storeAccountId },
select: { name: true, phone: true },
});
const name = acc?.name?.trim() || acc?.phone || String(storeAccountId);
return `门店 · ${name}`;
}