- 包含4个产业方向的前端项目:智能开发、智能制造、大健康、财经商贸 - 已清理node_modules、.yoyo等大文件,项目大小从2.6GB优化至631MB - 配置完善的.gitignore文件 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
128 lines
4.5 KiB
JavaScript
128 lines
4.5 KiB
JavaScript
import fs from 'fs';
|
||
|
||
// 读取CSV文件
|
||
const csvContent = fs.readFileSync('日历课程表.csv', 'utf-8');
|
||
const lines = csvContent.split('\n');
|
||
|
||
// 课程单元映射
|
||
const unitMap = {
|
||
'岗位体系认知': 'unit1',
|
||
'产业认知课': 'unit2',
|
||
'旅游产业全景与文旅基础知识': 'unit3',
|
||
'文旅服务:形象、沟通与体验的融合艺术': 'unit4',
|
||
'文旅与供应链基础': 'unit5',
|
||
'商业设计基础': 'unit6',
|
||
'AIGC人工智能生成内容': 'unit7',
|
||
' 全栈新媒体运营赋能文旅营销': 'unit8', // 注意CSV中前面有个空格
|
||
'活动策划基础': 'unit9',
|
||
'智慧文旅应用': 'unit10'
|
||
};
|
||
|
||
// 初始化课程列表结构
|
||
const courseLiveList = [];
|
||
const unitCoursesMap = new Map();
|
||
|
||
// 处理每一行数据(跳过标题行)
|
||
for (let i = 1; i < lines.length; i++) {
|
||
const line = lines[i].trim();
|
||
if (!line) continue;
|
||
|
||
const parts = line.split(',');
|
||
if (parts.length < 10) continue;
|
||
|
||
const date = parts[0];
|
||
const courseStatus = parts[2];
|
||
const courseName = parts[3];
|
||
const teacher = parts[6];
|
||
let unit = parts[7]; // 使用 let 以便可以重新赋值
|
||
const status = parts[8];
|
||
|
||
// 特殊处理:6月17日的单元小结应该属于商业设计基础(unit6)
|
||
if (date === '2025/6/17' && courseName === '单元小结') {
|
||
unit = '商业设计基础';
|
||
}
|
||
|
||
// 只处理有课的数据
|
||
if (courseStatus === '有课' && courseName && unit && unitMap[unit]) {
|
||
if (!unitCoursesMap.has(unit)) {
|
||
unitCoursesMap.set(unit, {
|
||
unitId: unitMap[unit],
|
||
unitName: unit,
|
||
courses: []
|
||
});
|
||
}
|
||
|
||
const unitData = unitCoursesMap.get(unit);
|
||
|
||
// 检查是否已存在相同课程(去重)
|
||
const existingCourse = unitData.courses.find(c =>
|
||
c.courseName === courseName && c.date === date
|
||
);
|
||
|
||
if (!existingCourse) {
|
||
const [year, month, day] = date.split('/');
|
||
const formattedDate = `${year}-${month.padStart(2, '0')}-${day.padStart(2, '0')}`;
|
||
|
||
// 判断课程状态
|
||
const today = new Date();
|
||
today.setHours(0, 0, 0, 0); // 重置时间部分,只比较日期
|
||
const courseDate = new Date(year, parseInt(month) - 1, parseInt(day));
|
||
courseDate.setHours(0, 0, 0, 0);
|
||
|
||
const timeDiff = courseDate - today;
|
||
const daysDiff = Math.floor(timeDiff / (24 * 60 * 60 * 1000));
|
||
|
||
// 判断课程状态:
|
||
// - 已完成:日期在今天之前
|
||
// - 直播中(current):今天的课程
|
||
// - 即将开始(upcoming):未来的课程
|
||
// 注意:忽略CSV中的状态,根据日期自动判断
|
||
const isCompleted = daysDiff < 0; // 只根据日期判断,过去的课程为已完成
|
||
const isCurrent = daysDiff === 0; // 今天的课程设为直播中
|
||
const isUpcoming = daysDiff > 0; // 所有未来的课程都标记为即将开始
|
||
|
||
unitData.courses.push({
|
||
courseId: `c${unitData.unitId.replace('unit', '')}-${unitData.courses.length + 1}`,
|
||
courseName: courseName.length > 20 ? courseName.substring(0, 20) + '...' : courseName,
|
||
teacherName: teacher || '未知老师',
|
||
date: formattedDate,
|
||
completed: isCompleted,
|
||
current: isCurrent, // 今天的课程标记为current
|
||
upcoming: isUpcoming // 未来7天内的课程
|
||
});
|
||
}
|
||
}
|
||
}
|
||
|
||
// 按单元顺序组装数据
|
||
const orderedUnits = [
|
||
'岗位体系认知',
|
||
'产业认知课',
|
||
'旅游产业全景与文旅基础知识',
|
||
'文旅服务:形象、沟通与体验的融合艺术',
|
||
'文旅与供应链基础',
|
||
'商业设计基础',
|
||
'AIGC人工智能生成内容',
|
||
' 全栈新媒体运营赋能文旅营销', // 注意CSV中前面有个空格
|
||
'活动策划基础',
|
||
'智慧文旅应用'
|
||
];
|
||
|
||
orderedUnits.forEach(unitName => {
|
||
if (unitCoursesMap.has(unitName)) {
|
||
const unitData = unitCoursesMap.get(unitName);
|
||
// 按日期排序课程
|
||
unitData.courses.sort((a, b) => a.date.localeCompare(b.date));
|
||
courseLiveList.push(unitData);
|
||
}
|
||
});
|
||
|
||
// 输出结果
|
||
console.log('// 课程直播间的课程列表数据(从CSV生成)');
|
||
console.log('mockData.courseLiveList =', JSON.stringify(courseLiveList, null, 2), ';');
|
||
|
||
// 写入到文件
|
||
fs.writeFileSync('courseLiveListData.json', JSON.stringify({ courseLiveList }, null, 2));
|
||
console.log('\n✅ 课程列表数据已生成');
|
||
console.log(`📚 共${courseLiveList.length}个单元`);
|
||
console.log(`📖 共${courseLiveList.reduce((acc, unit) => acc + unit.courses.length, 0)}门课程`); |