feat: 实现日历课程点击跳转到直播间功能
- 添加日历课程详情弹窗的点击跳转功能 - 公共课直播间和课程直播间支持URL参数自动选中课程 - 优化岗位详情页面样式,复用简洁卡片样式 - 为岗位详情标题添加图标 - 调整不同类型课程的跳转逻辑 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -47,7 +47,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 20px 0;
|
||||
margin: 10px 0;
|
||||
position: relative;
|
||||
|
||||
.divider-line {
|
||||
@@ -67,8 +67,46 @@
|
||||
background-color: #fff;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
/* 可点击的分割线样式 */
|
||||
.course-divider.clickable {
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.course-divider.clickable:hover .divider-text {
|
||||
color: #4080ff;
|
||||
}
|
||||
|
||||
.course-divider.clickable:hover .divider-line {
|
||||
border-color: #4080ff;
|
||||
}
|
||||
|
||||
/* 分类容器缓动效果 */
|
||||
.course-category-wrapper {
|
||||
overflow: hidden;
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transform-origin: top;
|
||||
}
|
||||
|
||||
.course-category-wrapper.expanded {
|
||||
max-height: 2000px;
|
||||
opacity: 1;
|
||||
transform: scaleY(1);
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.course-category-wrapper.collapsed {
|
||||
max-height: 0;
|
||||
opacity: 0;
|
||||
transform: scaleY(0);
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/* 自定义折叠面板元素 */
|
||||
.course-list-item {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { Collapse, Timeline, Spin } from "@arco-design/web-react";
|
||||
import { IconDown, IconRight } from "@arco-design/web-react/icon";
|
||||
import { getCourseLiveList } from "@/services/courseLive";
|
||||
import "./index.css";
|
||||
|
||||
@@ -11,6 +12,12 @@ const CourseList = ({ className = "", onCourseClick }) => {
|
||||
const [verticalCourseList, setVerticalCourseList] = useState([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [selectedCourseId, setSelectedCourseId] = useState(null);
|
||||
|
||||
// 控制各分类的展开/收缩状态,默认全部展开
|
||||
const [categoryExpanded, setCategoryExpanded] = useState({
|
||||
'compound': true, // 复合能力课
|
||||
'vertical': true // 垂直提升课
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
fetchCourseList();
|
||||
@@ -133,15 +140,21 @@ const CourseList = ({ className = "", onCourseClick }) => {
|
||||
>
|
||||
{/* 复合能力课分割线 */}
|
||||
{compoundCourseList.length > 0 && (
|
||||
<div className="course-divider">
|
||||
<div
|
||||
className="course-divider clickable"
|
||||
onClick={() => setCategoryExpanded(prev => ({ ...prev, compound: !prev.compound }))}
|
||||
>
|
||||
<span className="divider-line"></span>
|
||||
<span className="divider-text">复合能力课</span>
|
||||
<span className="divider-text">
|
||||
复合能力课
|
||||
</span>
|
||||
<span className="divider-line"></span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 复合能力课部分 */}
|
||||
{compoundCourseList.map((unit, index) => (
|
||||
<div className={`course-category-wrapper ${!categoryExpanded.compound ? 'collapsed' : 'expanded'}`}>
|
||||
{compoundCourseList.map((unit, index) => (
|
||||
<CollapseItem
|
||||
key={unit.unitId}
|
||||
header={unit.unitName}
|
||||
@@ -183,18 +196,25 @@ const CourseList = ({ className = "", onCourseClick }) => {
|
||||
</Timeline>
|
||||
</CollapseItem>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* 垂直能力课分割线 */}
|
||||
{verticalCourseList.length > 0 && (
|
||||
<div className="course-divider">
|
||||
<div
|
||||
className="course-divider clickable"
|
||||
onClick={() => setCategoryExpanded(prev => ({ ...prev, vertical: !prev.vertical }))}
|
||||
>
|
||||
<span className="divider-line"></span>
|
||||
<span className="divider-text">垂直能力课</span>
|
||||
<span className="divider-text">
|
||||
垂直能力课
|
||||
</span>
|
||||
<span className="divider-line"></span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 垂直能力课部分 */}
|
||||
{verticalCourseList.map((unit, index) => {
|
||||
<div className={`course-category-wrapper ${!categoryExpanded.vertical ? 'collapsed' : 'expanded'}`}>
|
||||
{verticalCourseList.map((unit, index) => {
|
||||
// 检查单元是否包含可试看课程
|
||||
const hasPreviewCourse = unit.courses.some(course => course.canPreview);
|
||||
|
||||
@@ -274,6 +294,7 @@ const CourseList = ({ className = "", onCourseClick }) => {
|
||||
</CollapseItem>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</Collapse>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -197,7 +197,7 @@ export default ({ className = "", isLock = false, selectedCourse, teacherData, u
|
||||
{displayCourse?.current && <div className="living-icon" />}
|
||||
</div>
|
||||
<span className="teacher-name">{currentTeacher?.name || ''}老师</span>
|
||||
<span className="teacher-tag">{displayCourse?.unitName || unitName}</span>
|
||||
<span className="teacher-tag">{displayCourse?.courseName || courseName || ''}</span>
|
||||
<div className="living-data">
|
||||
<div className="living-data-item">
|
||||
<span>开始</span>
|
||||
|
||||
@@ -43,6 +43,74 @@
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/*/* 分割线样式 */
|
||||
.course-list-wrapper .course-list-content .course-list .course-divider {
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 10px 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.course-list-wrapper .course-list-content .course-list .course-divider .divider-line {
|
||||
flex: 1;
|
||||
height: 1px;
|
||||
background: linear-gradient(90deg, transparent, #e5e6eb 20%, #e5e6eb 80%, transparent);
|
||||
border-style: dashed;
|
||||
border-width: 1px 0 0 0;
|
||||
border-color: #e5e6eb;
|
||||
}
|
||||
|
||||
.course-list-wrapper .course-list-content .course-list .course-divider .divider-text {
|
||||
padding: 0 16px;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: #86909c;
|
||||
background-color: #fff;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
/* 可点击的分割线样式 */
|
||||
.course-list-wrapper .course-list-content .course-list .course-divider.clickable {
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.course-list-wrapper .course-list-content .course-list .course-divider.clickable:hover .divider-text {
|
||||
color: #4080ff;
|
||||
}
|
||||
|
||||
.course-list-wrapper .course-list-content .course-list .course-divider.clickable:hover .divider-line {
|
||||
border-color: #4080ff;
|
||||
}
|
||||
|
||||
/* 分类容器缓动效果 */
|
||||
.course-list-wrapper .course-list-content .course-list .course-category-wrapper {
|
||||
overflow: hidden;
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transform-origin: top;
|
||||
}
|
||||
|
||||
.course-list-wrapper .course-list-content .course-list .course-category-wrapper.expanded {
|
||||
max-height: 2000px;
|
||||
opacity: 1;
|
||||
transform: scaleY(1);
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.course-list-wrapper .course-list-content .course-list .course-category-wrapper.collapsed {
|
||||
max-height: 0;
|
||||
opacity: 0;
|
||||
transform: scaleY(0);
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/* 自定义折叠面板元素 */
|
||||
.course-list-wrapper .course-list-content .course-list .course-list-item {
|
||||
width: 272px;
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { Collapse, Timeline, Spin } from "@arco-design/web-react";
|
||||
import { IconDown, IconRight } from "@arco-design/web-react/icon";
|
||||
import { getPublicCourseLiveList } from "@/services/courseLive";
|
||||
import "./index.css";
|
||||
|
||||
// 公共课单元海报数据
|
||||
const unitPosters = {
|
||||
"终生学习系统": "https://ddcz-1315997005.cos.ap-nanjing.myqcloud.com/static/img/public_bg/recuW7gMz6sRee.jpg", // AI课 -> sRee
|
||||
"企业高管公开课": "https://ddcz-1315997005.cos.ap-nanjing.myqcloud.com/static/img/public_bg/recuW7gMz6CiPN.jpg", // 公共课 -> CiPN
|
||||
"营销能力课": "https://ddcz-1315997005.cos.ap-nanjing.myqcloud.com/static/img/public_bg/recuW7gMz6zwRv.jpg" // 营销课 -> zwRv
|
||||
};
|
||||
// 单元海报数据将从服务器返回的数据中获取
|
||||
|
||||
const TimelineItem = Timeline.Item;
|
||||
const CollapseItem = Collapse.Item;
|
||||
@@ -17,6 +13,13 @@ const PublicCourseList = ({ className = "", onCourseClick }) => {
|
||||
const [courseLiveList, setCourseLiveList] = useState([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [selectedCourseId, setSelectedCourseId] = useState(null);
|
||||
|
||||
// 控制各分类的展开/收缩状态,默认全部展开
|
||||
const [categoryExpanded, setCategoryExpanded] = useState({
|
||||
'ai': true, // 终生学习系统
|
||||
'public': true, // 企业高管公开课
|
||||
'marketing': true // 营销能力课
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
fetchCourseList();
|
||||
@@ -95,54 +98,143 @@ const PublicCourseList = ({ className = "", onCourseClick }) => {
|
||||
expandIconPosition="right"
|
||||
defaultActiveKey={[]}
|
||||
>
|
||||
{courseLiveList.map((unit, index) => (
|
||||
<CollapseItem
|
||||
key={unit.unitId}
|
||||
header={unit.unitName}
|
||||
name={String(index + 1)}
|
||||
className="course-list-item"
|
||||
>
|
||||
<Timeline>
|
||||
{unit.courses.map((course) => (
|
||||
<TimelineItem
|
||||
key={course.courseId}
|
||||
dot={getDotIcon(course)}
|
||||
lineType="dashed"
|
||||
{courseLiveList.map((unit, index) => {
|
||||
// 判断当前单元属于哪个分类
|
||||
const isAIUnit = [
|
||||
"AI 入门与工具环境",
|
||||
"RAG 与检索增强",
|
||||
"AI 自动化与任务编排",
|
||||
"AI 项目开发与前端交互",
|
||||
"AI 大模型与核心原理",
|
||||
"AI 行业应用与综合实战"
|
||||
].includes(unit.unitName);
|
||||
|
||||
const isPublicUnit = [
|
||||
"沟通与协作能力",
|
||||
"问题解决与思维能力",
|
||||
"职场基础与个人发展",
|
||||
"职业发展与管理技能"
|
||||
].includes(unit.unitName);
|
||||
|
||||
const isMarketingUnit = [
|
||||
"必备营销技能",
|
||||
"自我营销课"
|
||||
].includes(unit.unitName);
|
||||
|
||||
// 判断是否需要显示分割线
|
||||
// 终生学习系统:第一个AI单元前显示
|
||||
const showAIDivider = isAIUnit && index === 0;
|
||||
|
||||
// 企业高管公开课:第一个企业高管单元前显示(前一个不是企业高管单元)
|
||||
const showPublicDivider = isPublicUnit && index > 0 &&
|
||||
!["沟通与协作能力", "问题解决与思维能力", "职场基础与个人发展", "职业发展与管理技能"]
|
||||
.includes(courseLiveList[index - 1]?.unitName);
|
||||
|
||||
// 营销能力课:第一个营销单元前显示(前一个不是营销单元)
|
||||
const showMarketingDivider = isMarketingUnit && index > 0 &&
|
||||
!["必备营销技能", "自我营销课"]
|
||||
.includes(courseLiveList[index - 1]?.unitName);
|
||||
|
||||
return (
|
||||
<div key={unit.unitId}>
|
||||
{/* 终生学习系统分割线 */}
|
||||
{showAIDivider && (
|
||||
<div
|
||||
className="course-divider clickable"
|
||||
onClick={() => setCategoryExpanded(prev => ({ ...prev, ai: !prev.ai }))}
|
||||
>
|
||||
<div
|
||||
className={`time-line-item ${getCourseStatus(course)} ${selectedCourseId === course.courseId ? 'selected' : ''}`}
|
||||
onClick={() => {
|
||||
setSelectedCourseId(course.courseId);
|
||||
// 调试日志
|
||||
console.log('点击课程单元:', unit.unitName);
|
||||
console.log('匹配的海报URL:', unitPosters[unit.unitName]);
|
||||
|
||||
onCourseClick && onCourseClick({
|
||||
...course,
|
||||
unitName: unit.unitName,
|
||||
unitPoster: unitPosters[unit.unitName] || unitPosters["终生学习系统"] || "https://ddcz-1315997005.cos.ap-nanjing.myqcloud.com/static/img/public_bg/recuW7gMz6sRee.jpg"
|
||||
});
|
||||
}}
|
||||
style={{ cursor: 'pointer' }}
|
||||
>
|
||||
<p style={{
|
||||
overflow: 'visible',
|
||||
textOverflow: 'unset',
|
||||
whiteSpace: 'normal',
|
||||
wordBreak: 'break-word'
|
||||
}}>
|
||||
{course.courseName}
|
||||
</p>
|
||||
<div className="time-line-item-info">
|
||||
<span>{course.teacherName}</span>
|
||||
<span className="course-date">{course.date}</span>
|
||||
</div>
|
||||
</div>
|
||||
</TimelineItem>
|
||||
))}
|
||||
</Timeline>
|
||||
</CollapseItem>
|
||||
))}
|
||||
<span className="divider-line"></span>
|
||||
<span className="divider-text">
|
||||
终生学习系统
|
||||
</span>
|
||||
<span className="divider-line"></span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 企业高管公开课分割线 */}
|
||||
{showPublicDivider && (
|
||||
<div
|
||||
className="course-divider clickable"
|
||||
onClick={() => setCategoryExpanded(prev => ({ ...prev, public: !prev.public }))}
|
||||
>
|
||||
<span className="divider-line"></span>
|
||||
<span className="divider-text">
|
||||
企业高管公开课
|
||||
</span>
|
||||
<span className="divider-line"></span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 营销能力课分割线 */}
|
||||
{showMarketingDivider && (
|
||||
<div
|
||||
className="course-divider clickable"
|
||||
onClick={() => setCategoryExpanded(prev => ({ ...prev, marketing: !prev.marketing }))}
|
||||
>
|
||||
<span className="divider-line"></span>
|
||||
<span className="divider-text">
|
||||
营销能力课
|
||||
</span>
|
||||
<span className="divider-line"></span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 根据分类的展开状态决定是否显示单元 */}
|
||||
<div
|
||||
className={`course-category-wrapper ${
|
||||
(isAIUnit && !categoryExpanded.ai) ||
|
||||
(isPublicUnit && !categoryExpanded.public) ||
|
||||
(isMarketingUnit && !categoryExpanded.marketing)
|
||||
? 'collapsed' : 'expanded'
|
||||
}`}
|
||||
>
|
||||
<CollapseItem
|
||||
key={unit.unitId}
|
||||
header={unit.unitName}
|
||||
name={String(index + 1)}
|
||||
className="course-list-item"
|
||||
>
|
||||
<Timeline>
|
||||
{unit.courses.map((course) => (
|
||||
<TimelineItem
|
||||
key={course.courseId}
|
||||
dot={getDotIcon(course)}
|
||||
lineType="dashed"
|
||||
>
|
||||
<div
|
||||
className={`time-line-item ${getCourseStatus(course)} ${selectedCourseId === course.courseId ? 'selected' : ''}`}
|
||||
onClick={() => {
|
||||
setSelectedCourseId(course.courseId);
|
||||
|
||||
onCourseClick && onCourseClick({
|
||||
...course,
|
||||
unitName: unit.unitName,
|
||||
unitPoster: unit.unitPoster || "https://ddcz-1315997005.cos.ap-nanjing.myqcloud.com/static/img/public_bg/recuW7gMz6sRee.jpg"
|
||||
});
|
||||
}}
|
||||
style={{ cursor: 'pointer' }}
|
||||
>
|
||||
<p style={{
|
||||
overflow: 'visible',
|
||||
textOverflow: 'unset',
|
||||
whiteSpace: 'normal',
|
||||
wordBreak: 'break-word'
|
||||
}}>
|
||||
{course.courseName}
|
||||
</p>
|
||||
<div className="time-line-item-info">
|
||||
<span>{course.teacherName}</span>
|
||||
<span className="course-date">{course.date}</span>
|
||||
</div>
|
||||
</div>
|
||||
</TimelineItem>
|
||||
))}
|
||||
</Timeline>
|
||||
</CollapseItem>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</Collapse>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user