feat: 完善专家支持中心和项目库单元导航功能

- 添加真实的文旅产业Q&A数据到专家支持中心
- 实现项目库到课程直播间的单元导航
- 新增CourseList组件的expandUnitByName方法
- 优化项目详情模态框的单元显示和交互

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
KQL
2025-09-12 19:52:36 +08:00
parent 0e7f98d3fc
commit 4738a8545c
11 changed files with 938 additions and 144 deletions

View File

@@ -27,6 +27,60 @@ const CourseList = forwardRef(({ className = "", onCourseClick }, ref) => {
// 暴露方法给父组件调用
useImperativeHandle(ref, () => ({
// 新增:通过单元名称展开对应的折叠面板
expandUnitByName: (unitName) => {
console.log('CourseList - expandUnitByName called:', unitName);
// 在两个列表中查找单元
const allLists = [
{ list: compoundCourseList, type: 'compound' },
{ list: verticalCourseList, type: 'vertical' }
];
for (const { list, type } of allLists) {
for (let i = 0; i < list.length; i++) {
const unit = list[i];
console.log(`Checking ${type} unit:`, unit.unitName);
if (unit.unitName === unitName) {
console.log('Found matching unit:', unit.unitName);
// 计算正确的 activeKey
let activeKey;
if (type === 'compound') {
activeKey = String(i + 1);
} else {
// 垂直课程使用特定的前缀
activeKey = `vertical-${i + 1}`;
}
// 展开对应的单元
setActiveKeys(prevKeys => {
if (!prevKeys.includes(activeKey)) {
console.log('Adding activeKey:', activeKey, 'to existing keys:', prevKeys);
return [...prevKeys, activeKey];
}
return prevKeys;
});
// 滚动到对应的单元位置
setTimeout(() => {
const collapseItems = document.querySelectorAll('.course-list-item');
if (collapseItems[type === 'compound' ? i : i + compoundCourseList.length]) {
collapseItems[type === 'compound' ? i : i + compoundCourseList.length].scrollIntoView({
behavior: 'smooth',
block: 'center'
});
}
}, 300);
return; // 找到后退出
}
}
}
console.log('Unit not found:', unitName);
},
selectCourse: (courseId, courseName) => {
console.log('CourseList - selectCourse called:', courseId, courseName);
console.log('CourseList - compoundCourseList:', compoundCourseList);

View File

@@ -0,0 +1,517 @@
// 专家支持中心问答数据
const expertSupportData = {
conversations: [
{
id: 1,
title: "文旅产业的就业前景如何?",
status: "finish",
date: "7天内",
messages: [
{
type: "user",
content: "你好,我是一名大学生,对文旅产业很感兴趣。请问文旅产业的就业前景如何?"
},
{
type: "assistant",
content: "你好文旅产业的就业前景非常广阔。根据最新数据中国文旅产业规模已超过5万亿元预计到2025年将达到10万亿元。这个行业涵盖了旅游、文化、娱乐、餐饮、住宿等多个领域提供了大量的就业机会。特别是在数字化转型的背景下文旅产业需要大量懂技术、懂运营、懂文化的复合型人才。",
mentor: "李老师"
}
]
},
{
id: 2,
title: "文旅产业有哪些主要的就业方向?",
status: "finish",
date: "7天内",
messages: [
{
type: "user",
content: "请问文旅产业有哪些主要的就业方向?我应该如何选择?"
},
{
type: "assistant",
content: "文旅产业的就业方向非常多样化:\n1. 旅游规划与开发:景区规划师、旅游产品设计师\n2. 运营管理:景区运营、酒店管理、民宿运营\n3. 市场营销:文旅营销策划、新媒体运营、品牌推广\n4. 文化创意文创产品设计、IP开发、展览策划\n5. 数字文旅智慧旅游平台运营、VR/AR体验设计\n6. 活动策展:会展策划、节庆活动组织、演艺制作\n\n选择时建议结合自己的兴趣特长和市场需求。",
mentor: "张老师"
}
]
},
{
id: 3,
title: "想进入文旅行业需要具备哪些技能?",
status: "finish",
date: "7天内",
messages: [
{
type: "user",
content: "我想进入文旅行业,需要具备哪些技能?"
},
{
type: "assistant",
content: "进入文旅行业需要的核心技能包括:\n\n基础技能\n- 良好的沟通表达能力\n- 团队协作能力\n- 服务意识和客户思维\n- 基本的英语交流能力\n\n专业技能\n- 旅游规划与线路设计\n- 市场营销与品牌推广\n- 新媒体运营(抖音、小红书等)\n- 数据分析能力\n- 项目管理能力\n\n加分技能\n- 摄影摄像技术\n- 文案写作能力\n- 第二外语\n- 数字化工具使用",
mentor: "王老师"
}
]
},
{
id: 4,
title: "文旅行业的薪资待遇怎么样?",
status: "finish",
date: "7天内",
messages: [
{
type: "user",
content: "请问文旅行业的薪资待遇怎么样?不同岗位差别大吗?"
},
{
type: "assistant",
content: "文旅行业的薪资待遇因岗位和地区而异:\n\n初级岗位1-3年\n- 旅游顾问4-6K/月\n- 活动执行5-8K/月\n- 新媒体运营5-8K/月\n\n中级岗位3-5年\n- 产品经理8-15K/月\n- 营销主管10-15K/月\n- 景区运营经理8-12K/月\n\n高级岗位5年以上\n- 运营总监15-30K/月\n- 项目总监20-40K/月\n- 区域负责人25-50K/月\n\n一线城市薪资普遍高30-50%,创新型岗位和数字化岗位薪资更高。",
mentor: "朱老师"
}
]
},
{
id: 5,
title: "如何准备文旅企业的面试?",
status: "finish",
date: "7天内",
messages: [
{
type: "user",
content: "我马上要参加一家文旅企业的面试,应该如何准备?"
},
{
type: "assistant",
content: "文旅企业面试准备建议:\n\n1. 了解企业背景\n- 研究公司的主营业务、发展历程、企业文化\n- 了解公司的代表性项目或产品\n- 关注公司最新动态和行业地位\n\n2. 准备常见问题\n- 为什么选择文旅行业?\n- 对文旅行业的理解和看法\n- 个人优势和相关经历\n- 职业规划\n\n3. 展示专业能力\n- 准备相关作品集或案例\n- 了解行业趋势和热点\n- 准备一个创新的文旅项目想法\n\n4. 注意形象礼仪\n- 着装得体,展现亲和力\n- 保持微笑,体现服务意识",
mentor: "陈老师"
}
]
},
{
id: 6,
title: "文旅产业的数字化转型趋势",
status: "finish",
date: "7天内",
messages: [
{
type: "user",
content: "听说文旅产业正在进行数字化转型,具体是什么情况?"
},
{
type: "assistant",
content: "文旅产业的数字化转型是当前最重要的趋势之一:\n\n1. 智慧旅游平台\n- 一站式旅游服务APP\n- 智能行程规划系统\n- 在线预订和支付系统\n\n2. 沉浸式体验\n- VR/AR景区导览\n- 数字博物馆和云展览\n- 元宇宙文旅项目\n\n3. 大数据应用\n- 游客行为分析\n- 精准营销推送\n- 景区流量预测和管理\n\n4. 内容营销创新\n- 短视频营销(抖音、小红书)\n- 直播带货和云旅游\n- KOL/KOC合作推广\n\n这些变化创造了大量新的就业机会特别需要既懂文旅又懂技术的人才。",
mentor: "赵老师"
}
]
},
{
id: 7,
title: "文旅行业的创业机会",
status: "finish",
date: "7天内",
messages: [
{
type: "user",
content: "我想在文旅行业创业,有什么好的方向吗?"
},
{
type: "assistant",
content: "文旅行业的创业机会很多,以下是一些有潜力的方向:\n\n低成本创业\n- 旅游自媒体和内容创作\n- 定制旅游服务(小众线路设计)\n- 民宿运营和管理\n- 文创产品设计和销售\n\n中等投入\n- 研学旅行组织\n- 露营地运营\n- 特色餐饮+文旅融合\n- 本地生活体验项目\n\n创新方向\n- 文旅科技产品开发\n- IP授权和运营\n- 沉浸式演艺项目\n- 康养旅游服务\n\n建议从自己熟悉的领域入手先做小而美的项目积累经验后再扩大规模。",
mentor: "刘老师"
}
]
},
{
id: 8,
title: "非旅游专业如何转行文旅?",
status: "finish",
date: "30天内",
messages: [
{
type: "user",
content: "我是学计算机的,但对文旅行业很感兴趣,可以转行吗?"
},
{
type: "assistant",
content: "计算机专业转行文旅其实很有优势!\n\n你的技术背景在文旅行业非常受欢迎\n1. 智慧旅游系统开发\n2. 旅游大数据分析\n3. 文旅APP和小程序开发\n4. VR/AR旅游体验设计\n5. 旅游电商平台运营\n\n转行建议\n- 先从文旅科技公司入手\n- 参与文旅相关的技术项目\n- 学习文旅行业知识和运营思维\n- 可以考虑OTA平台的技术岗位\n\n很多成功的文旅创业者都是跨界背景你的技术能力反而是差异化优势。",
mentor: "周老师"
}
]
},
{
id: 9,
title: "文旅行业的职业发展路径",
status: "finish",
date: "30天内",
messages: [
{
type: "user",
content: "在文旅行业工作,职业发展路径是怎样的?"
},
{
type: "assistant",
content: "文旅行业的职业发展路径比较多元化:\n\n传统晋升路径\n基层员工 → 主管 → 经理 → 总监 → VP/合伙人\n\n专业发展路径\n1. 运营线:运营专员 → 运营主管 → 运营经理 → 运营总监\n2. 产品线:产品助理 → 产品经理 → 高级产品经理 → 产品总监\n3. 营销线:营销专员 → 营销主管 → 营销经理 → CMO\n\n横向发展机会\n- 从执行岗转向策划岗\n- 从单一业务转向综合管理\n- 从传统文旅转向数字文旅\n- 从企业转向自主创业\n\n建议在职业早期多尝试不同岗位找到最适合自己的发展方向。",
mentor: "吴老师"
}
]
},
{
id: 10,
title: "文旅实习经历的重要性",
status: "finish",
date: "30天内",
messages: [
{
type: "user",
content: "大学期间的文旅实习经历重要吗?应该如何选择实习?"
},
{
type: "assistant",
content: "文旅实习经历非常重要,是进入行业的敲门砖!\n\n实习的价值\n- 了解行业实际运作\n- 积累实战经验\n- 建立行业人脉\n- 明确职业方向\n- 增加就业竞争力\n\n选择实习的建议\n1. 大型企业:学习规范流程和管理体系\n2. 创业公司:接触更多业务,成长更快\n3. 知名景区:了解一线运营\n4. OTA平台学习互联网思维\n5. 文旅局:了解政策和规划\n\n时间安排\n- 大二基础认知实习1-2个月\n- 大三专业深度实习3-6个月\n- 大四:就业导向实习(可转正)",
mentor: "郑老师"
}
]
},
{
id: 11,
title: "乡村振兴中的文旅机遇",
status: "finish",
date: "30天内",
messages: [
{
type: "user",
content: "听说乡村振兴有很多文旅项目,有什么机会吗?"
},
{
type: "assistant",
content: "乡村振兴确实为文旅行业带来了巨大机遇!\n\n政策支持\n- 国家大力支持乡村旅游发展\n- 各地都有补贴和扶持政策\n- 用地、税收等优惠措施\n\n发展机会\n1. 乡村民宿开发运营\n2. 农文旅融合项目\n3. 田园综合体规划\n4. 乡村文创产品开发\n5. 研学基地建设\n6. 康养度假村\n\n就业岗位\n- 乡村运营官\n- 民宿管家\n- 农旅策划师\n- 乡创导师\n\n这是一个充满机遇的蓝海市场特别适合有情怀、懂运营的年轻人。",
mentor: "孙老师"
}
]
},
{
id: 12,
title: "文旅行业需要考哪些证书?",
status: "finish",
date: "30天内",
messages: [
{
type: "user",
content: "进入文旅行业需要考哪些证书吗?"
},
{
type: "assistant",
content: "文旅行业的证书分为必需和加分两类:\n\n基础证书\n- 导游资格证(从事导游工作必需)\n- 普通话等级证书(二级乙等以上)\n- 英语四六级证书\n\n专业证书\n- 旅游规划师\n- 研学旅行指导师\n- 酒店管理师\n- 会展策划师\n- 茶艺师/咖啡师(特色项目)\n\n加分证书\n- 项目管理PMP\n- 市场营销类证书\n- 新媒体运营证书\n- 急救证书\n- 其他语言证书\n\n建议证书不是越多越好要结合自己的职业规划有针对性地考取。实践经验往往比证书更重要。",
mentor: "钱老师"
}
]
},
{
id: 13,
title: "如何打造个人文旅IP",
status: "finish",
date: "30天内",
messages: [
{
type: "user",
content: "看到很多旅游博主很成功如何打造个人文旅IP"
},
{
type: "assistant",
content: "打造个人文旅IP是很好的发展方向\n\n第一步找准定位\n- 确定内容方向(美食、民宿、小众景点等)\n- 明确目标受众\n- 打造个人特色和记忆点\n\n第二步内容创作\n- 保持更新频率\n- 注重内容质量\n- 真实、有用、有趣\n- 视频+图文结合\n\n第三步平台运营\n- 多平台分发抖音、小红书、B站\n- 了解平台规则和算法\n- 积极互动,建立粉丝群\n\n第四步商业变现\n- 广告合作\n- 定制旅游服务\n- 知识付费\n- 电商带货\n\n成功案例房琪kiki、@幻想家japaul等都是很好的学习对象。",
mentor: "马老师"
}
]
},
{
id: 14,
title: "文旅企业最看重什么能力?",
status: "finish",
date: "30天内",
messages: [
{
type: "user",
content: "文旅企业招聘时最看重应聘者的什么能力?"
},
{
type: "assistant",
content: "根据我们对多家文旅企业的调研,最看重以下能力:\n\n核心能力TOP5\n1. 沟通表达能力90%企业提及)\n2. 学习能力和适应性85%\n3. 团队协作精神80%\n4. 创新思维75%\n5. 抗压能力70%\n\n专业能力要求\n- 市场敏感度\n- 数据分析能力\n- 内容创作能力\n- 项目管理能力\n- 客户服务意识\n\n加分项\n- 有相关实习经验\n- 会新媒体运营\n- 有成功案例或作品\n- 多语言能力\n- 有资源或人脉\n\n建议在校期间多参与实践培养综合能力。",
mentor: "冯老师"
}
]
},
{
id: 15,
title: "文旅行业的工作生活平衡",
status: "finish",
date: "30天内",
messages: [
{
type: "user",
content: "听说文旅行业经常要加班,工作生活平衡怎么样?"
},
{
type: "assistant",
content: "文旅行业的工作节奏确实有其特点:\n\n行业特性\n- 旺季(节假日)工作强度大\n- 淡季相对轻松\n- 周末和节假日是工作高峰\n- 可能需要出差或驻场\n\n不同岗位差异\n- 一线服务:班制,相对规律\n- 活动策划:项目制,忙闲不均\n- 后台运营:相对稳定\n- 新媒体:需要追热点,时间灵活\n\n平衡建议\n- 选择适合自己节奏的岗位\n- 学会时间管理\n- 淡季好好休息充电\n- 把工作当成生活的一部分\n\n其实热爱这个行业的人工作本身就是一种生活方式。",
mentor: "杨老师"
}
]
},
{
id: 16,
title: "海外文旅市场的机会",
status: "finish",
date: "30天内",
messages: [
{
type: "user",
content: "有机会去海外从事文旅工作吗?"
},
{
type: "assistant",
content: "海外文旅市场机会很多,特别是:\n\n主要方向\n1. 出境游地接社\n2. 国际酒店集团\n3. 邮轮公司\n4. 国际会展公司\n5. 海外中文导游\n\n热门目的地\n- 东南亚(泰国、新加坡、马来西亚)\n- 日韩\n- 欧洲(法国、意大利、瑞士)\n- 澳新\n- 迪拜\n\n准备要求\n- 良好的外语能力\n- 了解目的地文化\n- 有国内工作经验\n- 适应能力强\n- 办理工作签证\n\n发展优势\n- 薪资待遇好\n- 开阔国际视野\n- 积累独特经验\n- 有助于回国发展",
mentor: "何老师"
}
]
},
{
id: 17,
title: "文旅+教育的发展前景",
status: "finish",
date: "30天内",
messages: [
{
type: "user",
content: "研学旅行现在很火,文旅+教育有什么发展前景?"
},
{
type: "assistant",
content: "文旅+教育是非常有前景的细分赛道!\n\n市场规模\n- 研学旅行市场规模超千亿\n- 政策大力支持\n- 家长教育投入意愿强\n\n主要业态\n1. 研学旅行\n2. 营地教育\n3. 自然教育\n4. 博物馆教育\n5. 非遗传承体验\n6. 劳动教育基地\n\n就业岗位\n- 研学课程设计师\n- 研学导师\n- 营地运营管理\n- 教育产品经理\n- 亲子活动策划\n\n发展建议\n- 需要教育学背景或教师资格证\n- 了解不同年龄段孩子特点\n- 掌握课程设计能力\n- 注重安全管理\n\n这个领域既有社会价值又有商业前景。",
mentor: "徐老师"
}
]
},
{
id: 18,
title: "文旅行业的新技术应用",
status: "finish",
date: "30天内",
messages: [
{
type: "user",
content: "AI、元宇宙这些新技术在文旅行业有什么应用"
},
{
type: "assistant",
content: "新技术在文旅行业的应用越来越广泛:\n\nAI应用\n- 智能客服和问答系统\n- 个性化推荐算法\n- 动态定价系统\n- 图像识别导览\n- 多语言实时翻译\n\n元宇宙应用\n- 虚拟景区游览\n- 数字藏品和NFT\n- 虚拟演唱会和展览\n- 沉浸式历史体验\n- 云旅游直播\n\n其他技术\n- 区块链票务系统\n- IoT智慧景区管理\n- 5G+8K直播\n- 无人机航拍服务\n\n就业机会\n- 数字文旅产品经理\n- XR内容创作者\n- 智慧旅游工程师\n- 数据分析师\n\n掌握这些技术的文旅人才非常抢手",
mentor: "唐老师"
}
]
},
{
id: 19,
title: "如何提升文旅项目策划能力?",
status: "finish",
date: "30天内",
messages: [
{
type: "user",
content: "想做文旅项目策划,如何提升策划能力?"
},
{
type: "assistant",
content: "提升文旅项目策划能力的方法:\n\n基础积累\n1. 多看案例\n- 研究成功项目\n- 分析失败案例\n- 关注行业报告\n\n2. 理论学习\n- 项目管理知识\n- 市场营销理论\n- 消费者心理学\n- 文化创意理论\n\n3. 实践训练\n- 参与学校项目\n- 实习项目策划\n- 参加策划比赛\n- 自己做小项目\n\n4. 能力培养\n- 逻辑思维能力\n- 创意思维训练\n- 文案写作能力\n- PPT制作技巧\n\n5. 资源积累\n- 建立供应商库\n- 积累人脉资源\n- 收集素材库\n\n推荐书籍《文旅项目策划实战》《体验经济》等。",
mentor: "韩老师"
}
]
},
{
id: 20,
title: "文旅行业的区域发展差异",
status: "finish",
date: "30天内",
messages: [
{
type: "user",
content: "不同地区的文旅发展有什么差异?去哪里发展比较好?"
},
{
type: "assistant",
content: "中国文旅发展确实存在区域差异:\n\n一线城市北上广深\n- 国际化程度高\n- 薪资待遇好\n- 竞争激烈\n- 主要是企业总部\n\n新一线城市成都、杭州、西安等\n- 文旅资源丰富\n- 发展潜力大\n- 生活成本适中\n- 创新氛围好\n\n旅游城市三亚、丽江、桂林等\n- 一线实践机会多\n- 季节性明显\n- 发展空间有限\n\n特色地区\n- 长三角:主题乐园、水乡古镇\n- 珠三角:主题公园、商务旅游\n- 西部:自然景观、民族文化\n- 东北:冰雪旅游、森林康养\n\n建议刚毕业去大城市学习积累经验后可以去二三线城市发展机会更多。",
mentor: "蔡老师"
}
]
},
{
id: 21,
title: "文创产品开发的要点",
status: "finish",
date: "30天内",
messages: [
{
type: "user",
content: "想做文创产品开发,有什么要注意的?"
},
{
type: "assistant",
content: "文创产品开发的成功要素:\n\n产品定位\n- 明确目标客群\n- 确定价格区间\n- 突出文化内涵\n- 强调实用性\n\n设计原则\n1. 文化性:深挖文化内涵\n2. 创意性:新颖独特\n3. 实用性:不只是摆设\n4. 系列化:形成产品体系\n5. 故事性:有故事可讲\n\n开发流程\n- 市场调研\n- 创意设计\n- 打样测试\n- 批量生产\n- 营销推广\n\n常见误区\n- 过度追求低价\n- 忽视版权保护\n- 同质化严重\n- 缺乏文化内涵\n\n成功案例故宫文创、敦煌文创、三星堆盲盒等都值得学习。",
mentor: "魏老师"
}
]
},
{
id: 22,
title: "民宿运营的核心要素",
status: "finish",
date: "30天内",
messages: [
{
type: "user",
content: "想开一家民宿,运营的核心要素是什么?"
},
{
type: "assistant",
content: "民宿运营的核心要素:\n\n选址定位\n- 风景优美或交通便利\n- 周边配套完善\n- 目标客群明确\n- 差异化定位\n\n设计装修\n- 风格独特统一\n- 注重体验设计\n- 功能布局合理\n- 成本控制\n\n运营管理\n1. 服务标准化\n2. 卫生管理严格\n3. 安全保障到位\n4. 管家服务专业\n5. 维护保养及时\n\n营销推广\n- OTA平台运营\n- 社交媒体营销\n- 口碑营销\n- 会员体系建设\n\n盈利模式\n- 住宿收入\n- 餐饮收入\n- 体验活动\n- 产品销售\n\n建议先从小规模开始积累经验后再扩大。",
mentor: "潘老师"
}
]
},
{
id: 23,
title: "新媒体营销在文旅中的应用",
status: "finish",
date: "30天内",
messages: [
{
type: "user",
content: "新媒体营销对文旅行业有多重要?怎么做?"
},
{
type: "assistant",
content: "新媒体营销已成为文旅营销的主战场:\n\n重要性\n- 获客成本低\n- 传播速度快\n- 互动性强\n- 可精准定位\n- 数据可追踪\n\n主要平台策略\n1. 抖音:短视频种草\n2. 小红书:图文攻略\n3. 微信:私域运营\n4. B站深度内容\n5. 微博:热点营销\n\n内容策略\n- 美景展示\n- 美食诱惑\n- 文化故事\n- 达人体验\n- 用户UGC\n\n运营技巧\n- 保持更新频率\n- 蹭热点话题\n- 互动回复及时\n- 数据分析优化\n- KOL合作\n\n成功案例重庆、西安等网红城市都是新媒体营销的受益者。",
mentor: "邓老师"
}
]
},
{
id: 24,
title: "文旅项目的融资渠道",
status: "finish",
date: "30天内",
messages: [
{
type: "user",
content: "文旅项目一般通过什么渠道融资?"
},
{
type: "assistant",
content: "文旅项目的融资渠道比较多样:\n\n传统融资\n1. 银行贷款\n2. 政府补贴\n3. 产业基金\n4. 企业自筹\n\n股权融资\n- 天使投资\n- VC/PE投资\n- 产业资本\n- 上市融资\n\n创新模式\n- 众筹平台\n- REITs房地产信托\n- PPP模式\n- 资产证券化\n\n政策支持\n- 文旅专项资金\n- 税收优惠\n- 土地政策\n- 贴息贷款\n\n注意事项\n- 项目策划要专业\n- 财务模型要清晰\n- 回报周期要合理\n- 风险控制要到位\n\n建议找专业的融资顾问协助。",
mentor: "石老师"
}
]
},
{
id: 25,
title: "景区运营管理的要点",
status: "finish",
date: "30天内",
messages: [
{
type: "user",
content: "景区运营管理主要做什么?有哪些要点?"
},
{
type: "assistant",
content: "景区运营管理是个系统工程:\n\n日常运营\n1. 游客服务管理\n2. 安全保障\n3. 设施维护\n4. 环境卫生\n5. 秩序维护\n\n营销管理\n- 市场推广\n- 渠道管理\n- 活动策划\n- 品牌建设\n\n收益管理\n- 门票定价\n- 二次消费\n- 商业租赁\n- 成本控制\n\n服务提升\n- 智慧化建设\n- 服务标准化\n- 投诉处理\n- 员工培训\n\n创新发展\n- 产品更新\n- 业态创新\n- 科技应用\n- 文化挖掘\n\n关键指标游客满意度、安全零事故、收入增长率、口碑传播度。",
mentor: "谭老师"
}
]
},
{
id: 26,
title: "会展活动策划的流程",
status: "finish",
date: "30天内",
messages: [
{
type: "user",
content: "想做会展活动策划,具体流程是怎样的?"
},
{
type: "assistant",
content: "会展活动策划的标准流程:\n\n前期准备3-6个月前\n1. 需求分析\n2. 方案策划\n3. 预算制定\n4. 场地选择\n5. 团队组建\n\n中期筹备1-3个月\n- 供应商对接\n- 嘉宾邀请\n- 宣传推广\n- 物料制作\n- 流程细化\n\n执行阶段活动当天\n- 现场搭建\n- 签到接待\n- 流程把控\n- 应急处理\n- 现场协调\n\n后期总结\n- 撤展清场\n- 费用结算\n- 效果评估\n- 资料归档\n- 经验总结\n\n核心能力\n- 统筹协调\n- 创意设计\n- 成本控制\n- 危机处理\n\n这个领域需要很强的执行力和抗压能力。",
mentor: "程老师"
}
]
},
{
id: 27,
title: "康养旅游的发展趋势",
status: "finish",
date: "30天内",
messages: [
{
type: "user",
content: "听说康养旅游很有前景,具体是什么情况?"
},
{
type: "assistant",
content: "康养旅游确实是未来的重要方向:\n\n市场驱动\n- 老龄化社会到来\n- 健康意识提升\n- 消费升级\n- 疫后健康需求\n\n主要类型\n1. 温泉康养\n2. 森林康养\n3. 中医康养\n4. 运动康养\n5. 禅修康养\n6. 候鸟式康养\n\n产品形态\n- 康养度假村\n- 康养小镇\n- 康养民宿\n- 康养基地\n\n就业机会\n- 康养产品设计\n- 健康管理师\n- 康养活动策划\n- 养生指导师\n\n发展建议\n- 学习健康管理知识\n- 了解中医养生文化\n- 掌握康养项目运营\n\n预计未来5年康养旅游市场规模将超过2万亿。",
mentor: "宋老师"
}
]
},
{
id: 28,
title: "文旅IP打造与运营",
status: "finish",
date: "30天内",
messages: [
{
type: "user",
content: "什么是文旅IP如何打造和运营"
},
{
type: "assistant",
content: "文旅IP是文旅产业的核心竞争力\n\n什么是文旅IP\n- 独特的文化符号\n- 可识别的形象\n- 持续的影响力\n- 商业价值\n\nIP打造步骤\n1. 挖掘文化内核\n2. 设计视觉形象\n3. 构建故事体系\n4. 创造体验场景\n5. 持续内容输出\n\n运营策略\n- 多渠道传播\n- 衍生品开发\n- 跨界合作\n- 粉丝运营\n- 版权保护\n\n变现方式\n- 门票收入\n- 授权费用\n- 衍生品销售\n- 品牌合作\n\n成功案例\n- 迪士尼米老鼠\n- 故宫文创\n- 熊本熊\n- 不倒翁小姐姐\n\n一个成功的IP可以带动整个目的地发展。",
mentor: "许老师"
}
]
},
{
id: 29,
title: "露营经济的商业模式",
status: "finish",
date: "30天内",
messages: [
{
type: "user",
content: "露营现在很火,想了解露营地的商业模式。"
},
{
type: "assistant",
content: "露营经济正处于快速发展期:\n\n市场现状\n- 市场规模超300亿\n- 用户超1亿\n- 年增长率超30%\n\n商业模式\n1. 基础模式\n- 场地租赁\n- 装备租赁\n- 餐饮服务\n\n2. 增值服务\n- 主题活动\n- 亲子教育\n- 团建拓展\n- 户外课程\n\n3. 产品销售\n- 露营装备\n- 户外用品\n- 文创产品\n- 本地特产\n\n投资要点\n- 选址近郊1-2小时车程\n- 基础设施(水电、卫生间)\n- 安全管理\n- 特色打造\n\n发展趋势\n- 精致露营\n- 主题露营\n- 露营+X模式\n\n初期投资20-50万即可起步回本周期1-2年。",
mentor: "罗老师"
}
]
},
{
id: 30,
title: "文旅行业的可持续发展",
status: "finish",
date: "30天内",
messages: [
{
type: "user",
content: "文旅行业如何实现可持续发展?"
},
{
type: "assistant",
content: "可持续发展是文旅行业的必然趋势:\n\n环境保护\n- 生态旅游开发\n- 碳中和实践\n- 垃圾分类管理\n- 资源循环利用\n- 野生动植物保护\n\n文化传承\n- 非遗保护传承\n- 传统技艺活化\n- 民俗文化展示\n- 历史建筑修复\n\n社区共享\n- 当地就业优先\n- 利益共享机制\n- 社区参与决策\n- 扶贫带动发展\n\n经济效益\n- 产业链延伸\n- 四季运营\n- 多元化收入\n- 品牌价值提升\n\n实践案例\n- 莫干山民宿集群\n- 袁家村乡村旅游\n- 乌镇模式\n\n未来趋势ESG理念将成为文旅企业的核心竞争力。",
mentor: "曹老师"
}
]
}
]
};
export default expertSupportData;

View File

@@ -0,0 +1,129 @@
// 项目案例对应单元映射数据
// 基于 网页未导入数据/文旅产业/项目案例对应单元.json
export const projectUnitsMapping = {
"舟山某民宿180天提升入住率项目": {
compoundUnits: ["全栈新媒体运营赋能文旅营销"],
verticalUnits: ["营销传播与品牌推广", "民宿运营策划与个性化体验"]
},
"希尔顿欢朋酒店经营管理与服务一体化优化项目": {
compoundUnits: ["文旅服务:形象、沟通与体验的融合艺术"],
verticalUnits: ["酒店项目经营与品牌塑造", "财务控制与风险防范", "营销传播与品牌推广", "项目全周期运营管理"]
},
"长安汽车新款车型线下推广活动": {
compoundUnits: ["活动策划基础"],
verticalUnits: ["品牌招商展全案策划与招商运营", "商业活动全程策划执行与运营优化"]
},
"春风 450MT新品上市营销活动策划项目": {
compoundUnits: ["活动策划基础"],
verticalUnits: ["品牌招商展全案策划与招商运营", "商业活动全程策划执行与运营优化"]
},
"敦煌文创品牌策划与IP运营": {
compoundUnits: ["商业设计基础"],
verticalUnits: ["商业空间与文创产品设计", "文旅衍生文创产品设计"]
},
"'长安幻夜'文创IP运营与品牌建设项目": {
compoundUnits: ["商业设计基础"],
verticalUnits: ["品牌招商展全案策划与招商运营", "商业空间与文创产品设计", "文旅衍生文创产品设计"]
},
"2024年深圳国际家具展策划项目": {
compoundUnits: ["活动策划基础"],
verticalUnits: ["商业活动策略设计与创意策划", "商业活动全程策划执行与运营优化", "商业空间与文创产品设计"]
},
"2024 合肥国际 3C 电子产业博览会策划项目": {
compoundUnits: ["活动策划基础"],
verticalUnits: ["消费电子展品牌策划与执行", "商业活动策略设计与创意策划", "商业活动全程策划执行与运营优化"]
},
"盐城第九届 ICGC 动漫嘉年华漫展策划项目": {
compoundUnits: ["活动策划基础"],
verticalUnits: ["商业活动策略设计与创意策划", "商业活动全程策划执行与运营优化", "漫展与二次元活动策划与执行"]
},
"某地森林湿地自然景区多平台新媒体运营方案": {
compoundUnits: ["全栈新媒体运营赋能文旅营销"],
verticalUnits: ["营销传播与品牌推广", "项目全周期运营管理"]
},
"漓江畔水墨居度假酒店新媒体直播运营方案": {
compoundUnits: ["全栈新媒体运营赋能文旅营销"],
verticalUnits: ["酒店项目经营与品牌塑造", "营销传播与品牌推广", "项目全周期运营管理"]
},
"某自驾游平台SEO/SEM全流程优化项目": {
compoundUnits: ["全栈新媒体运营赋能文旅营销"],
verticalUnits: ["营销传播与品牌推广"]
},
"环渤海经济圈城市足球冠军赛策划与执行项目": {
compoundUnits: ["文旅服务:形象、沟通与体验的融合艺术", "旅游产业全景与文旅基础知识"],
verticalUnits: ["传统体育赛事商业开发", "体育赛事经纪职业认知与服务实务"]
},
"某歌手2025公益演唱会策划与执行项目": {
compoundUnits: ["文旅服务:形象、沟通与体验的融合艺术", "旅游产业全景与文旅基础知识"],
verticalUnits: ["演艺经纪基础实务与从业规范", "艺人IP孵化与商业开发实操"]
},
"轻奢露营市集玩乐活动运营项目": {
compoundUnits: ["活动策划基础"],
verticalUnits: ["露营地规划与经营管理", "营销传播与品牌推广"]
},
"'水墨苏乡'文化创意产品设计与量产落地项目": {
compoundUnits: ["商业设计基础"],
verticalUnits: ["品牌招商展全案策划与招商运营", "商业空间与文创产品设计", "文旅衍生文创产品设计"]
},
"中国科学院武汉植物园生态科普与文旅运营项目": {
compoundUnits: ["文旅与供应链基础", "旅游产业全景与文旅基础知识"],
verticalUnits: ["文旅项目策划与设计", "项目全周期运营管理"]
},
"谷子店开店与经营管理": {
compoundUnits: ["文旅与供应链基础"],
verticalUnits: ["二次元周边店经营与粉丝经济构建", "营销传播与品牌推广"]
},
"贵州黔东南非遗文化探索之旅线路设计项目": {
compoundUnits: ["文旅与供应链基础", "旅游产业全景与文旅基础知识"],
verticalUnits: ["文旅项目策划与设计", "项目全周期运营管理"]
},
"某宠物生活馆经营改善项目": {
compoundUnits: ["文旅与供应链基础"],
verticalUnits: ["财务控制与风险防范", "项目全周期运营管理", "宠物乐园式门店经营与创新"]
}
};
// 获取项目的复合能力课程
export const getCompoundUnits = (projectTitle) => {
if (!projectTitle) return [];
// 直接匹配
if (projectUnitsMapping[projectTitle]) {
return projectUnitsMapping[projectTitle].compoundUnits || [];
}
// 尝试去除后缀后匹配(如"详情"
const cleanTitle = projectTitle.replace(/详情$/, '');
if (projectUnitsMapping[cleanTitle]) {
return projectUnitsMapping[cleanTitle].compoundUnits || [];
}
return [];
};
// 获取项目的垂直能力课程
export const getVerticalUnits = (projectTitle) => {
if (!projectTitle) return [];
// 直接匹配
if (projectUnitsMapping[projectTitle]) {
return projectUnitsMapping[projectTitle].verticalUnits || [];
}
// 尝试去除后缀后匹配(如"详情"
const cleanTitle = projectTitle.replace(/详情$/, '');
if (projectUnitsMapping[cleanTitle]) {
return projectUnitsMapping[cleanTitle].verticalUnits || [];
}
return [];
};
// 获取项目的所有对应单元
export const getProjectUnits = (projectTitle) => {
const mapping = projectUnitsMapping[projectTitle];
if (!mapping) return [];
return [...mapping.compoundUnits, ...mapping.verticalUnits];
};

View File

@@ -144,12 +144,24 @@
display: flex;
justify-content: flex-start;
align-items: center;
flex-wrap: wrap;
gap: 8px;
> li {
border: 1px solid #e5e6eb;
box-sizing: border-box;
padding: 3px 8px;
padding: 5px 12px;
background-color: #fff;
margin-right: 5px;
border-radius: 4px;
white-space: nowrap;
font-size: 14px;
cursor: pointer;
transition: all 0.2s ease;
&:hover {
background-color: #f2f3f5;
border-color: #0077ff;
color: #0077ff;
}
}
}
}

View File

@@ -46,8 +46,9 @@ const init = [
const MyIM = React.forwardRef((props, ref) => {
const { hanldeClickOpenModalBtn, initialMessages } = props;
const [currentMessages, setCurrentMessages] = useState(init);
// 使用ChatUI的消息管理hook
const { messages, appendMsg } = useMessages(initialMessages || init);
const { messages, appendMsg, setMessages } = useMessages(currentMessages);
const [isInit, setIsInit] = useState(true);
const id = useRef(undefined);
const childRef = useRef();
@@ -65,6 +66,59 @@ const MyIM = React.forwardRef((props, ref) => {
[studentInfo]
);
// 处理对话内容变化
useEffect(() => {
if (initialMessages && initialMessages.length > 0) {
// 构建新的消息数组
const newMessages = [];
initialMessages.forEach((msg) => {
if (msg.type === "user") {
newMessages.push({
type: "text",
content: { text: msg.content },
position: "right",
user: {
avatar: studentInfo?.avatar,
name: userAvatarDom,
},
});
} else if (msg.type === "assistant") {
const mentorName = msg.mentor ? `${msg.mentor}` : "专家";
const assistantAvatarDom = (
<div className="user-avatar-wrapper">
<span className="user-avatar-name">{mentorName}</span>
<div className="user-avatar-tag">专家</div>
<span className="user-avatar-time">
{dayjs().format("YYYY-MM-DD HH:mm")}
</span>
</div>
);
newMessages.push({
type: "text",
content: { text: msg.content },
position: "left",
user: {
avatar: ICONURL,
name: assistantAvatarDom,
},
});
}
});
// 设置新消息
if (setMessages) {
setMessages(newMessages);
} else {
// 如果setMessages不存在重新创建组件实例
setCurrentMessages(newMessages);
}
setIsInit(false);
}
}, [initialMessages, studentInfo, userAvatarDom]);
// 处理发送消息
const handleSend = async (type, val, showBtn = false) => {
setIsInit(false);

View File

@@ -91,6 +91,17 @@
background-color: #f4f7f9;
margin-top: 5px;
position: relative;
cursor: pointer;
transition: all 0.2s ease;
&:hover {
background-color: #e8ecf0;
}
&.selected {
background-color: #e8f0ff;
border-left: 3px solid #2c7aff;
}
> P {
width: 70%;
@@ -101,6 +112,9 @@
color: #1d2129;
font-size: 14px;
font-weight: 600;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.support-list-content-item-status {
width: 52px;

View File

@@ -1,5 +1,6 @@
import React from "react";
import React, { useState } from "react";
import IconFont from "@/components/IconFont";
import expertSupportData from "@/data/expertSupportData";
import "./index.css";
const STATUS = {
@@ -8,11 +9,25 @@ const STATUS = {
finish: { key: "finish", text: "已解决" },
};
const Index = () => {
const Index = ({ onSelectConversation }) => {
const [selectedId, setSelectedId] = useState(null);
const handleClickNew = () => {
console.log("点击了新对话");
};
const handleSelectConversation = (conversation) => {
setSelectedId(conversation.id);
if (onSelectConversation) {
onSelectConversation(conversation);
}
};
// 根据日期分组对话
const todayConversations = expertSupportData.conversations.filter(c => c.date === "今天");
const weekConversations = expertSupportData.conversations.filter(c => c.date === "7天内");
const monthConversations = expertSupportData.conversations.filter(c => c.date === "30天内");
return (
<div className="support-list-wrapper">
<div className="support-list-title">
@@ -26,114 +41,66 @@ const Index = () => {
</div>
</div>
<div className="support-list">
<>
<p className="support-list-date">今天</p>
<ul className="support-list-content">
<li className="support-list-content-item">
<p>这里是对话名称</p>
<div className="support-list-content-item-status status-waiting">
{STATUS.waiting.text}
</div>
</li>
<li className="support-list-content-item">
<p>这里是对话名称</p>
<div className="support-list-content-item-status status-processing">
{STATUS.processing.text}
</div>
</li>
<li className="support-list-content-item">
<p>这里是对话名称</p>
<div className="support-list-content-item-status status-finish">
{STATUS.finish.text}
</div>
</li>
</ul>
</>
<>
<p className="support-list-date">7天内</p>
<ul className="support-list-content">
<li className="support-list-content-item">
<p>这里是对话名称</p>
<div className="support-list-content-item-status status-finish">
{STATUS.finish.text}
</div>
</li>
<li className="support-list-content-item">
<p>这里是对话名称</p>
<div className="support-list-content-item-status status-finish">
{STATUS.finish.text}
</div>
</li>
<li className="support-list-content-item">
<p>这里是对话名称</p>
<div className="support-list-content-item-status status-finish">
{STATUS.finish.text}
</div>
</li>
</ul>
</>
<>
<p className="support-list-date">30天内</p>
<ul className="support-list-content">
<li className="support-list-content-item">
<p>这里是对话名称</p>
<div className="support-list-content-item-status status-finish">
{STATUS.finish.text}
</div>
</li>
<li className="support-list-content-item">
<p>这里是对话名称</p>
<div className="support-list-content-item-status status-finish">
{STATUS.finish.text}
</div>
</li>
<li className="support-list-content-item">
<p>这里是对话名称</p>
<div className="support-list-content-item-status status-finish">
{STATUS.finish.text}
</div>
</li>
<li className="support-list-content-item">
<p>这里是对话名称</p>
<div className="support-list-content-item-status status-finish">
{STATUS.finish.text}
</div>
</li>
<li className="support-list-content-item">
<p>这里是对话名称</p>
<div className="support-list-content-item-status status-finish">
{STATUS.finish.text}
</div>
</li>
<li className="support-list-content-item">
<p>这里是对话名称</p>
<div className="support-list-content-item-status status-finish">
{STATUS.finish.text}
</div>
</li>
<li className="support-list-content-item">
<p>这里是对话名称</p>
<div className="support-list-content-item-status status-finish">
{STATUS.finish.text}
</div>
</li>
<li className="support-list-content-item">
<p>这里是对话名称</p>
<div className="support-list-content-item-status status-finish">
{STATUS.finish.text}
</div>
</li>
<li className="support-list-content-item">
<p>这里是对话名称</p>
<div className="support-list-content-item-status status-finish">
{STATUS.finish.text}
</div>
</li>
</ul>
</>
{todayConversations.length > 0 && (
<>
<p className="support-list-date">今天</p>
<ul className="support-list-content">
{todayConversations.map(conversation => (
<li
key={conversation.id}
className={`support-list-content-item ${selectedId === conversation.id ? 'selected' : ''}`}
onClick={() => handleSelectConversation(conversation)}
>
<p>{conversation.title}</p>
<div className={`support-list-content-item-status status-${conversation.status}`}>
{STATUS[conversation.status].text}
</div>
</li>
))}
</ul>
</>
)}
{weekConversations.length > 0 && (
<>
<p className="support-list-date">7天内</p>
<ul className="support-list-content">
{weekConversations.map(conversation => (
<li
key={conversation.id}
className={`support-list-content-item ${selectedId === conversation.id ? 'selected' : ''}`}
onClick={() => handleSelectConversation(conversation)}
>
<p>{conversation.title}</p>
<div className={`support-list-content-item-status status-${conversation.status}`}>
{STATUS[conversation.status].text}
</div>
</li>
))}
</ul>
</>
)}
{monthConversations.length > 0 && (
<>
<p className="support-list-date">30天内</p>
<ul className="support-list-content">
{monthConversations.map(conversation => (
<li
key={conversation.id}
className={`support-list-content-item ${selectedId === conversation.id ? 'selected' : ''}`}
onClick={() => handleSelectConversation(conversation)}
>
<p>{conversation.title}</p>
<div className={`support-list-content-item-status status-${conversation.status}`}>
{STATUS[conversation.status].text}
</div>
</li>
))}
</ul>
</>
)}
</div>
</div>
);
};
export default Index;
export default Index;

View File

@@ -24,6 +24,7 @@ const ExpertSupportPage = () => {
const IMRef = useRef(null);
const [formVisible, setFormVisible] = useState(false);
const [initialMessages, setInitialMessages] = useState(null); // 设置消息
const [selectedConversation, setSelectedConversation] = useState(null);
const handleClose = () => {
setFormVisible(false);
@@ -33,6 +34,12 @@ const ExpertSupportPage = () => {
setFormVisible(true);
};
// 处理对话选择
const handleSelectConversation = (conversation) => {
setSelectedConversation(conversation);
setInitialMessages(conversation.messages);
};
// 调用子组件的方法
const handleSend = (type, val, showBtn) => {
if (IMRef.current) {
@@ -44,7 +51,7 @@ const ExpertSupportPage = () => {
<>
<div className="expert-support-page">
<div className="expert-support-left-wrapper">
<SupportList />
<SupportList onSelectConversation={handleSelectConversation} />
</div>
<div className="expert-support-right-wrapper">
<div className="expert-support-right-title-wrapper">

View File

@@ -10,19 +10,27 @@ const LivePage = () => {
const [searchParams] = useSearchParams();
const courseListRef = useRef(null);
// 检查URL参数如果有courseId或courseTitle则自动打开对应课程
// 检查URL参数如果有courseId或courseTitle则自动打开对应课程或单元
useEffect(() => {
const courseId = searchParams.get('courseId');
const courseTitle = searchParams.get('courseTitle');
const courseType = searchParams.get('courseType');
console.log('LivePage - URL params:', { courseId, courseTitle });
console.log('LivePage - URL params:', { courseId, courseTitle, courseType });
if (courseId || courseTitle) {
// 需要给组件时间加载数据
const timer = setTimeout(() => {
if (courseListRef.current) {
console.log('LivePage - Calling selectCourse via ref');
courseListRef.current.selectCourse(courseId, courseTitle);
// 如果courseTitle是单元名称从项目库跳转过来则展开对应的单元
if (courseType && (courseType === 'compound-skill' || courseType === 'vertical-skill')) {
console.log('LivePage - Calling expandUnitByName for unit:', courseTitle);
courseListRef.current.expandUnitByName(courseTitle);
} else {
// 否则按原来的逻辑选择课程
console.log('LivePage - Calling selectCourse via ref');
courseListRef.current.selectCourse(courseId, courseTitle);
}
}
}, 500); // 等待数据加载

View File

@@ -510,3 +510,19 @@
}
}
}
/* 可点击单元样式 */
.clickable-unit {
transition: all 0.2s ease-in-out;
}
.clickable-unit:hover {
background-color: #e8f4ff !important;
border-color: #4080ff !important;
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(64, 128, 255, 0.15);
}
.clickable-unit:active {
transform: translateY(0px);
}

View File

@@ -5,6 +5,7 @@ import PDFICON from "@/assets/images/Common/pdf_icon.png";
import FileIcon from "@/components/FileIcon";
import ReactMarkdown from "react-markdown";
import ImagePreviewModal from "../ImagePreviewModal";
import { getCompoundUnits, getVerticalUnits } from "@/data/projectUnitsMapping";
import "./index.css";
export default ({ visible, onClose, data }) => {
@@ -30,6 +31,30 @@ export default ({ visible, onClose, data }) => {
setPreviewVisible(true);
};
// 处理单元点击跳转到课程直播间
const handleUnitClick = (unitName, isCompound) => {
console.log('Unit clicked:', unitName, 'isCompound:', isCompound);
// 关闭当前模态框
onClose();
// 构建URL参数
const params = new URLSearchParams();
params.append('courseTitle', unitName);
// 根据单元类型设置课程类型
if (isCompound) {
params.append('courseType', 'compound-skill');
} else {
params.append('courseType', 'vertical-skill');
}
console.log('Navigate to live with params:', params.toString());
// 跳转到课程直播间
navigate(`/live?${params.toString()}`);
};
// 将换行符转换为Markdown格式
const formatMarkdownContent = (content) => {
if (!content) return "";
@@ -37,6 +62,7 @@ export default ({ visible, onClose, data }) => {
return content.replace(/\\n/g, '\n');
};
return (
<Modal visible={visible} onClose={handleCloseModal}>
<div className="project-cases-modal">
@@ -128,25 +154,20 @@ export default ({ visible, onClose, data }) => {
<div className="unit-category-section">
<p className="unit-category-subtitle">复合能力课</p>
<ul className="project-cases-modal-horizontal-list">
{data?.units?.filter(unit =>
unit.includes('商业活动') ||
unit.includes('营销') ||
unit.includes('品牌') ||
unit.includes('项目全周期')
).map((unit, index) => (
<li key={`compound-${index}`} className="class-list-item">
{getCompoundUnits(data?.title).map((unit, index) => (
<li
key={`compound-${index}`}
className="class-list-item clickable-unit"
onClick={() => handleUnitClick(unit, true)}
style={{ cursor: 'pointer' }}
>
<div className="class-list-item-title">
<i />
<span>{unit}</span>
</div>
</li>
)) || null}
{(!data?.units || data?.units?.filter(unit =>
unit.includes('商业活动') ||
unit.includes('营销') ||
unit.includes('品牌') ||
unit.includes('项目全周期')
).length === 0) && (
))}
{getCompoundUnits(data?.title).length === 0 && (
<li className="class-list-item">
<div className="class-list-item-title">
<i />
@@ -161,25 +182,20 @@ export default ({ visible, onClose, data }) => {
<div className="unit-category-section">
<p className="unit-category-subtitle">垂直能力课</p>
<ul className="project-cases-modal-horizontal-list">
{data?.units?.filter(unit =>
!unit.includes('商业活动') &&
!unit.includes('营销') &&
!unit.includes('品牌') &&
!unit.includes('项目全周期')
).map((unit, index) => (
<li key={`vertical-${index}`} className="class-list-item">
{getVerticalUnits(data?.title).map((unit, index) => (
<li
key={`vertical-${index}`}
className="class-list-item clickable-unit"
onClick={() => handleUnitClick(unit, false)}
style={{ cursor: 'pointer' }}
>
<div className="class-list-item-title">
<i />
<span>{unit}</span>
</div>
</li>
)) || null}
{(!data?.units || data?.units?.filter(unit =>
!unit.includes('商业活动') &&
!unit.includes('营销') &&
!unit.includes('品牌') &&
!unit.includes('项目全周期')
).length === 0) && (
))}
{getVerticalUnits(data?.title).length === 0 && (
<li className="class-list-item">
<div className="class-list-item-title">
<i />