fix(product-families): sort price-matrix option arrays by canonical display order
printCounts/crafts/logistics were materialized in first-encounter order (originGoods had no orderBy), so the H5 print/craft/logistics button groups rendered in an unstable, per-family arbitrary order. Add OPTION_DISPLAY_ORDER (单面→双面, 烫画→直喷→不打印, 不包邮→包邮) and stable-sort the aggregated arrays before materializing; out-of-vocabulary free-text labels (e.g. 海运) sink to the end preserving encounter order. Fix traversal order with orderBy id asc so recomputes are fully deterministic. Add recompute:families script for one-off re-materialize.
This commit is contained in:
@@ -71,6 +71,26 @@ const DIM_VALUES = {
|
||||
} as const satisfies Record<string, readonly string[]>;
|
||||
|
||||
type DimKey = keyof typeof DIM_VALUES;
|
||||
|
||||
/**
|
||||
* 选项组展示顺序(业务确认):printCount 单面→双面;craft 烫画→直喷→不打印;logistics 不包邮→包邮。
|
||||
* 与 DIM_VALUES 的"组合生成序"是两回事,物化前对聚合数组按此稳定排序;
|
||||
* 词表外自由文本(CUSTOM 标签,如"海运")沉底,相互间保持首次遇到序。
|
||||
*/
|
||||
const OPTION_DISPLAY_ORDER = {
|
||||
printCount: ['单面印花', '双面印花'],
|
||||
craft: ['烫画', '直喷', '不打印'],
|
||||
logistics: ['不包邮', '包邮'],
|
||||
} as const;
|
||||
|
||||
function optionRank(value: string, canon: readonly string[]): number {
|
||||
const i = canon.indexOf(value);
|
||||
return i === -1 ? canon.length : i;
|
||||
}
|
||||
|
||||
function sortOptions(values: string[], canon: readonly string[]): string[] {
|
||||
return [...values].sort((a, b) => optionRank(a, canon) - optionRank(b, canon));
|
||||
}
|
||||
export interface MatrixCombo {
|
||||
printCount: string;
|
||||
craft: string;
|
||||
@@ -268,9 +288,9 @@ export function derivePriceMatrix(members: Member[], overrides: OverrideRow[]):
|
||||
return {
|
||||
sizes: [...sizes.entries()].map(([key, name]) => ({ key, name })),
|
||||
colors: [...colors.entries()].map(([key, v]) => ({ key, ...v })),
|
||||
printCounts,
|
||||
crafts,
|
||||
logistics: logisticsOptions,
|
||||
printCounts: sortOptions(printCounts, OPTION_DISPLAY_ORDER.printCount),
|
||||
crafts: sortOptions(crafts, OPTION_DISPLAY_ORDER.craft),
|
||||
logistics: sortOptions(logisticsOptions, OPTION_DISPLAY_ORDER.logistics),
|
||||
rows,
|
||||
};
|
||||
}
|
||||
@@ -328,6 +348,8 @@ export class FamilyRecomputeService {
|
||||
include: {
|
||||
originGoods: {
|
||||
where: { delisted: false },
|
||||
// 固定遍历序:保证"首次遇到序"(未知自由文本取值的相对顺序)确定性,重算幂等
|
||||
orderBy: { id: 'asc' },
|
||||
include: {
|
||||
detail: true,
|
||||
variants: { where: { enabled: true }, orderBy: { sortOrder: 'asc' } },
|
||||
|
||||
Reference in New Issue
Block a user