feat(product-family): replace legacy good merge with family mechanism in config view and public detail
This commit is contained in:
@@ -221,7 +221,9 @@ export class PublicService {
|
||||
where: {
|
||||
OR: [
|
||||
{ originGood: { sdsGoodId: goodId, delisted: false } },
|
||||
// Merged secondary sources also resolve to the same good.
|
||||
// 族内任何成员链接均可命中同一商品(替代旧副源关联的可达性语义)
|
||||
{ family: { originGoods: { some: { sdsGoodId: goodId, delisted: false } } } },
|
||||
// 历史副源关联(good_origin_goods)只读保留,仍可命中
|
||||
{
|
||||
mergedOriginGoods: {
|
||||
some: { originGood: { sdsGoodId: goodId, delisted: false } },
|
||||
@@ -235,7 +237,25 @@ export class PublicService {
|
||||
if (!good) {
|
||||
throw new NotFoundException({ message: '不存在商品', error: 'PRODUCT_NOT_FOUND' });
|
||||
}
|
||||
const dto = this.toPublicGoodDetail(good);
|
||||
// 族机制(新):变体并集 = 主链接 ∪ 族成员 ∪ 旧副源(过渡期),按 (链接, 变体) 去重
|
||||
let familyVariants: Array<{
|
||||
originGoodId: bigint;
|
||||
variant: PublicGoodRow['originGood']['variants'][number];
|
||||
}> = [];
|
||||
const familyId = good.originGood.family?.id;
|
||||
if (familyId) {
|
||||
const members = await this.prisma.originGood.findMany({
|
||||
where: { familyId, delisted: false },
|
||||
select: {
|
||||
id: true,
|
||||
variants: { orderBy: [{ sortOrder: 'asc' }, { id: 'asc' }] },
|
||||
},
|
||||
});
|
||||
familyVariants = members
|
||||
.filter((m) => m.id !== good.originGoodId)
|
||||
.flatMap((m) => m.variants.map((variant) => ({ originGoodId: m.id, variant })));
|
||||
}
|
||||
const dto = this.toPublicGoodDetail(good, familyVariants);
|
||||
dto.category.categoryIcon = await this.resolveCategoryIcon(good.category);
|
||||
return dto;
|
||||
}
|
||||
@@ -362,13 +382,35 @@ export class PublicService {
|
||||
return null;
|
||||
}
|
||||
|
||||
private toPublicGoodDetail(good: PublicGoodRow): PublicGoodDetailDto {
|
||||
private toPublicGoodDetail(
|
||||
good: PublicGoodRow,
|
||||
familyVariants: Array<{
|
||||
originGoodId: bigint;
|
||||
variant: PublicGoodRow['originGood']['variants'][number];
|
||||
}> = [],
|
||||
): PublicGoodDetailDto {
|
||||
const base = this.toPublicGood(good);
|
||||
const detail = good.originGood.detail;
|
||||
// Merge primary and secondary origin good variants (dedup identical URLs).
|
||||
// 变体并集:主链接 ∪ 族成员(新机制)∪ 旧副源(过渡期);
|
||||
// 同一链接可能既是族成员又挂旧副源,按 `${originGoodId}:${sdsVariantId}` 去重。
|
||||
const seen = new Set<string>(['']);
|
||||
const dedupe = (originGoodId: bigint, variant: PublicGoodRow['originGood']['variants'][number]) => {
|
||||
const key = `${originGoodId}:${variant.sdsVariantId}`;
|
||||
if (seen.has(key)) return null;
|
||||
seen.add(key);
|
||||
return variant;
|
||||
};
|
||||
good.originGood.variants.forEach((v) => dedupe(good.originGoodId, v));
|
||||
const allVariants = [
|
||||
...good.originGood.variants,
|
||||
...good.mergedOriginGoods.flatMap((m) => m.originGood.variants),
|
||||
...familyVariants
|
||||
.map(({ originGoodId, variant }) => dedupe(originGoodId, variant))
|
||||
.filter((v): v is PublicGoodRow['originGood']['variants'][number] => v !== null),
|
||||
...good.mergedOriginGoods.flatMap((m) =>
|
||||
m.originGood.variants
|
||||
.map((variant) => dedupe(m.originGoodId, variant))
|
||||
.filter((v): v is PublicGoodRow['originGood']['variants'][number] => v !== null),
|
||||
),
|
||||
];
|
||||
return {
|
||||
...base,
|
||||
@@ -417,13 +459,13 @@ export class PublicService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 灰度族块(设计 D4:零新增公开端点):仅当 PUBLIC_DETAIL_FROM_FAMILY=true
|
||||
* 且主链接有所属族时输出;数据全部来自 ProductFamily 的物化 JSON,无额外查询。
|
||||
* 族块(设计 D4:零新增公开端点):默认输出;仅当 PUBLIC_DETAIL_FROM_FAMILY
|
||||
* 显式设为 'false' 时关闭(应急回退开关)。数据全部来自 ProductFamily 的物化 JSON。
|
||||
*/
|
||||
private familyBlock(
|
||||
good: PublicGoodRow,
|
||||
): Pick<PublicGoodDetailDto, 'family'> | Record<string, never> {
|
||||
if (process.env.PUBLIC_DETAIL_FROM_FAMILY !== 'true') return {};
|
||||
if (process.env.PUBLIC_DETAIL_FROM_FAMILY === 'false') return {};
|
||||
const family = good.originGood.family;
|
||||
if (!family || !family.priceMatrix) return {};
|
||||
const matrix = family.priceMatrix as {
|
||||
|
||||
Reference in New Issue
Block a user