This commit is contained in:
eric
2026-03-11 23:47:45 -05:00
parent 296d703307
commit 0c2ccadb6b
35 changed files with 2399 additions and 195 deletions

92
app/topic/config.ts Normal file
View File

@@ -0,0 +1,92 @@
/**
* 模块配置 - 模块 > 视频教程 > [模块名]
* 参考 cloudphone/nomadlms 结构
*/
import { CURRICULUM_CONFIG } from "@/app/cloudphone/config/course";
export type TopicConfig = {
id: string;
icon: string;
title: string;
subtitle: string;
desc: string;
stats: { value: string; label: string }[];
/** 使用的 curriculum 模块索引,空则用全部 */
moduleIndices?: number[];
/** 外部链接,有则显示「前往了解」而非课程列表 */
externalUrl?: string;
payUrl: string;
};
export const TOPIC_CONFIGS: Record<string, TopicConfig> = {
cloudphone: {
id: "cloudphone",
icon: "☁️",
title: "云手机模块",
subtitle: "低成本自建云手机,TikTok/YouTube 运营搭建指南",
desc: "用开源硬件打造云手机,Redroid、AOSP、ffmpeg、SRS,从零搭建无人直播工作室",
stats: [
{ value: "13", label: "节实战课程" },
{ value: "170+", label: "分钟视频" },
{ value: "5", label: "大模块" },
],
payUrl: "/cloudphone/pay",
},
livestream: {
id: "livestream",
icon: "📺",
title: "无人直播模块",
subtitle: "TikTok/YouTube 无人直播,24 小时自动化",
desc: "ffmpeg 拉流转推、SRS 直播服务器、油猴脚本自动化,实现 24 小时无人值守推流",
stats: [
{ value: "7", label: "节核心课程" },
{ value: "100+", label: "分钟视频" },
{ value: "2", label: "大模块" },
],
moduleIndices: [1, 2],
payUrl: "/cloudphone/pay",
},
indie: {
id: "indie",
icon: "🛠️",
title: "独立开发模块",
subtitle: "从想法到产品,独立开发者全流程指南",
desc: "即将上线,敬请期待。可先前往数字游民指南了解更多。",
stats: [
{ value: "—", label: "课程筹备中" },
{ value: "—", label: "敬请期待" },
],
externalUrl: "https://digital.hackrobot.cn/zh",
payUrl: "/",
},
aiagent: {
id: "aiagent",
icon: "🤖",
title: "AI Agent 模块",
subtitle: "AIGC 与智能体,Vibe Coding 跨界创造",
desc: "即将上线,敬请期待。可先前往数字游民指南了解更多。",
stats: [
{ value: "—", label: "课程筹备中" },
{ value: "—", label: "敬请期待" },
],
externalUrl: "https://digital.hackrobot.cn/zh",
payUrl: "/",
},
};
export function getTopicConfig(topicId: string): TopicConfig | null {
return TOPIC_CONFIGS[topicId] ?? null;
}
export function getTopicCurriculum(topicId: string) {
const config = getTopicConfig(topicId);
if (!config) return null;
if (config.externalUrl) return { modules: [], hasContent: false };
const indices = config.moduleIndices ?? CURRICULUM_CONFIG.modules.map((_, i) => i);
const modules = indices
.map((i) => ({ module: CURRICULUM_CONFIG.modules[i], originalIndex: i }))
.filter((x) => x.module)
.map(({ module: m, originalIndex }) => ({ ...m, originalModuleIndex: originalIndex }));
return { modules, hasContent: modules.length > 0 };
}