feat(admin): require business hours when creating stores
CI / verify (pull_request) Has been cancelled

HQ create-store wizard now collects 1-2 hour segments and avgPrice, and API validates them on create/update.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-26 10:19:58 +08:00
parent b810cabc6d
commit cc9933d1ce
3 changed files with 101 additions and 5 deletions
@@ -1,5 +1,6 @@
import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common';
import { Prisma } from '@prisma/client';
import { validateBusinessHours } from '@dukang/domain';
import { PrismaService } from '../../common/prisma/prisma.module';
import { serializeBigInt } from '../../common/decorators/current-user.decorator';
import { mapStoreCompat } from '../../common/compat/v31-compat';
@@ -176,6 +177,23 @@ export class AdminStoresService {
}
async updateStore(id: bigint, dto: UpdateStoreDto) {
const current = await this.prisma.store.findUnique({ where: { id } });
if (!current) throw new NotFoundException('门店不存在');
const openTime = dto.openTime !== undefined ? dto.openTime?.trim() || '' : current.openTime || '';
const closeTime = dto.closeTime !== undefined ? dto.closeTime?.trim() || '' : current.closeTime || '';
const openTime2 =
dto.openTime2 !== undefined ? dto.openTime2?.trim() || '' : current.openTime2 || '';
const closeTime2 =
dto.closeTime2 !== undefined ? dto.closeTime2?.trim() || '' : current.closeTime2 || '';
if (dto.openTime !== undefined || dto.closeTime !== undefined || dto.openTime2 !== undefined || dto.closeTime2 !== undefined) {
const hoursCheck = validateBusinessHours([
{ open: openTime || '10:00', close: closeTime || '22:00' },
...(openTime2 || closeTime2 ? [{ open: openTime2, close: closeTime2 }] : []),
]);
if (!hoursCheck.ok) throw new BadRequestException(hoursCheck.message);
}
const store = await this.prisma.store.update({
where: { id },
data: {
@@ -194,7 +212,6 @@ export class AdminStoresService {
});
if (dto.coverUrl) {
const current = await this.prisma.store.findUniqueOrThrow({ where: { id } });
if (current.coverResourceId) {
await this.prisma.commonResource.update({
where: { id: current.coverResourceId },
@@ -251,6 +268,16 @@ export class AdminStoresService {
const categoryId = BigInt(dto.categoryId);
await this.storeCategoryService.assertLeafCategoryId(categoryId);
const openTime = dto.openTime?.trim() || '10:00';
const closeTime = dto.closeTime?.trim() || '22:00';
const openTime2 = dto.openTime2?.trim() || '';
const closeTime2 = dto.closeTime2?.trim() || '';
const hoursCheck = validateBusinessHours([
{ open: openTime, close: closeTime },
...(openTime2 || closeTime2 ? [{ open: openTime2, close: closeTime2 }] : []),
]);
if (!hoursCheck.ok) throw new BadRequestException(hoursCheck.message);
const store = await this.prisma.store.create({
data: {
cityId: city.id,
@@ -265,10 +292,10 @@ export class AdminStoresService {
address: dto.address,
intro: dto.intro ?? null,
avgPrice: dto.avgPrice ?? null,
openTime: dto.openTime?.trim() || '10:00',
closeTime: dto.closeTime?.trim() || '22:00',
openTime2: dto.openTime2?.trim() || null,
closeTime2: dto.closeTime2?.trim() || null,
openTime,
closeTime,
openTime2: openTime2 || null,
closeTime2: closeTime2 || null,
status: 'OPEN',
auditStatus: 'APPROVED',
auditedAt: new Date(),