feat: 新增客片案例与团队共创模块,重构玩法与配置
- 新增客片案例全流程功能,包含前台页面、管理端配置、后端API、数据库迁移与文档 - 新增团队共创详情页面与对应接口 - 重构玩法模块:将静态playData替换为动态API获取,拆分类型定义到playTypes.ts - 优化vite构建配置与环境变量处理,调整详情页操作栏文案 - 更新全量相关文档与配图,新增客片案例、团队共创API文档 - 新增测试用例,完善数据归一化逻辑 - 调整路由配置与环境变量示例文件
This commit is contained in:
1 parent
cda8069630
commit
7ba92f3c5d
76 files changed
+7970
-137
No files matched your search
@@ -2,32 +2,114 @@ export type HomeWildArchive = {
|
||||
id: string;
|
||||
title: string;
|
||||
image: string;
|
||||
images: string[];
|
||||
photoCount: number;
|
||||
demandKeyword: string;
|
||||
};
|
||||
|
||||
export type HomeWildArchiveApiItem = {
|
||||
id?: string | null;
|
||||
title?: string | null;
|
||||
image?: string | null;
|
||||
images?: string[] | null;
|
||||
photoCount?: number | null;
|
||||
demandKeyword?: string | null;
|
||||
isActive?: boolean | null;
|
||||
sortOrder?: number | null;
|
||||
};
|
||||
|
||||
export type HomeWildArchives = HomeWildArchiveApiItem[];
|
||||
|
||||
export const homeWildArchiveMocks: HomeWildArchive[] = [
|
||||
{
|
||||
id: "hundred-meter-descent",
|
||||
title: "百米自降",
|
||||
image: "https://genk.mediacdn.vn/139269124445442048/2024/4/27/10-23-sinkhole-1714189653945948438879.jpg",
|
||||
images: [
|
||||
"https://genk.mediacdn.vn/139269124445442048/2024/4/27/10-23-sinkhole-1714189653945948438879.jpg",
|
||||
"https://q9.itc.cn/q_70/images03/20250810/b62f5afc191a4947a66e6b32721b0235.jpeg",
|
||||
],
|
||||
photoCount: 2,
|
||||
demandKeyword: "悬崖瀑降",
|
||||
},
|
||||
{
|
||||
id: "shilong-cave",
|
||||
title: "石龙洞",
|
||||
title: "石龙洞——客片案例",
|
||||
image: "https://www.zurnal24.si/media/img/5e/d5/9526a56dba168aa136f3.jpeg",
|
||||
images: [
|
||||
"https://www.zurnal24.si/media/img/5e/d5/9526a56dba168aa136f3.jpeg",
|
||||
"https://q9.itc.cn/q_70/images03/20250810/b62f5afc191a4947a66e6b32721b0235.jpeg",
|
||||
"https://dimg04.c-ctrip.com/images/0EQ5712000ca7t504EC0E_W_640_10000.jpg?proc=autoorient",
|
||||
"https://dimg04.c-ctrip.com/images/1mh0412000njfr1ot9453_W_640_10000.jpg?proc=autoorient",
|
||||
"https://p6.itc.cn/q_70/images03/20200918/df728d2b79d943da869333e2ea2c92c8.jpeg",
|
||||
],
|
||||
photoCount: 5,
|
||||
demandKeyword: "地心探险",
|
||||
},
|
||||
{
|
||||
id: "cliff-current",
|
||||
title: "绝壁迎流",
|
||||
image: "https://q9.itc.cn/q_70/images03/20250810/b62f5afc191a4947a66e6b32721b0235.jpeg",
|
||||
images: [
|
||||
"https://q9.itc.cn/q_70/images03/20250810/b62f5afc191a4947a66e6b32721b0235.jpeg",
|
||||
"https://dimg04.c-ctrip.com/images/0EQ5712000ca7t504EC0E_W_640_10000.jpg?proc=autoorient",
|
||||
],
|
||||
photoCount: 2,
|
||||
demandKeyword: "峡谷探险",
|
||||
},
|
||||
{
|
||||
id: "canyon-streaming",
|
||||
title: "峡谷溯溪",
|
||||
image: "https://dimg04.c-ctrip.com/images/0EQ5712000ca7t504EC0E_W_640_10000.jpg?proc=autoorient",
|
||||
images: [
|
||||
"https://dimg04.c-ctrip.com/images/0EQ5712000ca7t504EC0E_W_640_10000.jpg?proc=autoorient",
|
||||
"https://p6.itc.cn/q_70/images03/20200918/df728d2b79d943da869333e2ea2c92c8.jpeg",
|
||||
],
|
||||
photoCount: 2,
|
||||
demandKeyword: "峡谷溯溪",
|
||||
},
|
||||
];
|
||||
|
||||
export const homeWildArchiveFallback = homeWildArchiveMocks;
|
||||
|
||||
export function normalizeHomeWildArchives(
|
||||
items: HomeWildArchives | null | undefined,
|
||||
): HomeWildArchive[] {
|
||||
const fallback = homeWildArchiveFallback.map((item) => ({ ...item }));
|
||||
const activeItems = (items ?? [])
|
||||
.map((item, index) => ({ item, index }))
|
||||
.filter(({ item }) => item.isActive !== false && Boolean(item.title?.trim()))
|
||||
.sort(
|
||||
(left, right) =>
|
||||
(left.item.sortOrder ?? left.index) - (right.item.sortOrder ?? right.index),
|
||||
);
|
||||
|
||||
if (!activeItems.length) return fallback;
|
||||
|
||||
return activeItems.map(({ item }, index) => {
|
||||
const fallbackItem = homeWildArchiveFallback.find((candidate) => candidate.id === item.id)
|
||||
?? homeWildArchiveFallback[index]
|
||||
?? homeWildArchiveFallback[0];
|
||||
const title = item.title?.trim() || fallbackItem.title;
|
||||
const image = item.image?.trim() || fallbackItem.image;
|
||||
const images = (item.images ?? []).map((imageUrl) => imageUrl.trim()).filter(Boolean);
|
||||
const normalizedImages = images.length ? images : [image];
|
||||
return {
|
||||
id: item.id?.trim() || fallbackItem.id,
|
||||
title,
|
||||
image,
|
||||
images: normalizedImages,
|
||||
photoCount: item.photoCount && item.photoCount > 0 ? item.photoCount : normalizedImages.length,
|
||||
demandKeyword: item.demandKeyword?.trim() || title,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export function normalizeHomeWildArchiveDetail(
|
||||
item: HomeWildArchiveApiItem | null | undefined,
|
||||
): HomeWildArchive {
|
||||
const fallback = homeWildArchiveFallback.find((candidate) => candidate.id === item?.id)
|
||||
?? homeWildArchiveFallback[0];
|
||||
const normalized = normalizeHomeWildArchives(item ? [item] : [fallback])[0];
|
||||
return normalized;
|
||||
}
|
||||
Reference in new issue
Block a user