perf: 支持约课以及消息推送能力
This commit is contained in:
@@ -1,14 +1,47 @@
|
||||
import { Injectable, NotFoundException } from '@nestjs/common'
|
||||
import { MembershipStatus, BookingStatus, UserRole, CardTypeCategory } from '@mp-pilates/shared'
|
||||
import type { PaginatedData, UserProfileResponse, UserStatsResponse } from '@mp-pilates/shared'
|
||||
import {
|
||||
MembershipStatus,
|
||||
BookingStatus,
|
||||
UserRole,
|
||||
CardTypeCategory,
|
||||
SubscriptionMessageScene,
|
||||
} from '@mp-pilates/shared'
|
||||
import type {
|
||||
PaginatedData,
|
||||
UserProfileResponse,
|
||||
UserStatsResponse,
|
||||
SubscriptionMessageConsentSummary,
|
||||
SubscriptionMessageRequestItem,
|
||||
SubscriptionMessageRequestResult,
|
||||
SubscriptionMessageTemplateConfig,
|
||||
} from '@mp-pilates/shared'
|
||||
import { ConfigService } from '@nestjs/config'
|
||||
import { PrismaService } from '../prisma/prisma.service'
|
||||
import { UpdateUserMembershipDto } from './dto/update-user-membership.dto'
|
||||
|
||||
const VALID_CARD_TYPES = new Set<string>(Object.values(CardTypeCategory))
|
||||
|
||||
type SubscriptionMessageConsentDelegate = PrismaService['subscriptionMessageConsent']
|
||||
type SubscriptionMessageConsentRecord = Awaited<ReturnType<SubscriptionMessageConsentDelegate['findMany']>>[number]
|
||||
|
||||
@Injectable()
|
||||
export class UserService {
|
||||
constructor(private readonly prisma: PrismaService) {}
|
||||
constructor(
|
||||
private readonly prisma: PrismaService,
|
||||
private readonly configService: ConfigService,
|
||||
) {}
|
||||
|
||||
private buildSubscriptionTemplateConfig(): SubscriptionMessageTemplateConfig {
|
||||
return {
|
||||
templates: [
|
||||
{
|
||||
templateId: this.configService.get<string>('WX_SUBSCRIBE_TEMPLATE_BOOKING_CONFIRMED', ''),
|
||||
scene: SubscriptionMessageScene.BOOKING_CREATED,
|
||||
description: '购卡或预约时请求一次订阅,用于后续预约确认通知推送',
|
||||
},
|
||||
].filter((item) => item.templateId),
|
||||
}
|
||||
}
|
||||
|
||||
async getProfile(userId: string): Promise<UserProfileResponse> {
|
||||
const user = await this.prisma.user.findUnique({
|
||||
@@ -35,6 +68,7 @@ export class UserService {
|
||||
avatarUrl: user.avatarUrl,
|
||||
role: user.role as UserRole,
|
||||
activeMembershipCount: user._count.memberships,
|
||||
subscriptionMessageTemplates: this.buildSubscriptionTemplateConfig(),
|
||||
createdAt: user.createdAt.toISOString(),
|
||||
}
|
||||
}
|
||||
@@ -67,10 +101,86 @@ export class UserService {
|
||||
avatarUrl: updated.avatarUrl,
|
||||
role: updated.role as UserRole,
|
||||
activeMembershipCount: updated._count.memberships,
|
||||
subscriptionMessageTemplates: this.buildSubscriptionTemplateConfig(),
|
||||
createdAt: updated.createdAt.toISOString(),
|
||||
}
|
||||
}
|
||||
|
||||
getSubscriptionMessageTemplates(): SubscriptionMessageTemplateConfig {
|
||||
return this.buildSubscriptionTemplateConfig()
|
||||
}
|
||||
|
||||
async reportSubscriptionMessageRequests(
|
||||
userId: string,
|
||||
requests: readonly SubscriptionMessageRequestItem[],
|
||||
): Promise<SubscriptionMessageConsentSummary[]> {
|
||||
if (requests.length === 0) {
|
||||
return []
|
||||
}
|
||||
|
||||
await Promise.all(
|
||||
requests.map((item) => this.prisma.subscriptionMessageConsent.upsert({
|
||||
where: {
|
||||
userId_templateId_scene: {
|
||||
userId,
|
||||
templateId: item.templateId,
|
||||
scene: item.scene,
|
||||
},
|
||||
},
|
||||
create: {
|
||||
userId,
|
||||
templateId: item.templateId,
|
||||
scene: item.scene,
|
||||
totalRequestCount: 1,
|
||||
acceptCount: item.result === 'accept' ? 1 : 0,
|
||||
rejectCount: item.result === 'reject' ? 1 : 0,
|
||||
banCount: item.result === 'ban' ? 1 : 0,
|
||||
filterCount: item.result === 'filter' ? 1 : 0,
|
||||
sentCount: 0,
|
||||
lastResult: item.result,
|
||||
lastRequestedAt: new Date(),
|
||||
},
|
||||
update: {
|
||||
totalRequestCount: { increment: 1 },
|
||||
acceptCount: { increment: item.result === 'accept' ? 1 : 0 },
|
||||
rejectCount: { increment: item.result === 'reject' ? 1 : 0 },
|
||||
banCount: { increment: item.result === 'ban' ? 1 : 0 },
|
||||
filterCount: { increment: item.result === 'filter' ? 1 : 0 },
|
||||
lastResult: item.result,
|
||||
lastRequestedAt: new Date(),
|
||||
},
|
||||
})),
|
||||
)
|
||||
|
||||
const summaries = await this.prisma.subscriptionMessageConsent.findMany({
|
||||
where: {
|
||||
userId,
|
||||
OR: requests.map((item) => ({
|
||||
templateId: item.templateId,
|
||||
scene: item.scene,
|
||||
})),
|
||||
},
|
||||
orderBy: { updatedAt: 'desc' },
|
||||
})
|
||||
|
||||
return summaries.map((item: SubscriptionMessageConsentRecord) => ({
|
||||
userId: item.userId,
|
||||
templateId: item.templateId,
|
||||
scene: item.scene as SubscriptionMessageScene,
|
||||
totalRequestCount: item.totalRequestCount,
|
||||
acceptCount: item.acceptCount,
|
||||
rejectCount: item.rejectCount,
|
||||
banCount: item.banCount,
|
||||
filterCount: item.filterCount,
|
||||
sentCount: item.sentCount,
|
||||
lastResult: item.lastResult as SubscriptionMessageRequestResult,
|
||||
lastRequestedAt: item.lastRequestedAt.toISOString(),
|
||||
lastSentAt: item.lastSentAt?.toISOString() ?? null,
|
||||
createdAt: item.createdAt.toISOString(),
|
||||
updatedAt: item.updatedAt.toISOString(),
|
||||
}))
|
||||
}
|
||||
|
||||
async getStats(userId: string): Promise<UserStatsResponse> {
|
||||
const completedBookings = await this.prisma.booking.findMany({
|
||||
where: {
|
||||
|
||||
Reference in New Issue
Block a user