feat: 完善课程直播页面和首页Dashboard数据同步
- 修复6月17日单元小结归属问题,正确归入商业设计基础单元 - 添加单元海报功能,非直播状态显示单元海报图片 - 更新首页Dashboard开始上课和当日事项板块数据 - 实现课程数据与Dashboard数据自动同步 - 优化课程列表显示,包含完整100门课程数据 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
964
courseLiveListData.json
Normal file
964
courseLiveListData.json
Normal file
@@ -0,0 +1,964 @@
|
||||
{
|
||||
"courseLiveList": [
|
||||
{
|
||||
"unitId": "unit1",
|
||||
"unitName": "岗位体系认知",
|
||||
"courses": [
|
||||
{
|
||||
"courseId": "c1-1",
|
||||
"courseName": "教育体系认知",
|
||||
"teacherName": "刘杰",
|
||||
"date": "2025-03-04",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c1-2",
|
||||
"courseName": "现代文旅类企业的管理体系",
|
||||
"teacherName": "刘杰",
|
||||
"date": "2025-03-05",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c1-3",
|
||||
"courseName": "专科生的职业规划",
|
||||
"teacherName": "刘杰",
|
||||
"date": "2025-03-06",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"unitId": "unit2",
|
||||
"unitName": "产业认知课",
|
||||
"courses": [
|
||||
{
|
||||
"courseId": "c2-1",
|
||||
"courseName": "文旅产业认知课",
|
||||
"teacherName": "刘杰",
|
||||
"date": "2025-03-11",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c2-2",
|
||||
"courseName": "行业详解:旅游行业",
|
||||
"teacherName": "刘杰",
|
||||
"date": "2025-03-12",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c2-3",
|
||||
"courseName": "行业详解:酒店与民宿行业",
|
||||
"teacherName": "刘杰",
|
||||
"date": "2025-03-13",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c2-4",
|
||||
"courseName": "行业详解:活动与会展行业",
|
||||
"teacherName": "刘杰",
|
||||
"date": "2025-03-18",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c2-5",
|
||||
"courseName": "行业详解:文化服务行业",
|
||||
"teacherName": "刘杰",
|
||||
"date": "2025-03-19",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"unitId": "unit3",
|
||||
"unitName": "旅游产业全景与文旅基础知识",
|
||||
"courses": [
|
||||
{
|
||||
"courseId": "c3-1",
|
||||
"courseName": "现代文旅产业生态图谱",
|
||||
"teacherName": "刘杰",
|
||||
"date": "2025-03-20",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c3-2",
|
||||
"courseName": "文旅政策法规与风险管理",
|
||||
"teacherName": "刘杰",
|
||||
"date": "2025-03-25",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c3-3",
|
||||
"courseName": "旅游产品与旅游资源",
|
||||
"teacherName": "刘杰",
|
||||
"date": "2025-03-26",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c3-4",
|
||||
"courseName": "游客行为心理学基础",
|
||||
"teacherName": "刘杰",
|
||||
"date": "2025-03-27",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c3-5",
|
||||
"courseName": "可持续旅游发展",
|
||||
"teacherName": "刘杰",
|
||||
"date": "2025-04-01",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c3-6",
|
||||
"courseName": "单元小结",
|
||||
"teacherName": "刘杰",
|
||||
"date": "2025-04-02",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"unitId": "unit4",
|
||||
"unitName": "文旅服务:形象、沟通与体验的融合艺术",
|
||||
"courses": [
|
||||
{
|
||||
"courseId": "c4-1",
|
||||
"courseName": "文旅场景职业形象IP塑造",
|
||||
"teacherName": "郭建辉",
|
||||
"date": "2025-04-03",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c4-2",
|
||||
"courseName": "情境化服务体验设计",
|
||||
"teacherName": "郭建辉",
|
||||
"date": "2025-04-08",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c4-3",
|
||||
"courseName": "政务商务接待专项礼仪",
|
||||
"teacherName": "郭建辉",
|
||||
"date": "2025-04-09",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c4-4",
|
||||
"courseName": "文旅服务中的非语言表达",
|
||||
"teacherName": "郭建辉",
|
||||
"date": "2025-04-10",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c4-5",
|
||||
"courseName": "服务沟通技巧与表达训练",
|
||||
"teacherName": "郭建辉",
|
||||
"date": "2025-04-15",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c4-6",
|
||||
"courseName": "多元文化下的服务表达差异",
|
||||
"teacherName": "郭建辉",
|
||||
"date": "2025-04-16",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c4-7",
|
||||
"courseName": "单元小结",
|
||||
"teacherName": "郭建辉",
|
||||
"date": "2025-04-17",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"unitId": "unit5",
|
||||
"unitName": "文旅与供应链基础",
|
||||
"courses": [
|
||||
{
|
||||
"courseId": "c5-1",
|
||||
"courseName": "供应链管理的内容",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-04-22",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c5-2",
|
||||
"courseName": "文旅资源调度",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-04-23",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c5-3",
|
||||
"courseName": "文旅产品全生命周期管理",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-04-24",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c5-4",
|
||||
"courseName": "文旅商品供应链",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-04-29",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c5-5",
|
||||
"courseName": "住宿业资源协同",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-04-30",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c5-6",
|
||||
"courseName": "小型文旅项目的供应链角色模拟",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-05-01",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c5-7",
|
||||
"courseName": "文旅项目供应链特征",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-05-06",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c5-8",
|
||||
"courseName": "文旅供应链中的B2B与B2C模式",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-05-07",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c5-9",
|
||||
"courseName": "单元小结",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-05-08",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"unitId": "unit6",
|
||||
"unitName": "商业设计基础",
|
||||
"courses": [
|
||||
{
|
||||
"courseId": "c6-1",
|
||||
"courseName": "现代设计行业的发展现状",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-05-13",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c6-2",
|
||||
"courseName": "设计基础",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-05-14",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c6-3",
|
||||
"courseName": "字体设计与中文字体情绪表达",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-05-15",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c6-4",
|
||||
"courseName": "商业平面色彩搭配",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-05-20",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c6-5",
|
||||
"courseName": "平面设计构图",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-05-21",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c6-6",
|
||||
"courseName": "图像编辑工具:Photoshop",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-05-22",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c6-7",
|
||||
"courseName": "图像编辑工具:Photoshop",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-05-27",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c6-8",
|
||||
"courseName": "矢量与标志设计:Illustrator",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-05-28",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c6-9",
|
||||
"courseName": "矢量与标志设计:Illustrator",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-05-29",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c6-10",
|
||||
"courseName": "快速设计工具使用:Canva",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-06-03",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c6-11",
|
||||
"courseName": "快速设计工具使用:Canva",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-06-04",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c6-12",
|
||||
"courseName": "移动端视觉原型设计:Figma",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-06-05",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c6-13",
|
||||
"courseName": "移动端视觉原型设计:Figma",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-06-10",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c6-14",
|
||||
"courseName": "视频剪辑入门:剪映",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-06-11",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c6-15",
|
||||
"courseName": "视频剪辑入门:剪映",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-06-12",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c6-16",
|
||||
"courseName": "单元小结",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-06-17",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"unitId": "unit7",
|
||||
"unitName": "AIGC人工智能生成内容",
|
||||
"courses": [
|
||||
{
|
||||
"courseId": "c7-1",
|
||||
"courseName": "AIGC发展简史与基本逻辑",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-09-02",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c7-2",
|
||||
"courseName": "AIGC的基本概念与各领域的应用",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-09-03",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c7-3",
|
||||
"courseName": "AIGC语言模型:chatgpt的灵活应...",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-09-04",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c7-4",
|
||||
"courseName": "AIGC生成内容的版权问题与合规使用",
|
||||
"teacherName": "刘杰",
|
||||
"date": "2025-09-09",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c7-5",
|
||||
"courseName": "AIGC图像生成模型:Stable Di...",
|
||||
"teacherName": "刘杰",
|
||||
"date": "2025-09-10",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c7-6",
|
||||
"courseName": "AIGC图像生成模型:Stable Di...",
|
||||
"teacherName": "刘杰",
|
||||
"date": "2025-09-11",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c7-7",
|
||||
"courseName": "AIGC图像生成模型:Stable Di...",
|
||||
"teacherName": "刘杰",
|
||||
"date": "2025-09-16",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c7-8",
|
||||
"courseName": "AIGC图像生成模型:Stable Di...",
|
||||
"teacherName": "刘杰",
|
||||
"date": "2025-09-17",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c7-9",
|
||||
"courseName": "AIGC视频应用:音视频生成与AI自动剪...",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-09-18",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c7-10",
|
||||
"courseName": "AIGC视频应用:音视频生成与AI自动剪...",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-09-23",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c7-11",
|
||||
"courseName": "AI词曲创作:suno",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-09-24",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c7-12",
|
||||
"courseName": "AI词曲创作:suno",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-09-25",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c7-13",
|
||||
"courseName": "单元小结",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-09-30",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"unitId": "unit8",
|
||||
"unitName": " 全栈新媒体运营赋能文旅营销",
|
||||
"courses": [
|
||||
{
|
||||
"courseId": "c8-1",
|
||||
"courseName": "新媒体应用传播学",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-10-01",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c8-2",
|
||||
"courseName": "新媒体故事结构入门",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-10-02",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c8-3",
|
||||
"courseName": "新媒体产品策划",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-10-07",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c8-4",
|
||||
"courseName": "平台账号经营与内容赛道",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-10-08",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c8-5",
|
||||
"courseName": "各平台变现方式与具体方法",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-10-09",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c8-6",
|
||||
"courseName": "内容运营:短视频的制作工具",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-10-14",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c8-7",
|
||||
"courseName": "内容运营:短视频的制作工具",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-10-15",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c8-8",
|
||||
"courseName": "内容运营:短视频的制作工具",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-10-16",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c8-9",
|
||||
"courseName": "内容运营:短视频的制作工具",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-10-21",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c8-10",
|
||||
"courseName": "内容运营:短视频制作内容对标",
|
||||
"teacherName": "刘杰",
|
||||
"date": "2025-10-22",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c8-11",
|
||||
"courseName": "内容运营:短视频制作内容对标",
|
||||
"teacherName": "刘杰",
|
||||
"date": "2025-10-23",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c8-12",
|
||||
"courseName": "直播运营:直播间的搭建",
|
||||
"teacherName": "刘杰",
|
||||
"date": "2025-10-28",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c8-13",
|
||||
"courseName": "直播运营:直播间的搭建",
|
||||
"teacherName": "刘杰",
|
||||
"date": "2025-10-29",
|
||||
"completed": true,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c8-14",
|
||||
"courseName": "品牌运营:当地文化IP数字化传播",
|
||||
"teacherName": "刘杰",
|
||||
"date": "2025-10-30",
|
||||
"completed": false,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c8-15",
|
||||
"courseName": "品牌运营:当地文化IP数字化传播",
|
||||
"teacherName": "刘杰",
|
||||
"date": "2025-11-04",
|
||||
"completed": false,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c8-16",
|
||||
"courseName": "品牌运营:跨界营销创新",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-11-05",
|
||||
"completed": false,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c8-17",
|
||||
"courseName": "品牌运营:跨界营销创新",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-11-06",
|
||||
"completed": false,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c8-18",
|
||||
"courseName": "私域运营:私域流量池的运营",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-11-11",
|
||||
"completed": false,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c8-19",
|
||||
"courseName": "私域运营:私域流量池的运营",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-11-12",
|
||||
"completed": false,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c8-20",
|
||||
"courseName": "单元小结",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-11-13",
|
||||
"completed": false,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"unitId": "unit9",
|
||||
"unitName": "活动策划基础",
|
||||
"courses": [
|
||||
{
|
||||
"courseId": "c9-1",
|
||||
"courseName": "活动类型与功能认知",
|
||||
"teacherName": "郭建辉",
|
||||
"date": "2025-11-18",
|
||||
"completed": false,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c9-2",
|
||||
"courseName": "受众定位与主题创意方法",
|
||||
"teacherName": "郭建辉",
|
||||
"date": "2025-11-19",
|
||||
"completed": false,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c9-3",
|
||||
"courseName": "活动宣传渠道与推广方式",
|
||||
"teacherName": "郭建辉",
|
||||
"date": "2025-11-20",
|
||||
"completed": false,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c9-4",
|
||||
"courseName": "活动宣传渠道与推广方式",
|
||||
"teacherName": "郭建辉",
|
||||
"date": "2025-11-25",
|
||||
"completed": false,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c9-5",
|
||||
"courseName": "活动文案写作与表达技巧",
|
||||
"teacherName": "郭建辉",
|
||||
"date": "2025-11-26",
|
||||
"completed": false,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c9-6",
|
||||
"courseName": "活动文案写作与表达技巧",
|
||||
"teacherName": "郭建辉",
|
||||
"date": "2025-11-27",
|
||||
"completed": false,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c9-7",
|
||||
"courseName": "活动流程设计与时间节点把控",
|
||||
"teacherName": "郭建辉",
|
||||
"date": "2025-12-02",
|
||||
"completed": false,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c9-8",
|
||||
"courseName": "活动流程设计与时间节点把控",
|
||||
"teacherName": "郭建辉",
|
||||
"date": "2025-12-03",
|
||||
"completed": false,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c9-9",
|
||||
"courseName": "活动场地选择与布置基础",
|
||||
"teacherName": "郭建辉",
|
||||
"date": "2025-12-04",
|
||||
"completed": false,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c9-10",
|
||||
"courseName": "活动预算与资源统筹",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-12-09",
|
||||
"completed": false,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c9-11",
|
||||
"courseName": "应急预案与活动风险管理",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-12-10",
|
||||
"completed": false,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c9-12",
|
||||
"courseName": "活动复盘报告撰写与数据分析方法",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-12-11",
|
||||
"completed": false,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c9-13",
|
||||
"courseName": "活动复盘报告撰写与数据分析方法",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-12-16",
|
||||
"completed": false,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c9-14",
|
||||
"courseName": "单元小结",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-12-17",
|
||||
"completed": false,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"unitId": "unit10",
|
||||
"unitName": "智慧文旅应用",
|
||||
"courses": [
|
||||
{
|
||||
"courseId": "c10-1",
|
||||
"courseName": "智慧文旅概论",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-12-18",
|
||||
"completed": false,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c10-2",
|
||||
"courseName": "OTA平台运营",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-12-23",
|
||||
"completed": false,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c10-3",
|
||||
"courseName": "票务分销平台",
|
||||
"teacherName": "刘杰",
|
||||
"date": "2025-12-24",
|
||||
"completed": false,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c10-4",
|
||||
"courseName": "景区智能导览系统",
|
||||
"teacherName": "赵志强",
|
||||
"date": "2025-12-25",
|
||||
"completed": false,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c10-5",
|
||||
"courseName": "智能导览设备运用",
|
||||
"teacherName": "刘杰",
|
||||
"date": "2025-12-30",
|
||||
"completed": false,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c10-6",
|
||||
"courseName": "智慧酒店/智慧景区体验场景模拟",
|
||||
"teacherName": "刘杰",
|
||||
"date": "2025-12-31",
|
||||
"completed": false,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
},
|
||||
{
|
||||
"courseId": "c10-7",
|
||||
"courseName": "单元小结",
|
||||
"teacherName": "刘杰",
|
||||
"date": "2026-01-01",
|
||||
"completed": false,
|
||||
"current": false,
|
||||
"upcoming": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
127
generateCourseLiveList.js
Normal file
127
generateCourseLiveList.js
Normal file
@@ -0,0 +1,127 @@
|
||||
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):未来7天内的课程(在组件中会显示为"即将开始")
|
||||
const isCompleted = status === '已结束' || daysDiff < 0;
|
||||
const isCurrent = daysDiff === 0; // 今天的课程设为直播中
|
||||
const isUpcoming = !isCompleted && !isCurrent && daysDiff > 0 && daysDiff <= 7; // 未来7天内
|
||||
|
||||
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 && !isCompleted,
|
||||
upcoming: isUpcoming // 添加即将开始标识
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 按单元顺序组装数据
|
||||
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)}门课程`);
|
||||
81
src/components/ClassRank/index.jsx
Normal file
81
src/components/ClassRank/index.jsx
Normal file
@@ -0,0 +1,81 @@
|
||||
import { Avatar, Spin, Empty } from "@arco-design/web-react";
|
||||
import IconFont from "@/components/IconFont";
|
||||
import "./index.css";
|
||||
|
||||
const positions = ["item2", "item1", "item3"];
|
||||
const icons = ["icon2", "icon1", "icon3"];
|
||||
|
||||
const Rank = ({ className, data, loading }) => {
|
||||
const rankings = data?.rankings?.slice(0, 6) || [];
|
||||
|
||||
// 安全处理领奖台学生,确保至少有3个位置
|
||||
const podiumStudents = [
|
||||
rankings[1] || null, // 第2名
|
||||
rankings[0] || null, // 第1名
|
||||
rankings[2] || null, // 第3名
|
||||
];
|
||||
|
||||
const listStudents = rankings.slice(3);
|
||||
|
||||
return (
|
||||
<div className={`module-class-rank ${className}`}>
|
||||
<p className="module-class-rank-title">
|
||||
<IconFont className="title-icon" src="recuUY5nNf7DWT" />
|
||||
<span>班级排名</span>
|
||||
</p>
|
||||
{loading ? (
|
||||
<Spin size={40} className="module-class-rank-spin" />
|
||||
) : !data || !data?.rankings || data?.rankings?.length === 0 ? (
|
||||
<Empty description="暂无排名数据" className="empty-data" />
|
||||
) : (
|
||||
<>
|
||||
<ul className="module-class-rank-podium">
|
||||
{podiumStudents.map((student, index) => {
|
||||
return student ? (
|
||||
<li
|
||||
key={student.studentId}
|
||||
className={`module-class-rank-podium-${positions[index]}`}
|
||||
>
|
||||
<Avatar className="module-class-rank-podium-avatar">
|
||||
{student.avatar ? (
|
||||
<img alt="avatar" src={student.avatar} />
|
||||
) : (
|
||||
student.studentName?.charAt(0) || "?"
|
||||
)}
|
||||
</Avatar>
|
||||
<span className="module-class-rank-podium-name">
|
||||
{student.studentName || "未知"}
|
||||
</span>
|
||||
<i className={`module-class-rank-podium-${icons[index]}`}></i>
|
||||
</li>
|
||||
) : (
|
||||
<li
|
||||
key={`empty-${index}`}
|
||||
className={`module-class-rank-podium-${positions[index]} empty`}
|
||||
>
|
||||
<div className="module-class-rank-podium-placeholder">
|
||||
<span>-</span>
|
||||
</div>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
<ul className="module-class-rank-list">
|
||||
{listStudents.map((student, index) => (
|
||||
<li
|
||||
key={student.studentId}
|
||||
className="module-class-rank-list-item"
|
||||
>
|
||||
<em className="module-class-rank-num">{index + 4}</em>
|
||||
<p>{student.studentName || "未知"}</p>
|
||||
<span>{student.score}分</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Rank;
|
||||
@@ -14,7 +14,7 @@
|
||||
height: 545px;
|
||||
box-sizing: border-box;
|
||||
padding: 16px;
|
||||
border-radius: 8px;
|
||||
border-radius: 16px;
|
||||
background-color: #fff;
|
||||
border: 1px solid #fff;
|
||||
|
||||
@@ -51,6 +51,12 @@
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
}
|
||||
.courses-video-player-info {
|
||||
@@ -58,7 +64,7 @@
|
||||
width: 100%;
|
||||
height: 234px;
|
||||
border: 2px solid #fff;
|
||||
border-radius: 8px;
|
||||
border-radius: 16px;
|
||||
box-sizing: border-box;
|
||||
padding: 16px;
|
||||
background-image: linear-gradient(180deg, #daecff, #ffffff);
|
||||
@@ -80,16 +86,35 @@
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
position: relative;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
img {
|
||||
width: 150%;
|
||||
height: 150%;
|
||||
object-fit: cover;
|
||||
object-position: center 30%;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: -5px;
|
||||
left: 50%;
|
||||
top: 2%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
}
|
||||
|
||||
.avatar-wrapper {
|
||||
position: relative;
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
|
||||
.living-icon {
|
||||
position: absolute;
|
||||
left: 1px;
|
||||
bottom: -8px;
|
||||
width: 62px;
|
||||
height: 20px;
|
||||
background-image: url("@/assets/images/CoursesVideoPlayer/living_icon.png");
|
||||
background-size: 100% 100%;
|
||||
z-index: 10;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,7 +145,7 @@
|
||||
align-items: center;
|
||||
|
||||
.living-data-item {
|
||||
width: 78px;
|
||||
min-width: 78px;
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
@@ -137,6 +162,11 @@
|
||||
color: #1d2129;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
min-width: 100px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -155,42 +185,44 @@
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #1d2129;
|
||||
box-sizing: border-box;
|
||||
padding-left: 25px;
|
||||
text-align: left;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
.title-icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background-size: 100% 100%;
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.teacher-introduce {
|
||||
width: 100%;
|
||||
min-height: 84px;
|
||||
max-height: 120px;
|
||||
overflow-y: auto;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
color: #4e5969;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
background: #f2f3f5;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: #c9cdd4;
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.icon1 {
|
||||
&::before {
|
||||
background-image: url("@/assets/images/CoursesVideoPlayer/hat_icon.png");
|
||||
}
|
||||
}
|
||||
|
||||
.icon2 {
|
||||
&::before {
|
||||
background-image: url("@/assets/images/CoursesVideoPlayer/blank_icon.png");
|
||||
}
|
||||
}
|
||||
.teacher-introduce {
|
||||
width: 100%;
|
||||
height: 84px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.courses-video-player-teacher-introduce {
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
margin-bottom: 20px;
|
||||
min-height: 100px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.courses-video-player-teacher-tags {
|
||||
width: 100%;
|
||||
@@ -209,13 +241,13 @@
|
||||
|
||||
> li {
|
||||
box-sizing: border-box;
|
||||
padding: 0 10px;
|
||||
background-color: #f2f3f5;
|
||||
color: #1d2129;
|
||||
padding: 2px 8px;
|
||||
background-color: #e5f1ff;
|
||||
color: #0077ff;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
font-weight: 400;
|
||||
margin-right: 10px;
|
||||
border-radius: 2px;
|
||||
border-radius: 4px;
|
||||
flex-shrink: 0;
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
|
||||
@@ -2,11 +2,65 @@ import { Avatar } from "@arco-design/web-react";
|
||||
import Locked from "@/components/Locked";
|
||||
import "./index.css";
|
||||
|
||||
export default ({ className = "", isLock = false }) => {
|
||||
export default ({ className = "", isLock = false, selectedCourse, teacherData, unitPosters }) => {
|
||||
const handleClickBtn = (item) => {
|
||||
console.log(item);
|
||||
};
|
||||
|
||||
// 获取当前课程的导师信息
|
||||
const currentTeacher = selectedCourse && teacherData
|
||||
? teacherData[selectedCourse.teacherName]
|
||||
: teacherData?.["魏立慧"] || {
|
||||
name: "魏立慧",
|
||||
introduction: "企业资深一线HR,专注于为求职者提供一对一的个性化指导。通过真实招聘视角,深入剖析个人优势与短板、传授面试技巧、规划职业定位与发展路径,帮助学生快速提升求职竞争力。求职策略以实用落地为核心,注重互动交流与角色定位,让学员在轻松氛围中获得直击痛点的求职策略。",
|
||||
specialties: ["深谙用人逻辑", "擅长挖掘优势", "沟通真诚自然", "点评直击要害"],
|
||||
avatar: "//p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/3ee5f13fb09879ecb5185e440cef6eb9.png~tplv-uwbnlip3yd-webp.webp",
|
||||
type: "企业资深HR"
|
||||
};
|
||||
|
||||
// 需要调整头像位置的导师
|
||||
const needsAdjustment = ["赵志强", "魏立慧", "郭建辉"].includes(currentTeacher.name);
|
||||
|
||||
// 根据导师设置不同的背景色 - 这些颜色提取自实际的PNG图片背景
|
||||
const getAvatarBackground = (name) => {
|
||||
const backgrounds = {
|
||||
"刘杰": "#E3E2E0", // 浅灰色
|
||||
"郭建辉": "#E0D9D3", // 米灰色
|
||||
"赵志强": "#E3E2E0", // 浅灰色
|
||||
"孙应战": "#E3E2E0", // 浅灰色
|
||||
"魏立慧": "#DCD8D4" // 灰褐色
|
||||
};
|
||||
return backgrounds[name] || "#E3E2E0";
|
||||
};
|
||||
|
||||
console.log("当前导师:", currentTeacher.name, "需要调整:", needsAdjustment);
|
||||
|
||||
// 获取当前课程信息
|
||||
const courseName = selectedCourse?.courseName || "钢铁是怎样炼成的";
|
||||
const courseDate = selectedCourse?.date || "09.01";
|
||||
const unitName = selectedCourse?.unitName || "教育体系认知";
|
||||
|
||||
// 格式化日期时间
|
||||
const formatDateTime = (date) => {
|
||||
// 将 "2025-09-02" 格式转换为 "09.02"
|
||||
if (date && date.includes('-')) {
|
||||
const parts = date.split('-');
|
||||
if (parts.length === 3) {
|
||||
return `${parts[1]}.${parts[2]}`;
|
||||
}
|
||||
}
|
||||
// 将 "9/1" 格式转换为 "09.01"
|
||||
if (date && date.includes('/')) {
|
||||
const parts = date.split('/');
|
||||
if (parts.length === 2) {
|
||||
const month = parts[0].padStart(2, '0');
|
||||
const day = parts[1].padStart(2, '0');
|
||||
return `${month}.${day}`;
|
||||
}
|
||||
}
|
||||
return date;
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`${className} courses-video-player-wrapper`}>
|
||||
{/* 直播板块 */}
|
||||
@@ -22,12 +76,20 @@ export default ({ className = "", isLock = false }) => {
|
||||
<div className="courses-video-player-header">
|
||||
<span onClick={() => handleClickBtn(1)}>< 上一集</span>
|
||||
<span className="courses-video-player-header-title">
|
||||
钢铁是怎样炼成的
|
||||
{courseName}
|
||||
</span>
|
||||
<span onClick={() => handleClickBtn(2)}>下一集 ></span>
|
||||
</div>
|
||||
<div className="courses-video-player-video">
|
||||
{selectedCourse?.current ? (
|
||||
<video src="/live.mp4" autoPlay controls></video>
|
||||
) : (
|
||||
<img
|
||||
src={unitPosters?.[unitName] || unitPosters?.["岗位体系认知"]}
|
||||
alt={unitName}
|
||||
style={{ width: '100%', height: '100%', objectFit: 'cover' }}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
@@ -35,18 +97,24 @@ export default ({ className = "", isLock = false }) => {
|
||||
<div className="courses-video-player-info">
|
||||
{/* 直播观众信息 */}
|
||||
<div className="courses-video-player-audience-info">
|
||||
<Avatar className="teacher-avatar">
|
||||
<div className="avatar-wrapper">
|
||||
<Avatar
|
||||
className={`teacher-avatar ${needsAdjustment ? 'avatar-adjust' : ''}`}
|
||||
style={{ backgroundColor: getAvatarBackground(currentTeacher.name) }}
|
||||
>
|
||||
<img
|
||||
alt="avatar"
|
||||
src="//p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/3ee5f13fb09879ecb5185e440cef6eb9.png~tplv-uwbnlip3yd-webp.webp"
|
||||
src={currentTeacher.avatar}
|
||||
/>
|
||||
</Avatar>
|
||||
<span className="teacher-name">魏立慧</span>
|
||||
<span className="teacher-tag">教育体系认知</span>
|
||||
{selectedCourse?.current && <div className="living-icon" />}
|
||||
</div>
|
||||
<span className="teacher-name">{currentTeacher.name}老师</span>
|
||||
<span className="teacher-tag">{unitName}</span>
|
||||
<div className="living-data">
|
||||
<div className="living-data-item">
|
||||
<span>开始</span>
|
||||
<span>9/1 10:00</span>
|
||||
<span>{formatDateTime(courseDate)} - 14:00</span>
|
||||
</div>
|
||||
<div className="living-data-item">
|
||||
<span>时长</span>
|
||||
@@ -63,16 +131,15 @@ export default ({ className = "", isLock = false }) => {
|
||||
<div className="courses-video-player-teacher-introduce">
|
||||
<p className="title icon1">导师介绍</p>
|
||||
<p className="teacher-introduce">
|
||||
企业资深一线HR,专注于为求职者提供一对一的个性化指导。通过真实招聘视角,深入剖析个人优势与短板、传授面试技巧、规划职业定位与发展路径,帮助学生快速提升求职竞争力。求职策略以实用落地为核心,注重互动交流与角色定位,让学员在轻松氛围中获得直击痛点的求职策略。
|
||||
{currentTeacher.introduction}
|
||||
</p>
|
||||
</div>
|
||||
<div className="courses-video-player-teacher-tags">
|
||||
<p className="title icon2">教师专长</p>
|
||||
<ul className="teacher-tags">
|
||||
<li>深谙用人逻辑</li>
|
||||
<li>擅长挖掘优势</li>
|
||||
<li>沟通真诚自然</li>
|
||||
<li>点评直击要害</li>
|
||||
{currentTeacher.specialties.map((specialty, index) => (
|
||||
<li key={index}>{specialty}</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
109
src/components/EchartsProgress/index.jsx
Normal file
109
src/components/EchartsProgress/index.jsx
Normal file
@@ -0,0 +1,109 @@
|
||||
import { useEffect, useRef } from "react";
|
||||
import * as echarts from "echarts";
|
||||
|
||||
const EchartsProgress = ({
|
||||
percent = 0,
|
||||
strokeWidth = 20,
|
||||
progressColor = new echarts.graphic.LinearGradient(0, 0, 1, 0, [
|
||||
{ offset: 0, color: "#0275F2" },
|
||||
{ offset: 1, color: "#389CFA" },
|
||||
]), // 进度条颜色,默认为渐变色
|
||||
backgroundColor = "#FFF", // 背景颜色
|
||||
}) => {
|
||||
const chartRef = useRef(null);
|
||||
const chartInstance = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
// 初始化图表
|
||||
if (chartRef.current && !chartInstance.current) {
|
||||
chartInstance.current = echarts.init(chartRef.current);
|
||||
}
|
||||
|
||||
// 配置图表选项 - 得分环
|
||||
const option = {
|
||||
series: [
|
||||
{
|
||||
type: "gauge",
|
||||
startAngle: 90,
|
||||
radius: "100%",
|
||||
endAngle: -270,
|
||||
pointer: {
|
||||
show: false,
|
||||
},
|
||||
progress: {
|
||||
show: true,
|
||||
overlap: false,
|
||||
roundCap: true,
|
||||
clip: false,
|
||||
itemStyle: {
|
||||
borderWidth: 0,
|
||||
color: progressColor, // 设置进度条颜色
|
||||
},
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
width: strokeWidth,
|
||||
color: [
|
||||
[1, backgroundColor], // 背景颜色
|
||||
],
|
||||
},
|
||||
},
|
||||
splitLine: {
|
||||
show: false,
|
||||
distance: 0,
|
||||
length: 10,
|
||||
},
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
axisLabel: {
|
||||
show: false,
|
||||
distance: 50,
|
||||
},
|
||||
data: [
|
||||
{
|
||||
value: percent,
|
||||
detail: {
|
||||
valueAnimation: true,
|
||||
offsetCenter: ["0%", "0%"],
|
||||
},
|
||||
},
|
||||
],
|
||||
detail: {
|
||||
formatter: "{a|{value}%}\n{c| }\n{b|整体课程完成进度}",
|
||||
rich: {
|
||||
a: {
|
||||
color: "#0077FF",
|
||||
fontSize: 40,
|
||||
align: "center",
|
||||
},
|
||||
c: { color: "transparent", lineHeight: 20 }, // 透明占位行
|
||||
b: {
|
||||
color: "#4E5969",
|
||||
fontSize: 20,
|
||||
align: "center",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
// 设置图表选项
|
||||
chartInstance.current.setOption(option);
|
||||
|
||||
// 响应窗口大小变化
|
||||
const resizeHandler = () => {
|
||||
chartInstance.current.resize();
|
||||
};
|
||||
|
||||
window.addEventListener("resize", resizeHandler);
|
||||
return () => {
|
||||
window.removeEventListener("resize", resizeHandler);
|
||||
};
|
||||
}, [backgroundColor, percent, progressColor, strokeWidth]);
|
||||
|
||||
return <div ref={chartRef} style={{ width: "18vw", height: "18vw" }} />;
|
||||
};
|
||||
|
||||
export default EchartsProgress;
|
||||
@@ -1,21 +1,28 @@
|
||||
.module-calendar-task-wrapper {
|
||||
width: 360px;
|
||||
height: 508px;
|
||||
background-color: #fff;
|
||||
width: 100%;
|
||||
height: 393px;
|
||||
border-radius: 16px;
|
||||
border: 1px solid #fff;
|
||||
border-bottom: 1px solid #fff;
|
||||
flex-shrink: 0;
|
||||
box-sizing: border-box;
|
||||
padding: 20px;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
|
||||
.module-calendar-task-title {
|
||||
height: 30px;
|
||||
width: 100%;
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
line-height: 30px;
|
||||
color: #262626;
|
||||
margin-bottom: 20px;
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: 160px;
|
||||
height: 160px;
|
||||
background-image: url("@/assets/images/Dashboard/CalendarTaskModule/calendar_task_bg.png");
|
||||
background-size: 100% 100%;
|
||||
z-index: -1;
|
||||
}
|
||||
.arco-calendar {
|
||||
background-color: transparent;
|
||||
}
|
||||
.arco-calendar-header {
|
||||
height: 50px;
|
||||
@@ -46,10 +53,23 @@
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
|
||||
&.is-today {
|
||||
.date-number {
|
||||
background-color: rgb(0, 119, 255);
|
||||
background-color: rgb(0, 119, 255) !important;
|
||||
color: white;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-current-day {
|
||||
.date-number {
|
||||
background-color: rgba(10, 216, 239, 0.696);
|
||||
color: white;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
|
||||
@@ -1,31 +1,30 @@
|
||||
import dayjs from "dayjs";
|
||||
import { Calendar } from "@arco-design/web-react";
|
||||
import "./index.css";
|
||||
import { Calendar, Skeleton } from "@arco-design/web-react";
|
||||
|
||||
const CalendarTaskModule = ({ tasks = [], selectedDate, onDateChange, loading }) => {
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="module-calendar-task-wrapper">
|
||||
<p className="module-calendar-task-title">日历</p>
|
||||
<Skeleton loading={true} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const CalendarTaskModule = ({ tasks = [], selectedDate, onDateChange }) => {
|
||||
// 格式化今天的日期
|
||||
const today = new Date();
|
||||
const formattedToday = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, "0")}-${String(today.getDate()).padStart(2, "0")}`;
|
||||
const formattedToday = `${today.getFullYear()}-${String(
|
||||
today.getMonth() + 1
|
||||
).padStart(2, "0")}-${String(today.getDate()).padStart(2, "0")}`;
|
||||
|
||||
// 获取有任务的日期集合
|
||||
const datesWithTasks = new Set(tasks?.map(task => task.date) || []);
|
||||
const datesWithTasks = new Set(tasks?.map((task) => task.date) || []);
|
||||
|
||||
// 日历单元格渲染函数
|
||||
const dateRender = (current) => {
|
||||
const dateStr = current.format('YYYY-MM-DD');
|
||||
const hasTasks = datesWithTasks.has(dateStr);
|
||||
const dateStr = current.format("YYYY-MM-DD");
|
||||
const hasTasks = datesWithTasks.has(dateStr); // 存在任务
|
||||
const isCurrentDay = dateStr === dayjs(selectedDate).format("YYYY-MM-DD");
|
||||
const isToday = dateStr === formattedToday;
|
||||
|
||||
return (
|
||||
<div className={`calendar-date-cell ${hasTasks ? 'has-tasks' : ''} ${isToday ? 'is-today' : ''}`}>
|
||||
<div
|
||||
className={`calendar-date-cell ${hasTasks ? "has-tasks" : ""} ${
|
||||
isCurrentDay ? "is-current-day" : ""
|
||||
} ${isToday ? "is-today" : ""}`}
|
||||
>
|
||||
<div className="date-number">{current.date()}</div>
|
||||
{hasTasks && <div className="task-dot"></div>}
|
||||
</div>
|
||||
@@ -37,14 +36,14 @@ const CalendarTaskModule = ({ tasks = [], selectedDate, onDateChange, loading })
|
||||
// Arco Calendar passes a dayjs object
|
||||
if (date && date.format) {
|
||||
// Convert dayjs to Date object
|
||||
const dateStr = date.format('YYYY-MM-DD');
|
||||
const dateObj = new Date(dateStr + 'T00:00:00');
|
||||
const dateStr = date.format("YYYY-MM-DD");
|
||||
const dateObj = new Date(dateStr + "T00:00:00");
|
||||
if (!isNaN(dateObj.getTime())) {
|
||||
onDateChange(dateObj);
|
||||
}
|
||||
} else if (dateString) {
|
||||
// Fallback to dateString if available
|
||||
const dateObj = new Date(dateString + 'T00:00:00');
|
||||
const dateObj = new Date(dateString + "T00:00:00");
|
||||
if (!isNaN(dateObj.getTime())) {
|
||||
onDateChange(dateObj);
|
||||
}
|
||||
@@ -54,12 +53,15 @@ const CalendarTaskModule = ({ tasks = [], selectedDate, onDateChange, loading })
|
||||
|
||||
return (
|
||||
<div className="module-calendar-task-wrapper">
|
||||
<p className="module-calendar-task-title">日历</p>
|
||||
<Calendar
|
||||
panelWidth="300"
|
||||
panel
|
||||
defaultValue={formattedToday}
|
||||
value={selectedDate ? selectedDate.toISOString().split('T')[0] : formattedToday}
|
||||
value={
|
||||
selectedDate
|
||||
? selectedDate.toISOString().split("T")[0]
|
||||
: formattedToday
|
||||
}
|
||||
style={{ fontSize: "18px" }}
|
||||
onChange={handleDateChange}
|
||||
dateRender={dateRender}
|
||||
|
||||
@@ -1,35 +1,54 @@
|
||||
.module-quick-access-wrapper {
|
||||
width: 265px;
|
||||
height: 508px;
|
||||
width: 100%;
|
||||
height: 181px;
|
||||
background-color: #fff;
|
||||
border-radius: 16px;
|
||||
margin-right: 20px;
|
||||
border: 1px solid #fff;
|
||||
flex-shrink: 0;
|
||||
box-sizing: border-box;
|
||||
padding: 20px;
|
||||
margin-top: 20px;
|
||||
background-image: linear-gradient(0deg, #e5f1ff, #f1f9ff);
|
||||
position: relative;
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background-image: url("@/assets/images/Dashboard/QuickAccess/bg.png");
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
|
||||
.module-quick-access-title {
|
||||
height: 30px;
|
||||
height: 27px;
|
||||
width: 100%;
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
line-height: 30px;
|
||||
color: #262626;
|
||||
font-weight: 700;
|
||||
line-height: 27px;
|
||||
color: #1d2129;
|
||||
margin-bottom: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.title-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.module-quick-access-list {
|
||||
width: 100%;
|
||||
height: 428px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
|
||||
.module-quick-access-item {
|
||||
width: 223px;
|
||||
height: 126px;
|
||||
width: 172px;
|
||||
height: 102px;
|
||||
background-color: #fafafa;
|
||||
border-radius: 16px;
|
||||
display: flex;
|
||||
@@ -37,16 +56,19 @@
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
cursor: pointer;
|
||||
background-image: url("@/assets/images/Dashboard/QuickAccess/item_bg.png");
|
||||
background-size: 100% 100%;
|
||||
z-index: 1;
|
||||
|
||||
.module-quick-access-item-icon {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
}
|
||||
|
||||
.module-quick-access-item-text {
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
color: #616065;
|
||||
color: #1d2129;
|
||||
margin-top: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,26 @@
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import icon1 from "@/assets/images/Dashboard/QuickAccess/icon1.png";
|
||||
import icon2 from "@/assets/images/Dashboard/QuickAccess/icon2.png";
|
||||
import icon3 from "@/assets/images/Dashboard/QuickAccess/icon3.png";
|
||||
import IconFont from "@/components/IconFont";
|
||||
import "./index.css";
|
||||
|
||||
const QuickAccessArray = [
|
||||
{
|
||||
name: "我的简历与面试题",
|
||||
src: "recuV81M2OeGcv",
|
||||
route: "/resume-interview",
|
||||
},
|
||||
{ name: "日历", src: "recuV83P0hfWEO", route: "/calendar" },
|
||||
{
|
||||
name: "个人档案",
|
||||
src: "recuV81JPXTspn",
|
||||
route: "/profile",
|
||||
},
|
||||
{
|
||||
name: "课后作业",
|
||||
src: "recuV81LmPLGOM",
|
||||
route: "/homework",
|
||||
},
|
||||
];
|
||||
|
||||
const QuickAccess = () => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
@@ -12,41 +29,24 @@ const QuickAccess = () => {
|
||||
};
|
||||
return (
|
||||
<div className="module-quick-access-wrapper">
|
||||
<p className="module-quick-access-title">快捷入口</p>
|
||||
<p className="module-quick-access-title">
|
||||
<IconFont className="title-icon" src="recuUY5mia5pYp" />
|
||||
<span>快捷入口</span>
|
||||
</p>
|
||||
<ul className="module-quick-access-list">
|
||||
{QuickAccessArray.map((item, index) => (
|
||||
<li
|
||||
key={index}
|
||||
className="module-quick-access-item"
|
||||
onClick={() => handleClick("/expert-support")}
|
||||
onClick={() => handleClick(item.route)}
|
||||
>
|
||||
<img
|
||||
src={icon1}
|
||||
alt="icon1"
|
||||
<IconFont
|
||||
className="module-quick-access-item-icon"
|
||||
src={item.src}
|
||||
/>
|
||||
<p className="module-quick-access-item-text">专家支持中心</p>
|
||||
</li>
|
||||
<li
|
||||
className="module-quick-access-item"
|
||||
onClick={() => handleClick("/live")}
|
||||
>
|
||||
<img
|
||||
src={icon2}
|
||||
alt="icon1"
|
||||
className="module-quick-access-item-icon"
|
||||
/>
|
||||
<p className="module-quick-access-item-text">课程直播间</p>
|
||||
</li>
|
||||
<li
|
||||
className="module-quick-access-item"
|
||||
onClick={() => handleClick("/career-tree")}
|
||||
>
|
||||
<img
|
||||
src={icon3}
|
||||
alt="icon1"
|
||||
className="module-quick-access-item-icon"
|
||||
/>
|
||||
<p className="module-quick-access-item-text">就业管家知识树</p>
|
||||
<p className="module-quick-access-item-text">{item.name}</p>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
.start-class-wrapper {
|
||||
width: 455px;
|
||||
height: 508px;
|
||||
margin-right: 20px;
|
||||
width: 100%;
|
||||
height: 325px;
|
||||
border-radius: 16px;
|
||||
border: 1px solid #fff;
|
||||
flex-shrink: 0;
|
||||
background-position: 50% 30%;
|
||||
box-sizing: border-box;
|
||||
padding: 20px;
|
||||
padding: 10px 20px;
|
||||
background-color: #e2edff;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
@@ -23,75 +23,108 @@
|
||||
}
|
||||
|
||||
.start-class-title {
|
||||
height: 30px;
|
||||
width: 100%;
|
||||
height: 27px;
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
line-height: 30px;
|
||||
color: #262626;
|
||||
margin-bottom: 20px;
|
||||
font-weight: 700;
|
||||
line-height: 27px;
|
||||
color: #1d2129;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
padding-left: 30px;
|
||||
margin-bottom: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
.title-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
content: "";
|
||||
background-image: url("@/assets/images/Dashboard/StartClass/start_class_title_icon.png");
|
||||
background-size: 100% 100%;
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.start-class-content {
|
||||
height: 421px;
|
||||
width: 100%;
|
||||
overflow-y: auto;
|
||||
height: 246px;
|
||||
overflow-y: hidden;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.start-class-item-left {
|
||||
width: 357px;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
|
||||
.start-class-item {
|
||||
margin-bottom: 15px;
|
||||
> li {
|
||||
width: 100%;
|
||||
height: 117px;
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
border-radius: 12px;
|
||||
background-color: #fff;
|
||||
box-sizing: border-box;
|
||||
padding: 15px;
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.start-class-item-right {
|
||||
width: 357px;
|
||||
height: 100%;
|
||||
|
||||
> li {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 12px;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
background-color: #fff;
|
||||
box-sizing: border-box;
|
||||
padding: 15px;
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.start-class-item {
|
||||
.start-class-item-title {
|
||||
width: 100%;
|
||||
height: 27px;
|
||||
line-height: 27px;
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
color: #262626;
|
||||
height: 25px;
|
||||
line-height: 25px;
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: #1d2129;
|
||||
text-align: left;
|
||||
box-sizing: border-box;
|
||||
padding-left: 15px;
|
||||
position: relative;
|
||||
margin-bottom: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 4px;
|
||||
height: 16px;
|
||||
background-color: #0275f2;
|
||||
border-radius: 100px;
|
||||
.title-icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
> .num {
|
||||
margin-left: 10px;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
text-align: center;
|
||||
line-height: 15px;
|
||||
box-sizing: border-box;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
color: #0077ff;
|
||||
background-color: rgba(0, 119, 255, 0.1);
|
||||
border: 1px solid rgba(0, 119, 255, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,10 +134,11 @@
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
overflow-y: auto;
|
||||
|
||||
.start-class-item-list-item {
|
||||
width: 100%;
|
||||
color: #616065;
|
||||
color: #86909c;
|
||||
font-size: 14px;
|
||||
text-align: left;
|
||||
margin-top: 5px;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Skeleton } from "@arco-design/web-react";
|
||||
import IconFont from "@/components/IconFont";
|
||||
import "./index.css";
|
||||
|
||||
const StartClass = ({ courses, tasks, loading }) => {
|
||||
@@ -12,9 +13,12 @@ const StartClass = ({ courses, tasks, loading }) => {
|
||||
}
|
||||
|
||||
// 获取待办任务
|
||||
const pendingTasks = tasks?.allTasks?.filter(task =>
|
||||
task.status === 'PENDING' || task.status === 'IN_PROGRESS'
|
||||
).slice(0, 5) || [];
|
||||
const pendingTasks =
|
||||
tasks?.allTasks
|
||||
?.filter(
|
||||
(task) => task.status === "PENDING" || task.status === "IN_PROGRESS"
|
||||
)
|
||||
.slice(0, 5) || [];
|
||||
|
||||
// 格式化日期显示
|
||||
const formatCourseDate = (dateStr) => {
|
||||
@@ -23,9 +27,9 @@ const StartClass = ({ courses, tasks, loading }) => {
|
||||
const yesterday = new Date(today.getTime() - 24 * 60 * 60 * 1000);
|
||||
|
||||
if (date.toDateString() === today.toDateString()) {
|
||||
return '今日已上';
|
||||
return "今日已上";
|
||||
} else if (date.toDateString() === yesterday.toDateString()) {
|
||||
return '昨日已上';
|
||||
return "昨日已上";
|
||||
} else {
|
||||
return `${date.getMonth() + 1}/${date.getDate()}已上`;
|
||||
}
|
||||
@@ -33,37 +37,26 @@ const StartClass = ({ courses, tasks, loading }) => {
|
||||
|
||||
return (
|
||||
<div className="start-class-wrapper">
|
||||
<p className="start-class-title">开始上课</p>
|
||||
<p className="start-class-title">
|
||||
<IconFont className="title-icon" src="recuUY5ua0CLHi" />
|
||||
<span>开始上课</span>
|
||||
</p>
|
||||
<ul className="start-class-content">
|
||||
<div className="start-class-item-left">
|
||||
<li className="start-class-item">
|
||||
<p className="start-class-item-title">最近课程</p>
|
||||
<ul className="start-class-item-list">
|
||||
{courses?.recentCourses?.length > 0 ? (
|
||||
courses.recentCourses.slice(0, 3).map((course, index) => (
|
||||
<li key={index} className="start-class-item-list-item">
|
||||
{formatCourseDate(course.date)}《{course.courseName}》
|
||||
</li>
|
||||
))
|
||||
) : (
|
||||
<li className="start-class-item-list-item">暂无最近课程记录</li>
|
||||
)}
|
||||
{courses?.todaysCourses?.length > 0 && (
|
||||
courses.todaysCourses.slice(0, 2).map((course, index) => (
|
||||
<li key={`today-${index}`} className="start-class-item-list-item">
|
||||
今日计划《{course.courseName}》
|
||||
</li>
|
||||
))
|
||||
)}
|
||||
</ul>
|
||||
</li>
|
||||
<li className="start-class-item">
|
||||
<p className="start-class-item-title">下次上课</p>
|
||||
<p className="start-class-item-title">
|
||||
<IconFont className="title-icon" src="recuUY5km8qdgo" />
|
||||
<span>下次上课</span>
|
||||
<span className="num">{courses?.nextCourse?.length || 0}</span>
|
||||
</p>
|
||||
<ul className="start-class-item-list">
|
||||
{courses?.nextCourse ? (
|
||||
<li className="start-class-item-list-item">
|
||||
《{courses.nextCourse.courseName}》
|
||||
{courses.nextCourse.classroom && (
|
||||
<span className="classroom"> - {courses.nextCourse.classroom}</span>
|
||||
<span className="classroom">
|
||||
- {courses.nextCourse.classroom}
|
||||
</span>
|
||||
)}
|
||||
</li>
|
||||
) : (
|
||||
@@ -73,7 +66,9 @@ const StartClass = ({ courses, tasks, loading }) => {
|
||||
</li>
|
||||
<li className="start-class-item">
|
||||
<p className="start-class-item-title">
|
||||
待办事项({pendingTasks.length})
|
||||
<IconFont className="title-icon" src="recuUY5jNLbEPE" />
|
||||
<span>待办事项</span>
|
||||
<span className="num">{pendingTasks.length || 0}</span>
|
||||
</p>
|
||||
<ul className="start-class-item-list">
|
||||
{pendingTasks.length > 0 ? (
|
||||
@@ -87,6 +82,28 @@ const StartClass = ({ courses, tasks, loading }) => {
|
||||
)}
|
||||
</ul>
|
||||
</li>
|
||||
</div>
|
||||
|
||||
<div className="start-class-item-right">
|
||||
<li className="start-class-item">
|
||||
<p className="start-class-item-title">
|
||||
<IconFont className="title-icon" src="recuUY5rdMHBHn" />
|
||||
<span>最近课程</span>
|
||||
<span className="num">{courses?.recentCourses?.length || 0}</span>
|
||||
</p>
|
||||
<ul className="start-class-item-list">
|
||||
{courses?.recentCourses?.length > 0 ? (
|
||||
courses?.recentCourses?.map((course, index) => (
|
||||
<li key={index} className="start-class-item-list-item">
|
||||
{formatCourseDate(course.date)}《{course.courseName}》
|
||||
</li>
|
||||
))
|
||||
) : (
|
||||
<li className="start-class-item-list-item">暂无最近课程记录</li>
|
||||
)}
|
||||
</ul>
|
||||
</li>
|
||||
</div>
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
.module-study-status-wrapper {
|
||||
width: 360px;
|
||||
height: 413px;
|
||||
margin-right: 20px;
|
||||
width: 373px;
|
||||
height: 420px;
|
||||
border-radius: 16px;
|
||||
border: 1px solid #fff;
|
||||
overflow: hidden;
|
||||
flex-shrink: 0;
|
||||
background-size: 150% 120%;
|
||||
background-position: 50% 30%;
|
||||
box-sizing: border-box;
|
||||
padding: 20px;
|
||||
background-color: #e8f6ff;
|
||||
margin-top: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
@@ -38,18 +37,13 @@
|
||||
margin-bottom: 20px;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
padding-left: 30px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
.title-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
content: "";
|
||||
background-image: url("@/assets/images/Dashboard/StudyStatus/study-status_title_icon.png");
|
||||
background-size: 100% 100%;
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,25 +1,16 @@
|
||||
import EchartsProgress from "../EchartsProgress";
|
||||
import { Skeleton } from "@arco-design/web-react";
|
||||
import EchartsProgress from "@/components/EchartsProgress";
|
||||
import IconFont from "@/components/IconFont";
|
||||
import "./index.css";
|
||||
|
||||
const StudyStatus = ({ progress = 0, loading }) => {
|
||||
if (loading) {
|
||||
const StudyStatus = ({ progress = 0 }) => {
|
||||
return (
|
||||
<div className="module-study-status-wrapper">
|
||||
<p className="module-study-status-title">学习情况</p>
|
||||
<Skeleton loading={true} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="module-study-status-wrapper">
|
||||
<p className="module-study-status-title">学习情况</p>
|
||||
<p className="module-study-status-title">
|
||||
<IconFont className="title-icon" src="recuUY5mDawm4e" />
|
||||
<span>学习情况</span>
|
||||
</p>
|
||||
<div className="progress-container">
|
||||
<EchartsProgress percent={progress || 0} strokeWidth={20} />
|
||||
<span className="progress-text">
|
||||
整体课程完成进度 ({progress || 0}%)
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
.module-tasks-wrapper {
|
||||
width: 360px;
|
||||
height: 413px;
|
||||
width: 100%;
|
||||
background-color: #fff;
|
||||
border-radius: 16px;
|
||||
border: 1px solid #fff;
|
||||
@@ -12,6 +11,18 @@
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
position: relative;
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 127px;
|
||||
height: 95px;
|
||||
background-image: url("@/assets/images/Dashboard/TaskList/task_list_bg.png");
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
|
||||
.module-tasks-title {
|
||||
height: 30px;
|
||||
@@ -20,23 +31,22 @@
|
||||
font-weight: 500;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.task-count {
|
||||
font-size: 14px;
|
||||
color: #86909c;
|
||||
font-weight: normal;
|
||||
.title-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.no-tasks {
|
||||
margin-top: 130px;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
|
||||
.task-type {
|
||||
font-weight: bold;
|
||||
color: #1d2129;
|
||||
@@ -64,19 +74,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
.classroom {
|
||||
color: #86909c;
|
||||
font-size: 12px;
|
||||
line-height: 30px;
|
||||
color: #262626;
|
||||
}
|
||||
|
||||
.module-tasks-list {
|
||||
margin-top: 20px;
|
||||
width: 100%;
|
||||
height: 326px;
|
||||
height: 452px;
|
||||
box-sizing: border-box;
|
||||
padding: 0 20px;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
@@ -122,7 +125,7 @@
|
||||
}
|
||||
|
||||
.module-tasks-item-content {
|
||||
width: 294;
|
||||
width: 100%;
|
||||
height: 64px;
|
||||
margin-top: 5px;
|
||||
margin-left: 16px;
|
||||
@@ -156,12 +159,13 @@
|
||||
}
|
||||
|
||||
.module-tasks-item-content-info {
|
||||
width: 287px;
|
||||
width: 100%;
|
||||
height: 58px;
|
||||
border-radius: 8px;
|
||||
background-color: #fafafa;
|
||||
padding: 10px;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
> p {
|
||||
font-size: 10px;
|
||||
color: #616065;
|
||||
@@ -178,7 +182,7 @@
|
||||
|
||||
.module-tasks-item-content-info-duration {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
right: 20px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
font-size: 10px;
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { Avatar, Empty, Skeleton } from "@arco-design/web-react";
|
||||
import { Avatar, Skeleton, Empty } from "@arco-design/web-react";
|
||||
import IconFont from "@/components/IconFont";
|
||||
import "./index.css";
|
||||
|
||||
const TaskList = ({ tasks = [], selectedDate, loading }) => {
|
||||
const TaskList = ({ tasks = [], loading }) => {
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="module-tasks-wrapper">
|
||||
@@ -11,14 +12,6 @@ const TaskList = ({ tasks = [], selectedDate, loading }) => {
|
||||
);
|
||||
}
|
||||
|
||||
const formatDate = (date) => {
|
||||
return date.toLocaleDateString("zh-CN", {
|
||||
year: "numeric",
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
});
|
||||
};
|
||||
|
||||
const getTaskTypeText = (type) => {
|
||||
const typeMap = {
|
||||
HOMEWORK: "作业",
|
||||
@@ -30,25 +23,12 @@ const TaskList = ({ tasks = [], selectedDate, loading }) => {
|
||||
return typeMap[type] || type;
|
||||
};
|
||||
|
||||
// const getPriorityClass = (priority) => {
|
||||
// const classMap = {
|
||||
// URGENT: "urgent",
|
||||
// HIGH: "high",
|
||||
// MEDIUM: "medium",
|
||||
// LOW: "low",
|
||||
// };
|
||||
// return classMap[priority] || "medium";
|
||||
// };
|
||||
|
||||
return (
|
||||
<div className="module-tasks-wrapper">
|
||||
<p className="module-tasks-title">
|
||||
事项 - {formatDate(selectedDate)}
|
||||
{tasks.length > 0 && (
|
||||
<span className="task-count">({tasks.length})</span>
|
||||
)}
|
||||
<IconFont className="title-icon" src="recuUY5obMePNQ" />
|
||||
<span>当日事项</span>
|
||||
</p>
|
||||
|
||||
{tasks.length === 0 ? (
|
||||
<div className="no-tasks">
|
||||
<Empty description="该日无事项" />
|
||||
|
||||
@@ -14,15 +14,51 @@
|
||||
.dashboard {
|
||||
width: 100%;
|
||||
animation: fadeIn 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
/* Dashboard网格布局 - 按用户要求的两排布局 */
|
||||
.dashboard-grid {
|
||||
.dashboard-wrapper {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
flex-shrink: 0;
|
||||
box-sizing: border-box;
|
||||
padding: 20px;
|
||||
|
||||
.dashboard-left-content {
|
||||
width: 766px;
|
||||
height: 966px;
|
||||
flex-shrink: 0;
|
||||
|
||||
.status-rank-wrapper {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-top: 20px;
|
||||
|
||||
.class-rank-wrapper {
|
||||
height: 420px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dashboard-right-content {
|
||||
flex: 1;
|
||||
height: 966px;
|
||||
margin-left: 20px;
|
||||
background-color: #ffffff;
|
||||
border-radius: 16px;
|
||||
position: relative;
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
background-image: url("@/assets/images/Dashboard/right_content_bg.png");
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import StartClass from "./components/StartClass";
|
||||
import QuickAccess from "./components/QuickAccess";
|
||||
import CalendarTaskModule from "./components/CalendarTaskModule";
|
||||
import StudyStatus from "./components/StudyStatus";
|
||||
import Rank from "@/components/Rank";
|
||||
import ClassRank from "@/components/ClassRank";
|
||||
import StageProgress from "@/components/StageProgress";
|
||||
import TaskList from "./components/TaskList";
|
||||
import { getDashboardStatistics } from "@/services";
|
||||
@@ -52,24 +52,21 @@ const Dashboard = () => {
|
||||
<div className="dashboard">
|
||||
<StageProgress showBlockageAlert={true} />
|
||||
|
||||
<div className="dashboard-grid">
|
||||
<div className="dashboard-wrapper">
|
||||
<div className="dashboard-left-content">
|
||||
<StartClass
|
||||
courses={dashboardData?.courses}
|
||||
tasks={dashboardData?.tasks}
|
||||
loading={loading}
|
||||
/>
|
||||
<QuickAccess />
|
||||
<CalendarTaskModule
|
||||
tasks={dashboardData?.tasks?.allTasks}
|
||||
selectedDate={selectedDate}
|
||||
onDateChange={setSelectedDate}
|
||||
loading={loading}
|
||||
/>
|
||||
<div className="status-rank-wrapper">
|
||||
<StudyStatus
|
||||
progress={dashboardData?.overview?.overallProgress}
|
||||
loading={loading}
|
||||
/>
|
||||
<Rank
|
||||
<ClassRank
|
||||
className="class-rank-wrapper"
|
||||
data={
|
||||
dashboardData?.ranking
|
||||
? {
|
||||
@@ -77,13 +74,17 @@ const Dashboard = () => {
|
||||
}
|
||||
: null
|
||||
}
|
||||
loading={loading}
|
||||
/>
|
||||
<TaskList
|
||||
tasks={getTasksForDate(selectedDate)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="dashboard-right-content">
|
||||
<CalendarTaskModule
|
||||
tasks={dashboardData?.tasks?.allTasks}
|
||||
selectedDate={selectedDate}
|
||||
loading={loading}
|
||||
onDateChange={setSelectedDate}
|
||||
/>
|
||||
<TaskList tasks={getTasksForDate(selectedDate)} loading={loading} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,15 +1,23 @@
|
||||
import { useState } from "react";
|
||||
import CoursesVideoPlayer from "@/components/CoursesVideoPlayer";
|
||||
import CourseList from "@/components/CourseList";
|
||||
import StageProgress from "@/components/StageProgress";
|
||||
import { mockData } from "@/data/mockData";
|
||||
import "./index.css";
|
||||
|
||||
const LivePage = () => {
|
||||
const [selectedCourse, setSelectedCourse] = useState(null);
|
||||
|
||||
const handleCourseClick = (course) => {
|
||||
setSelectedCourse(course);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="live-page">
|
||||
<StageProgress />
|
||||
<div className="live-page-content">
|
||||
<CoursesVideoPlayer />
|
||||
<CourseList />
|
||||
<CoursesVideoPlayer selectedCourse={selectedCourse} teacherData={mockData.teacherData} unitPosters={mockData.unitPosters} />
|
||||
<CourseList onCourseClick={handleCourseClick} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -73,16 +73,16 @@ const AttendanceRingChart = ({
|
||||
<div
|
||||
ref={chartRef}
|
||||
style={{
|
||||
width: "90%",
|
||||
height: "90%",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
}}
|
||||
/>
|
||||
{centerContent && (
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: "45%",
|
||||
left: "45%",
|
||||
top: "50%",
|
||||
left: "50%",
|
||||
transform: "translate(-50%, -50%)",
|
||||
textAlign: "center",
|
||||
...centerContentStyle,
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
.profile-card-wrapper {
|
||||
width: 100%;
|
||||
height: 374px;
|
||||
border-radius: 8px;
|
||||
background-image: url("@/assets/images/PersonalProfile/personal_profile_bg.png");
|
||||
background-size: 100% 100%;
|
||||
height: 364px;
|
||||
border-radius: 16px;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
@@ -11,6 +9,19 @@
|
||||
box-sizing: border-box;
|
||||
padding: 16px;
|
||||
flex-shrink: 0;
|
||||
background-image: linear-gradient(180deg, #e1ebff, #f3f7ff);
|
||||
position: relative;
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
background-image: url("@/assets/images/PersonalProfile/personal_profile_bg.png");
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
|
||||
.profile-card-user-info {
|
||||
width: 100%;
|
||||
@@ -115,23 +126,8 @@
|
||||
margin-bottom: 15px;
|
||||
|
||||
.profile-card-class-info-item-icon {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
.icon-school {
|
||||
background-image: url("@/assets/images/PersonalProfile/school_icon.png");
|
||||
}
|
||||
.icon-major {
|
||||
background-image: url("@/assets/images/PersonalProfile/major_icon.png");
|
||||
}
|
||||
.icon-location {
|
||||
background-image: url("@/assets/images/PersonalProfile/location_icon.png");
|
||||
}
|
||||
.icon-course {
|
||||
background-image: url("@/assets/images/PersonalProfile/course_icon.png");
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.profile-card-class-info-item-title {
|
||||
@@ -139,7 +135,7 @@
|
||||
font-weight: 400;
|
||||
color: #4e5969;
|
||||
position: absolute;
|
||||
left: 40px;
|
||||
left: 25px;
|
||||
}
|
||||
|
||||
.profile-card-class-info-item-text {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { Avatar } from "@arco-design/web-react";
|
||||
import { useSelector } from "react-redux";
|
||||
import IconFont from "@/components/IconFont";
|
||||
import "./index.css";
|
||||
|
||||
const ProfileCard = () => {
|
||||
const studentInfo = useSelector((state) => state.student.studentInfo);
|
||||
|
||||
return (
|
||||
<div className="profile-card-wrapper">
|
||||
<div className="profile-card-user-info">
|
||||
@@ -47,29 +47,43 @@ const ProfileCard = () => {
|
||||
</ul>
|
||||
<ul className="profile-card-class-info">
|
||||
<li className="profile-card-class-info-item">
|
||||
<i className="profile-card-class-info-item-icon icon-school" />
|
||||
<IconFont
|
||||
className="profile-card-class-info-item-icon"
|
||||
src="recuUY5p8rDCck"
|
||||
/>
|
||||
<span className="profile-card-class-info-item-title">学校</span>
|
||||
<span className="profile-card-class-info-item-text">
|
||||
{studentInfo?.school || "-"}
|
||||
</span>
|
||||
</li>
|
||||
<li className="profile-card-class-info-item">
|
||||
<i className="profile-card-class-info-item-icon icon-major" />
|
||||
<IconFont
|
||||
className="profile-card-class-info-item-icon"
|
||||
src="recuUY5pyDDMub"
|
||||
/>
|
||||
<span className="profile-card-class-info-item-title">专业</span>
|
||||
<span className="profile-card-class-info-item-text">
|
||||
{studentInfo?.major || "-"}
|
||||
</span>
|
||||
</li>
|
||||
<li className="profile-card-class-info-item">
|
||||
<i className="profile-card-class-info-item-icon icon-location" />
|
||||
<span className="profile-card-class-info-item-title">班级</span>
|
||||
<IconFont
|
||||
className="profile-card-class-info-item-icon"
|
||||
src="recuUY5pWmMoaQ"
|
||||
/>
|
||||
<span className="profile-card-class-info-item-title">
|
||||
就业管家课程
|
||||
</span>
|
||||
<span className="profile-card-class-info-item-text">
|
||||
{studentInfo?.className || "-"}
|
||||
</span>
|
||||
</li>
|
||||
<li className="profile-card-class-info-item">
|
||||
<i className="profile-card-class-info-item-icon icon-course" />
|
||||
<span className="profile-card-class-info-item-title">学习阶段</span>
|
||||
<IconFont
|
||||
className="profile-card-class-info-item-icon"
|
||||
src="recuUY5tMX7M6A"
|
||||
/>
|
||||
<span className="profile-card-class-info-item-title">垂直方向</span>
|
||||
<span className="profile-card-class-info-item-text">
|
||||
{studentInfo?.stageName || "-"}
|
||||
</span>
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
import React, { useRef, useEffect } from "react";
|
||||
import { useRef, useEffect } from "react";
|
||||
import * as echarts from "echarts";
|
||||
const screenWidth = window.screen.width; // 物理屏幕宽度(单位:像素)
|
||||
|
||||
const ScoreRingChart = ({
|
||||
className = "",
|
||||
ringData = [], // 数据
|
||||
title = "",
|
||||
bgColor = "#F7F8FA", // 未填充部分背景色
|
||||
bgColor = "#EDF4FF", // 未填充部分背景色
|
||||
}) => {
|
||||
// 创建图表容器引用
|
||||
const chartRef = useRef(null);
|
||||
@@ -44,7 +42,7 @@ const ScoreRingChart = ({
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
width: 10,
|
||||
width: 20,
|
||||
color: [[1, bgColor]],
|
||||
},
|
||||
},
|
||||
@@ -58,23 +56,13 @@ const ScoreRingChart = ({
|
||||
show: false,
|
||||
},
|
||||
data: [ringData[0]],
|
||||
title: {
|
||||
fontSize: 14,
|
||||
},
|
||||
detail: {
|
||||
fontSize: 16,
|
||||
color: "#1D2129",
|
||||
formatter: title,
|
||||
lineHeight: 20,
|
||||
height: 40,
|
||||
offsetCenter: [0, 0],
|
||||
},
|
||||
detail: false,
|
||||
},
|
||||
{
|
||||
type: "gauge",
|
||||
startAngle: 90,
|
||||
endAngle: -270,
|
||||
radius: "80%",
|
||||
radius: "70%",
|
||||
pointer: {
|
||||
show: false,
|
||||
},
|
||||
@@ -86,7 +74,7 @@ const ScoreRingChart = ({
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
width: 10,
|
||||
width: 20,
|
||||
color: [[1, bgColor]],
|
||||
},
|
||||
},
|
||||
@@ -126,7 +114,7 @@ const ScoreRingChart = ({
|
||||
chartInstance.current = null;
|
||||
}
|
||||
};
|
||||
}, [ringData, title, bgColor]);
|
||||
}, [ringData, bgColor]);
|
||||
|
||||
return <div ref={chartRef} className={className} />;
|
||||
};
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
.study-studes-card-wrapper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 8px;
|
||||
background-color: #fff;
|
||||
border-radius: 16px;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
padding: 20px;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
overflow: hidden;
|
||||
|
||||
.study-studes-card-title {
|
||||
height: 30px;
|
||||
@@ -18,7 +20,16 @@
|
||||
line-height: 30px;
|
||||
color: #262626;
|
||||
margin-bottom: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.title-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.study-studes-card-spin {
|
||||
margin: auto;
|
||||
}
|
||||
@@ -27,164 +38,208 @@
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
justify-content: space-around;
|
||||
align-items: flex-start;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.study-studes-card-study-info {
|
||||
width: 356px;
|
||||
height: 310px;
|
||||
flex-shrink: 0;
|
||||
width: 338px;
|
||||
height: 308px;
|
||||
border-radius: 12px;
|
||||
position: relative;
|
||||
background-image: url("@/assets/images/PersonalProfile/study_study_bg.png");
|
||||
background-size: 100% 100%;
|
||||
background-color: rgba(255, 255, 255, 0.6);
|
||||
border: 2px solid rgba(255, 255, 255, 0.8);
|
||||
box-sizing: border-box;
|
||||
padding: 10px 0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
|
||||
.study-studes-card-time-wrapper {
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
border-radius: 8px;
|
||||
border: 1px solid #fff;
|
||||
width: 314px;
|
||||
height: 156px;
|
||||
width: 324px;
|
||||
height: 133px;
|
||||
background-color: #fff;
|
||||
box-shadow: 2px 2px 16.4px 0px rgba(103, 162, 247, 0.25);
|
||||
box-sizing: border-box;
|
||||
padding: 20px;
|
||||
.study-studes-card-study-time-wrapper {
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
padding: 20px 10px;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
flex-direction: column;
|
||||
|
||||
.study-studes-card-study-info-title {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #4e5969;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.study-studes-card-study-time-line-class {
|
||||
> i {
|
||||
background: linear-gradient(
|
||||
to right,
|
||||
#4564ff,
|
||||
#ab2cff
|
||||
) !important;
|
||||
}
|
||||
}
|
||||
.study-studes-card-study-time-line {
|
||||
width: 265px;
|
||||
height: 10px;
|
||||
border-radius: 12px;
|
||||
background-color: #cedefa;
|
||||
width: 100%;
|
||||
height: 24px;
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
color: #1d2129;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
padding-left: 30px;
|
||||
|
||||
&::before {
|
||||
content: "";
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
background-image: url("@/assets/images/PersonalProfile/title_icon.png");
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.study-studes-card-study-time-line {
|
||||
width: 290px;
|
||||
height: 12px;
|
||||
border-radius: 12px;
|
||||
background-color: #f4f7f9;
|
||||
position: relative;
|
||||
margin-bottom: 10px;
|
||||
> i {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
border-radius: 12px;
|
||||
background: linear-gradient(to right, #2c7aff, #00aeff);
|
||||
|
||||
> span {
|
||||
position: absolute;
|
||||
display: block;
|
||||
right: 0;
|
||||
top: 30%;
|
||||
transform: translate(50%, 30%);
|
||||
top: -25px;
|
||||
transform: translateX(50%);
|
||||
font-style: normal;
|
||||
width: 38px;
|
||||
height: 21px;
|
||||
line-height: 22px;
|
||||
width: 46px;
|
||||
height: 24px;
|
||||
line-height: 20px;
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: #2358ed;
|
||||
background-image: url("@/assets/images/PersonalProfile/line_icon.png");
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
color: #fff;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
|
||||
.icon1 {
|
||||
background-image: url("@/assets/images/PersonalProfile/line_icon1.png");
|
||||
}
|
||||
.icon2 {
|
||||
background-image: url("@/assets/images/PersonalProfile/line_icon2.png");
|
||||
}
|
||||
}
|
||||
.line1 {
|
||||
background: linear-gradient(to right, #2c7dff, #2da7ff);
|
||||
}
|
||||
.line2 {
|
||||
background: linear-gradient(to right, #37c850, #86e263);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.study-studes-card-study-progress {
|
||||
height: 310px;
|
||||
width: 356px;
|
||||
box-sizing: border-box;
|
||||
border-radius: 12px;
|
||||
background-color: rgba(255, 255, 255, 0.6);
|
||||
border: 2px solid rgba(255, 255, 255, 0.8);
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
height: 308px;
|
||||
width: 330px;
|
||||
border-radius: 8px;
|
||||
margin-left: 20px;
|
||||
|
||||
.study-studes-card-study-progress-chart {
|
||||
width: 250px;
|
||||
height: 250px;
|
||||
margin-top: 50px;
|
||||
margin-left: 15px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.study-studes-card-study-progress-title {
|
||||
color: #1d2129;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
margin-top: 20px;
|
||||
}
|
||||
}
|
||||
.study-studes-card-curriculum-homework {
|
||||
margin-left: 40px;
|
||||
margin-right: 40px;
|
||||
}
|
||||
.study-studes-card-curriculum {
|
||||
width: 194px;
|
||||
height: 350px;
|
||||
width: 232px;
|
||||
height: 390px;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
margin-top: 20px;
|
||||
box-sizing: border-box;
|
||||
border-radius: 12px;
|
||||
background-color: rgba(255, 255, 255, 0.6);
|
||||
border: 2px solid rgba(255, 255, 255, 0.8);
|
||||
padding: 10px;
|
||||
|
||||
.study-studes-card-curriculum-title {
|
||||
width: 100%;
|
||||
height: 24px;
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
color: #1d2129;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
padding-left: 30px;
|
||||
margin-bottom: 10px;
|
||||
|
||||
&::before {
|
||||
content: "";
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
background-image: url("@/assets/images/PersonalProfile/title_icon.png");
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.study-studes-card-curriculum-chart {
|
||||
width: 194px;
|
||||
height: 200px;
|
||||
margin-bottom: 30px;
|
||||
width: 180px;
|
||||
height: 180px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.study-studes-card-curriculum-info:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.study-studes-card-curriculum-info {
|
||||
width: 194px;
|
||||
height: 69px;
|
||||
border-radius: 8px;
|
||||
background-color: #f7f8fa;
|
||||
width: 200px;
|
||||
height: 73px;
|
||||
border-radius: 12px;
|
||||
background-color: #ffffff;
|
||||
box-sizing: border-box;
|
||||
padding: 10px;
|
||||
margin-bottom: 20px;
|
||||
margin-bottom: 10px;
|
||||
|
||||
> p {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
> i {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 3px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
.my-i {
|
||||
background-image: linear-gradient(0deg, #2c7aff, #2cb1ff);
|
||||
}
|
||||
.class-i {
|
||||
background-image: linear-gradient(0deg, #25c343, #99e869);
|
||||
}
|
||||
.loss-i {
|
||||
background-image: linear-gradient(0deg, #ff9a2d, #ffc02d);
|
||||
}
|
||||
> span {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
color: #4e5969;
|
||||
color: #1d2129;
|
||||
}
|
||||
}
|
||||
> span {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.study-studes-card-curriculum-info-span1 {
|
||||
color: #0aa4ff;
|
||||
}
|
||||
.study-studes-card-curriculum-info-span2 {
|
||||
color: #5e57ff;
|
||||
}
|
||||
.study-studes-card-curriculum-info-span3 {
|
||||
color: #ff9d2c;
|
||||
font-weight: 900;
|
||||
font-family: "HarmonyOS Sans TC";
|
||||
color: #1d2129;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import * as echarts from "echarts";
|
||||
import { useSelector } from "react-redux";
|
||||
import { Spin } from "@arco-design/web-react";
|
||||
import StudyProgress from "../StudyProgress";
|
||||
import IconFont from "@/components/IconFont";
|
||||
import EchartsProgress from "@/components/EchartsProgress";
|
||||
import ScoreRingChart from "../ScoreRingChart";
|
||||
import AttendanceRingChart from "../AttendanceRingChart";
|
||||
import "./index.css";
|
||||
@@ -28,27 +29,27 @@ const StudyStudes = ({ studyStatistics, learningProgress, loading }) => {
|
||||
const courseRingData = [
|
||||
{
|
||||
value: personalCourseProgress,
|
||||
name: "我的",
|
||||
title: {
|
||||
offsetCenter: ["-30%", "-90%"],
|
||||
},
|
||||
// name: "我的",
|
||||
// title: {
|
||||
// offsetCenter: ["-30%", "-90%"],
|
||||
// },
|
||||
itemStyle: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 1, 1, [
|
||||
{ offset: 0, color: "#2C7AFF" },
|
||||
{ offset: 1, color: "#00AEFF" },
|
||||
{ offset: 1, color: "#2CB9FF" },
|
||||
]),
|
||||
},
|
||||
},
|
||||
{
|
||||
value: classAverageCourseProgress,
|
||||
name: "班级",
|
||||
title: {
|
||||
offsetCenter: ["-60%", "-90%"],
|
||||
},
|
||||
// name: "班级",
|
||||
// title: {
|
||||
// offsetCenter: ["-60%", "-90%"],
|
||||
// },
|
||||
itemStyle: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 1, 1, [
|
||||
{ offset: 0, color: "#4564FF" },
|
||||
{ offset: 1, color: "#AB2CFF" },
|
||||
{ offset: 0, color: "#25C343" },
|
||||
{ offset: 1, color: "#A3EB6C" },
|
||||
]),
|
||||
},
|
||||
},
|
||||
@@ -57,27 +58,27 @@ const StudyStudes = ({ studyStatistics, learningProgress, loading }) => {
|
||||
const homeworkRingData = [
|
||||
{
|
||||
value: personalHomeworkProgress,
|
||||
name: "我的",
|
||||
title: {
|
||||
offsetCenter: ["-30%", "-90%"],
|
||||
},
|
||||
// name: "我的",
|
||||
// title: {
|
||||
// offsetCenter: ["-30%", "-90%"],
|
||||
// },
|
||||
itemStyle: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 1, 1, [
|
||||
{ offset: 0, color: "#2C7AFF" },
|
||||
{ offset: 1, color: "#00AEFF" },
|
||||
{ offset: 1, color: "#2CB9FF" },
|
||||
]),
|
||||
},
|
||||
},
|
||||
{
|
||||
value: classAverageHomeworkProgress,
|
||||
name: "班级",
|
||||
title: {
|
||||
offsetCenter: ["-60%", "-90%"],
|
||||
},
|
||||
// name: "班级",
|
||||
// title: {
|
||||
// offsetCenter: ["-60%", "-90%"],
|
||||
// },
|
||||
itemStyle: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 1, 1, [
|
||||
{ offset: 0, color: "#4564FF" },
|
||||
{ offset: 1, color: "#AB2CFF" },
|
||||
{ offset: 0, color: "#25C343" },
|
||||
{ offset: 1, color: "#A3EB6C" },
|
||||
]),
|
||||
},
|
||||
},
|
||||
@@ -90,16 +91,28 @@ const StudyStudes = ({ studyStatistics, learningProgress, loading }) => {
|
||||
itemStyle: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 1, 1, [
|
||||
{ offset: 0, color: "#2C7AFF" },
|
||||
{ offset: 1, color: "#00D5FF" },
|
||||
{ offset: 1, color: "#2CB9FF" },
|
||||
]),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "缺勤率",
|
||||
value: absenceRate,
|
||||
itemStyle: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 1, 1, [
|
||||
{ offset: 0, color: "#FF9A2D" },
|
||||
{ offset: 1, color: "#FFC02D" },
|
||||
]),
|
||||
},
|
||||
},
|
||||
{ name: "缺勤率", value: absenceRate, itemStyle: { color: "#FF9D2C" } },
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="study-studes-card-wrapper">
|
||||
<p className="study-studes-card-title">学习情况</p>
|
||||
<p className="study-studes-card-title">
|
||||
<IconFont className="title-icon" src="recuUY5mDawm4e" />
|
||||
<span>学习情况</span>
|
||||
</p>
|
||||
{loading ? (
|
||||
<Spin size={40} className="study-studes-card-spin" />
|
||||
) : (
|
||||
@@ -107,12 +120,12 @@ const StudyStudes = ({ studyStatistics, learningProgress, loading }) => {
|
||||
{/* 时长 */}
|
||||
<li className="study-studes-card-study-info">
|
||||
<div className="study-studes-card-time-wrapper">
|
||||
<div className="study-studes-card-study-time-wrapper">
|
||||
<p className="study-studes-card-study-info-title">
|
||||
个人学习时长(h)
|
||||
</p>
|
||||
<p className="study-studes-card-study-time-line">
|
||||
<i
|
||||
className="line1"
|
||||
style={{
|
||||
width: `${Math.min(
|
||||
(personalStudyHours / classAverageStudyHours) * 70,
|
||||
@@ -120,74 +133,77 @@ const StudyStudes = ({ studyStatistics, learningProgress, loading }) => {
|
||||
)}%`,
|
||||
}}
|
||||
>
|
||||
<span>{personalStudyHours}</span>
|
||||
<span className="icon1">{personalStudyHours}</span>
|
||||
</i>
|
||||
</p>
|
||||
</div>
|
||||
<div className="study-studes-card-study-time-wrapper">
|
||||
<div className="study-studes-card-time-wrapper">
|
||||
<p className="study-studes-card-study-info-title">
|
||||
班级平均学习时长(h)
|
||||
</p>
|
||||
<p className="study-studes-card-study-time-line study-studes-card-study-time-line-class">
|
||||
<i style={{ width: "80%" }}>
|
||||
<span>{classAverageStudyHours}</span>
|
||||
<i className="line2" style={{ width: "80%" }}>
|
||||
<span className="icon2">{classAverageStudyHours}</span>
|
||||
</i>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{/* 进度 */}
|
||||
<li className="study-studes-card-study-progress">
|
||||
<StudyProgress
|
||||
value={overallProgress}
|
||||
className="study-studes-card-study-progress-chart"
|
||||
/>
|
||||
<p className="study-studes-card-study-progress-title">
|
||||
整体课程完成进度
|
||||
</p>
|
||||
<EchartsProgress percent={overallProgress || 0} strokeWidth={20} />
|
||||
</li>
|
||||
{/* 课程整体完成情况 */}
|
||||
<li className="study-studes-card-curriculum">
|
||||
<p className="study-studes-card-curriculum-title">
|
||||
整体课程完成情况
|
||||
</p>
|
||||
<ScoreRingChart
|
||||
title={`整体课程\n完成情况`}
|
||||
ringData={courseRingData}
|
||||
className="study-studes-card-curriculum-chart"
|
||||
/>
|
||||
<div className="study-studes-card-curriculum-info">
|
||||
<p>班级平均进度</p>
|
||||
<span className="study-studes-card-curriculum-info-span1">
|
||||
{classAverageCourseProgress}%
|
||||
</span>
|
||||
<p>
|
||||
<i className="my-i" />
|
||||
<span>我的进度</span>
|
||||
</p>
|
||||
<span>{personalCourseProgress}%</span>
|
||||
</div>
|
||||
<div className="study-studes-card-curriculum-info">
|
||||
<p>我的进度</p>
|
||||
<span className="study-studes-card-curriculum-info-span2">
|
||||
{personalCourseProgress}%
|
||||
</span>
|
||||
<p>
|
||||
<i className="class-i" />
|
||||
<span>班级平均进度</span>
|
||||
</p>
|
||||
<span>{classAverageCourseProgress}%</span>
|
||||
</div>
|
||||
</li>
|
||||
{/* 课后作业完成情况 */}
|
||||
<li className="study-studes-card-curriculum-homework study-studes-card-curriculum">
|
||||
<p className="study-studes-card-curriculum-title">
|
||||
课后作业完成情况
|
||||
</p>
|
||||
<ScoreRingChart
|
||||
title={`课后作业\n完成情况`}
|
||||
ringData={homeworkRingData}
|
||||
className="study-studes-card-curriculum-chart"
|
||||
/>
|
||||
<div className="study-studes-card-curriculum-info">
|
||||
<p>班级平均进度</p>
|
||||
<span className="study-studes-card-curriculum-info-span1">
|
||||
{classAverageHomeworkProgress}%
|
||||
</span>
|
||||
<p>
|
||||
<i className="my-i" />
|
||||
<span>我的进度</span>
|
||||
</p>
|
||||
<span>{personalHomeworkProgress}%</span>
|
||||
</div>
|
||||
<div className="study-studes-card-curriculum-info">
|
||||
<p>我的进度</p>
|
||||
<span className="study-studes-card-curriculum-info-span2">
|
||||
{personalHomeworkProgress}%
|
||||
</span>
|
||||
<p>
|
||||
<i className="class-i" />
|
||||
<span>班级平均进度</span>
|
||||
</p>
|
||||
<span>{classAverageHomeworkProgress}%</span>
|
||||
</div>
|
||||
</li>
|
||||
{/* 考勤情况 */}
|
||||
<li className="study-studes-card-curriculum">
|
||||
<p className="study-studes-card-curriculum-title">考勤情况</p>
|
||||
<AttendanceRingChart
|
||||
data={attendanceData}
|
||||
centerContent={
|
||||
@@ -198,16 +214,18 @@ const StudyStudes = ({ studyStatistics, learningProgress, loading }) => {
|
||||
/>
|
||||
|
||||
<div className="study-studes-card-curriculum-info">
|
||||
<p>出勤率</p>
|
||||
<span className="study-studes-card-curriculum-info-span1">
|
||||
{attendanceRate}%
|
||||
</span>
|
||||
<p>
|
||||
<i className="my-i" />
|
||||
<span>出勤率</span>
|
||||
</p>
|
||||
<span>{attendanceRate}%</span>
|
||||
</div>
|
||||
<div className="study-studes-card-curriculum-info">
|
||||
<p>缺勤率</p>
|
||||
<span className="study-studes-card-curriculum-info-span3">
|
||||
{absenceRate}%
|
||||
</span>
|
||||
<p>
|
||||
<i className="loss-i" />
|
||||
<span>缺勤率</span>
|
||||
</p>
|
||||
<span>{absenceRate}%</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -19,23 +19,37 @@
|
||||
margin-top: 20px;
|
||||
|
||||
.unified-profile-left {
|
||||
width: 360px;
|
||||
width: 373px;
|
||||
height: 100%;
|
||||
margin-right: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
.unified-profile-rank {
|
||||
height: 385px;
|
||||
height: 420px;
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.unified-profile-right {
|
||||
width: 744px;
|
||||
height: 781px;
|
||||
border-radius: 8px;
|
||||
background-color: #fff;
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
border-radius: 16px;
|
||||
background-color: #e8f6ff;
|
||||
position: relative;
|
||||
border: 2px solid #fff;
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
background-image: url("@/assets/images/PersonalProfile/unified_profile_right_bg.png");
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { useDispatch } from "react-redux";
|
||||
import ProfileCard from "./components/ProfileCard";
|
||||
import Rank from "@/components/Rank";
|
||||
import ClassRank from "@/components/ClassRank";
|
||||
import StageProgress from "@/components/StageProgress";
|
||||
import StudyStudes from "./components/StudyStudes";
|
||||
import { updateStudentInfo } from "@/store/slices/studentSlice";
|
||||
@@ -26,13 +26,7 @@ const PersonalProfile = () => {
|
||||
// 更新Redux中的学生信息
|
||||
const studentInfo = {
|
||||
...data.studentInfo,
|
||||
realName: data.studentInfo.name,
|
||||
studentNo: data.studentInfo.studentId,
|
||||
mbtiType: data.studentInfo.mbti || 'ENFJ',
|
||||
myRank: {
|
||||
...data.ranking.myRank,
|
||||
score: data.studentInfo.credits,
|
||||
},
|
||||
myRank: data.ranking.myRank,
|
||||
classInfo: data.ranking.classInfo,
|
||||
};
|
||||
|
||||
@@ -58,7 +52,7 @@ const PersonalProfile = () => {
|
||||
<div className="unified-profile-layout">
|
||||
<div className="unified-profile-left">
|
||||
<ProfileCard />
|
||||
<Rank
|
||||
<ClassRank
|
||||
className="unified-profile-rank"
|
||||
data={
|
||||
profileData?.ranking
|
||||
|
||||
Reference in New Issue
Block a user