feat: implement booking and customer order flow

This commit is contained in:
2026-09-18 16:21:00 +08:00
parent bd45625d36
commit 1e03d055aa
3 changed files with 200 additions and 26 deletions

View File

@@ -4,16 +4,18 @@ import {
Body,
Controller,
Get,
Injectable,
Module,
Param,
Post,
Req,
} from "@nestjs/common";
import { NestFactory } from "@nestjs/core";
import { FastifyAdapter } from "@nestjs/platform-fastify";
import type { NestFastifyApplication } from "@nestjs/platform-fastify";
import { PrismaClient } from "@prisma/client";
import { PrismaService } from "./prisma.service.js";
import { WechatAuthService } from "./wechat-auth.js";
import { BookingService } from "./booking.service.js";
import type { CreateBookingInput } from "./booking.service.js";
import type { FastifyRequest } from "fastify";
import { createHmac } from "node:crypto";
@@ -37,13 +39,6 @@ function readIdentity(token: string): { brandId: string; openid: string } {
};
}
@Injectable()
export class PrismaService extends PrismaClient {
async onModuleDestroy(): Promise<void> {
await this.$disconnect();
}
}
@Controller("health")
export class HealthController {
@Get()
@@ -114,27 +109,39 @@ export class CustomerSessionController {
@Controller("customer/bookings")
export class CustomerBookingController {
constructor(private readonly prisma: PrismaService) {}
constructor(
private readonly prisma: PrismaService,
private readonly bookings: BookingService,
) {}
@Post()
async create(@Req() request: FastifyRequest, @Body() body: CreateBookingInput): Promise<unknown> {
const identity = this.identity(request);
const customer = await this.prisma.customerUser.findUnique({
where: { brandId_openid: identity },
});
if (!customer) throw new BadRequestException("请先完成微信登录");
return this.bookings.create(identity.brandId, customer.id, body);
}
@Get()
async list(@Req() request: FastifyRequest): Promise<unknown> {
const identity = this.identity(request);
return this.prisma.booking.findMany({
where: { customerUser: { brandId: identity.brandId, openid: identity.openid } },
orderBy: { createdAt: "desc" },
select: {
bookingNo: true,
requestType: true,
customerName: true,
status: true,
estimatedAmount: true,
requestedDate: true,
requestedTime: true,
fulfillmentType: true,
createdAt: true,
items: { select: { serviceNameSnapshot: true, quantity: true, subtotalSnapshot: true } },
},
const customer = await this.prisma.customerUser.findUnique({
where: { brandId_openid: identity },
});
if (!customer) throw new BadRequestException("请先完成微信登录");
return this.bookings.listForCustomer(identity.brandId, customer.id);
}
@Post(":id/cancel")
async cancel(@Req() request: FastifyRequest, @Param("id") id: string): Promise<unknown> {
const identity = this.identity(request);
const customer = await this.prisma.customerUser.findUnique({
where: { brandId_openid: identity },
});
if (!customer) throw new BadRequestException("请先完成微信登录");
return this.bookings.cancelForCustomer(identity.brandId, customer.id, id);
}
private identity(request: FastifyRequest): { brandId: string; openid: string } {
@@ -149,14 +156,42 @@ export class CustomerBookingController {
}
}
@Controller("admin/bookings")
export class AdminBookingController {
constructor(private readonly bookings: BookingService) {}
@Get()
list(): Promise<unknown> {
return this.bookings.listForAdmin(
process.env.DEFAULT_BRAND_ID ?? "00000000-0000-0000-0000-000000000001",
);
}
@Post(":id/status")
update(
@Param("id") id: string,
@Body()
body: {
status: "received" | "contacting" | "confirmed" | "completed" | "cancelled";
adminNote?: string;
},
): Promise<unknown> {
return this.bookings.updateStatus(
process.env.DEFAULT_BRAND_ID ?? "00000000-0000-0000-0000-000000000001",
id,
body.status,
body.adminNote,
);
}
}
@Module({
controllers: [
HealthController,
PublicController,
CustomerSessionController,
CustomerBookingController,
AdminBookingController,
],
providers: [PrismaService, WechatAuthService],
providers: [PrismaService, WechatAuthService, BookingService],
exports: [PrismaService, WechatAuthService],
})
export class AppModule {}