feat: 完善专家支持中心、简历详情和日历页面功能
- 专家支持中心:填充真实Q&A数据,修改为"多多畅职机器人",按月份分组对话,禁用新对话按钮 - 简历详情:修复14个岗位的简历显示问题,支持markdown解析,添加编辑权限控制提示 - 日历页面:优化AI课和营销能力课显示,使用统一的event-description样式 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -3979,8 +3979,54 @@ const resumeTemplates = {
|
|||||||
position: "露营地运营专员",
|
position: "露营地运营专员",
|
||||||
level: "普通岗",
|
level: "普通岗",
|
||||||
content: {
|
content: {
|
||||||
original: "露营地运营专员简历内容",
|
original: `# 对应岗位:露营地运营专员
|
||||||
modified: "露营地运营专员简历内容"
|
|
||||||
|
# 一、项目经历
|
||||||
|
|
||||||
|
### (一)项目名称:轻奢露营市集玩乐活动运营项目
|
||||||
|
|
||||||
|
### (二)实习岗位:露营地运营专员
|
||||||
|
|
||||||
|
### (三)实习单位:某某公司
|
||||||
|
|
||||||
|
### (四)实习时间:XXXX时间
|
||||||
|
|
||||||
|
### (五)岗位职责
|
||||||
|
|
||||||
|
1. 协助整理《活动总述》《区域规划图》与《应急与安全方案》等前期资料,参与六大功能区规划讨论,初步熟悉露营地场景布局与功能设计逻辑;
|
||||||
|
2. 参与KV主视觉海报、倒计时物料与招募话术的内容校对与素材归档,辅助完成社群渠道报名表的发布与数据登记;
|
||||||
|
3. 在布置阶段协助场地标识、签到区、导视系统及打卡区域的布设工作,配合布置市集摊位、帐篷区及照明装饰,保证视觉统一与体验顺畅;
|
||||||
|
4. 活动当天负责签到引导、票务核验、手环发放及礼品包分发,协助游客入场分流与体验区问询,保障人流动线与秩序稳定;
|
||||||
|
5. 参与"帐篷搭建赛""森林音乐会""星空影院"等活动的流程协助与舞台支持,协助主持人控场并负责节目表的时间提示与衔接;
|
||||||
|
6. 协助运营组整理现场视频/照片素材,参与"云相册"上线与素材初筛,配合后期剪辑团队完成线上传播内容初步编排;
|
||||||
|
7. 活动结束后协助物资回收、摊位清理及满意度问卷收集,并参与复盘会议内容整理,输出基础版运营反馈报告。
|
||||||
|
|
||||||
|
# 二、掌握技能
|
||||||
|
|
||||||
|
### (一)核心能力
|
||||||
|
|
||||||
|
1. 掌握营地日常运营全流程管理,包括接待流程优化、设施巡检维护及运营数据统计分析能力,能独立运用Office办公软件完成经营报表制作与可视化呈现
|
||||||
|
2. 具备线上线下活动落地执行经验,熟悉场景搭建、活动动线规划与现场摄影直播技术操作,能熟练操作无人机航拍、手持云台等设备完成多媒体素材采集
|
||||||
|
3. 精通数字化营地管理工具应用,包括OTA渠道管理后台(如携程商旅、美团商家端)、微信群控工具、自媒体运营平台(抖音企业号、小红书专业号)的数据分析与内容发布
|
||||||
|
4. 具备团队管理与标准化建设能力,熟悉服务业人员排班调度、绩效考核方案设计,能通过钉钉/企业微信等协同工具实现跨部门任务分配与进度管控
|
||||||
|
5. 擅长用户社群运营与私域流量转化,具备客户需求分析、会员体系搭建及精准营销活动策划能力,熟练使用SCRM系统进行客户分层管理与精准触达
|
||||||
|
6. 掌握露营行业趋势分析与竞品调研方法论,能通过行业垂直平台(如露营天下、户外资料网)持续更新运营策略,具备基础商业计划书撰写与营收模型构建能力
|
||||||
|
|
||||||
|
### (二)复合能力
|
||||||
|
|
||||||
|
1. 活动执行与现场管理能力: 了解活动从前期策划、主题创意、文案撰写、宣传推广,到流程设计、现场布置、预算管理、应急预案及数据复盘的完整流程,具备基础的统筹与执行配合能力。
|
||||||
|
2. 文旅行业理解能力: 具备现代文旅产业结构与政策环境的整体认知,了解旅游资源分类、游客行为特征与行业合规要点,初步建立了岗位适应能力。
|
||||||
|
3. 新媒体平台运营能力: 具备新媒体平台账号经营、内容赛道规划与短视频制作的基础能力,能够参与直播搭建、私域维护与跨平台内容策划等简单的工作内容,辅助文旅项目的数字传播落地。
|
||||||
|
4. 智慧文旅应用能力: 了解OTA平台、票务分销、导览系统、智能设备及智慧酒店等新型文旅科技应用,具备智慧场景运营的基础认知与设备使用能力。
|
||||||
|
5. 服务体验优化和资源协同能力: 理解文旅服务的形象表达与情境化设计原则,掌握文旅项目中各类资源(如住宿、交通、商品)的调度逻辑与协同机制,具备在多元文化与B2B/B2C场景下开展基础服务支持与供应协作的能力。
|
||||||
|
6. 文化IP策划与品牌传播能力: 理解本地文化IP的挖掘逻辑与数字化表达方式,具备参与品牌定位、跨界联动与差异化推广的初步经验。
|
||||||
|
7. AIGC工具使用能力: 了解AIGC内容生成逻辑,能够使用ChatGPT、Stable Diffusion、Suno等AI工具完成图像生成、文案创作与音视频剪辑等初级创作任务。
|
||||||
|
8. 商业视觉表达与工具应用能力: 了解平面设计、色彩搭配、字体表现与视觉规范的基础知识,能使用Canva、Figma、Photoshop、剪映等工具进行简单的视觉表达与内容制作。
|
||||||
|
9. 产品营销基础: 具备基本营销思维与客户画像构建能力,能够理解产品定位、传播路径与沟通逻辑,支持策划与执行文旅项目的推广策略。
|
||||||
|
|
||||||
|
# 三、个人评价
|
||||||
|
|
||||||
|
我是一名刚完成实习的大专毕业生,在露营地运营项目中担任助理角色,接触了从活动前期策划到现场执行、再到后期传播的全流程,对文旅活动的实际运作有了较为清晰的认识。在项目中,我能够主动承担任务、及时响应需求、配合团队完成细节工作。虽然经验尚浅,但我有较强的责任感与适应能力,愿意从基层做起,逐步积累经验,努力成长为一名综合型的运营人才。`
|
||||||
},
|
},
|
||||||
studentInfo: {
|
studentInfo: {
|
||||||
project_experience: {
|
project_experience: {
|
||||||
|
|||||||
@@ -131,6 +131,8 @@ const EventDetailModal = ({ isOpen, event, onClose }) => {
|
|||||||
navigate(`/live?${params.toString()}`);
|
navigate(`/live?${params.toString()}`);
|
||||||
break;
|
break;
|
||||||
case 'public-course':
|
case 'public-course':
|
||||||
|
case 'ai-course':
|
||||||
|
case 'marketing-course':
|
||||||
// 公开课(包括AI课、企业高管公开课、营销课) - 跳转到公共课直播间
|
// 公开课(包括AI课、企业高管公开课、营销课) - 跳转到公共课直播间
|
||||||
navigate(`/public-courses?${params.toString()}`);
|
navigate(`/public-courses?${params.toString()}`);
|
||||||
break;
|
break;
|
||||||
@@ -226,6 +228,13 @@ const EventDetailModal = ({ isOpen, event, onClose }) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* AI课和营销能力课显示课程信息 */}
|
||||||
|
{(eventItem.type === 'ai-course' || eventItem.type === 'marketing-course') && (
|
||||||
|
<div className="event-description">
|
||||||
|
{eventItem.title} - {eventItem.teacher}老师
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* 企业高管公开课添加线下参与标签 */}
|
{/* 企业高管公开课添加线下参与标签 */}
|
||||||
{eventItem.type === 'public-course' && (
|
{eventItem.type === 'public-course' && (
|
||||||
<div className="event-info-row" style={{ marginTop: '8px' }}>
|
<div className="event-info-row" style={{ marginTop: '8px' }}>
|
||||||
|
|||||||
@@ -10,6 +10,16 @@
|
|||||||
background-image: url("@/assets/images/Common/modal_bg.png");
|
background-image: url("@/assets/images/Common/modal_bg.png");
|
||||||
background-size: 100% 100%;
|
background-size: 100% 100%;
|
||||||
|
|
||||||
|
/* 保存按钮hover提示样式 */
|
||||||
|
.save-button-wrapper {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
|
||||||
|
&:hover .save-button-tooltip {
|
||||||
|
opacity: 1 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.close-icon {
|
.close-icon {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 20px;
|
right: 20px;
|
||||||
|
|||||||
@@ -68,7 +68,8 @@ export default ({ visible, onClose, data, initialVersion = "2" }) => {
|
|||||||
currentContent = customVersion?.content || '';
|
currentContent = customVersion?.content || '';
|
||||||
} else if (data?.content) {
|
} else if (data?.content) {
|
||||||
const hasModified = !!data.content.modified;
|
const hasModified = !!data.content.modified;
|
||||||
currentContent = (!hasModified || version === "1") ? data.content.original : data.content.modified;
|
// 如果没有modified版本,始终使用original
|
||||||
|
currentContent = (version === "1" || !hasModified) ? data.content.original : data.content.modified;
|
||||||
}
|
}
|
||||||
|
|
||||||
const parsed = parseResumeMarkdown(currentContent);
|
const parsed = parseResumeMarkdown(currentContent);
|
||||||
@@ -209,19 +210,20 @@ export default ({ visible, onClose, data, initialVersion = "2" }) => {
|
|||||||
result.personalInfo.name = positionMatch[1].trim();
|
result.personalInfo.name = positionMatch[1].trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 提取项目经历
|
// 提取项目经历 - 兼容"专业技能"和"掌握技能"两种标题
|
||||||
const projectSectionMatch = markdownContent.match(/# 一、项目经历\s+([\s\S]*?)(?=# 二、专业技能|$)/);
|
const projectSectionMatch = markdownContent.match(/# 一、项目经历\s+([\s\S]*?)(?=# 二、(?:专业技能|掌握技能)|# 三、|$)/);
|
||||||
if (projectSectionMatch) {
|
if (projectSectionMatch) {
|
||||||
const projectContent = projectSectionMatch[1];
|
const projectContent = projectSectionMatch[1];
|
||||||
|
|
||||||
// 提取项目名称
|
// 提取项目名称
|
||||||
const projectNameMatch = projectContent.match(/### (一)项目名称:(.+)/);
|
const projectNameMatch = projectContent.match(/### (一)项目名称:(.+)/);
|
||||||
const roleMatch = projectContent.match(/### (二)实习岗位:(.+)/);
|
const roleMatch = projectContent.match(/### (二)实习岗位:(.+)/);
|
||||||
const timeMatch = projectContent.match(/### (三)实习时间:(.+)/);
|
// 兼容不同的顺序 - 使用非捕获组(?:)
|
||||||
const companyMatch = projectContent.match(/### (四)实习单位:(.+)/);
|
const timeMatch = projectContent.match(/### (?:(三)|(四))实习时间:(.+)/);
|
||||||
|
const companyMatch = projectContent.match(/### (?:(三)|(四))实习单位:(.+)/);
|
||||||
|
|
||||||
// 提取岗位职责内容 - 从"### (五)岗位职责:"开始到下一个section
|
// 提取岗位职责内容 - 兼容有冒号和没有冒号的情况
|
||||||
const responsibilityMatch = projectContent.match(/### (五)岗位职责:\s+([\s\S]*?)$/);
|
const responsibilityMatch = projectContent.match(/### (五)岗位职责[::]?\s+([\s\S]*?)$/);
|
||||||
|
|
||||||
if (projectNameMatch) {
|
if (projectNameMatch) {
|
||||||
result.projects = [{
|
result.projects = [{
|
||||||
@@ -234,8 +236,8 @@ export default ({ visible, onClose, data, initialVersion = "2" }) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 提取专业技能
|
// 提取专业技能 - 兼容"专业技能"和"掌握技能"两种标题
|
||||||
const skillsSectionMatch = markdownContent.match(/# 二、专业技能\s+([\s\S]*?)$/);
|
const skillsSectionMatch = markdownContent.match(/# 二、(?:专业技能|掌握技能)\s+([\s\S]*?)(?=# 三、|$)/);
|
||||||
if (skillsSectionMatch) {
|
if (skillsSectionMatch) {
|
||||||
const skillsContent = skillsSectionMatch[1];
|
const skillsContent = skillsSectionMatch[1];
|
||||||
|
|
||||||
@@ -250,7 +252,7 @@ export default ({ visible, onClose, data, initialVersion = "2" }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 提取复合能力
|
// 提取复合能力
|
||||||
const additionalSkillsMatch = skillsContent.match(/### (二)复合能力\s+([\s\S]*?)$/);
|
const additionalSkillsMatch = skillsContent.match(/### (二)复合能力\s+([\s\S]*?)(?=# 三、|$)/);
|
||||||
if (additionalSkillsMatch) {
|
if (additionalSkillsMatch) {
|
||||||
const additionalSkills = additionalSkillsMatch[1]
|
const additionalSkills = additionalSkillsMatch[1]
|
||||||
.split(/\d+\.\s+/)
|
.split(/\d+\.\s+/)
|
||||||
@@ -260,6 +262,15 @@ export default ({ visible, onClose, data, initialVersion = "2" }) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 提取个人评价/个人总结 - 兼容两种标题
|
||||||
|
const personalSummaryMatch = markdownContent.match(/# 三、(?:个人评价|个人总结)\s+([\s\S]*?)$/);
|
||||||
|
if (personalSummaryMatch) {
|
||||||
|
const summaryText = personalSummaryMatch[1].trim();
|
||||||
|
if (summaryText) {
|
||||||
|
result.personalSummary = [summaryText];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -286,7 +297,8 @@ export default ({ visible, onClose, data, initialVersion = "2" }) => {
|
|||||||
if (data.content.original) {
|
if (data.content.original) {
|
||||||
// 有original字段,可能有或没有modified字段
|
// 有original字段,可能有或没有modified字段
|
||||||
const hasModified = !!data.content.modified;
|
const hasModified = !!data.content.modified;
|
||||||
const selectedContent = (!hasModified || version === "1") ? data.content.original : data.content.modified;
|
// 如果没有modified版本,始终使用original
|
||||||
|
const selectedContent = (version === "1" || !hasModified) ? data.content.original : data.content.modified;
|
||||||
console.log('选择的内容长度:', selectedContent ? selectedContent.length : 0);
|
console.log('选择的内容长度:', selectedContent ? selectedContent.length : 0);
|
||||||
|
|
||||||
// 如果是markdown格式的字符串,使用解析器
|
// 如果是markdown格式的字符串,使用解析器
|
||||||
@@ -322,7 +334,8 @@ export default ({ visible, onClose, data, initialVersion = "2" }) => {
|
|||||||
console.log('处理content.original结构');
|
console.log('处理content.original结构');
|
||||||
// 处理有content.original的数据结构
|
// 处理有content.original的数据结构
|
||||||
const hasModified = !!currentTemplate.content.modified;
|
const hasModified = !!currentTemplate.content.modified;
|
||||||
const selectedContent = (!hasModified || version === "1") ? currentTemplate.content.original : currentTemplate.content.modified;
|
// 如果没有modified版本,始终使用original
|
||||||
|
const selectedContent = (version === "1" || !hasModified) ? currentTemplate.content.original : currentTemplate.content.modified;
|
||||||
|
|
||||||
const parsedContent = parseResumeMarkdown(selectedContent);
|
const parsedContent = parseResumeMarkdown(selectedContent);
|
||||||
if (parsedContent) {
|
if (parsedContent) {
|
||||||
@@ -483,17 +496,45 @@ export default ({ visible, onClose, data, initialVersion = "2" }) => {
|
|||||||
</Button>
|
</Button>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<Button
|
<div className="save-button-wrapper">
|
||||||
type="primary"
|
<Button
|
||||||
size="small"
|
type="primary"
|
||||||
icon={<IconSave />}
|
size="small"
|
||||||
onClick={handleSaveEdit}
|
icon={<IconSave />}
|
||||||
style={{
|
disabled={true}
|
||||||
borderRadius: '4px'
|
style={{
|
||||||
}}
|
borderRadius: '4px',
|
||||||
>
|
backgroundColor: '#d9d9d9',
|
||||||
保存
|
borderColor: '#d9d9d9',
|
||||||
</Button>
|
color: '#ffffff',
|
||||||
|
cursor: 'not-allowed',
|
||||||
|
opacity: 0.5
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
保存
|
||||||
|
</Button>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: '-35px',
|
||||||
|
left: '50%',
|
||||||
|
transform: 'translateX(-50%)',
|
||||||
|
backgroundColor: 'rgba(0, 0, 0, 0.75)',
|
||||||
|
color: '#fff',
|
||||||
|
padding: '6px 12px',
|
||||||
|
borderRadius: '4px',
|
||||||
|
fontSize: '12px',
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
pointerEvents: 'none',
|
||||||
|
opacity: 0,
|
||||||
|
transition: 'opacity 0.3s',
|
||||||
|
zIndex: 1000
|
||||||
|
}}
|
||||||
|
className="save-button-tooltip"
|
||||||
|
>
|
||||||
|
非学员与导师无修改权限
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<Button
|
<Button
|
||||||
size="small"
|
size="small"
|
||||||
icon={<IconClose />}
|
icon={<IconClose />}
|
||||||
|
|||||||
@@ -22,6 +22,8 @@
|
|||||||
color: #1d2129;
|
color: #1d2129;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
|
position: relative;
|
||||||
|
overflow: visible;
|
||||||
|
|
||||||
.support-list-title-content {
|
.support-list-title-content {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -30,6 +32,7 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
border-bottom: 1px solid #e4ecf2;
|
border-bottom: 1px solid #e4ecf2;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
overflow: visible;
|
||||||
|
|
||||||
.support-list-title-icon {
|
.support-list-title-icon {
|
||||||
width: 24px;
|
width: 24px;
|
||||||
@@ -37,23 +40,81 @@
|
|||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.support-list-title-new-btn-wrapper {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
|
||||||
|
&:hover .support-list-tooltip {
|
||||||
|
opacity: 1;
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.support-list-tooltip {
|
||||||
|
position: absolute;
|
||||||
|
top: calc(100% + 8px);
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
padding: 6px 12px;
|
||||||
|
background-color: rgba(0, 0, 0, 0.75);
|
||||||
|
color: #fff;
|
||||||
|
font-size: 12px;
|
||||||
|
border-radius: 4px;
|
||||||
|
white-space: nowrap;
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 9999;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
bottom: 100%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
border-left: 5px solid transparent;
|
||||||
|
border-right: 5px solid transparent;
|
||||||
|
border-bottom: 5px solid rgba(0, 0, 0, 0.75);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.support-list-title-new-btn {
|
.support-list-title-new-btn {
|
||||||
width: 80px;
|
width: 80px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
background-color: #0077ff;
|
background-color: #0077ff;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
> span {
|
> span {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
margin: 0 2px;
|
margin: 0 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.disabled {
|
||||||
|
background-color: #c9cdd4;
|
||||||
|
cursor: not-allowed;
|
||||||
|
opacity: 0.6;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #c9cdd4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(.disabled):hover {
|
||||||
|
background-color: #0066dd;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState, useEffect, Fragment } from "react";
|
||||||
import IconFont from "@/components/IconFont";
|
import IconFont from "@/components/IconFont";
|
||||||
import expertSupportData from "@/data/expertSupportData";
|
import expertSupportData from "@/data/expertSupportData";
|
||||||
import "./index.css";
|
import "./index.css";
|
||||||
@@ -12,6 +12,17 @@ const STATUS = {
|
|||||||
const Index = ({ onSelectConversation }) => {
|
const Index = ({ onSelectConversation }) => {
|
||||||
const [selectedId, setSelectedId] = useState(null);
|
const [selectedId, setSelectedId] = useState(null);
|
||||||
|
|
||||||
|
// 页面加载时默认选中第一个对话
|
||||||
|
useEffect(() => {
|
||||||
|
if (expertSupportData?.conversations && expertSupportData.conversations.length > 0 && !selectedId) {
|
||||||
|
const firstConversation = expertSupportData.conversations[0];
|
||||||
|
setSelectedId(firstConversation.id);
|
||||||
|
if (onSelectConversation) {
|
||||||
|
onSelectConversation(firstConversation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [onSelectConversation]);
|
||||||
|
|
||||||
const handleClickNew = () => {
|
const handleClickNew = () => {
|
||||||
console.log("点击了新对话");
|
console.log("点击了新对话");
|
||||||
};
|
};
|
||||||
@@ -24,9 +35,22 @@ const Index = ({ onSelectConversation }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 根据日期分组对话
|
// 根据日期分组对话
|
||||||
const todayConversations = expertSupportData.conversations.filter(c => c.date === "今天");
|
const groupedConversations = {};
|
||||||
const weekConversations = expertSupportData.conversations.filter(c => c.date === "7天内");
|
expertSupportData.conversations.forEach(conversation => {
|
||||||
const monthConversations = expertSupportData.conversations.filter(c => c.date === "30天内");
|
const dateGroup = conversation.date;
|
||||||
|
if (!groupedConversations[dateGroup]) {
|
||||||
|
groupedConversations[dateGroup] = [];
|
||||||
|
}
|
||||||
|
groupedConversations[dateGroup].push(conversation);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 定义日期组的显示顺序(最新的在前)
|
||||||
|
const dateGroupOrder = [
|
||||||
|
"2024年12月", "2024年11月", "2024年10月",
|
||||||
|
"2024年9月", "2024年8月", "2024年7月",
|
||||||
|
"2024年6月", "2024年5月", "2024年4月",
|
||||||
|
"2024年3月", "更早"
|
||||||
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="support-list-wrapper">
|
<div className="support-list-wrapper">
|
||||||
@@ -34,70 +58,40 @@ const Index = ({ onSelectConversation }) => {
|
|||||||
<div className="support-list-title-content">
|
<div className="support-list-title-content">
|
||||||
<IconFont className="support-list-title-icon" src="recuUY5vFY3hVP" />
|
<IconFont className="support-list-title-icon" src="recuUY5vFY3hVP" />
|
||||||
<span>咨询对话</span>
|
<span>咨询对话</span>
|
||||||
<div className="support-list-title-new-btn" onClick={handleClickNew}>
|
<div className="support-list-title-new-btn-wrapper">
|
||||||
<span>+</span>
|
<div className="support-list-title-new-btn disabled">
|
||||||
<span>新对话</span>
|
<span>+</span>
|
||||||
|
<span>新对话</span>
|
||||||
|
</div>
|
||||||
|
<div className="support-list-tooltip">非学员本人暂无权限</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="support-list">
|
<div className="support-list">
|
||||||
{todayConversations.length > 0 && (
|
{dateGroupOrder.map(dateGroup => {
|
||||||
<>
|
const conversations = groupedConversations[dateGroup];
|
||||||
<p className="support-list-date">今天</p>
|
if (!conversations || conversations.length === 0) return null;
|
||||||
<ul className="support-list-content">
|
|
||||||
{todayConversations.map(conversation => (
|
return (
|
||||||
<li
|
<Fragment key={dateGroup}>
|
||||||
key={conversation.id}
|
<p className="support-list-date">{dateGroup}</p>
|
||||||
className={`support-list-content-item ${selectedId === conversation.id ? 'selected' : ''}`}
|
<ul className="support-list-content">
|
||||||
onClick={() => handleSelectConversation(conversation)}
|
{conversations.map(conversation => (
|
||||||
>
|
<li
|
||||||
<p>{conversation.title}</p>
|
key={conversation.id}
|
||||||
<div className={`support-list-content-item-status status-${conversation.status}`}>
|
className={`support-list-content-item ${selectedId === conversation.id ? 'selected' : ''}`}
|
||||||
{STATUS[conversation.status].text}
|
onClick={() => handleSelectConversation(conversation)}
|
||||||
</div>
|
>
|
||||||
</li>
|
<p>{conversation.title}</p>
|
||||||
))}
|
<div className={`support-list-content-item-status status-${conversation.status}`}>
|
||||||
</ul>
|
{STATUS[conversation.status].text}
|
||||||
</>
|
</div>
|
||||||
)}
|
</li>
|
||||||
{weekConversations.length > 0 && (
|
))}
|
||||||
<>
|
</ul>
|
||||||
<p className="support-list-date">7天内</p>
|
</Fragment>
|
||||||
<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>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user