feat(store): 门店套餐 v3.4.10 全端实现

新增 StorePackage 与变更审核流,覆盖总部直存、合伙/门店提审、C 端展示与套餐异议工单;同步 PRD/开发文档与 REQ 索引。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-03 19:30:59 +08:00
parent 7e3dc131ad
commit 3c19b7dd97
35 changed files with 2128 additions and 28 deletions
@@ -0,0 +1,104 @@
import { Body, Controller, Get, Param, Put, Query, UseGuards } from '@nestjs/common';
import { JwtAuthGuard, AuthUser } from '../../common/guards/jwt-auth.guard';
import { HqAuthGuard } from '../../common/guards/hq-auth.guard';
import { ShopStoreGuard } from '../../common/guards/shop-store.guard';
import { CurrentUser } from '../../common/decorators/current-user.decorator';
import { StorePackageService } from './store-package.service';
@Controller('partner/stores')
@UseGuards(JwtAuthGuard)
export class PartnerStorePackageController {
constructor(private readonly packages: StorePackageService) {}
@Get(':storeId/packages')
getPackages(@CurrentUser() user: AuthUser, @Param('storeId') storeId: string) {
return this.packages.getPartnerPackages(user.actorId, BigInt(storeId));
}
@Put(':storeId/packages')
submitPackages(
@CurrentUser() user: AuthUser,
@Param('storeId') storeId: string,
@Body() body: { packages: unknown },
) {
const normalized = this.packages.normalizePackages(body.packages);
return this.packages.submitPartnerChangeRequest(user.actorId, BigInt(storeId), normalized);
}
@Get(':storeId/package-change-requests')
listRequests(@CurrentUser() user: AuthUser, @Param('storeId') storeId: string) {
return this.packages.listPartnerChangeRequests(user.actorId, BigInt(storeId));
}
}
@Controller('shop/store')
@UseGuards(JwtAuthGuard, ShopStoreGuard)
export class ShopStorePackageController {
constructor(private readonly packages: StorePackageService) {}
@Get('packages')
getPackages(@CurrentUser() user: AuthUser) {
return this.packages.getShopPackages(user.actorId, user.storeId!);
}
@Put('packages')
submitPackages(@CurrentUser() user: AuthUser, @Body() body: { packages: unknown }) {
const normalized = this.packages.normalizePackages(body.packages);
return this.packages.submitShopChangeRequest(user.actorId, user.storeId!, normalized);
}
}
@Controller('admin/stores')
@UseGuards(HqAuthGuard)
export class AdminStorePackageController {
constructor(private readonly packages: StorePackageService) {}
@Get(':storeId/packages')
getPackages(@Param('storeId') storeId: string) {
return this.packages.adminGetPackages(BigInt(storeId));
}
@Put(':storeId/packages')
savePackages(@Param('storeId') storeId: string, @Body() body: { packages: unknown }) {
const normalized = this.packages.normalizePackages(body.packages);
return this.packages.adminDirectSave(BigInt(storeId), normalized);
}
}
@Controller('admin/store-package-audits')
@UseGuards(HqAuthGuard)
export class AdminStorePackageAuditController {
constructor(private readonly packages: StorePackageService) {}
@Get()
list(
@Query('status') status?: string,
@Query('page') page?: string,
@Query('pageSize') pageSize?: string,
) {
return this.packages.adminListAudits({
status: status || undefined,
page: page ? Number(page) : undefined,
pageSize: pageSize ? Number(pageSize) : undefined,
});
}
@Put(':requestId/audit')
audit(
@CurrentUser() user: AuthUser,
@Param('requestId') requestId: string,
@Body() body: { action: 'APPROVE' | 'REJECT'; rejectReason?: string },
) {
return this.packages.adminAuditRequest(BigInt(requestId), user.actorId, body);
}
}
@Controller('stores')
export class PublicStorePackageController {
constructor(private readonly packages: StorePackageService) {}
@Get(':storeId/packages')
list(@Param('storeId') storeId: string) {
return this.packages.listLivePackages(BigInt(storeId));
}
}