377 lines
11 KiB
JavaScript
377 lines
11 KiB
JavaScript
// 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,
|
|
};
|