# 教务系统数据架构与产业替换指南 ## 核心原则 ⚠️ ### 🔴 绝对不可修改的内容 1. **页面样式和布局** - 保持所有CSS类名、样式文件完全不变 2. **组件结构** - 不改动React组件的结构和渲染逻辑 3. **数据处理逻辑** - 保留所有数据转换、过滤、排序等处理函数 4. **字段名称** - 保持JSON和对象的所有字段名不变(包括中文字段名) 5. **数据流向** - 维持组件间的数据传递方式和状态管理 ### ✅ 只替换以下内容 1. **具体数据值** - 学生姓名、课程名称、岗位名称等实际内容 2. **图片URL** - 头像、海报、背景图等资源链接 3. **文本内容** - 简历内容、项目描述、面试题等文字 4. **数值数据** - 学分、排名、薪资等数值 ### 📋 替换原则总结 ``` 保持框架不变,只换内容 保持逻辑不变,只换数据 保持样式不变,只换文字 保持结构不变,只换数值 ``` ## 一、系统整体数据架构 ### 核心数据文件结构 ``` src/ ├── data/ │ ├── mockData.js # 中央数据存储(最重要) │ ├── courseLiveDataImport.js # 课程数据导入配置 │ ├── companyJobsNew.json # 企业内推岗位数据 │ ├── interviewStatus.json # 岗位面试状态 │ ├── expertSupportData.js # 专家支持中心数据 │ ├── joblevel.json # 岗位级别分类 │ ├── 智能制造课程日历.json # 课程日历源数据 │ └── 智能制造单元背景.json # 单元海报数据 ├── mocks/ │ ├── resumeInterviewMock.js # 简历与面试页面数据 │ └── projectLibraryMock.js # 项目库数据 └── 网页未导入数据/ └── 智能制造产业/ ├── 智能制造个人档案.json # 学生个人信息 ├── 智能制造岗位面试状态.json # 面试状态数据 └── 智能制造修改版简历/ # 修改版简历文件夹 ``` ## 二、各页面详细数据逻辑 ### 1. 主页 (Dashboard) **文件位置**: `src/pages/DashboardPage/index.jsx` #### 数据来源: - **班级排名**: `mockData.js` → `dashboardStatistics.ranking.topStudents` - **学习进度**: `mockData.js` → `dashboardStatistics.learningProgress` - **推荐岗位**: `mockData.js` → `dashboardStatistics.recommendedJobs` - **用户信息**: `mockData.js` → `personalProfile` #### 数据流: ```javascript // mockData.js 中的数据结构 dashboardStatistics: { ranking: { currentRank: 2, // 当前排名 totalStudents: 45, // 总人数 topStudents: [...] // 前10名学生数据 }, learningProgress: {...}, recommendedJobs: [...] } ``` #### 替换要点: 1. 更新 `topStudents` 数组中的学生信息 2. **保持数据结构不变,只替换内容** 3. **不修改任何样式和组件逻辑** --- ### 2. 个人档案页面 (PersonalProfile) **文件位置**: `src/pages/PersonalProfilePage/index.jsx` #### 数据来源: - **个人信息**: `mockData.js` → `personalProfile` - **班级排名**: `mockData.js` → `personalProfile.classRanking` - **学习记录**: `mockData.js` → `personalProfile.learningRecords` #### 数据流: ```javascript personalProfile: { basicInfo: { name: "王强", studentId: "2325010211", school: "苏州健雄职业技术学院", major: "模具设计与制造", // ... }, classRanking: [...], credits: 95 } ``` #### 替换要点: 1. 从产业个人档案JSON导入数据 2. 更新头像路径 3. 保持MBTI等个性化数据 4. **不修改页面布局和CSS样式** 5. **保留所有数据处理逻辑** --- ### 3. 简历与面试页面 (ResumeInterview) **文件位置**: `src/pages/ResumeInterviewPage/index.jsx` #### 数据来源: - **岗位群数据**: `resumeInterviewMock.js` → `industries` - **岗位列表**: `resumeInterviewMock.js` → `industries[].positions` - **简历模板**: `resumeInterviewMock.js` → `resumeTemplates` - **面试题**: `resumeInterviewMock.js` → `industries[].questions` - **修改版标记**: 页面内 `hasRealModifiedVersion()` 函数 #### 数据结构: ```javascript // resumeInterviewMock.js industries: [ { id: "manufacturing_1", name: "3D打印工艺", positions: [...], // 该岗位群下的所有岗位 questions: [...] // 该岗位群的面试题 } ] resumeTemplates: { "3D打印工艺": [ { position: "3D打印工程师", content: { original: "原始版简历内容", modified: "修改版简历内容" } } ] } ``` #### 替换要点: 1. 替换岗位群名称和ID 2. 更新每个岗位的详细信息 3. 替换简历内容(**保持original和modified结构**) 4. 更新面试题内容 5. 修改 `hasRealModifiedVersion` 函数中的岗位列表 6. **绝不改动组件渲染逻辑和样式** --- ### 4. 企业内推岗位页面 (CompanyJobs) **文件位置**: `src/pages/CompanyJobsPage/index.jsx` #### 数据来源: - **岗位列表**: `companyJobsNew.json` - **面试状态**: `interviewStatus.json` - **岗位详情**: `companyJobsNew.json` → 各岗位的详细字段 #### 数据结构: ```javascript // companyJobsNew.json [ { "公司名称": "苏州某科技有限公司", "查询岗位名称": "PLC控制工程师", "招聘人数": "2人", "学历要求": "大专及以上", "薪资": "8-12K", // ... } ] // interviewStatus.json [ { "查询岗位名称": "PLC控制工程师", "阶段日期": "收到Offer:2025/9/14 16:17", "面试状态": "已收到Offer,请于2天内答复" } ] ``` #### 替换要点: 1. **保持JSON字段名不变(中文字段名)** 2. 更新岗位内容为新产业岗位 3. 同步更新面试状态数据 4. **不修改页面交互逻辑** 5. **保持原有动画效果** --- ### 5. 项目库页面 (ProjectLibrary) **文件位置**: `src/pages/ProjectLibraryPage/index.jsx` #### 数据来源: - **项目列表**: `projectLibraryMock.js` → `projects` - **项目详情**: `projectLibraryMock.js` → `projects[].details` - **适用岗位**: `projectLibraryMock.js` → `projects[].suitablePositions` - **对应单元**: `projectLibraryMock.js` → `projects[].relatedUnit` #### 数据结构: ```javascript // projectLibraryMock.js projects: [ { id: 1, title: "90°弯管液压歧管3D打印项目", category: "3D打印工艺", suitablePositions: ["3D打印工程师", "3D打印产品设计师"], relatedUnit: "单元一", details: { background: "项目背景...", objectives: ["目标1", "目标2"], // ... } } ] ``` #### 替换要点: 1. 更新项目名称和分类 2. 替换适用岗位列表 3. 更新项目详情内容 4. **保持单元映射关系** 5. **不改动模态框和卡片组件** --- ### 6. 课程直播间页面 (CourseLive) **文件位置**: `src/pages/CourseLivePage/index.jsx` #### 数据来源: - **课程列表**: `mockData.js` → `courseLiveList` (复合能力课) - **垂直课程**: `mockData.js` → `verticalCourseLiveList` - **公共课程**: `mockData.js` → `publicCourseLiveList` - **单元海报**: `courseLiveDataImport.js` → `unitPosters` #### 数据流: ```javascript // 从智能制造课程日历.json生成 courseLiveList: generateCourseLiveListFromCalendar('compound-skill') verticalCourseLiveList: generateCourseLiveListFromCalendar('vertical-skill') // 单元海报映射 unitPosters: { "单元一": "https://xxx.com/unit1.jpg", // ... } ``` #### 替换要点: 1. 更新课程日历JSON文件 2. 更新单元背景JSON文件 3. 确保课程类型字段正确(复合课阶段/垂直课阶段) 4. **保持课程卡片样式不变** 5. **不修改数据转换函数** --- ### 7. 日历页面 (Calendar) **文件位置**: `src/pages/CalendarPage/index.jsx` #### 数据来源: - **日历事件**: `mockData.js` → `calendarEvents` - **源数据**: `智能制造课程日历.json` #### 数据转换流程: ```javascript // courseLiveDataImport.js 智能制造课程日历.json → transformCalendarCourses() → calendarEvents // 事件类型判断 课程阶段(个人课程)包含"复合" → type: 'compound-skill' 课程阶段(个人课程)包含"垂直" → type: 'vertical-skill' 公共课字段有值 → type: 'public' ``` #### 替换要点: 1. 更新课程日历JSON 2. **保持日期格式(YYYY/M/D)** 3. 正确设置课程类型字段 4. **不改动日历组件和事件渲染** --- ### 8. 课程作业页面 (Homework) **文件位置**: `src/pages/HomeworkPage/index.jsx` #### 数据来源: - **作业列表**: `mockData.js` → `homework` - **动态生成**: 从 `courseLiveList` 自动生成 #### 数据生成逻辑: ```javascript // mockData.js 中的动态生成 if (mockData.homework && mockData.homework[0]) { // 从courseLiveList生成复合能力课作业 mockData.courseLiveList.forEach(unit => { unit.courses.forEach(course => { // 生成作业项 }); }); } ``` #### 替换要点: 1. 作业内容自动从课程列表生成 2. 无需手动更新作业数据 3. **保持作业卡片样式** 4. **不修改生成逻辑** --- ### 9. 岗位攻略详情页 (JobStrategyDetail) **文件位置**: `src/pages/JobStrategyDetailPage/index.jsx` #### 数据来源: - **岗位详情**: 从URL参数获取岗位,匹配 `companyJobsNew.json` - **优先级数据**: 页面内定义 #### 替换要点: 1. 更新岗位优先级列表 2. 更新岗位分析内容 3. **保持图表和可视化组件不变** --- ### 10. 专家支持中心 (ExpertSupport) **文件位置**: `src/pages/ExpertSupportPage/index.jsx` #### 数据来源: - **问答数据**: `expertSupportData.js` - **聊天记录**: `expertSupportData.js` → `chatMessages` #### 数据结构: ```javascript // expertSupportData.js export const expertSupportData = { faqs: [...], chatMessages: [...], expertProfiles: [...] } ``` #### 替换要点: 1. 更新FAQ内容 2. 更新预设的聊天消息 3. 更新专家信息 4. **保持聊天界面样式** 5. **不修改消息处理逻辑** --- ## 三、导师信息替换专项指南 ### 导师数据结构说明 导师信息存储在 `src/data/mockData.js` 的 `teacherData` 对象中,通过 `updateTeacherCourses` 函数与课程日历事件关联。 ### 导师类型分类 1. **复合课导师** - 产业专属,需要替换 2. **公共课导师** - 通用导师,保持不变 3. **AI课导师** - 通用导师,保持不变 4. **企业资深HR** - 通用导师,保持不变 ### 替换步骤 1. **识别需要替换的导师** - 查找所有 `type: "复合课导师"` 的导师 - 这些是产业相关的专业导师 2. **准备新导师数据** - 从"导师信息(通用).json"中选择新产业相关导师 - 确保导师的垂直方向与产业匹配 3. **更新导师信息** ```javascript // 示例:智能制造产业导师 "王军": { name: "王军", introduction: "导师介绍内容...", specialties: ["30年研发专家", "主导国标制定", "资深机械结构专家", "单产品创收百万"], avatar: "https://头像URL", type: "复合课导师", verticalDirection: "机械加工工艺", courses: [] // 自动由updateTeacherCourses函数填充 } ``` 4. **垂直方向对应关系** - 智能制造:机械加工工艺、智能机械产品结构与外观设计、智能制造非标自动化产线搭建、自动化设备智能调试 - 文旅:项目经营管理、商业活动策划、文化服务 - 其他产业:根据实际垂直方向设置 5. **注意事项** - ⚠️ 保持导师对象的键名与name属性一致 - ⚠️ courses数组留空,由系统自动填充 - ⚠️ 不要修改updateTeacherCourses函数逻辑 - ⚠️ 保留所有公共课导师、AI课导师和HR导师 ### 导师信息验证 1. 检查导师是否在课程播放器中正确显示 2. 验证导师的课程列表是否自动更新 3. 确认导师头像URL可访问 ## 四、各页面详细替换步骤指南 ### 📌 页面1:主页 (Dashboard) #### 步骤流程: 1. **准备数据** - 从新产业个人档案JSON获取前10名学生数据 - 准备学生头像图片URL 2. **修改文件**: `src/data/mockData.js` ```javascript // 找到 dashboardStatistics.ranking.topStudents // 替换为新的学生数组,格式如下: topStudents: [ { rank: 1, name: "新学生名", studentId: "新学号", school: "新学校", major: "新专业", credits: 97, avatar: "/images/avatars/新头像.jpg" }, // ... 继续添加前10名 ] ``` 3. **验证要点** - ✅ 确保rank从1到10递增 - ✅ 学分按降序排列 - ✅ 头像路径正确可访问 - ❌ 不要修改字段名称 - ❌ 不要改动组件样式 --- ### 📌 页面2:个人档案 (PersonalProfile) #### 步骤流程: 1. **选择目标学生** - 从个人档案JSON中选择一个学生(如排名第2的学生) 2. **修改文件**: `src/data/mockData.js` ```javascript // 找到 personalProfile 对象 personalProfile: { basicInfo: { name: "王强", // 替换为新学生名 studentId: "2325010211", // 新学号 school: "苏州健雄职业技术学院", // 新学校 major: "模具设计与制造", // 新专业 class: "智能制造1班", // 新班级 credits: 95, // 新学分 ranking: 2, // 新排名 avatar: "/images/avatars/wangqiang.jpg", // 新头像 mbti: "ESTJ", // 保持或更新MBTI direction: "自动化设备智能调试" // 新方向 }, classRanking: [/* 更新为新的前10名数组 */], learningRecords: [/* 可选:更新学习记录 */] } ``` 3. **同步更新侧边栏** - 确保Sidebar组件引用的是同一个personalProfile数据 4. **验证要点** - ✅ 个人信息与选定学生一致 - ✅ 班级排名数据与Dashboard同步 - ❌ 不要修改组件结构 --- ### 📌 页面3:简历与面试 (ResumeInterview) #### 步骤流程: 1. **准备简历数据** - 整理新产业的岗位群和岗位列表 - 准备每个岗位的原始版和修改版简历 2. **修改文件**: `src/mocks/resumeInterviewMock.js` ```javascript // 1. 更新 industries 数组 industries: [ { id: "manufacturing_1", name: "3D打印工艺", // 新岗位群名称 icon: "🖨️", // 可选:更新图标 positions: [ { id: "3d_engineer", title: "3D打印工程师", // 新岗位名称 company: "苏州某科技", // 新公司 salary: "8-12K", // 新薪资 requirements: ["要求1", "要求2"] // 新要求 } // ... 更多岗位 ], questions: [/* 新的面试题 */] } // ... 更多岗位群 ] // 2. 更新 resumeTemplates resumeTemplates: { "3D打印工艺": [ { position: "3D打印工程师", content: { original: "# 原始简历内容\n...", modified: "# 修改版简历内容\n..." } } ] } // 3. 更新 myResume myResume: { personalInfo: { name: "王强", // 与personalProfile一致 // ... 其他个人信息 } } ``` 3. **修改页面文件**: `src/pages/ResumeInterviewPage/index.jsx` ```javascript // 更新 hasRealModifiedVersion 函数 const hasRealModifiedVersion = (positionTitle) => { const modifiedPositions = [ "新岗位1", "新岗位2", // ... 有修改版的岗位列表 ]; return modifiedPositions.includes(positionTitle); }; ``` 4. **验证要点** - ✅ 岗位群和岗位数据完整 - ✅ 简历内容格式正确(Markdown) - ✅ 修改版标记正确显示 - ❌ 不要改动Tab切换逻辑 --- ### 📌 页面4:企业内推岗位 (CompanyJobs) #### 步骤流程: 1. **准备岗位数据** - 整理新产业的企业岗位信息 - 准备对应的面试状态数据 2. **修改文件**: `src/data/companyJobsNew.json` ```json [ { "公司名称": "苏州某科技有限公司", "查询岗位名称": "PLC控制工程师", "招聘人数": "2人", "学历要求": "大专及以上", "薪资": "8-12K", "工作地点": "苏州工业园区", "岗位职责": ["职责1", "职责2"], "任职要求": ["要求1", "要求2"] } // ... 更多岗位 ] ``` 3. **修改文件**: `src/data/interviewStatus.json` ```json [ { "查询岗位名称": "PLC控制工程师", "阶段日期": "收到Offer:2025/9/14 16:17", "面试状态": "已收到Offer,请于2天内答复" } // ... 更多状态 ] ``` 4. **修改简历模态框默认值**: `src/pages/CompanyJobsPage/components/ResumeInfoModal/index.jsx` ```javascript education: [{ school: '新学校名称', major: '新专业名称', period: '2020.9-2023.6' }] ``` 5. **验证要点** - ✅ 岗位信息字段完整 - ✅ 面试状态与岗位对应 - ✅ 保持中文字段名 - ❌ 不要修改动画效果 --- ### 📌 页面5:项目库 (ProjectLibrary) #### 步骤流程: 1. **准备项目数据** - 整理新产业的项目案例 - 确定项目与岗位的映射关系 2. **修改文件**: `src/mocks/projectLibraryMock.js` ```javascript projects: [ { id: 1, title: "90°弯管液压歧管3D打印项目", // 新项目名 category: "3D打印工艺", // 新分类 suitablePositions: ["3D打印工程师", "产品设计师"], // 适用岗位 relatedUnit: "单元一", // 对应单元 details: { background: "项目背景描述...", objectives: ["目标1", "目标2"], requirements: ["需求1", "需求2"], process: ["步骤1", "步骤2"], results: ["成果1", "成果2"], skills: ["技能1", "技能2"] } } // ... 更多项目 ] ``` 3. **验证要点** - ✅ 项目详情结构完整 - ✅ 岗位名称与简历页面一致 - ❌ 不要修改卡片组件样式 --- ### 📌 页面6:课程直播间 (CourseLive) #### 步骤流程: 1. **准备课程数据** - 整理课程日历JSON - 准备单元背景图片 2. **更新数据文件**: - 将新的课程日历JSON放到 `src/data/[产业名称]课程日历.json` - 将单元背景JSON放到 `src/data/[产业名称]单元背景.json` 3. **修改导入配置**: `src/data/courseLiveDataImport.js` ```javascript // 修改导入路径 import calendarData from './[产业名称]课程日历.json'; import unitPostersData from './[产业名称]单元背景.json'; // 数据会自动通过transformCalendarCourses转换 ``` 4. **数据格式要求** ```json // 课程日历JSON格式 { "个人课程表": "课程名称", "课程阶段(个人课程)": "复合课阶段/垂直课阶段", "所属单元(个人课程)": "单元一", "日期": "2024/7/15" } ``` 5. **更新导师信息**: `src/data/mockData.js` - 在teacherData对象中替换导师信息 - 复合课导师需要替换为新产业相关导师 - 公共课导师、AI课导师、HR导师保持不变 ```javascript teacherData: updateTeacherCourses({ "导师名": { name: "导师名", introduction: "导师介绍...", specialties: ["特长1", "特长2", "特长3", "特长4"], avatar: "头像URL", type: "复合课导师/公共课导师/AI课导师/企业资深HR", verticalDirection: "垂直方向", courses: [] }, // ... 更多导师 }, allCalendarEvents) ``` 6. **验证要点** - ✅ 课程正确分类(复合/垂直) - ✅ 单元海报URL可访问 - ✅ 公共课保持不变 - ✅ 导师信息与产业匹配 - ❌ 不要修改课程卡片样式 - ❌ 不要修改导师卡片组件 --- ### 📌 页面7:日历 (Calendar) #### 步骤流程: 1. **准备日历数据文件** - 创建`智能开发课程日历.json`和`智能开发单元背景.json` - 确保日期格式为 YYYY/M/D 2. **创建数据转换脚本** `convertCalendarData.cjs` ```javascript const fs = require('fs'); // 读取课程日历和单元背景数据 const calendarData = JSON.parse( fs.readFileSync('./网页未导入数据/智能开发产业/智能开发课程日历.json', 'utf-8') ); // 转换日期格式和课程类型 const allCalendarEvents = []; calendarData.forEach(item => { // 日期转换:YYYY/M/D → YYYY-MM-DD const dateParts = item['日期'].split('/'); const formattedDate = `${dateParts[0]}-${dateParts[1].padStart(2, '0')}-${dateParts[2].padStart(2, '0')}`; // 处理各类课程 if (item['个人课程表']) { allCalendarEvents.push({ title: item['个人课程表'], startTime: `${formattedDate} ${startTime}`, endTime: `${formattedDate} ${endTime}`, type: courseType.includes('复合') ? 'compound-skill' : 'vertical-skill', // ... }); } }); // 复制文件到src/data目录 fs.copyFileSync('./网页未导入数据/智能开发产业/智能开发课程日历.json', './src/data/智能开发课程日历.json'); ``` 3. **更新mockData.js导入路径** ```javascript // 必须更新这两行导入! import calendarCoursesData from './智能开发课程日历.json'; import intelligentManufacturingUnitData from './智能开发单元背景.json'; ``` 4. **更新导师头像映射** ```javascript const teacherAvatars = { // 原有导师... // 新增智能开发产业导师 "谢宇程": "头像URL", "何思远": "头像URL", // ... }; ``` 5. **验证要点** - ✅ mockData.js导入路径已更新 - ✅ JSON文件已复制到src/data - ✅ 日期格式转换正确 - ✅ 课程类型判断准确 - ✅ 导师头像映射完整 - ❌ 不要修改日历组件 - ❌ 不要修改transformCalendarCourses函数 --- ### 📌 页面8:课程作业 (Homework) #### 步骤流程: 1. **自动生成机制** - 作业从courseLiveList自动生成 - 无需手动修改 2. **验证生成逻辑**: `src/data/mockData.js` ```javascript // 检查动态生成代码是否正常工作 if (mockData.homework && mockData.homework[0]) { // 复合能力课作业生成 // 垂直能力课作业生成 } ``` 3. **验证要点** - ✅ 作业与课程对应 - ✅ 单元分组正确 - ❌ 不要修改作业卡片 --- ### 📌 页面9:岗位攻略详情 (JobStrategyDetail) #### 步骤流程: 1. **更新岗位分析数据** - 岗位数据从companyJobsNew.json读取 - 可在页面内更新优先级分析 2. **修改页面文件(如需要)**: `src/pages/JobStrategyDetailPage/index.jsx` ```javascript // 更新岗位优先级数据 const jobPriorities = [ { name: '新岗位1', priority: 'high' }, { name: '新岗位2', priority: 'medium' }, // ... ]; ``` 3. **验证要点** - ✅ 岗位详情正确显示 - ✅ 图表数据更新 - ❌ 不要修改图表组件 --- ### 📌 页面10:专家支持中心 (ExpertSupport) #### 步骤流程: 1. **准备FAQ和聊天数据** - 整理新产业相关的常见问题 - 准备预设聊天消息 2. **修改文件**: `src/data/expertSupportData.js` ```javascript export const expertSupportData = { faqs: [ { question: "新产业相关问题1?", answer: "答案1" } // ... 更多FAQ ], chatMessages: [ { type: 'expert', content: '欢迎咨询新产业相关问题', time: '10:00' } // ... 预设消息 ], expertProfiles: [ { name: "专家名", title: "新产业专家", expertise: ["领域1", "领域2"] } ] } ``` 3. **验证要点** - ✅ FAQ内容相关 - ✅ 聊天消息合理 - ❌ 不要修改聊天界面 ## 三、产业数据替换步骤指南 ### 第一步:准备源数据文件 1. **创建产业数据文件夹** ``` 网页未导入数据/[产业名称]/ ├── [产业名称]个人档案.json ├── [产业名称]课程日历.json ├── [产业名称]单元背景.json ├── [产业名称]岗位面试状态.json └── [产业名称]修改版简历/ ├── 岗位1.md ├── 岗位2.md └── ... ``` 2. **数据格式要求** - 个人档案:包含学生信息、学校、专业、学分、排名等 - 课程日历:包含日期、课程名称、课程阶段、所属单元等 - 单元背景:包含单元名称和海报URL - 岗位面试状态:包含岗位名称、面试阶段、状态描述 ### 第二步:更新核心数据文件 1. **更新 mockData.js** ```javascript // 1. 导入新的数据文件 import personalData from "@/data/[产业名称]个人档案.json"; import calendarData from "@/data/[产业名称]课程日历.json"; // 2. 更新personalProfile const targetStudent = personalData[1]; // 选择目标学生 mockData.personalProfile = { basicInfo: { name: targetStudent.学员名称, studentId: targetStudent.学号, // ... } }; // 3. 更新班级排名 mockData.dashboardStatistics.ranking.topStudents = personalData.slice(0, 10); // 4. 更新导师信息(替换复合课导师) teacherData: updateTeacherCourses({ "新导师名": { name: "新导师名", introduction: "导师介绍...", specialties: ["特长1", "特长2", "特长3", "特长4"], avatar: "头像URL", type: "复合课导师", verticalDirection: "产业相关方向", courses: [] }, // ... 保留公共课导师、AI课导师、HR导师 }, allCalendarEvents) ``` 2. **更新 resumeInterviewMock.js** - 替换 industries 数组(岗位群) - 替换 resumeTemplates 对象(简历内容) - 更新 myResume 对象(个人简历) 3. **更新 projectLibraryMock.js** - 替换 projects 数组 - 更新项目与岗位的映射关系 4. **更新其他JSON文件** - companyJobsNew.json:企业岗位数据 - interviewStatus.json:面试状态数据 ### 第三步:更新页面特定逻辑 1. **ResumeInterviewPage** ```javascript // 更新修改版岗位列表 const hasRealModifiedVersion = (positionTitle) => { const modifiedPositions = [ // 新产业的岗位列表 ]; return modifiedPositions.includes(positionTitle); }; ``` 2. **ResumeInfoModal** ```javascript // 更新默认教育经历 education: [{ school: '新学校名称', major: '新专业名称', period: '2020.9-2023.6' }] ``` ### 第四步:验证数据完整性 1. **检查清单** - [ ] 个人信息是否正确显示 - [ ] 班级排名数据是否同步 - [ ] 课程列表是否正确分类 - [ ] 岗位和简历是否匹配 - [ ] 项目库内容是否更新 - [ ] 面试状态是否正确 - [ ] 修改版标记是否显示 2. **常见问题排查** - 数据不显示:检查import路径 - 类型错误:检查数据格式 - 样式错乱:保持原有CSS类名 ## 四、数据更新注意事项 ### 1. 🔴 绝对禁止的操作 - **禁止修改任何CSS文件或样式** - **禁止改动组件的JSX结构** - **禁止修改数据处理函数逻辑** - **禁止重命名任何变量或函数** - **禁止改变文件目录结构** ### 2. 保持数据结构一致性 - **不要修改**字段名称 - **不要改变**数据层级结构 - **只替换**具体内容值 - **保留**所有原始的数据处理逻辑 ### 3. 中文字段名处理 ```javascript // 保持中文字段名不变 { "查询岗位名称": "新岗位名", // ✓ 正确 "jobName": "新岗位名" // ✗ 错误,不要改字段名 } ``` ### 4. 图片资源处理 - 使用CDN链接或public目录 - 保持相同的图片尺寸比例 - 优化图片大小(建议<500KB) ### 5. 日期格式统一 ```javascript // 课程日历:YYYY/M/D "日期": "2024/7/15" // 面试状态:YYYY/M/D H:mm "阶段日期": "2025/9/14 16:17" ``` ### 6. 备份原数据 ```bash # 备份命令 cp src/data/mockData.js src/data/mockData.js.backup_$(date +%Y%m%d_%H%M%S) ``` ## 五、快速替换脚本示例 ```javascript // updateIndustryData.js import fs from 'fs'; import path from 'path'; const updateIndustryData = (industryName) => { // 1. 读取新产业数据 const personalData = JSON.parse( fs.readFileSync(`网页未导入数据/${industryName}/${industryName}个人档案.json`) ); // 2. 更新mockData.js // ... 更新逻辑 // 3. 更新其他文件 // ... 更新逻辑 console.log(`✅ 已更新为${industryName}产业数据`); }; // 使用 updateIndustryData('智能制造'); ``` ## 六、数据流程图 ```mermaid graph TD A[产业源数据] --> B[数据导入层] B --> C[mockData.js] B --> D[resumeInterviewMock.js] B --> E[projectLibraryMock.js] C --> F[Dashboard] C --> G[PersonalProfile] C --> H[Calendar] C --> I[CourseLive] C --> J[Homework] D --> K[ResumeInterview] E --> L[ProjectLibrary] M[companyJobsNew.json] --> N[CompanyJobs] O[interviewStatus.json] --> N P[expertSupportData.js] --> Q[ExpertSupport] ``` ## 七、完整替换流程检查清单 ### ✅ 替换前准备 - [ ] 备份所有将要修改的文件 - [ ] 准备完整的产业数据文件 - [ ] 确认数据格式符合要求 - [ ] 测试环境可正常运行 ### ✅ 数据替换检查 - [ ] **mockData.js** - [ ] personalProfile 更新完成 - [ ] dashboardStatistics 更新完成 - [ ] 班级排名数据同步 - [ ] teacherData 导师信息更新 - [ ] 复合课导师替换为产业相关导师 - [ ] 公共课导师保持不变 - [ ] **resumeInterviewMock.js** - [ ] industries 数组替换 - [ ] resumeTemplates 更新 - [ ] myResume 信息同步 - [ ] **projectLibraryMock.js** - [ ] projects 数组更新 - [ ] 岗位映射关系正确 - [ ] **companyJobsNew.json** - [ ] 岗位信息完整 - [ ] 字段名保持中文 - [ ] **interviewStatus.json** - [ ] 面试状态对应 - [ ] 日期格式正确 - [ ] **课程相关数据** - [ ] 课程日历JSON导入 - [ ] 单元背景JSON配置 - [ ] 课程分类正确 ### ✅ 页面功能验证 - [ ] 主页班级排名显示正确 - [ ] 个人档案信息一致 - [ ] 简历修改版标记显示 - [ ] 企业岗位列表完整 - [ ] 项目库内容更新 - [ ] 课程直播间分类正确 - [ ] 课程直播间导师信息显示 - [ ] 导师头像正常加载 - [ ] 导师课程列表自动更新 - [ ] 日历事件显示正常 - [ ] 作业自动生成成功 - [ ] 岗位攻略数据准确 - [ ] 专家支持内容相关 ### ✅ 数据一致性检查 - [ ] 学生姓名全局一致 - [ ] 学号信息匹配 - [ ] 学校专业同步 - [ ] 岗位名称统一 - [ ] 课程类型分类正确 ## 八、常见问题与解决方案 ### 问题1:数据不显示 **症状**:页面空白或数据缺失 **解决**: 1. 检查import路径是否正确 2. 确认JSON文件格式无误 3. 查看浏览器控制台错误 ### 问题2:样式错乱 **症状**:布局混乱或样式丢失 **原因**:可能修改了CSS类名或组件结构 **解决**:恢复原始组件代码,只修改数据 ### 问题3:修改版标记不显示 **症状**:简历页面修改版标记缺失 **解决**: 1. 检查hasRealModifiedVersion函数 2. 确认岗位名称完全匹配 3. 验证modified字段有内容 ### 问题4:课程分类错误 **症状**:复合课和垂直课混淆 **解决**: 1. 检查"课程阶段(个人课程)"字段 2. 确认包含"复合"或"垂直"关键字 3. 验证transformCalendarCourses函数 ### 问题5:作业不生成 **症状**:作业页面为空 **解决**: 1. 确认courseLiveList有数据 2. 检查动态生成代码执行 3. 验证课程类型判断逻辑 ### 问题6:头像不显示 **症状**:学生头像404 **解决**: 1. 将头像文件放到public/images/avatars/ 2. 使用正确的相对路径 3. 确认文件名大小写匹配 ### 问题7:日期格式错误 **症状**:日历事件不显示 **解决**: 1. 使用YYYY/M/D格式(斜杠分隔) 2. 不要补零(7/15而非07/15) 3. 检查日期字段名称 ### 问题8:中文字段名问题 **症状**:数据读取失败 **解决**: 1. 保持原有中文字段名 2. 不要改为英文 3. 注意字段名完全匹配 ### 问题9:日历页面数据未更新 **症状**:日历页面仍显示原始数据,即使已替换了课程日历JSON文件 **原因**:mockData.js中的导入路径未更新 **解决**: 1. 检查`src/data/mockData.js`中的导入语句: ```javascript // 错误:仍然导入旧的智能制造数据 import calendarCoursesData from './intelligentManufacturingCalendar.json'; import intelligentManufacturingUnitData from '../../网页未导入数据/智能制造产业/智能制造单元背景.json'; // 正确:导入新的产业数据 import calendarCoursesData from './智能开发课程日历.json'; import intelligentManufacturingUnitData from './智能开发单元背景.json'; ``` 2. 确保新的JSON文件已复制到`src/data/`目录 3. 更新teacherAvatars映射,添加新产业的导师头像 4. 验证transformCalendarCourses函数能处理新的数据格式 **预防措施**: - 创建数据转换脚本时,同时更新mockData.js的导入路径 - 使用脚本自动复制数据文件到正确位置 - 在转换脚本中添加导入路径更新逻辑 ### 问题10:面试题卡片显示异常 **症状**:一个岗位群显示多个面试题卡片,而不是一个卡片包含所有问题 **原因**:面试题数据结构不正确,每个问题被创建为独立卡片 **解决**: 1. 确保每个岗位群只有一个面试题对象: ```javascript // 错误:为每个问题创建独立卡片 questions: [ { id: 'q1', question: '问题1', answer: '答案1' }, { id: 'q2', question: '问题2', answer: '答案2' } ] // 正确:一个卡片包含所有问题 questions: [{ id: 'group_q1', question: '岗位群面试题', subQuestions: [ { id: 'q1', question: '问题1', answer: '答案1' }, { id: 'q2', question: '问题2', answer: '答案2' } ] }] ``` 2. 在数据转换脚本中正确处理面试题: ```javascript // 收集所有子问题 const allSubQuestions = []; // ... 解析面试题内容 // 创建单个面试题卡片 if (allSubQuestions.length > 0) { questions.push({ id: 'group_q1', question: `${groupName}面试题`, subQuestions: allSubQuestions.slice(0, 10) // 限制最多10个问题 }); } ``` **预防措施**: - 每个岗位群的questions数组应只包含一个对象 - 使用subQuestions字段包含所有具体问题 - 限制每个卡片最多显示10个问题,避免内容过多 ### 问题11:所有岗位都显示修改版标记 **症状**:简历页面所有岗位都有绿色的"修改版"样式,即使没有修改版简历 **原因**:hasRealModifiedVersion函数包含了所有岗位名称 **解决**: 1. 检查`src/pages/ResumeInterviewPage/index.jsx`中的函数: ```javascript // 错误:包含所有岗位 const hasRealModifiedVersion = (positionTitle) => { const modifiedPositions = [/* 47个岗位名称 */]; return modifiedPositions.includes(positionTitle); }; // 正确:只包含真正有修改版的岗位 const hasRealModifiedVersion = (positionTitle) => { const modifiedPositions = [ "AI算法工程师", "AI前端工程师", // ... 只列出实际有修改版文件的岗位 ]; return modifiedPositions.includes(positionTitle); }; ``` 2. 验证修改版文件是否存在: ```bash ls 网页未导入数据/智能开发产业/智能开发修改版简历/ ``` **预防措施**: - 在数据转换脚本中自动检测修改版文件 - 只为实际存在修改版文件的岗位添加标记 - 保持hasRealModifiedVersion函数与实际文件同步 ### 问题13:项目库页面数据引用错误合集 **症状**:项目库页面出现多个数据显示和功能问题 **解决过程记录**: #### 13.1 项目名称显示为undefined **原因**:使用了错误的字段名"项目名称",实际JSON中使用的是"案例名称" **错误代码**: ```javascript // 错误:使用不存在的字段名 const projectDetails = {}; projectsData.forEach((project, index) => { projectDetails[index + 1] = { title: project['项目名称'] + '详情', // undefined }; }); ``` **正确代码**: ```javascript // 正确:使用实际存在的字段名 const projectDetails = {}; projectsData.forEach((project, index) => { projectDetails[index + 1] = { title: project['案例名称'] + '详情', // 正确显示 }; }); ``` #### 13.2 岗位等级标签颜色错误 **原因**:className判断条件使用了错误的等级名称 **错误代码**: ```jsx // 错误:使用"普通岗" ``` **正确代码**: ```jsx // 正确:使用"基础岗" ``` #### 13.3 对应单元分类错误 **原因**:使用简单的关键词匹配而不是正确的映射函数 **错误做法**:尝试通过判断单元名称中是否包含"复合"或"垂直"来分类 **正确做法**: 1. 创建projectUnitsMapping.js文件定义项目与单元的映射关系 2. 导入并使用getCompoundUnits和getVerticalUnits函数 ```javascript import { getCompoundUnits, getVerticalUnits } from '@/data/projectUnitsMapping'; // 使用映射函数获取正确的单元分类 {getCompoundUnits(data?.title).map((unit, index) => (...))} {getVerticalUnits(data?.title).map((unit, index) => (...))} ``` #### 13.4 单元点击功能缺失 **原因**:没有实现handleUnitClick函数,没有添加点击事件 **解决方案**: ```javascript // 添加单元点击处理函数 const handleUnitClick = (unitName, isCompound) => { onClose(); // 关闭模态框 const params = new URLSearchParams(); params.append('courseTitle', unitName); params.append('courseType', isCompound ? 'compound-skill' : 'vertical-skill'); navigate(`/live?${params.toString()}`); }; ``` #### 13.5 单元hover效果缺失 **原因**:缺少clickable-unit类名 **解决方案**: ```jsx // 添加clickable-unit类名
  • handleUnitClick(unit, true)}> ``` #### 13.6 适用岗位未排序 **原因**:没有根据岗位等级进行排序 **解决方案**: ```javascript {data?.applicablePositions?.sort((a, b) => { const levelOrder = { '基础岗': 1, '技术骨干岗': 2, '储备干部岗': 3 }; return (levelOrder[a.level] || 999) - (levelOrder[b.level] || 999); }).map((pos, index) => (...))} ``` #### 13.7 Markdown内容多余标题 **原因**:项目流程和关键技术点内容中包含重复的标题 **解决方案**: ```javascript const formatMarkdownContent = (content) => { if (!content) return ""; let formattedContent = content.replace(/\\n/g, '\n'); // 移除多余标题 formattedContent = formattedContent.replace(/^#\s*二、\s*项目整体流程介绍\s*\n*/m, ''); formattedContent = formattedContent.replace(/^#\s*三、\s*项目案例关键技术点\s*\n*/m, ''); return formattedContent.trim(); }; ``` #### 13.8 Mock文件语法错误 **原因**:attachments数组后有多余的]符号 **错误代码**: ```javascript attachments: [] ] // 多余的] }, ``` **正确代码**: ```javascript attachments: [] }, ``` ### 问题14:修改版简历格式处理错误 **症状**:修改版简历中包含删除线符号(~~)和加粗符号(**) **原因**:Markdown格式未正确处理 **解决**: 1. 创建处理函数清理Markdown格式: ```javascript function processModifiedResume(content) { // 1. 删除所有删除线内容(包括符号和内容) content = content.replace(/~~[^~]+~~/g, ''); // 2. 去掉加粗符号但保留内容 content = content.replace(/\*\*([^*]+)\*\*/g, '$1'); // 3. 清理多余的空行 content = content.replace(/\n\s*\n\s*\n/g, '\n\n'); // 4. 清理行尾空格 content = content.replace(/ +$/gm, ''); return content.trim(); } ``` 2. 在导入修改版简历时应用处理: ```javascript modifiedFiles.forEach(file => { const content = fs.readFileSync(filePath, 'utf-8'); const processedContent = processModifiedResume(content); modifiedResumes[positionName] = processedContent; }); ``` **预防措施**: - 制定修改版简历的格式规范 - 在数据导入时统一处理格式 - 保留原始内容和处理后内容的对照 ### 问题12:岗位等级标签未显示 **症状**:简历页面的岗位卡片没有显示等级标签(储备干部岗/技术骨干岗/普通岗) **原因**:joblevel.json文件未更新或数据不匹配 **解决**: 1. 更新`src/data/joblevel.json`文件: ```javascript { "data": { "high": { "name": "储备干部岗", "list": [ { "position_name": "岗位名称", "img": "头像URL" } // ... 所有储备干部岗位 ] }, "middle": { "name": "技术骨干岗", "list": [/* ... */] }, "ordinary": { "name": "普通岗", "list": [/* ... */] } } } ``` 2. 确保岗位名称完全匹配: - resumeInterviewMock.js中的position.title - joblevel.json中的position_name - 名称必须一字不差 3. 创建更新脚本自动生成joblevel.json: ```javascript const updateJobLevel = () => { const jobLevelData = { data: { high: { name: "储备干部岗", list: [] }, middle: { name: "技术骨干岗", list: [] }, ordinary: { name: "普通岗", list: [] } } }; // 根据岗位等级标签分类 positions.forEach(pos => { const level = pos['岗位等级标签']; const data = { position_name: pos['岗位名称'], img: pos['简历头像url'] }; if (level === '储备干部岗') { jobLevelData.data.high.list.push(data); } else if (level === '技术骨干岗') { jobLevelData.data.middle.list.push(data); } else { jobLevelData.data.ordinary.list.push(data); } }); fs.writeFileSync('./src/data/joblevel.json', JSON.stringify(jobLevelData, null, 2)); }; ``` **预防措施**: - 在主数据转换脚本中同时更新joblevel.json - 确保所有相关文件的岗位名称保持一致 - 使用脚本自动化更新,避免手动错误 ## 九、项目库页面正确数据替换流程总结 ### 步骤1:准备数据文件 1. **获取项目案例JSON数据** - 确保JSON使用正确的字段名(如"案例名称"而非"项目名称") - 验证所有必需字段存在 2. **创建项目单元映射文件** ```javascript // src/data/projectUnitsMapping.js export const projectUnitsMapping = { "项目名称": { "compoundUnits": ["复合能力课1", "复合能力课2"], "verticalUnits": ["垂直能力课1", "垂直能力课2"] } }; ``` ### 步骤2:更新Mock文件 1. **使用正确的字段名** ```javascript // 解析JSON时使用实际的字段名 title: project['案例名称'] + '详情', // 不是'项目名称' ``` 2. **正确设置岗位等级** ```javascript applicablePositions: [ { level: '基础岗', position: '岗位名' }, // 不是'普通岗' { level: '技术骨干岗', position: '岗位名' }, { level: '储备干部岗', position: '岗位名' } ] ``` ### 步骤3:更新组件逻辑 1. **导入映射函数** ```javascript import { getCompoundUnits, getVerticalUnits } from '@/data/projectUnitsMapping'; ``` 2. **添加单元点击处理** ```javascript const handleUnitClick = (unitName, isCompound) => { onClose(); const params = new URLSearchParams(); params.append('courseTitle', unitName); params.append('courseType', isCompound ? 'compound-skill' : 'vertical-skill'); navigate(`/live?${params.toString()}`); }; ``` 3. **处理Markdown内容** ```javascript const formatMarkdownContent = (content) => { if (!content) return ""; let formattedContent = content.replace(/\\n/g, '\n'); // 移除重复标题 formattedContent = formattedContent.replace(/^#\s*二、.*\n*/m, ''); formattedContent = formattedContent.replace(/^#\s*三、.*\n*/m, ''); return formattedContent.trim(); }; ``` ### 步骤4:添加样式类 1. **确保hover效果** ```jsx
  • ``` 2. **正确的等级样式判断** ```jsx className={pos.level === '基础岗' ? 'low' : pos.level === '技术骨干岗' ? 'medium' : 'high'} ``` ### 步骤5:数据验证 1. **检查语法错误** ```bash node -c src/mocks/projectLibraryMock.js ``` 2. **验证数据完整性** - 项目名称正确显示 - 岗位等级标签颜色正确 - 单元分类准确 - 点击功能正常 - hover效果存在 - 岗位按等级排序 - 附件显示"暂无附件" ### 关键要点总结 1. **永远不要假设字段名** - 始终检查实际JSON的字段名 2. **保持数据一致性** - 等级名称、岗位名称必须全局一致 3. **使用映射而非硬编码** - 通过映射文件管理项目与单元关系 4. **处理数据格式** - 正确处理Markdown、换行符等格式问题 5. **验证每一步** - 每次修改后立即验证,不要累积问题 ## 十、测试验证方法 ### 1. 单元测试 ```javascript // 测试数据完整性 describe('产业数据完整性测试', () => { test('个人信息应包含必要字段', () => { expect(mockData.personalProfile.basicInfo).toHaveProperty('name'); expect(mockData.personalProfile.basicInfo).toHaveProperty('studentId'); }); }); ``` ### 2. 集成测试 - 访问每个页面检查数据显示 - 测试数据交互功能 - 验证数据同步性 ### 3. 数据一致性检查 ```javascript // 检查学生姓名是否全局一致 const checkNameConsistency = () => { const name1 = mockData.personalProfile.basicInfo.name; const name2 = resumeInterviewMock.myResume.personalInfo.name; const name3 = mockData.dashboardStatistics.ranking.topStudents[1].name; return name1 === name2 && name2 === name3; }; ``` ## 十、快速命令参考 ### 备份命令 ```bash # 备份核心文件 cp src/data/mockData.js src/data/mockData.js.backup_$(date +%Y%m%d_%H%M%S) cp src/mocks/resumeInterviewMock.js src/mocks/resumeInterviewMock.js.backup_$(date +%Y%m%d_%H%M%S) cp src/mocks/projectLibraryMock.js src/mocks/projectLibraryMock.js.backup_$(date +%Y%m%d_%H%M%S) ``` ### 语法检查 ```bash # 检查JavaScript语法 node -c src/data/mockData.js node -c src/mocks/resumeInterviewMock.js ``` ### 开发服务器 ```bash # 启动开发服务器 npm run dev # 清理缓存后启动 rm -rf node_modules/.vite npm run dev ``` ### Git操作 ```bash # 查看修改的文件 git status # 查看具体修改内容 git diff src/data/mockData.js # 提交更改 git add . git commit -m "feat: 替换为[产业名称]产业数据" ``` ## 十一、数据替换最佳实践 ### 👍 推荐做法 1. **分步替换**:先替换一个页面,测试后再继续 2. **版本控制**:每完成一个模块就提交一次 3. **注释标记**:在修改处添加注释说明 4. **数据验证**:使用console.log验证数据加载 5. **团队协作**:记录修改内容供团队参考 ### 👎 避免做法 1. **批量替换**:不要使用全局查找替换 2. **跳过备份**:不要直接修改无备份文件 3. **忽略错误**:不要忽视控制台警告 4. **修改框架**:不要改动React组件逻辑 5. **更改样式**:不要修改CSS文件 ## 十二、产业切换总结 ### 核心要点回顾 1. **数据与逻辑分离**:只替换数据,保持逻辑 2. **结构保持一致**:维护原有数据结构 3. **样式不做修改**:保留所有样式文件 4. **字段名不改变**:特别是中文字段名 5. **测试验证充分**:每步都要验证结果 ### 成功标准 - ✅ 所有页面正常显示 - ✅ 数据内容正确更新 - ✅ 功能交互正常工作 - ✅ 样式布局保持原样 - ✅ 无控制台错误警告 --- **最后更新时间**: 2025年9月16日 **当前产业**: 智能开发 **维护人员**: System Admin **文档版本**: v2.4 ## 十三、"我完成的项目"板块数据替换实战指南 ### 问题描述与解决历程 #### 遇到的问题 1. **初始问题**:购物网站项目点击后显示的是班级项目库的内容,而不是本地定义的内容 2. **根本原因**:数据结构不匹配、组件内外定义混乱、handleProjectClick逻辑错误 #### 解决过程记录 ##### 尝试1:修改handleProjectClick函数(失败) ```javascript // 错误的尝试:添加detailContent判断 if (item?.isClickable && (item?.detailContent || item?.content)) { setModalData(item?.detailContent || item?.content); } ``` **问题**:数据结构本身有问题,修改判断逻辑无效 ##### 尝试2:移动clickableProjects到组件外部(失败) ```javascript // 尝试像智能制造项目那样定义在组件外 const clickableProjects = [...]; const ProjectLibraryPage = () => {...} ``` **问题**:没有解决根本的数据结构问题 ##### 最终解决方案:参考智能制造项目的完整结构 1. **删除原有的错误结构** 2. **复制智能制造项目的数据格式** 3. **使用正确的content字段结构** ### 正确的实现方式 #### 1. 数据结构(参考智能制造项目) ```javascript const clickableProjects = [ { id: "clickable-1", name: "项目完整名称", // 显示在卡片上的名称 unitName: "对应单元", // 单元标签 isClickable: true, // 标记为可点击 content: { // 直接使用content字段 title: "项目标题", description: "项目描述", images: [ // 项目效果图数组 { url: "图片路径", title: "图片说明" } ], sections: [ // 内容章节 { title: "章节标题", content: "章节内容(支持Markdown)" } ] } } ]; ``` #### 2. handleProjectClick函数逻辑 ```javascript const handleProjectClick = async (item) => { // 如果是普通的"我的项目",不允许点击 if (item?.isMyProject && !item?.isClickable) { return; } // 如果是可点击的特殊项目,直接显示内容 if (item?.isClickable && item?.content) { setModalData(item.content); // 使用content字段 setProjectCasesModalVisible(true); return; } // 只有班级项目库的项目才调用API if (item?.id && !item?.isClickable) { const res = await getProjectsdetail(item.id); // ... } }; ``` #### 3. ProjectCasesModal组件处理 Modal组件会根据data.sections判断使用哪种渲染方式: - 有sections:使用新格式渲染(支持Markdown) - 无sections:使用旧格式渲染(兼容班级项目库) ### 数据替换步骤(以购物网站项目为例) #### 步骤1:准备项目数据 1. 读取项目MD文件 2. 准备项目效果图列表 3. 确定单元标签 #### 步骤2:构建数据结构 ```javascript { id: "clickable-1", name: "购物网站前端展示页面开发项目", unitName: "智能前端项目", isClickable: true, content: { title: "购物网站前端展示页面开发项目", description: "项目描述...", images: [ { url: "/网页未导入数据/.../图片.jpg", title: "首页展示" }, // ... 更多图片 ], sections: [ { title: "一、项目背景", content: "内容文本\n\n支持Markdown格式" }, // ... 更多章节 ] } } ``` #### 步骤3:处理Markdown内容 - 使用 `\n` 表示换行(在字符串中) - 支持Markdown语法(**加粗**、表格、列表等) - 处理特殊字符转义 ### 关键注意事项 #### ✅ 正确做法 1. **使用content字段**,不要使用detailContent 2. **保持数据结构一致**,参考智能制造项目 3. **设置isClickable: true**,标记为可点击项目 4. **sections数组格式**,每个section有title和content #### ❌ 错误做法 1. 不要在content中嵌套多余的字段 2. 不要混用content和detailContent 3. 不要忘记设置isClickable标志 4. 不要修改Modal组件的渲染逻辑 ### 问题排查清单 - [ ] clickableProjects数组定义位置正确(组件内部) - [ ] 数据结构使用content字段(不是detailContent) - [ ] isClickable设置为true - [ ] handleProjectClick函数检查isClickable和content - [ ] sections数组格式正确 - [ ] Markdown内容正确转义(\n表示换行) - [ ] 图片路径正确且可访问 ### 功能说明 "我完成的项目库"是项目库页面中的特殊板块,展示学生已完成的项目列表。这些项目显示为灰色、不可点击的样式,表示已完成但不提供详情查看。 ### 数据结构 ```javascript // src/pages/ProjectLibraryPage/index.jsx const myProjectsData = [ { unitName: "单元名称", projects: ["项目1", "项目2", ...] }, // ... 更多单元 ]; ``` ### 通用替换方法 #### 步骤1:分析数据源格式 检查原始JSON数据的字段结构,识别关键字段: - 产业/方向标识字段 - 单元名称字段 - 项目列表字段 #### 步骤2:创建数据转换脚本 基本脚本结构: ```javascript const fs = require('fs'); // 1. 读取源数据 const sourceData = JSON.parse(fs.readFileSync('数据源路径', 'utf-8')); // 2. 筛选目标数据 const filteredData = sourceData.filter(item => { // 根据产业特征筛选 return item['产业字段'] === '目标产业'; }); // 3. 转换数据格式 const formattedData = filteredData.map(item => ({ unitName: item['单元字段'], projects: item['项目字段'] .filter(p => p && p.trim() !== '') .map(p => { // 清理项目名称格式(去除序号等) return p.replace(/^\d+\.\s*/, ''); }) })); // 4. 替换页面数据 const targetFile = './src/pages/ProjectLibraryPage/index.jsx'; let fileContent = fs.readFileSync(targetFile, 'utf-8'); fileContent = fileContent.replace( /const myProjectsData = \[\s*[\s\S]*?\];/, `const myProjectsData = ${JSON.stringify(formattedData, null, 2)};` ); fs.writeFileSync(targetFile, fileContent); ``` #### 步骤3:数据格式化处理 常见的格式处理需求: - 去除项目名称前的序号 - 过滤空项目 - 统一单元名称格式 - 处理特殊字符 ### 数据要求 #### 必要字段 - **unitName**: 单元名称(与课程系统对应) - **projects**: 项目名称数组 #### 格式规范 - 单元名称需与课程单元系统保持一致 - 项目名称应简洁明确 - 避免重复的序号或标记 ### 验证要点 1. **数据完整性** - 确认所有单元都有对应的项目 - 检查项目数量是否合理 2. **格式一致性** - 单元名称格式统一 - 项目名称无多余格式符号 3. **显示效果** - 项目正确分组显示 - 样式为灰色不可点击状态 ### 常见问题处理 #### 问题:数据未显示 - 检查筛选条件是否正确 - 验证字段名称匹配 - 确认数据路径正确 #### 问题:格式异常 - 检查正则表达式处理逻辑 - 验证JSON格式正确性 - 确认字符编码一致 #### 问题:单元分组错误 - 核对单元名称映射 - 检查数据分组逻辑 - 验证源数据结构 ### 与系统其他部分的关联 - **课程系统**: 单元名称需保持一致 - **个人档案**: 可作为学习成果展示 - **可点击项目**: 两者独立,互不影响 ### 版本更新记录 - v2.5 (2025-09-16): 重构第十三节为"我完成的项目"板块数据替换实战指南 - 记录完整的问题解决历程和多次尝试过程 - 提供正确的clickableProjects数据结构示例 - 详细说明handleProjectClick函数逻辑 - 明确content字段vs detailContent字段的使用 - 添加问题排查清单和注意事项 - v2.4 (2025-09-16): 新增第十四节:"我完成的项目库"板块数据逻辑与替换指南 - 说明通用的数据结构和替换方法 - 提供脚本模板和处理流程 - 列出常见问题的通用解决方案 - v2.3 (2025-09-16): 添加项目库页面数据替换详细问题记录和解决方案 - 问题13:项目库页面数据引用错误合集(8个子问题) - 13.1:项目名称显示undefined - 字段名错误 - 13.2:岗位等级标签颜色错误 - 等级名称不匹配 - 13.3:对应单元分类错误 - 缺少映射函数 - 13.4:单元点击功能缺失 - 未实现handleUnitClick - 13.5:单元hover效果缺失 - 缺少CSS类名 - 13.6:适用岗位未排序 - 缺少排序逻辑 - 13.7:Markdown内容多余标题 - 格式处理不当 - 13.8:Mock文件语法错误 - 多余的]符号 - 新增第九节:项目库页面正确数据替换流程总结 - 问题14:修改版简历格式处理错误 - v2.2 (2025-09-15): 完善常见问题部分,添加问题10-12的详细解决方案 - 问题10:面试题卡片显示异常的解决方案 - 问题11:修改版标记显示错误的处理方法 - 问题12:岗位等级标签配置指南 - v2.1 (2025-09-15): 添加日历数据替换问题及解决方案,更新为智能开发产业 - v2.0 (2024-09-15): 完善数据架构文档,添加详细替换步骤 - v1.0 (2024-09-01): 初始版本