feat: 迭代

This commit is contained in:
2026-05-15 11:28:02 +08:00
parent 6a7ec5fca7
commit 8c908ea557
120 changed files with 1139 additions and 238 deletions
+7 -7
View File
@@ -7,11 +7,11 @@ import jwtConfig from './config/jwt.config';
import redisConfig from './config/redis.config';
import { ScheduleModule as TaskScheduleModule } from './schedule/schedule.module';
// 新的模块结构
import { UserModule } from './modules/user/user.module';
// 新的模块结构 - 按端分类
import { AppModule as AppClientModule } from './modules/app/app.module';
import { MerchantModule } from './modules/merchant/merchant.module';
import { AdminModule } from './modules/admin/admin.module';
import { CommonModule } from './modules/common/common.module';
import { SharedModule } from './modules/shared/shared.module';
import { WebsiteModule } from './modules/website/website.module';
@Module({
@@ -39,11 +39,11 @@ import { WebsiteModule } from './modules/website/website.module';
}),
}),
// 新的模块结构:按端分组
UserModule, // 用户端(C端)
MerchantModule, // 商家端(B端
AppClientModule, // 应用端(小程序C端)
MerchantModule, // 商家端(小程序商家端+商家管理后台
AdminModule, // 平台管理端
CommonModule, // 公共模块
WebsiteModule, // 官网模块
SharedModule, // 共享模块(上传、配置等)
WebsiteModule, // 官网
],
})
export class AppModule {}
@@ -1,4 +1,5 @@
import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, Index } from 'typeorm';
import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, Index, ManyToOne, JoinColumn } from 'typeorm';
import { User } from './user.entity';
@Entity('mkt_invite_withdrawals')
export class MktInviteWithdrawal {
@@ -13,6 +14,10 @@ export class MktInviteWithdrawal {
@Index()
user_id: number;
@ManyToOne(() => User)
@JoinColumn({ name: 'user_id' })
user: User;
@Column({ type: 'decimal', precision: 10, scale: 2, comment: '提现金额' })
amount: number;
+12
View File
@@ -16,14 +16,26 @@ export class Review {
@Column({ name: 'order_id', type: 'bigint', unsigned: true, unique: true, comment: '订单ID' })
orderId: number;
@ManyToOne(() => User)
@JoinColumn({ name: 'user_id' })
user: User;
@Index()
@Column({ name: 'user_id', type: 'bigint', unsigned: true, comment: '用户ID' })
userId: number;
@ManyToOne(() => Merchant)
@JoinColumn({ name: 'merchant_id' })
merchant: Merchant;
@Index()
@Column({ name: 'merchant_id', type: 'bigint', unsigned: true, comment: '商家ID' })
merchantId: number;
@ManyToOne(() => Room)
@JoinColumn({ name: 'room_id' })
room: Room;
@Column({ name: 'room_id', type: 'bigint', unsigned: true, comment: '房型ID' })
roomId: number;
+4
View File
@@ -42,6 +42,10 @@ async function bootstrap() {
.setDescription('平台后端接口文档')
.setVersion('1.0')
.addBearerAuth()
.addTag('应用端', '小程序C端用户使用的接口')
.addTag('商家端', '小程序商家端和商家管理后台使用的接口')
.addTag('平台管理端', '平台管理后台使用的接口')
.addTag('官网', '官方网站使用的接口')
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api/docs', app, document);
@@ -1,8 +1,8 @@
import { Controller, Get, Put, Body, UseGuards } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
import { ConfigService } from '@/modules/common/config/config.service';
import { ConfigService } from '@/modules/shared/config/config.service';
import { JwtAuthGuard, RolesGuard, Roles } from '@/common';
import { UploadService } from '@/modules/common/upload/upload.service';
import { UploadService } from '@/modules/shared/upload/upload.service';
@ApiTags('管理端-系统配置')
@ApiBearerAuth()
@@ -1,6 +1,6 @@
import { Module } from '@nestjs/common';
import { ConfigModule as CommonConfigModule } from '@/modules/common/config/config.module';
import { UploadModule } from '@/modules/common/upload/upload.module';
import { ConfigModule as CommonConfigModule } from '@/modules/shared/config/config.module';
import { UploadModule } from '@/modules/shared/upload/upload.module';
import { AdminConfigController } from './config.controller';
@Module({
@@ -10,7 +10,7 @@ import {
UseGuards,
} from '@nestjs/common';
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
import { CouponService } from '@/modules/common/coupon/coupon.service';
import { CouponService } from '@/modules/shared/coupon/coupon.service';
import { JwtAuthGuard, RolesGuard } from '@/common';
import { Roles } from '@/common/decorators/roles.decorator';
import { CurrentUser } from '@/common/decorators/current-user.decorator';
@@ -1,5 +1,5 @@
import { Module } from '@nestjs/common';
import { CouponModule } from '@/modules/common/coupon/coupon.module';
import { CouponModule } from '@/modules/shared/coupon/coupon.module';
import { CouponController } from './coupon.controller';
@Module({
@@ -1,2 +1,2 @@
// 复用共享的 CouponService
export { CouponService } from '@/modules/common/coupon/coupon.service';
export { CouponService } from '@/modules/shared/coupon/coupon.service';
@@ -1 +1 @@
export * from '@/modules/common/coupon/dto/coupon.dto';
export * from '@/modules/shared/coupon/dto/coupon.dto';
@@ -6,10 +6,10 @@ import {
UseGuards,
} from '@nestjs/common';
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
import { AccountService } from './account.service';
import { AccountService } from '@/modules/shared/finance/account.service';
import { JwtAuthGuard, RolesGuard } from '@/common';
import { Roles } from '@/common/decorators/roles.decorator';
import { QueryUserAccountsDto, QueryMerchantAccountsDto } from './dto/account.dto';
import { QueryUserAccountsDto, QueryMerchantAccountsDto } from '@/modules/shared/finance/dto/account.dto';
@ApiTags('账户管理(管理员)')
@Controller('admin/finance/accounts')
@@ -1,9 +1,22 @@
import { Module } from '@nestjs/common';
import { FinanceModule as CommonFinanceModule } from '@/modules/common/finance/finance.module';
import { FinanceModule as CommonFinanceModule } from '@/modules/shared/finance/finance.module';
import { AccountAdminController } from './account-admin.controller';
import { ReconciliationAdminController } from './reconciliation-admin.controller';
import { ReportAdminController } from './report-admin.controller';
import { SettlementAdminController } from './settlement-admin.controller';
import { TransactionAdminController } from './transaction-admin.controller';
import { WithdrawalAdminController } from './withdrawal-admin.controller';
@Module({
imports: [CommonFinanceModule],
controllers: [],
controllers: [
AccountAdminController,
ReconciliationAdminController,
ReportAdminController,
SettlementAdminController,
TransactionAdminController,
WithdrawalAdminController,
],
})
export class AdminFinanceModule {}
@@ -10,11 +10,11 @@ import {
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
import { JwtAuthGuard, RolesGuard } from '@/common';
import { Roles } from '@/common/decorators/roles.decorator';
import { ReconciliationService } from './reconciliation.service';
import { ReconciliationService } from '@/modules/shared/finance/reconciliation.service';
import {
ManualReconciliationDto,
QueryReconciliationDto,
} from './dto/reconciliation.dto';
} from '@/modules/shared/finance/dto/reconciliation.dto';
@ApiTags('对账管理(管理员)')
@Controller('admin/finance/reconciliations')
@@ -5,7 +5,7 @@ import {
UseGuards,
} from '@nestjs/common';
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
import { ReportService } from './report.service';
import { ReportService } from '@/modules/shared/finance/report.service';
import { JwtAuthGuard, RolesGuard } from '@/common';
import { Roles } from '@/common/decorators/roles.decorator';
import {
@@ -13,7 +13,7 @@ import {
QueryDailyReportDto,
QueryWeeklyReportDto,
QueryMonthlyReportDto,
} from './dto/report.dto';
} from '@/modules/shared/finance/dto/report.dto';
@ApiTags('财务报表(管理员)')
@Controller('admin/finance/reports')
@@ -32,25 +32,24 @@ export class ReportAdminController {
@Get('trend')
@ApiOperation({ summary: '财务趋势' })
async getTrend(@Query() dto: QueryTrendDto) {
return this.reportService.getTrend({
startDate: dto.startDate,
endDate: dto.endDate,
});
const startDate = dto.startDate || new Date(Date.now() - 30 * 24 * 60 * 60 * 1000).toISOString().split('T')[0];
const endDate = dto.endDate || new Date().toISOString().split('T')[0];
return this.reportService.getTrend({ startDate, endDate });
}
@Get('daily')
@ApiOperation({ summary: '日报表' })
async getDailyReport(@Query() dto: QueryDailyReportDto) {
return this.reportService.getDailyReport(dto.date);
const date = dto.date || new Date().toISOString().split('T')[0];
return this.reportService.getDailyReport(date);
}
@Get('weekly')
@ApiOperation({ summary: '周报表' })
async getWeeklyReport(@Query() dto: QueryWeeklyReportDto) {
return this.reportService.getWeeklyReport({
startDate: dto.startDate,
endDate: dto.endDate,
});
const endDate = dto.endDate || new Date().toISOString().split('T')[0];
const startDate = dto.startDate || new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString().split('T')[0];
return this.reportService.getWeeklyReport({ startDate, endDate });
}
@Get('monthly')
@@ -9,7 +9,7 @@ import {
UseGuards,
} from '@nestjs/common';
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
import { SettlementService } from './settlement.service';
import { SettlementService } from '@/modules/shared/finance/settlement.service';
import { JwtAuthGuard, RolesGuard } from '@/common';
import { Roles } from '@/common/decorators/roles.decorator';
import {
@@ -17,7 +17,7 @@ import {
ManualSettlementDto,
ApproveSettlementDto,
RejectSettlementDto,
} from './dto/settlement.dto';
} from '@/modules/shared/finance/dto/settlement.dto';
@ApiTags('结算管理(管理员)')
@Controller('admin/finance/settlements')
@@ -8,12 +8,12 @@ import {
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
import { JwtAuthGuard, RolesGuard } from '@/common';
import { Roles } from '@/common/decorators/roles.decorator';
import { TransactionService } from './transaction.service';
import { TransactionService } from '@/modules/shared/finance/transaction.service';
import {
QueryUserTransactionDto,
QueryMerchantTransactionDto,
QueryPlatformTransactionDto,
} from './dto/transaction.dto';
} from '@/modules/shared/finance/dto/transaction.dto';
@ApiTags('交易流水管理(管理员)')
@Controller('admin/finance/transactions')
@@ -9,7 +9,7 @@ import {
UseGuards,
} from '@nestjs/common';
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
import { WithdrawalService } from './withdrawal.service';
import { WithdrawalService } from '@/modules/shared/finance/withdrawal.service';
import { JwtAuthGuard, RolesGuard } from '@/common';
import { Roles } from '@/common/decorators/roles.decorator';
import { CurrentUser } from '@/common/decorators/current-user.decorator';
@@ -20,7 +20,7 @@ import {
QueryMerchantWithdrawalDto,
RejectWithdrawalDto,
ConfirmPaymentDto,
} from './dto/withdrawal.dto';
} from '@/modules/shared/finance/dto/withdrawal.dto';
@ApiTags('提现管理(管理员)')
@Controller('admin/finance/withdrawals')
@@ -0,0 +1,84 @@
import {
Controller,
Get,
Post,
Body,
Query,
UseGuards,
} from '@nestjs/common';
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
import { ActivityService } from './activity.service';
import { JwtAuthGuard, CurrentUser } from '@/common';
import {
BindInvitationDto,
CreateInviteWithdrawalDto,
QueryInviteRecordsDto,
} from './dto/activity.dto';
// ===== 用户端活动接口 =====
@ApiTags('用户端-活动')
@Controller('app/activity')
export class ActivityController {
constructor(private readonly activityService: ActivityService) {}
@Get('list')
@ApiOperation({ summary: '获取活动列表' })
async getActivityList() {
const activity = await this.activityService.getEnabledInviteCashbackActivity();
return activity ? [activity] : [];
}
@Get('invite/config')
@ApiOperation({ summary: '获取邀请活动配置' })
async getInviteConfig() {
return this.activityService.getEnabledInviteCashbackActivity();
}
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@Get('invite/stats')
@ApiOperation({ summary: '获取我的邀请统计' })
async getStats(@CurrentUser('sub') userId: number) {
return this.activityService.getUserStats(userId);
}
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@Post('invite/bind')
@ApiOperation({ summary: '绑定邀请关系' })
async bind(@CurrentUser('sub') userId: number, @Body() dto: BindInvitationDto) {
return this.activityService.bindInvitation(userId, dto);
}
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@Get('invite/records')
@ApiOperation({ summary: '邀请记录列表' })
async getRecords(@CurrentUser('sub') userId: number, @Query() dto: QueryInviteRecordsDto) {
return this.activityService.getInviteRecords(userId, dto);
}
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@Get('invite/cashbacks')
@ApiOperation({ summary: '返现记录列表' })
async getCashbacks(@CurrentUser('sub') userId: number, @Query() dto: QueryInviteRecordsDto) {
return this.activityService.getCashbackRecords(userId, dto);
}
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@Post('invite/withdraw')
@ApiOperation({ summary: '申请提现' })
async createWithdrawal(@CurrentUser('sub') userId: number, @Body() dto: CreateInviteWithdrawalDto) {
return this.activityService.createWithdrawal(userId, dto);
}
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@Get('invite/withdrawals')
@ApiOperation({ summary: '提现记录列表' })
async getWithdrawals(@CurrentUser('sub') userId: number, @Query() dto: QueryInviteRecordsDto) {
return this.activityService.getWithdrawalRecords(userId, dto);
}
}
@@ -205,6 +205,11 @@ export class ActivityService {
take: pageSize,
});
// 如果没有邀请记录,直接返回
if (list.length === 0) {
return { list: [], total: 0 };
}
// 获取每个被邀请人的订单数
const inviteeIds = list.map((item) => item.inviteeId);
const orderCounts = await this.orderRepo
@@ -1,4 +1,9 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Merchant } from '@/entities/merchant.entity';
import { MerchantAccount } from '@/entities/merchant-account.entity';
import { Room } from '@/entities/room.entity';
import { RoomCalendar } from '@/entities/room-calendar.entity';
import { UserAuthModule } from './auth/auth.module';
import { UserProfileModule } from './profile/profile.module';
import { UserGuestModule } from './guest/guest.module';
@@ -7,9 +12,13 @@ import { UserReviewModule } from './review/review.module';
import { UserCouponModule } from './coupon/coupon.module';
import { UserFinanceModule } from './finance/finance.module';
import { UserActivityModule } from './activity/activity.module';
import { RoomModule } from './room/room.module';
import { MerchantController } from './merchant/merchant.controller';
import { MerchantService } from '@/modules/merchant/merchant.service';
@Module({
imports: [
TypeOrmModule.forFeature([Merchant, MerchantAccount, Room, RoomCalendar]),
UserAuthModule,
UserProfileModule,
UserGuestModule,
@@ -18,6 +27,9 @@ import { UserActivityModule } from './activity/activity.module';
UserCouponModule,
UserFinanceModule,
UserActivityModule,
RoomModule,
],
controllers: [MerchantController],
providers: [MerchantService],
})
export class UserModule {}
export class AppModule {}
@@ -11,7 +11,7 @@ import {
import { JwtAuthGuard } from '@/common/guards/jwt-auth.guard';
@ApiTags('用户认证')
@Controller('user/auth')
@Controller('app/auth')
export class AuthController {
constructor(private readonly authService: AuthService) {}
@@ -14,7 +14,7 @@ import { CurrentUser } from '@/common/decorators/current-user.decorator';
import { ReceiveCouponDto, QueryUserCouponDto, QueryCouponDto } from './dto/coupon.dto';
@ApiTags('优惠券(用户)')
@Controller('user/coupons')
@Controller('app/coupons')
@UseGuards(JwtAuthGuard)
@ApiBearerAuth()
export class CouponUserController {
@@ -14,7 +14,7 @@ import { CurrentUser } from '@/common/decorators/current-user.decorator';
import { ReceiveCouponDto, QueryUserCouponDto, QueryCouponDto } from './dto/coupon.dto';
@ApiTags('优惠券(用户)')
@Controller('user/coupons')
@Controller('app/coupons')
@UseGuards(JwtAuthGuard)
@ApiBearerAuth()
export class CouponController {
@@ -0,0 +1,2 @@
// 复用现有的 CouponDto
export * from '@/modules/shared/coupon/dto/coupon.dto';
@@ -9,17 +9,17 @@ import {
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
import { JwtAuthGuard } from '@/common';
import { CurrentUser } from '@/common/decorators/current-user.decorator';
import { WithdrawalService } from './withdrawal.service';
import { TransactionService } from './transaction.service';
import { AccountService } from './account.service';
import { WithdrawalService } from '@/modules/shared/finance/withdrawal.service';
import { TransactionService } from '@/modules/shared/finance/transaction.service';
import { AccountService } from '@/modules/shared/finance/account.service';
import {
CreateUserWithdrawalDto,
QueryUserWithdrawalDto,
QueryTransactionDto,
} from './dto/finance.dto';
} from '@/modules/shared/finance/dto/finance.dto';
@ApiTags('财务管理(用户)')
@Controller('user/finance')
@Controller('app/finance')
@UseGuards(JwtAuthGuard)
@ApiBearerAuth()
export class FinanceUserController {
@@ -1,9 +1,10 @@
import { Module } from '@nestjs/common';
import { FinanceModule as CommonFinanceModule } from '@/modules/common/finance/finance.module';
import { FinanceModule as CommonFinanceModule } from '@/modules/shared/finance/finance.module';
import { FinanceUserController } from './finance-user.controller';
@Module({
imports: [CommonFinanceModule],
controllers: [],
controllers: [FinanceUserController],
})
export class UserFinanceModule {}
@@ -8,16 +8,16 @@ import {
UseGuards,
} from '@nestjs/common';
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
import { WithdrawalService } from './withdrawal.service';
import { WithdrawalService } from '@/modules/shared/finance/withdrawal.service';
import { JwtAuthGuard } from '@/common';
import { CurrentUser } from '@/common/decorators/current-user.decorator';
import {
CreateUserWithdrawalDto,
QueryUserWithdrawalDto,
} from './dto/withdrawal.dto';
} from '@/modules/shared/finance/dto/withdrawal.dto';
@ApiTags('提现管理(用户)')
@Controller('user/finance/withdrawals')
@Controller('app/finance/withdrawals')
@UseGuards(JwtAuthGuard)
@ApiBearerAuth()
export class WithdrawalUserController {
@@ -13,7 +13,7 @@ import { GuestService } from './guest.service';
import { CreateGuestDto, UpdateGuestDto } from './dto/guest.dto';
import { JwtAuthGuard } from '@/common/guards/jwt-auth.guard';
@Controller('user/guests')
@Controller('app/guests')
@UseGuards(JwtAuthGuard)
export class GuestController {
constructor(private readonly guestService: GuestService) {}
@@ -1,11 +1,11 @@
import { Controller, Get, Param, Query } from '@nestjs/common';
import { ApiTags, ApiOperation } from '@nestjs/swagger';
import { MerchantService } from './merchant.service';
import { QueryMerchantDto } from './dto/merchant.dto';
import { MerchantService } from '@/modules/merchant/merchant.service';
import { QueryMerchantDto } from '@/modules/merchant/dto/merchant.dto';
@ApiTags('商家')
@Controller('public/merchants')
export class MerchantPublicController {
@Controller('app/merchants')
export class MerchantController {
constructor(private readonly merchantService: MerchantService) {}
@Get()
@@ -19,7 +19,7 @@ import {
} from './dto/order.dto';
@ApiTags('订单(用户)')
@Controller('user/orders')
@Controller('app/orders')
@UseGuards(JwtAuthGuard)
@ApiBearerAuth()
export class OrderController {
@@ -6,10 +6,10 @@ import { Order } from '@/entities/order.entity';
import { Room } from '@/entities/room.entity';
import { RoomCalendar } from '@/entities/room-calendar.entity';
import { Review } from '@/entities/review.entity';
import { UserActivityModule } from '@/modules/user/activity/activity.module';
import { ConfigModule } from '@/modules/common/config/config.module';
import { FinanceModule } from '@/modules/common/finance/finance.module';
import { UserCouponModule } from '@/modules/user/coupon/coupon.module';
import { UserActivityModule } from '@/modules/app/activity/activity.module';
import { ConfigModule } from '@/modules/shared/config/config.module';
import { FinanceModule } from '@/modules/shared/finance/finance.module';
import { UserCouponModule } from '@/modules/app/coupon/coupon.module';
@Module({
imports: [
@@ -6,10 +6,10 @@ import { Room } from '@/entities/room.entity';
import { RoomCalendar } from '@/entities/room-calendar.entity';
import { Review } from '@/entities/review.entity';
import { CreateOrderDto, QueryOrderDto } from './dto/order.dto';
import { ActivityService } from '@/modules/user/activity/activity.service';
import { ConfigService } from '@/modules/common/config/config.service';
import { RefundService } from '@/modules/common/finance/refund.service';
import { CouponService } from '@/modules/user/coupon/coupon.service';
import { ActivityService } from '@/modules/app/activity/activity.service';
import { ConfigService } from '@/modules/shared/config/config.service';
import { RefundService } from '@/modules/shared/finance/refund.service';
import { CouponService } from '@/modules/app/coupon/coupon.service';
@Injectable()
export class OrderService {
@@ -20,7 +20,7 @@ import {
} from './dto/user.dto';
@ApiTags('用户信息')
@Controller('user/profile')
@Controller('app/profile')
@UseGuards(JwtAuthGuard)
@ApiBearerAuth()
export class ProfileController {
@@ -14,7 +14,7 @@ import { CreateReviewDto, QueryReviewDto } from './dto/review.dto';
import { JwtAuthGuard } from '@/common/guards/jwt-auth.guard';
// 用户端评价接口
@Controller('user/reviews')
@Controller('app/reviews')
export class ReviewController {
constructor(private readonly reviewService: ReviewService) {}
@@ -0,0 +1,56 @@
import { IsOptional, IsInt, IsDateString, Min } from 'class-validator';
import { Type } from 'class-transformer';
import { ApiPropertyOptional } from '@nestjs/swagger';
export class QueryAvailableRoomsDto {
@ApiPropertyOptional({ description: '商家ID' })
@IsOptional()
@Type(() => Number)
@IsInt()
merchantId?: number;
@ApiPropertyOptional({ description: '入住日期', example: '2026-05-15' })
@IsOptional()
@IsDateString()
checkIn?: string;
@ApiPropertyOptional({ description: '退房日期', example: '2026-05-16' })
@IsOptional()
@IsDateString()
checkOut?: string;
@ApiPropertyOptional({ description: '房间数量', default: 1 })
@IsOptional()
@Type(() => Number)
@IsInt()
@Min(1)
roomCount?: number;
@ApiPropertyOptional({ description: '成人数量', default: 1 })
@IsOptional()
@Type(() => Number)
@IsInt()
@Min(1)
adultCount?: number;
@ApiPropertyOptional({ description: '儿童数量', default: 0 })
@IsOptional()
@Type(() => Number)
@IsInt()
@Min(0)
childCount?: number;
@ApiPropertyOptional({ description: '页码', default: 1 })
@IsOptional()
@Type(() => Number)
@IsInt()
@Min(1)
page?: number;
@ApiPropertyOptional({ description: '每页数量', default: 10 })
@IsOptional()
@Type(() => Number)
@IsInt()
@Min(1)
pageSize?: number;
}
@@ -0,0 +1,22 @@
import { Controller, Get, Query, Param } from '@nestjs/common';
import { ApiTags, ApiOperation } from '@nestjs/swagger';
import { RoomService } from './room.service';
import { QueryAvailableRoomsDto } from './dto/room.dto';
@ApiTags('房源')
@Controller('app/rooms')
export class RoomController {
constructor(private readonly roomService: RoomService) {}
@Get()
@ApiOperation({ summary: '查询可用房源' })
async findAvailable(@Query() query: QueryAvailableRoomsDto) {
return this.roomService.findAvailable(query);
}
@Get(':id')
@ApiOperation({ summary: '获取房源详情' })
async findOne(@Param('id') id: number) {
return this.roomService.findById(id);
}
}
@@ -0,0 +1,15 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Room } from '@/entities/room.entity';
import { RoomCalendar } from '@/entities/room-calendar.entity';
import { Merchant } from '@/entities/merchant.entity';
import { RoomController } from './room.controller';
import { RoomService } from './room.service';
@Module({
imports: [TypeOrmModule.forFeature([Room, RoomCalendar, Merchant])],
controllers: [RoomController],
providers: [RoomService],
exports: [RoomService],
})
export class RoomModule {}
@@ -0,0 +1,83 @@
import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, Between, LessThanOrEqual, MoreThanOrEqual } from 'typeorm';
import { Room } from '@/entities/room.entity';
import { RoomCalendar } from '@/entities/room-calendar.entity';
import { QueryAvailableRoomsDto } from './dto/room.dto';
@Injectable()
export class RoomService {
constructor(
@InjectRepository(Room)
private roomRepo: Repository<Room>,
@InjectRepository(RoomCalendar)
private calendarRepo: Repository<RoomCalendar>,
) {}
async findById(id: number) {
const room = await this.roomRepo.findOne({
where: { id: Number(id) },
relations: ['merchant'],
});
if (!room) throw new NotFoundException('房源不存在');
return room;
}
async findAvailable(query: QueryAvailableRoomsDto) {
const {
merchantId,
checkIn,
checkOut,
roomCount = 1,
adultCount = 1,
childCount = 0,
page = 1,
pageSize = 10,
} = query;
const qb = this.roomRepo
.createQueryBuilder('room')
.leftJoinAndSelect('room.merchant', 'merchant')
.where('room.status = :status', { status: 'on_sale' })
.andWhere('room.audit_status = :auditStatus', { auditStatus: 'approved' });
// 按商家筛选
if (merchantId) {
qb.andWhere('room.merchant_id = :merchantId', { merchantId });
}
// 按容纳人数筛选
const totalGuests = adultCount + childCount;
qb.andWhere('room.max_guests >= :totalGuests', { totalGuests });
// 如果提供了日期,检查可用性
if (checkIn && checkOut) {
// 查询在该日期范围内有库存的房间
const availableRoomIds = await this.calendarRepo
.createQueryBuilder('cal')
.select('DISTINCT cal.room_id', 'roomId')
.where('cal.date >= :checkIn', { checkIn })
.andWhere('cal.date < :checkOut', { checkOut })
.andWhere('cal.status = :status', { status: 'available' })
.andWhere('(cal.stock - cal.sold) >= :roomCount', { roomCount })
.groupBy('cal.room_id')
.having('COUNT(*) = DATEDIFF(:checkOut, :checkIn)', { checkIn, checkOut })
.getRawMany();
if (availableRoomIds.length > 0) {
const roomIds = availableRoomIds.map(item => item.roomId);
qb.andWhere('room.id IN (:...roomIds)', { roomIds });
} else {
// 没有可用房间,返回空结果
return { list: [], total: 0, page, pageSize };
}
}
qb.orderBy('room.created_at', 'DESC');
qb.skip((page - 1) * pageSize).take(pageSize);
const [list, total] = await qb.getManyAndCount();
return { list, total, page, pageSize };
}
}
@@ -20,7 +20,7 @@ import {
} from './dto/user.dto';
@ApiTags('用户')
@Controller('user')
@Controller('app')
@UseGuards(JwtAuthGuard)
@ApiBearerAuth()
export class UserUserController {
@@ -37,6 +37,12 @@ export class MerchantFinanceController {
return account;
}
@Get('wallet')
@ApiOperation({ summary: '获取商家钱包信息' })
async getWallet(@CurrentSeller('sub') sellerId: number) {
return this.getAccount(sellerId);
}
@Get('transactions')
@ApiOperation({ summary: '交易流水列表' })
async getTransactions(
@@ -7,11 +7,11 @@ import {
NotFoundException,
} from '@nestjs/common';
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
import { SettlementService } from './settlement.service';
import { SettlementService } from '@/modules/shared/finance/settlement.service';
import { SellerJwtAuthGuard } from '@/common/guards/seller-jwt-auth.guard';
import { CurrentSeller } from '@/common/decorators/current-seller.decorator';
import { MerchantService } from '@/modules/merchant/merchant.service';
import { QuerySettlementDto } from './dto/settlement.dto';
import { QuerySettlementDto } from '@/modules/shared/finance/dto/settlement.dto';
@ApiTags('结算管理(商家)')
@Controller('merchant/finance/settlements')
@@ -8,10 +8,10 @@ import {
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
import { SellerJwtAuthGuard } from '@/common/guards/seller-jwt-auth.guard';
import { CurrentSeller } from '@/common/decorators/current-seller.decorator';
import { TransactionService } from './transaction.service';
import { AccountService } from './account.service';
import { TransactionService } from '@/modules/shared/finance/transaction.service';
import { AccountService } from '@/modules/shared/finance/account.service';
import { MerchantService } from '@/modules/merchant/merchant.service';
import { QueryTransactionDto } from './dto/finance.dto';
import { QueryTransactionDto } from '@/modules/shared/finance/dto/finance.dto';
@ApiTags('交易流水(商家)')
@Controller('merchant/finance/transactions')
@@ -9,14 +9,14 @@ import {
NotFoundException,
} from '@nestjs/common';
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
import { WithdrawalService } from './withdrawal.service';
import { WithdrawalService } from '@/modules/shared/finance/withdrawal.service';
import { SellerJwtAuthGuard } from '@/common/guards/seller-jwt-auth.guard';
import { CurrentSeller } from '@/common/decorators/current-seller.decorator';
import { MerchantService } from '@/modules/merchant/merchant.service';
import {
CreateMerchantWithdrawalDto,
QueryMerchantWithdrawalDto,
} from './dto/withdrawal.dto';
} from '@/modules/shared/finance/dto/withdrawal.dto';
@ApiTags('提现管理(商家)')
@Controller('merchant/finance/withdrawals')
@@ -27,6 +27,12 @@ export class MerchantAdminController {
return this.merchantService.findAll(query);
}
@Get(':id')
@ApiOperation({ summary: '获取商家详情' })
async findById(@Param('id') id: number) {
return this.merchantService.findById(id);
}
@Put(':id/approve')
@ApiOperation({ summary: '审核通过' })
async approve(@Param('id') id: number) {
@@ -17,7 +17,7 @@ import {
} from './dto/merchant.dto';
@ApiTags('商家管理(商家)')
@Controller('seller/merchant')
@Controller('merchant/merchant')
@UseGuards(SellerJwtAuthGuard)
@ApiBearerAuth()
export class MerchantSellerController {
@@ -7,7 +7,6 @@ import { RoomCalendar } from '@/entities/room-calendar.entity';
import { Order } from '@/entities/order.entity';
import { MerchantService } from './merchant.service';
import { StatisticsService } from './statistics.service';
import { MerchantPublicController } from './merchant-public.controller';
import { MerchantSellerController } from './merchant-seller.controller';
import { MerchantAdminController } from './merchant-admin.controller';
import { StatisticsSellerController } from './statistics-seller.controller';
@@ -33,7 +32,6 @@ import { MerchantStatisticsModule } from './statistics/statistics.module';
MerchantStatisticsModule,
],
controllers: [
MerchantPublicController,
MerchantSellerController,
MerchantAdminController,
StatisticsSellerController,
@@ -10,7 +10,7 @@ import { StatisticsService } from './statistics.service';
@ApiBearerAuth()
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles('merchant')
@Controller('seller/statistics')
@Controller('merchant/statistics')
export class StatisticsSellerController {
constructor(private readonly statisticsService: StatisticsService) {}
@@ -3,13 +3,11 @@ import { TypeOrmModule } from '@nestjs/typeorm';
import { Coupon } from '@/entities/coupon.entity';
import { UserCoupon } from '@/entities/user-coupon.entity';
import { CouponService } from './coupon.service';
import { CouponAdminController } from './coupon-admin.controller';
import { CouponUserController } from './coupon-user.controller';
// 注意:coupon-admin 和 coupon-user controller 已移动到各自模块
@Module({
imports: [TypeOrmModule.forFeature([Coupon, UserCoupon])],
controllers: [CouponAdminController, CouponUserController],
providers: [CouponService],
exports: [CouponService],
exports: [CouponService, TypeOrmModule],
})
export class CouponModule {}
@@ -3,29 +3,34 @@ import { Type } from 'class-transformer';
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
export class QueryTrendDto {
@ApiProperty({ description: '开始日期', example: '2026-05-01' })
@ApiPropertyOptional({ description: '开始日期', example: '2026-05-01' })
@IsOptional()
@IsDateString()
startDate: string;
startDate?: string;
@ApiProperty({ description: '结束日期', example: '2026-05-31' })
@ApiPropertyOptional({ description: '结束日期', example: '2026-05-31' })
@IsOptional()
@IsDateString()
endDate: string;
endDate?: string;
}
export class QueryDailyReportDto {
@ApiProperty({ description: '日期', example: '2026-05-12' })
@ApiPropertyOptional({ description: '日期', example: '2026-05-12' })
@IsOptional()
@IsDateString()
date: string;
date?: string;
}
export class QueryWeeklyReportDto {
@ApiProperty({ description: '开始日期', example: '2026-05-06' })
@ApiPropertyOptional({ description: '开始日期', example: '2026-05-06' })
@IsOptional()
@IsDateString()
startDate: string;
startDate?: string;
@ApiProperty({ description: '结束日期', example: '2026-05-12' })
@ApiPropertyOptional({ description: '结束日期', example: '2026-05-12' })
@IsOptional()
@IsDateString()
endDate: string;
endDate?: string;
}
export class QueryMonthlyReportDto {
@@ -21,17 +21,7 @@ import { TransactionService } from './transaction.service';
import { ReconciliationService } from './reconciliation.service';
import { ReportService } from './report.service';
import { RefundService } from './refund.service';
import { FinanceUserController } from './finance-user.controller';
import { TransactionSellerController } from './transaction-seller.controller';
import { TransactionAdminController } from './transaction-admin.controller';
import { ReconciliationAdminController } from './reconciliation-admin.controller';
import { AccountAdminController } from './account-admin.controller';
import { WithdrawalAdminController } from './withdrawal-admin.controller';
import { WithdrawalUserController } from './withdrawal-user.controller';
import { WithdrawalMerchantController } from './withdrawal-merchant.controller';
import { SettlementAdminController } from './settlement-admin.controller';
import { SettlementMerchantController } from './settlement-merchant.controller';
import { ReportAdminController } from './report-admin.controller';
// 注意:所有 controller 已移动到各自模块(app/merchant/admin
import { MerchantModule } from '@/modules/merchant/merchant.module';
@Module({
@@ -54,19 +44,6 @@ import { MerchantModule } from '@/modules/merchant/merchant.module';
]),
MerchantModule,
],
controllers: [
FinanceUserController,
TransactionSellerController,
TransactionAdminController,
ReconciliationAdminController,
AccountAdminController,
WithdrawalAdminController,
WithdrawalUserController,
WithdrawalMerchantController,
SettlementAdminController,
SettlementMerchantController,
ReportAdminController,
],
providers: [
SettlementService,
WithdrawalService,
@@ -84,6 +61,7 @@ import { MerchantModule } from '@/modules/merchant/merchant.module';
ReconciliationService,
ReportService,
RefundService,
TypeOrmModule,
],
})
export class FinanceModule {}
@@ -18,4 +18,4 @@ import { ConfigModule } from './config/config.module';
ConfigModule,
],
})
export class CommonModule {}
export class SharedModule {}
@@ -1,48 +0,0 @@
import {
Controller,
Get,
Post,
Body,
Query,
UseGuards,
} from '@nestjs/common';
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
import { ActivityService } from './activity.service';
import { JwtAuthGuard, CurrentUser } from '@/common';
import {
BindInvitationDto,
QueryInviteRecordsDto,
} from './dto/activity.dto';
// ===== 用户端邀请接口 =====
@ApiTags('用户端-邀请返现')
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@Controller('user/activity/invite')
export class ActivityController {
constructor(private readonly activityService: ActivityService) {}
@Get('stats')
@ApiOperation({ summary: '获取我的邀请统计' })
async getStats(@CurrentUser('sub') userId: number) {
return this.activityService.getUserStats(userId);
}
@Post('bind')
@ApiOperation({ summary: '绑定邀请关系' })
async bind(@CurrentUser('sub') userId: number, @Body() dto: BindInvitationDto) {
return this.activityService.bindInvitation(userId, dto);
}
@Get('records')
@ApiOperation({ summary: '邀请记录列表' })
async getRecords(@CurrentUser('sub') userId: number, @Query() dto: QueryInviteRecordsDto) {
return this.activityService.getInviteRecords(userId, dto);
}
@Get('cashbacks')
@ApiOperation({ summary: '返现记录列表' })
async getCashbacks(@CurrentUser('sub') userId: number, @Query() dto: QueryInviteRecordsDto) {
return this.activityService.getCashbackRecords(userId, dto);
}
}
@@ -1,2 +0,0 @@
// 复用现有的 CouponDto
export * from '@/modules/common/coupon/dto/coupon.dto';
+1 -1
View File
@@ -3,7 +3,7 @@ import { TypeOrmModule } from '@nestjs/typeorm';
import { Order } from '@/entities/order.entity';
import { OrderSchedule } from './order.schedule';
import { SettlementSchedule } from './settlement.schedule';
import { FinanceModule } from '@/modules/common/finance/finance.module';
import { FinanceModule } from '@/modules/shared/finance/finance.module';
@Module({
imports: [
@@ -1,6 +1,6 @@
import { Injectable, Logger } from '@nestjs/common';
import { Cron } from '@nestjs/schedule';
import { SettlementService } from '@/modules/common/finance/settlement.service';
import { SettlementService } from '@/modules/shared/finance/settlement.service';
@Injectable()
export class SettlementSchedule {