feat: 支持会员管理筛选
This commit is contained in:
@@ -6,7 +6,7 @@ import {
|
||||
Query,
|
||||
UseGuards,
|
||||
} from '@nestjs/common'
|
||||
import { UserRole } from '@mp-pilates/shared'
|
||||
import { UserRole, CardTypeCategory } from '@mp-pilates/shared'
|
||||
import { JwtAuthGuard } from '../auth/jwt-auth.guard'
|
||||
import { RolesGuard } from '../auth/roles.guard'
|
||||
import { Roles } from '../auth/roles.decorator'
|
||||
@@ -14,6 +14,8 @@ import { CurrentUser } from '../common/decorators/current-user.decorator'
|
||||
import { UserService } from './user.service'
|
||||
import { UpdateProfileDto } from './dto/update-profile.dto'
|
||||
|
||||
const VALID_CARD_TYPES = new Set<string>(Object.values(CardTypeCategory))
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Controller()
|
||||
export class UserController {
|
||||
@@ -46,11 +48,17 @@ export class UserController {
|
||||
@Query('page') page?: string,
|
||||
@Query('limit') limit?: string,
|
||||
@Query('search') search?: string,
|
||||
@Query('cardType') cardType?: string,
|
||||
) {
|
||||
const validCardType =
|
||||
cardType && cardType !== 'undefined' && (VALID_CARD_TYPES.has(cardType) || cardType === 'NONE')
|
||||
? cardType
|
||||
: undefined
|
||||
return this.userService.getMembers(
|
||||
page ? Number(page) : 1,
|
||||
limit ? Number(limit) : 20,
|
||||
search && search !== 'undefined' ? search : undefined,
|
||||
validCardType,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { Injectable, NotFoundException } from '@nestjs/common'
|
||||
import { MembershipStatus, BookingStatus, UserRole } from '@mp-pilates/shared'
|
||||
import { MembershipStatus, BookingStatus, UserRole, CardTypeCategory } from '@mp-pilates/shared'
|
||||
import type { PaginatedData, UserProfileResponse, UserStatsResponse } from '@mp-pilates/shared'
|
||||
import { PrismaService } from '../prisma/prisma.service'
|
||||
|
||||
const VALID_CARD_TYPES = new Set<string>(Object.values(CardTypeCategory))
|
||||
|
||||
@Injectable()
|
||||
export class UserService {
|
||||
constructor(private readonly prisma: PrismaService) {}
|
||||
@@ -124,6 +126,7 @@ export class UserService {
|
||||
page: number,
|
||||
limit: number,
|
||||
search?: string,
|
||||
cardType?: string,
|
||||
): Promise<PaginatedData<{
|
||||
userId: string
|
||||
openid: string
|
||||
@@ -134,7 +137,16 @@ export class UserService {
|
||||
completedBookings: number
|
||||
cancelledBookings: number
|
||||
}>> {
|
||||
const where = search
|
||||
const where: {
|
||||
OR?: Array<{ [key: string]: unknown }>
|
||||
memberships?: {
|
||||
some: {
|
||||
status: MembershipStatus
|
||||
cardType?: { type: CardTypeCategory }
|
||||
}
|
||||
}
|
||||
NOT?: { memberships?: { some: { status: MembershipStatus } } }
|
||||
} = search
|
||||
? {
|
||||
OR: [
|
||||
{ nickname: { contains: search, mode: 'insensitive' as const } },
|
||||
@@ -144,6 +156,18 @@ export class UserService {
|
||||
}
|
||||
: {}
|
||||
|
||||
// cardType filter: NONE = no active membership, otherwise filter by card type category
|
||||
if (cardType === 'NONE') {
|
||||
where.NOT = { memberships: { some: { status: MembershipStatus.ACTIVE } } }
|
||||
} else if (cardType && VALID_CARD_TYPES.has(cardType)) {
|
||||
where.memberships = {
|
||||
some: {
|
||||
status: MembershipStatus.ACTIVE,
|
||||
cardType: { type: cardType as CardTypeCategory },
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const [users, total] = await Promise.all([
|
||||
this.prisma.user.findMany({
|
||||
where,
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user