初始化12个产业教务系统项目
主要内容: - 包含12个产业的完整教务系统前端代码 - 智能启动脚本 (start-industry.sh) - 可视化产业导航页面 (index.html) - 项目文档 (README.md) 优化内容: - 删除所有node_modules和.yoyo文件夹,从7.5GB减少到2.7GB - 添加.gitignore文件避免上传不必要的文件 - 自动依赖管理和智能启动系统 产业列表: 1. 文旅产业 (5150) 2. 智能制造 (5151) 3. 智能开发 (5152) 4. 财经商贸 (5153) 5. 视觉设计 (5154) 6. 交通物流 (5155) 7. 大健康 (5156) 8. 土木水利 (5157) 9. 食品产业 (5158) 10. 化工产业 (5159) 11. 能源产业 (5160) 12. 环保产业 (5161) 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
27
frontend_食品/src/utils/LinePathGenerator.js
Normal file
27
frontend_食品/src/utils/LinePathGenerator.js
Normal file
@@ -0,0 +1,27 @@
|
||||
// 贝塞尔曲线路径生成工具
|
||||
export const createLinePathForCurve = (
|
||||
fx, // 起始点 x 坐标
|
||||
fy, // 起始点 y 坐标
|
||||
tx, // 终点 x 坐标
|
||||
ty, // 终点 y 坐标
|
||||
toLeft = false // 是否向左连接
|
||||
) => {
|
||||
const __buff_x = tx - fx;
|
||||
const __buff_y = ty - fy;
|
||||
const startDirection_x = toLeft ? -100 : 100;
|
||||
const startDirection_y = 0;
|
||||
const endDirection_x = toLeft ? 100 : -100;
|
||||
const endDirection_y = 0;
|
||||
|
||||
const forceX = Math.min(200, Math.max(100, Math.abs(__buff_x / 2)));
|
||||
const forceY = Math.min(200, Math.max(100, Math.abs(__buff_y / 2)));
|
||||
const startForceX = startDirection_x / (Math.abs(startDirection_x) + Math.abs(startDirection_y)) * forceX;
|
||||
const startForceY = startDirection_y / (Math.abs(startDirection_x) + Math.abs(startDirection_y)) * forceY;
|
||||
const ctrl1 = {x: startForceX, y: startForceY};
|
||||
const endForceX = endDirection_x / (Math.abs(endDirection_x) + Math.abs(endDirection_y)) * forceX + __buff_x;
|
||||
const endForceY = endDirection_y / (Math.abs(endDirection_x) + Math.abs(endDirection_y)) * forceY + __buff_y;
|
||||
const ctrl2 = {x: endForceX, y: endForceY};
|
||||
|
||||
const path = `M ${Math.round(fx)},${Math.round(fy)} c ${Math.round(ctrl1.x)},${Math.round(ctrl1.y)} ${Math.round(ctrl2.x)},${Math.round(ctrl2.y)} ${Math.round(__buff_x)},${Math.round(__buff_y)}`;
|
||||
return path;
|
||||
};
|
||||
49
frontend_食品/src/utils/calendarEventStyles.js
Normal file
49
frontend_食品/src/utils/calendarEventStyles.js
Normal file
@@ -0,0 +1,49 @@
|
||||
import eventTypesData from "../../网页未导入数据/文旅产业/日历事项.json";
|
||||
|
||||
// 创建事项名称到样式的映射
|
||||
export const createEventStyleMapping = () => {
|
||||
const styleMapping = {};
|
||||
|
||||
eventTypesData.forEach(item => {
|
||||
styleMapping[item.事项名称] = {
|
||||
icon: item.icon,
|
||||
textColor: `#${item.字体颜色}`,
|
||||
backgroundColor: `#${item.事项背景色}`,
|
||||
name: item.事项名称
|
||||
};
|
||||
});
|
||||
|
||||
return styleMapping;
|
||||
};
|
||||
|
||||
// 根据事项标题获取样式
|
||||
export const getEventStyleByType = (eventType) => {
|
||||
// 事件类型到日历事项配置的映射
|
||||
const typeMapping = {
|
||||
'ai-course': 'AI课',
|
||||
'public-course': '企业高管公开课',
|
||||
'marketing-course': '营销课',
|
||||
'compound-skill': '复合能力课',
|
||||
'vertical-skill': '垂直能力课',
|
||||
'one-on-one': '1v1求职规划',
|
||||
'interview': '线下面试模拟'
|
||||
};
|
||||
|
||||
const styleMapping = createEventStyleMapping();
|
||||
const configName = typeMapping[eventType];
|
||||
|
||||
if (configName && styleMapping[configName]) {
|
||||
return styleMapping[configName];
|
||||
}
|
||||
|
||||
// 默认样式
|
||||
return {
|
||||
icon: null,
|
||||
textColor: '#1d2129',
|
||||
backgroundColor: '#f3f4f6',
|
||||
name: '其他'
|
||||
};
|
||||
};;
|
||||
|
||||
// 导出样式映射对象供其他地方使用
|
||||
export const EVENT_STYLE_MAPPING = createEventStyleMapping();
|
||||
376
frontend_食品/src/utils/dataMapper.js
Normal file
376
frontend_食品/src/utils/dataMapper.js
Normal file
@@ -0,0 +1,376 @@
|
||||
// Data mapping utilities for converting backend data to frontend format
|
||||
|
||||
// Map student data from backend to frontend format
|
||||
export const mapStudent = (backendData) => {
|
||||
if (!backendData) return null;
|
||||
|
||||
return {
|
||||
id: backendData.id,
|
||||
name: backendData.realName, // realName -> name
|
||||
studentId: backendData.studentNo, // studentNo -> studentId
|
||||
gender: backendData.gender === "MALE" ? "男" : "女",
|
||||
school: backendData.school,
|
||||
major: backendData.major,
|
||||
enrollDate: backendData.enrollDate,
|
||||
mbtiType: backendData.mbtiType,
|
||||
className: backendData.class?.name,
|
||||
classId: backendData.classId,
|
||||
stageName: backendData.currentStage?.name,
|
||||
stageId: backendData.currentStageId,
|
||||
// User info
|
||||
email: backendData.user?.email,
|
||||
phone: backendData.user?.phone,
|
||||
username: backendData.user?.username,
|
||||
lastLogin: backendData.user?.lastLogin,
|
||||
};
|
||||
};
|
||||
|
||||
// Map student list
|
||||
export const mapStudentList = (backendList) => {
|
||||
if (!Array.isArray(backendList)) return [];
|
||||
return backendList.map(mapStudent);
|
||||
};
|
||||
|
||||
// Map course data
|
||||
export const mapCourse = (backendData) => {
|
||||
if (!backendData) return null;
|
||||
|
||||
return {
|
||||
id: backendData.id,
|
||||
name: backendData.name,
|
||||
code: backendData.code,
|
||||
description: backendData.description,
|
||||
category: backendData.category,
|
||||
type: backendData.type,
|
||||
credits: backendData.credits,
|
||||
hours: backendData.hours,
|
||||
isAiCourse: backendData.isAiCourse,
|
||||
teacher: backendData.teacher
|
||||
? {
|
||||
id: backendData.teacher.id,
|
||||
name: backendData.teacher.realName,
|
||||
}
|
||||
: null,
|
||||
stage: backendData.stage,
|
||||
enrollmentCount:
|
||||
backendData.enrollmentCount || backendData._count?.enrollments || 0,
|
||||
};
|
||||
};
|
||||
|
||||
// Map course list
|
||||
export const mapCourseList = (backendList) => {
|
||||
if (!Array.isArray(backendList)) return [];
|
||||
return backendList.map(mapCourse);
|
||||
};
|
||||
|
||||
// Map job data
|
||||
export const mapJob = (backendData) => {
|
||||
if (!backendData) return null;
|
||||
|
||||
// Format salary range
|
||||
let salary = "面议";
|
||||
if (backendData.salaryMin && backendData.salaryMax) {
|
||||
const min = Math.floor(backendData.salaryMin / 1000);
|
||||
const max = Math.floor(backendData.salaryMax / 1000);
|
||||
salary = `${min}K-${max}K`;
|
||||
}
|
||||
|
||||
return {
|
||||
id: backendData.id,
|
||||
company: backendData.company,
|
||||
position: backendData.title, // title -> position
|
||||
description: backendData.description,
|
||||
requirements: backendData.requirements,
|
||||
responsibilities: backendData.responsibilities,
|
||||
companyName: backendData.company?.name || "",
|
||||
companyId: backendData.companyId,
|
||||
type: mapJobType(backendData.type),
|
||||
jobType: backendData.type === "INTERNSHIP" ? "internship" : "fulltime",
|
||||
level: backendData.level,
|
||||
location: backendData.location,
|
||||
salary: salary,
|
||||
salaryMin: backendData.salaryMin,
|
||||
salaryMax: backendData.salaryMax,
|
||||
benefits: backendData.benefits || [],
|
||||
skills: backendData.skills || [],
|
||||
isActive: backendData.isActive,
|
||||
status: backendData.isActive ? "available" : "closed",
|
||||
remainingPositions: backendData._count?.interviews || 5, // Mock remaining positions
|
||||
applicationStatus: "not_applied", // Default status
|
||||
tags: generateJobTags(backendData),
|
||||
deadline: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString(), // 30 days from now
|
||||
};
|
||||
};
|
||||
|
||||
// Map job list
|
||||
export const mapJobList = (backendList) => {
|
||||
if (!Array.isArray(backendList)) return [];
|
||||
return backendList.map(mapJob);
|
||||
};
|
||||
|
||||
// Map job type
|
||||
const mapJobType = (type) => {
|
||||
const typeMap = {
|
||||
FULLTIME: "全职",
|
||||
PARTTIME: "兼职",
|
||||
INTERNSHIP: "实习",
|
||||
CONTRACT: "合同制",
|
||||
REMOTE: "远程",
|
||||
};
|
||||
return typeMap[type] || type;
|
||||
};
|
||||
|
||||
// Generate job tags
|
||||
const generateJobTags = (job) => {
|
||||
const tags = [];
|
||||
if (job.location) tags.push(job.location.split("市")[0] + "市");
|
||||
if (job.type === "FULLTIME") tags.push("五险一金");
|
||||
if (job.benefits?.includes("双休")) tags.push("双休");
|
||||
if (job.benefits?.includes("弹性工作")) tags.push("弹性工作");
|
||||
return tags.slice(0, 4); // Max 4 tags
|
||||
};
|
||||
|
||||
// Map company data
|
||||
export const mapCompany = (backendData) => {
|
||||
if (!backendData) return null;
|
||||
|
||||
return {
|
||||
id: backendData.id,
|
||||
name: backendData.name,
|
||||
companyName: backendData.name, // Alias for compatibility
|
||||
description: backendData.description,
|
||||
industry: backendData.industry,
|
||||
scale: mapCompanyScale(backendData.scale),
|
||||
location: backendData.location,
|
||||
website: backendData.website,
|
||||
logo: backendData.logo,
|
||||
contact: backendData.contact,
|
||||
jobCount: backendData._count?.jobs || 0,
|
||||
jobs: backendData.jobs ? mapJobList(backendData.jobs) : [],
|
||||
};
|
||||
};
|
||||
|
||||
// Map company list
|
||||
export const mapCompanyList = (backendList) => {
|
||||
if (!Array.isArray(backendList)) return [];
|
||||
return backendList.map(mapCompany);
|
||||
};
|
||||
|
||||
// Map company scale
|
||||
const mapCompanyScale = (scale) => {
|
||||
const scaleMap = {
|
||||
SMALL: "50人以下",
|
||||
MEDIUM: "50-200人",
|
||||
LARGE: "200-1000人",
|
||||
ENTERPRISE: "1000人以上",
|
||||
};
|
||||
return scaleMap[scale] || scale;
|
||||
};
|
||||
|
||||
// Map resume data
|
||||
export const mapResume = (backendData) => {
|
||||
if (!backendData) return null;
|
||||
|
||||
return {
|
||||
id: backendData.id,
|
||||
title: backendData.title,
|
||||
content: backendData.content,
|
||||
isActive: backendData.isActive,
|
||||
version: backendData.version,
|
||||
student: backendData.student ? mapStudent(backendData.student) : null,
|
||||
studentId: backendData.studentId,
|
||||
createdAt: backendData.createdAt,
|
||||
updatedAt: backendData.updatedAt,
|
||||
};
|
||||
};
|
||||
|
||||
// Map interview data
|
||||
export const mapInterview = (backendData) => {
|
||||
if (!backendData) return null;
|
||||
|
||||
return {
|
||||
id: backendData.id,
|
||||
scheduledAt: backendData.scheduledAt,
|
||||
interviewTime: new Date(backendData.scheduledAt).toLocaleString("zh-CN"),
|
||||
type: backendData.type,
|
||||
status: backendData.status,
|
||||
location: backendData.location,
|
||||
notes: backendData.notes,
|
||||
feedback: backendData.feedback,
|
||||
result: backendData.result,
|
||||
student: backendData.student ? mapStudent(backendData.student) : null,
|
||||
job: backendData.job ? mapJob(backendData.job) : {
|
||||
// Provide default job object when no job relation exists
|
||||
salary: "面议",
|
||||
tags: [],
|
||||
company: { name: backendData.company || "" }
|
||||
},
|
||||
company: backendData.company || backendData.job?.company?.name || "",
|
||||
position: backendData.position || backendData.job?.title || "",
|
||||
// Map status for frontend
|
||||
statusText: mapInterviewStatus(backendData.status, backendData.result),
|
||||
};
|
||||
};
|
||||
|
||||
// Map interview list
|
||||
export const mapInterviewList = (backendList) => {
|
||||
if (!Array.isArray(backendList)) return [];
|
||||
return backendList.map(mapInterview);
|
||||
};
|
||||
|
||||
// Map interview status
|
||||
const mapInterviewStatus = (status, result) => {
|
||||
if (status === "COMPLETED") {
|
||||
if (result === "PASS" || result === "OFFER") return "面试成功";
|
||||
if (result === "FAIL") return "面试失败";
|
||||
return "已完成";
|
||||
}
|
||||
|
||||
const statusMap = {
|
||||
SCHEDULED: "待面试",
|
||||
CANCELLED: "已取消",
|
||||
NO_SHOW: "未到场",
|
||||
};
|
||||
return statusMap[status] || status;
|
||||
};
|
||||
|
||||
// Map enrollment data
|
||||
export const mapEnrollment = (backendData) => {
|
||||
if (!backendData) return null;
|
||||
|
||||
return {
|
||||
id: backendData.id,
|
||||
courseId: backendData.courseId,
|
||||
studentId: backendData.studentId,
|
||||
status: backendData.status,
|
||||
progress: backendData.progress || 0,
|
||||
score: backendData.score,
|
||||
enrolledAt: backendData.enrolledAt,
|
||||
completedAt: backendData.completedAt,
|
||||
course: backendData.course ? mapCourse(backendData.course) : null,
|
||||
student: backendData.student ? mapStudent(backendData.student) : null,
|
||||
// Map status for display
|
||||
statusText: mapEnrollmentStatus(backendData.status),
|
||||
};
|
||||
};
|
||||
|
||||
// Map enrollment status
|
||||
const mapEnrollmentStatus = (status) => {
|
||||
const statusMap = {
|
||||
NOT_STARTED: "未开始",
|
||||
IN_PROGRESS: "学习中",
|
||||
COMPLETED: "已完成",
|
||||
};
|
||||
return statusMap[status] || status;
|
||||
};
|
||||
|
||||
// Map class data
|
||||
export const mapClass = (backendData) => {
|
||||
if (!backendData) return null;
|
||||
|
||||
return {
|
||||
id: backendData.id,
|
||||
name: backendData.name,
|
||||
className: backendData.name, // Alias for compatibility
|
||||
description: backendData.description,
|
||||
startDate: backendData.startDate,
|
||||
endDate: backendData.endDate,
|
||||
isActive: backendData.isActive,
|
||||
teacher: backendData.teacher
|
||||
? {
|
||||
id: backendData.teacher.id,
|
||||
name: backendData.teacher.realName,
|
||||
}
|
||||
: null,
|
||||
studentCount: backendData._count?.students || 0,
|
||||
students: backendData.students ? mapStudentList(backendData.students) : [],
|
||||
};
|
||||
};
|
||||
|
||||
// Map stage data
|
||||
export const mapStage = (backendData) => {
|
||||
if (!backendData) return null;
|
||||
|
||||
return {
|
||||
id: backendData.id,
|
||||
name: backendData.name,
|
||||
description: backendData.description,
|
||||
order: backendData.order,
|
||||
duration: backendData.duration,
|
||||
requirements: backendData.requirements,
|
||||
courseCount: backendData._count?.courses || 0,
|
||||
studentCount: backendData._count?.students || 0,
|
||||
courses: backendData.courses ? mapCourseList(backendData.courses) : [],
|
||||
students: backendData.students ? mapStudentList(backendData.students) : [],
|
||||
};
|
||||
};
|
||||
|
||||
// Map learning record
|
||||
export const mapLearningRecord = (backendData) => {
|
||||
if (!backendData) return null;
|
||||
|
||||
return {
|
||||
id: backendData.id,
|
||||
studentId: backendData.studentId,
|
||||
courseId: backendData.courseId,
|
||||
date: backendData.date,
|
||||
duration: backendData.duration,
|
||||
progress: backendData.progress,
|
||||
content: backendData.content,
|
||||
};
|
||||
};
|
||||
|
||||
// Map profile data (for personal profile page)
|
||||
export const mapProfile = (studentData) => {
|
||||
if (!studentData) return null;
|
||||
|
||||
const mapped = mapStudent(studentData);
|
||||
|
||||
return {
|
||||
...mapped,
|
||||
avatar: "/api/placeholder/80/80", // Default avatar
|
||||
badges: {
|
||||
credits: 84, // Mock data, should come from backend
|
||||
classRank: 9, // Mock data, should come from backend
|
||||
mbti: studentData.mbtiType || "ENTP",
|
||||
},
|
||||
courses: studentData.enrollments
|
||||
? studentData.enrollments.map((e) => e.course?.name).filter(Boolean)
|
||||
: [],
|
||||
mbtiReport:
|
||||
studentData.mbtiReport || generateMockMBTIReport(studentData.mbtiType),
|
||||
};
|
||||
};
|
||||
|
||||
// Generate mock MBTI report (temporary until backend provides)
|
||||
const generateMockMBTIReport = (type) => {
|
||||
return {
|
||||
type: type || "ENTP",
|
||||
title: "Personality Type",
|
||||
description: "Your personality type description",
|
||||
characteristics: ["Creative", "Analytical", "Strategic"],
|
||||
strengths: ["Problem-solving", "Leadership", "Innovation"],
|
||||
recommendations: ["Focus on execution", "Develop patience", "Listen more"],
|
||||
careerSuggestions: ["Product Manager", "Consultant", "Entrepreneur"],
|
||||
};
|
||||
};
|
||||
|
||||
// Export all mappers
|
||||
export default {
|
||||
mapStudent,
|
||||
mapStudentList,
|
||||
mapCourse,
|
||||
mapCourseList,
|
||||
mapJob,
|
||||
mapJobList,
|
||||
mapCompany,
|
||||
mapCompanyList,
|
||||
mapResume,
|
||||
mapInterview,
|
||||
mapInterviewList,
|
||||
mapEnrollment,
|
||||
mapClass,
|
||||
mapStage,
|
||||
mapLearningRecord,
|
||||
mapProfile,
|
||||
};
|
||||
79
frontend_食品/src/utils/interviewQuestionMapper.js
Normal file
79
frontend_食品/src/utils/interviewQuestionMapper.js
Normal file
@@ -0,0 +1,79 @@
|
||||
import interviewQuestionsData from '@/data/interviewQuestions.json';
|
||||
|
||||
// 创建岗位群名称到面试题内容的映射
|
||||
const createInterviewQuestionsMap = () => {
|
||||
const map = {};
|
||||
|
||||
interviewQuestionsData.forEach(item => {
|
||||
// 根据岗位群名称创建映射
|
||||
map[item['岗位群名称']] = {
|
||||
groupName: item['岗位群名称'],
|
||||
questionTitle: item['面试题名称'],
|
||||
content: item['面试题内容']
|
||||
};
|
||||
});
|
||||
|
||||
return map;
|
||||
};
|
||||
|
||||
// 导出映射
|
||||
export const interviewQuestionsMap = createInterviewQuestionsMap();
|
||||
|
||||
// 根据岗位群名称获取面试题内容
|
||||
export const getInterviewQuestionsByGroup = (groupName) => {
|
||||
return interviewQuestionsMap[groupName] || null;
|
||||
};
|
||||
|
||||
// 将Markdown格式的内容解析为结构化数据(用于简单展示)
|
||||
export const parseInterviewContent = (content) => {
|
||||
if (!content) return [];
|
||||
|
||||
const sections = [];
|
||||
const lines = content.split('\n');
|
||||
let currentSection = null;
|
||||
let currentQuestion = null;
|
||||
|
||||
lines.forEach(line => {
|
||||
// 匹配一级标题(章节)
|
||||
if (line.startsWith('# ')) {
|
||||
if (currentSection) {
|
||||
sections.push(currentSection);
|
||||
}
|
||||
currentSection = {
|
||||
title: line.replace('# ', '').trim(),
|
||||
questions: []
|
||||
};
|
||||
currentQuestion = null;
|
||||
}
|
||||
// 匹配问题(数字开头)
|
||||
else if (/^\d+\.\s/.test(line)) {
|
||||
if (currentQuestion && currentSection) {
|
||||
currentSection.questions.push(currentQuestion);
|
||||
}
|
||||
currentQuestion = {
|
||||
question: line.replace(/^\d+\.\s/, '').trim(),
|
||||
answer: ''
|
||||
};
|
||||
}
|
||||
// 匹配答案或示例回答
|
||||
else if (line.includes('答案:') || line.includes('示例回答:') || line.includes('参考答案:')) {
|
||||
if (currentQuestion) {
|
||||
currentQuestion.answer = line.replace(/^(答案:|示例回答:|参考答案:)/, '').trim();
|
||||
}
|
||||
}
|
||||
// 继续收集答案内容
|
||||
else if (currentQuestion && currentQuestion.answer && line.trim()) {
|
||||
currentQuestion.answer += '\n' + line.trim();
|
||||
}
|
||||
});
|
||||
|
||||
// 添加最后的section和question
|
||||
if (currentQuestion && currentSection) {
|
||||
currentSection.questions.push(currentQuestion);
|
||||
}
|
||||
if (currentSection) {
|
||||
sections.push(currentSection);
|
||||
}
|
||||
|
||||
return sections;
|
||||
};
|
||||
93
frontend_食品/src/utils/interviewQuestionsFormatter.js
Normal file
93
frontend_食品/src/utils/interviewQuestionsFormatter.js
Normal file
@@ -0,0 +1,93 @@
|
||||
// 将面试题内容.json的Markdown格式转换为组件需要的结构化数据
|
||||
import interviewQuestionsData from '../data/interviewQuestions.json';
|
||||
|
||||
// 解析Markdown格式的面试题内容
|
||||
export const parseInterviewQuestions = (content) => {
|
||||
if (!content) return [];
|
||||
|
||||
const questions = [];
|
||||
const lines = content.split('\n').filter(line => line.trim());
|
||||
|
||||
let currentQuestion = null;
|
||||
let currentAnswer = '';
|
||||
let collectingAnswer = false;
|
||||
let questionIndex = 0;
|
||||
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const line = lines[i].trim();
|
||||
|
||||
// 跳过标题行
|
||||
if (line.startsWith('#')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 匹配问题(数字开头)
|
||||
if (/^\d+\.\s/.test(line)) {
|
||||
// 保存上一个问题
|
||||
if (currentQuestion && currentAnswer) {
|
||||
questions.push({
|
||||
id: `q${questionIndex}`,
|
||||
question: currentQuestion,
|
||||
answer: currentAnswer.trim()
|
||||
});
|
||||
questionIndex++;
|
||||
}
|
||||
|
||||
// 开始新问题
|
||||
currentQuestion = line.replace(/^\d+\.\s/, '').trim();
|
||||
currentAnswer = '';
|
||||
collectingAnswer = false;
|
||||
}
|
||||
// 匹配答案标记
|
||||
else if (line.includes('答案:') || line.includes('示例回答:') || line.includes('参考答案:')) {
|
||||
collectingAnswer = true;
|
||||
// 提取答案内容(可能在同一行)
|
||||
const answerMatch = line.match(/(?:答案:|示例回答:|参考答案:)(.*)/);
|
||||
if (answerMatch && answerMatch[1]) {
|
||||
currentAnswer = answerMatch[1].trim();
|
||||
}
|
||||
}
|
||||
// 收集答案内容
|
||||
else if (collectingAnswer && line) {
|
||||
// 如果是新的段落或列表项,添加换行
|
||||
if (currentAnswer && !line.startsWith('-') && !line.startsWith('•')) {
|
||||
currentAnswer += ' ';
|
||||
}
|
||||
currentAnswer += line;
|
||||
}
|
||||
}
|
||||
|
||||
// 保存最后一个问题
|
||||
if (currentQuestion && currentAnswer) {
|
||||
questions.push({
|
||||
id: `q${questionIndex}`,
|
||||
question: currentQuestion,
|
||||
answer: currentAnswer.trim()
|
||||
});
|
||||
}
|
||||
|
||||
return questions;
|
||||
};
|
||||
|
||||
// 创建岗位群到面试题的映射
|
||||
export const createInterviewQuestionsMap = () => {
|
||||
const map = {};
|
||||
|
||||
interviewQuestionsData.forEach(item => {
|
||||
const groupName = item['岗位群名称'];
|
||||
const questions = parseInterviewQuestions(item['面试题内容']);
|
||||
|
||||
// 只保留前10个问题(避免内容过多)
|
||||
map[groupName] = questions.slice(0, 10);
|
||||
});
|
||||
|
||||
return map;
|
||||
};
|
||||
|
||||
// 导出映射
|
||||
export const interviewQuestionsMap = createInterviewQuestionsMap();
|
||||
|
||||
// 根据岗位群名称获取格式化的面试题
|
||||
export const getFormattedQuestions = (groupName) => {
|
||||
return interviewQuestionsMap[groupName] || [];
|
||||
};
|
||||
84
frontend_食品/src/utils/request.js
Normal file
84
frontend_食品/src/utils/request.js
Normal file
@@ -0,0 +1,84 @@
|
||||
// 引入axios
|
||||
import axios from "axios";
|
||||
import store from "@/store/index";
|
||||
import {
|
||||
showGlobalLoading,
|
||||
hideGlobalLoading,
|
||||
} from "@/store/slices/loadingSlice";
|
||||
const baseURL = import.meta.env.VITE_API_BASE_URL || "http://localhost:3000";
|
||||
|
||||
// 全局加载状态loading,基于redux
|
||||
const handleGlobalLoading = (namespace, type) => {
|
||||
if (!namespace) return;
|
||||
store.dispatch(
|
||||
type === "show"
|
||||
? showGlobalLoading({ namespace })
|
||||
: hideGlobalLoading({ namespace })
|
||||
);
|
||||
};
|
||||
// 创建axios实例
|
||||
const axiosInstance = axios.create({
|
||||
baseURL, // 基础URL
|
||||
timeout: 10000, // 请求超时时间
|
||||
headers: {
|
||||
"Content-Type": "application/json;charset=utf-8",
|
||||
},
|
||||
});
|
||||
|
||||
// 请求拦截器
|
||||
axiosInstance.interceptors.request.use(
|
||||
(config) => {
|
||||
// 开发阶段使用固定的 x-user-id
|
||||
// 这个ID对应种子数据中的开发默认用户
|
||||
config.headers["x-user-id"] = "dev-user-id";
|
||||
|
||||
// 后续对接飞书后使用token
|
||||
// const token = localStorage.getItem("token");
|
||||
// if (token) {
|
||||
// config.headers["Authorization"] = `Bearer ${token}`;
|
||||
// }
|
||||
return config;
|
||||
},
|
||||
(error) => {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
// 响应拦截器
|
||||
axiosInstance.interceptors.response.use(
|
||||
(response) => {
|
||||
// 处理响应数据
|
||||
const res = response.data;
|
||||
return res;
|
||||
},
|
||||
(error) => {
|
||||
// 处理响应错误
|
||||
console.error("请求错误:", error);
|
||||
const message =
|
||||
error.response?.data?.message || error.message || "网络错误";
|
||||
return Promise.reject(new Error(message));
|
||||
}
|
||||
);
|
||||
|
||||
// 导出请求方法
|
||||
export default function request({
|
||||
url,
|
||||
apiUrl,
|
||||
namespace,
|
||||
method = "get",
|
||||
data,
|
||||
params,
|
||||
headers = {},
|
||||
}) {
|
||||
handleGlobalLoading(namespace, "show");
|
||||
// 返回Promise对象
|
||||
return axiosInstance({
|
||||
method,
|
||||
url: `${apiUrl ? apiUrl : baseURL}${url}`,
|
||||
data,
|
||||
params,
|
||||
headers,
|
||||
}).finally(() => {
|
||||
handleGlobalLoading(namespace, "hide");
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user