feat(wanfa): 新增路线详情参考价格配置及展示功能
- 新增数据库迁移脚本,为详情表添加四个价格相关字段 - 完善后端schema校验、序列化逻辑,增加价格相关的数据清理与验证规则 - 新增价格配置校验逻辑,设置起售价时必须选择对应的计价单位 - 在Admin UI详情编辑器中新增价格配置模块,支持配置起售价、计价单位、适用人数范围和价格说明 - 更新小程序端详情页面,支持展示配置的参考价格信息 - 补充相关测试用例,更新API文档与类型定义
This commit is contained in:
1 parent
f18971a430
commit
feec6ab80f
20 files changed
+351
-17
No files matched your search
@@ -31,6 +31,10 @@ function createRouteFallback(route: PlayRoute): DetailPresentation {
|
||||
"最终行程以出行日期、人数和资源确认结果为准。",
|
||||
],
|
||||
gallery: Array.from(new Set([route.image, ...sharedGallery])).slice(0, 5),
|
||||
priceStartingValue: null,
|
||||
priceUnit: null,
|
||||
pricePeopleRange: "",
|
||||
priceDescription: "",
|
||||
conciergeAdvisor: null,
|
||||
};
|
||||
}
|
||||
@@ -61,6 +65,19 @@ function cleanGallery(value: unknown) {
|
||||
);
|
||||
}
|
||||
|
||||
function cleanPriceStartingValue(value: unknown, fallback: number | null) {
|
||||
if (typeof value !== "number" || !Number.isFinite(value) || value < 0) return fallback;
|
||||
return Number(value.toFixed(2));
|
||||
}
|
||||
|
||||
function cleanPriceUnit(value: unknown, fallback: PublicDetail["priceUnit"]): PublicDetail["priceUnit"] {
|
||||
return value === "person" || value === "day" || value === "group" ? value : fallback;
|
||||
}
|
||||
|
||||
function cleanOptionalText(value: unknown, fallback: string) {
|
||||
return cleanText(value) || fallback;
|
||||
}
|
||||
|
||||
export function findWanfaRouteDetailFallback(routeId: string) {
|
||||
return routeFallbacks.get(routeId) ?? null;
|
||||
}
|
||||
@@ -78,6 +95,10 @@ export function normalizeDetailPresentation(
|
||||
const intro = cleanText(source.intro) || fallback?.intro || "";
|
||||
const gallery = cleanGallery(source.gallery);
|
||||
const conciergeAdvisor = normalizeConciergeAdvisor(source.conciergeAdvisor);
|
||||
const priceStartingValue = cleanPriceStartingValue(source.priceStartingValue, fallback?.priceStartingValue ?? null);
|
||||
const priceUnit = cleanPriceUnit(source.priceUnit, fallback?.priceUnit ?? null);
|
||||
const pricePeopleRange = cleanOptionalText(source.pricePeopleRange, fallback?.pricePeopleRange ?? "");
|
||||
const priceDescription = cleanOptionalText(source.priceDescription, fallback?.priceDescription ?? "");
|
||||
|
||||
if (!key || !eyebrow || !duration || !title || !subtitle || !intro) {
|
||||
return fallback;
|
||||
@@ -95,6 +116,10 @@ export function normalizeDetailPresentation(
|
||||
excluded: cleanList(source.excluded).length ? cleanList(source.excluded) : fallback?.excluded ?? [],
|
||||
notes: cleanList(source.notes).length ? cleanList(source.notes) : fallback?.notes ?? [],
|
||||
gallery: gallery.length ? gallery : fallback?.gallery ?? [],
|
||||
priceStartingValue,
|
||||
priceUnit,
|
||||
pricePeopleRange,
|
||||
priceDescription,
|
||||
conciergeAdvisor,
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user