113 lines
5.1 KiB
TypeScript
113 lines
5.1 KiB
TypeScript
/**
|
||
* 课程章节详情配置 - 数字游民主题(来自 nomadlms)
|
||
*/
|
||
|
||
const SAMPLE_VIDEO = "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4";
|
||
|
||
const SAMPLE_MARKDOWN = `# 课程概述
|
||
|
||
本小节将带你理解数字游民的核心概念,掌握关键技能。
|
||
|
||
## 学习目标
|
||
|
||
- 理解数字游民的本质与生活方式
|
||
- 掌握远程变现的基础路径
|
||
- 完成个人定位与规划
|
||
|
||
## 核心要点
|
||
|
||
1. **定义**:数字游民 = 远程工作 + 自由旅行 + 地点独立
|
||
2. **技能**:选择可远程交付的技能方向
|
||
3. **心态**:自律与自由是相辅相成的
|
||
|
||
## 行动清单
|
||
|
||
- [ ] 评估自己的技能是否可远程交付
|
||
- [ ] 列出3个你想旅居的城市
|
||
- [ ] 设定6个月内的转型目标
|
||
|
||
### 代码示例
|
||
|
||
\`\`\`bash
|
||
# 安装依赖
|
||
pnpm install
|
||
|
||
# 启动开发
|
||
pnpm dev
|
||
\`\`\`
|
||
|
||
行内代码示例:\`npm run build\` 可生成生产版本。
|
||
|
||
## 注意事项
|
||
|
||
> 数字游民不是逃避,而是主动选择。建议先有稳定收入再考虑长期旅居。
|
||
|
||
| 项目 | 说明 |
|
||
|------|------|
|
||
| 收入 | 建议月收入稳定在 1 万以上 |
|
||
| 技能 | 至少 1 项可远程交付 |
|
||
| 心态 | 自律与自由平衡 |
|
||
`;
|
||
|
||
export type LessonDetail = {
|
||
name: string;
|
||
duration: string;
|
||
videoUrl: string;
|
||
markdown: string;
|
||
};
|
||
|
||
/** 扁平化课程数据:moduleIndex-lessonIndex 作为 key */
|
||
export const LESSONS_MAP: Record<string, LessonDetail> = {
|
||
"0-0": {
|
||
name: "01 什么是数字游民?你适合吗?",
|
||
duration: "11:58",
|
||
videoUrl: SAMPLE_VIDEO,
|
||
markdown: SAMPLE_MARKDOWN.replace("本小节", "本节").replace("核心概念", "数字游民的定义与自我评估"),
|
||
},
|
||
"0-1": {
|
||
name: "02 从朝九晚五到边旅行边赚钱的路径",
|
||
duration: "14:32",
|
||
videoUrl: SAMPLE_VIDEO,
|
||
markdown: SAMPLE_MARKDOWN.replace("本小节", "本节").replace("核心概念", "从上班族到数字游民的转型路径"),
|
||
},
|
||
"1-0": {
|
||
name: "3.1 最适合远程的5大技能方向",
|
||
duration: "06:25",
|
||
videoUrl: SAMPLE_VIDEO,
|
||
markdown: SAMPLE_MARKDOWN.replace("本小节", "本节").replace("核心概念", "编程、设计、写作、营销、咨询等远程技能"),
|
||
},
|
||
"1-1": {
|
||
name: "3.2 如何打造你的技能组合与作品集",
|
||
duration: "07:34",
|
||
videoUrl: SAMPLE_VIDEO,
|
||
markdown: SAMPLE_MARKDOWN.replace("本小节", "本节").replace("核心概念", "作品集搭建与个人品牌展示"),
|
||
},
|
||
"2-0": { name: "04 从接单到产品的思维转变", duration: "04:16", videoUrl: SAMPLE_VIDEO, markdown: SAMPLE_MARKDOWN },
|
||
"2-1": { name: "05 打造你的第一个数字产品", duration: "06:18", videoUrl: SAMPLE_VIDEO, markdown: SAMPLE_MARKDOWN },
|
||
"2-2": { name: "06 海外平台接单与变现", duration: "02:30", videoUrl: SAMPLE_VIDEO, markdown: SAMPLE_MARKDOWN },
|
||
"2-3": { name: "07 被动收入组合:课程+会员+咨询", duration: "06:25", videoUrl: SAMPLE_VIDEO, markdown: SAMPLE_MARKDOWN },
|
||
"2-4": { name: "08 如何定价才能既赚又自由", duration: "03:09", videoUrl: SAMPLE_VIDEO, markdown: SAMPLE_MARKDOWN },
|
||
"3-0": { name: "09 数字游民的时间管理心法", duration: "07:49", videoUrl: SAMPLE_VIDEO, markdown: SAMPLE_MARKDOWN },
|
||
"3-1": { name: "09-1 独处与社交的平衡", duration: "01:24", videoUrl: SAMPLE_VIDEO, markdown: SAMPLE_MARKDOWN },
|
||
"3-2": { name: "10 如何应对家人的不理解", duration: "04:07", videoUrl: SAMPLE_VIDEO, markdown: SAMPLE_MARKDOWN },
|
||
"4-0": { name: "11 签证与长期居留规划", duration: "04:12", videoUrl: SAMPLE_VIDEO, markdown: SAMPLE_MARKDOWN },
|
||
"4-1": { name: "12 住宿选择:短租、民宿、Co-living", duration: "05:19", videoUrl: SAMPLE_VIDEO, markdown: SAMPLE_MARKDOWN },
|
||
"4-2": { name: "13 网络、保险与紧急预案", duration: "04:11", videoUrl: SAMPLE_VIDEO, markdown: SAMPLE_MARKDOWN },
|
||
"5-0": { name: "14 巴厘岛数字游民社区探访", duration: "12:02", videoUrl: SAMPLE_VIDEO, markdown: SAMPLE_MARKDOWN },
|
||
"5-1": { name: "15 曼谷/清迈生活成本与体验", duration: "09:39", videoUrl: SAMPLE_VIDEO, markdown: SAMPLE_MARKDOWN },
|
||
"5-2": { name: "16 欧洲数字游民签证攻略", duration: "09:04", videoUrl: SAMPLE_VIDEO, markdown: SAMPLE_MARKDOWN },
|
||
"5-3": { name: "17 一人公司如何合法合规运营", duration: "05:12", videoUrl: SAMPLE_VIDEO, markdown: SAMPLE_MARKDOWN },
|
||
"6-0": { name: "18 从一人到小团队的进化", duration: "11:25", videoUrl: SAMPLE_VIDEO, markdown: SAMPLE_MARKDOWN },
|
||
"6-1": { name: "19 建立你的数字游民品牌", duration: "25:57", videoUrl: SAMPLE_VIDEO, markdown: SAMPLE_MARKDOWN },
|
||
"6-2": { name: "20 年度旅居计划与预算规划", duration: "12:34", videoUrl: SAMPLE_VIDEO, markdown: SAMPLE_MARKDOWN },
|
||
"6-3": { name: "21 长期数字游民的可持续之道", duration: "08:53", videoUrl: SAMPLE_VIDEO, markdown: SAMPLE_MARKDOWN },
|
||
};
|
||
|
||
export function getLessonKey(moduleIndex: number, lessonIndex: number): string {
|
||
return `${moduleIndex}-${lessonIndex}`;
|
||
}
|
||
|
||
export function getLesson(moduleIndex: number, lessonIndex: number): LessonDetail | null {
|
||
return LESSONS_MAP[getLessonKey(moduleIndex, lessonIndex)] ?? null;
|
||
}
|