feat(goods): per-member detail tabs in edit dialog; revert right-tree to raw names; split configured/family badges; add GET /origin-goods/:id
This commit is contained in:
@@ -26,6 +26,12 @@ export class OriginGoodsController {
|
||||
return this.service.findAll(query);
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
@ApiOperation({ summary: '单链接详情(detail + variants,成员展开面板用)' })
|
||||
findOne(@Param('id') id: string) {
|
||||
return this.service.findOne(BigInt(id));
|
||||
}
|
||||
|
||||
@Get(':id/tags')
|
||||
@ApiOperation({ summary: '链接当前标签(含 manual 标记)' })
|
||||
getTags(@Param('id') id: string) {
|
||||
|
||||
@@ -40,6 +40,20 @@ describe('OriginGoodsService', () => {
|
||||
expect(service).toBeDefined();
|
||||
});
|
||||
|
||||
it('findOne returns og with detail/variants payload', async () => {
|
||||
const og = await prisma.originGood.findFirstOrThrow({
|
||||
where: { sdsGoodId: `sds-${stamp}-3` },
|
||||
});
|
||||
const result = await service.findOne(og.id);
|
||||
expect(result.id).toBe(og.id.toString());
|
||||
expect(result.sdsGoodId).toBe(`sds-${stamp}-3`);
|
||||
expect(result.variantCount).toBe(0);
|
||||
expect(result.hasDetail).toBe(false);
|
||||
expect(result.detail).toBeNull();
|
||||
expect(result.variants).toEqual([]);
|
||||
await expect(service.findOne(og.id + 10_000_000n)).rejects.toThrow();
|
||||
});
|
||||
|
||||
it('returns paginated results', async () => {
|
||||
const page1 = await service.findAll({
|
||||
page: 1,
|
||||
|
||||
@@ -175,6 +175,54 @@ export class OriginGoodsService {
|
||||
return this.getTags(id);
|
||||
}
|
||||
|
||||
/** 单链接详情(含 detail 与 variants,成员展开面板用) */
|
||||
async findOne(id: bigint) {
|
||||
const og = await this.prisma.originGood.findUnique({
|
||||
where: { id },
|
||||
include: {
|
||||
detail: true,
|
||||
variants: { orderBy: [{ sortOrder: 'asc' }, { id: 'asc' }] },
|
||||
_count: { select: { variants: true } },
|
||||
},
|
||||
});
|
||||
if (!og) throw new NotFoundException(`Origin good ${id} not found`);
|
||||
const detail = og.detail;
|
||||
return {
|
||||
id: og.id.toString(),
|
||||
sdsGoodId: og.sdsGoodId,
|
||||
goodName: og.goodName,
|
||||
goodImage: og.goodImage,
|
||||
goodPrice: og.goodPrice === null || og.goodPrice === undefined ? null : og.goodPrice.toString(),
|
||||
source: og.source,
|
||||
delisted: og.delisted,
|
||||
hasDetail: Boolean(detail),
|
||||
detailSyncedAt: detail?.syncedAt.toISOString() ?? null,
|
||||
variantCount: og._count.variants,
|
||||
detail: detail
|
||||
? {
|
||||
productCode: detail.productCode,
|
||||
englishName: detail.englishName,
|
||||
productionCycleHours: detail.productionCycleHours,
|
||||
minWeightG: detail.minWeightG === null ? null : detail.minWeightG.toString(),
|
||||
productionProcess: detail.productionProcess,
|
||||
materialDescription: detail.materialDescription,
|
||||
sizeChart: (detail.sizeChart ?? null) as unknown,
|
||||
packageSpecs: (detail.packageSpecs ?? null) as unknown,
|
||||
}
|
||||
: null,
|
||||
variants: og.variants.map((v) => ({
|
||||
sdsVariantId: v.sdsVariantId,
|
||||
sku: v.sku,
|
||||
sizeId: v.sizeId,
|
||||
sizeName: v.sizeName,
|
||||
colorId: v.colorId,
|
||||
colorName: v.colorName,
|
||||
price: v.price === null ? null : v.price.toString(),
|
||||
enabled: v.enabled,
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
||||
async findAll(query: QueryOriginGoodDto): Promise<PaginatedOriginGoods> {
|
||||
const { page, pageSize, keyword } = query;
|
||||
const where: Prisma.OriginGoodWhereInput = {
|
||||
|
||||
Reference in New Issue
Block a user