Files
gongxue-base/apps/admin/src/components/StudentProfileContent/shared.ts

217 lines
5.9 KiB
TypeScript

export interface StudentInfo {
id: number;
name: string;
phone: string;
idNumber: string;
studentNo: string;
gender?: string;
ethnicity?: string;
emergencyContact?: string;
emergencyPhone?: string;
organizationId?: number;
organization?: { id?: number; name?: string } | null;
supervisor?: string;
status: string;
}
export interface ProfileData {
targetCollege?: string;
targetMajor?: string;
collegeSchool?: string;
collegeMajor?: string;
subjectDirection?: string;
grade?: string;
profileDate?: string;
notes?: string;
}
export interface EnrollmentRecord {
id: number;
courseCategory: string;
classType: string;
className?: string;
headTeacher?: string;
subjectTeacher?: string;
startDate?: string;
endDate?: string;
status: string;
}
export interface ExamScoreRecord {
id: number;
status?: string;
examId?: number;
exam?: { class?: { name?: string } };
examType: string;
examName?: string;
subject: string;
score: number | null;
classAvg?: number;
rank?: number;
examDate?: string;
enrollmentId?: number;
}
export interface LearningRecord {
id: number;
status?: string;
recordDate: string;
recordType: string;
content: string;
followUpMethod?: string;
nextStep?: string;
}
export interface ResultData {
cultureFinalScore?: number;
professionalFinalScore?: number;
admissionStatus?: string;
admittedCollege?: string;
admittedMajor?: string;
}
export interface AttachmentRecord {
id: number;
status?: string;
category: string;
fileName: string;
fileSize: number;
}
export interface AttendanceRecordItem {
id: number;
attendanceDate: string;
session: string;
status: string;
source?: string;
remark?: string | null;
punchTime?: string | null;
punchDeviceName?: string | null;
punchDeviceId?: string | null;
schedule?: { subject?: string } | null;
class?: { name?: string } | null;
}
export interface StudentProfileAggregate {
student: StudentInfo;
profile: ProfileData | null;
enrollments: EnrollmentRecord[];
examScores: ExamScoreRecord[];
learningRecords: LearningRecord[];
result: ResultData | null;
attachments: AttachmentRecord[];
attendances: AttendanceRecordItem[];
}
export interface StudentProfileContentProps {
studentId: number;
inDrawer?: boolean;
onClose?: () => void;
}
export const ADMISSION_STATUS_MAP: Record<string, { text: string; color: string }> = {
admitted: { text: '已录取', color: 'green' },
pending: { text: '待录取', color: 'orange' },
rejected: { text: '未录取', color: 'red' },
withdrawn: { text: '放弃', color: '#999' },
};
export const EXAM_TYPE_OPTIONS = [
{ value: 'monthly', label: '月考' },
{ value: 'midterm', label: '期中' },
{ value: 'final', label: '期末' },
{ value: 'mock', label: '模拟考' },
{ value: 'entrance', label: '入学测试' },
{ value: 'other', label: '其他' },
];
export const RECORD_TYPE_OPTIONS = [
{ value: 'study_feedback', label: '学习反馈' },
{ value: 'parent_communication', label: '家长沟通' },
{ value: 'behavior_note', label: '行为记录' },
{ value: 'meeting', label: '会议记录' },
{ value: 'other', label: '其他' },
];
export const ENROLLMENT_STATUS_MAP: Record<string, { text: string; color: string }> = {
active: { text: '报读中', color: 'green' },
completed: { text: '已结课', color: 'blue' },
withdrawn: { text: '已退训', color: 'red' },
archived: { text: '已归档', color: '#999' },
};
export const COURSE_CATEGORY_OPTIONS = [
{ value: 'culture', label: '文化课' },
{ value: 'professional', label: '专业课' },
{ value: 'comprehensive', label: '综合' },
];
export const CLASS_TYPE_OPTIONS = [
{ value: 'one_on_one', label: '一对一' },
{ value: 'small_group', label: '小班' },
{ value: 'large_class', label: '大班' },
{ value: 'online', label: '线上' },
{ value: 'offline', label: '线下' },
];
export const getOptionLabel = (
options: Array<{ value: string; label: string }>,
value?: string | null,
): string => {
if (!value) return '-';
return options.find((option) => option.value === value)?.label || value;
};
export const getCourseCategoryLabel = (value?: string | null): string =>
getOptionLabel(COURSE_CATEGORY_OPTIONS, value);
export const getClassTypeLabel = (value?: string | null): string =>
getOptionLabel(CLASS_TYPE_OPTIONS, value);
export const getEnrollmentStatus = (value?: string | null): { text: string; color: string } => {
if (!value) return { text: '-', color: 'default' };
return ENROLLMENT_STATUS_MAP[value] || { text: value, color: 'default' };
};
export const formatEnrollmentDisplayName = (enrollment: EnrollmentRecord): string =>
enrollment.className ||
(enrollment.courseCategory
? getCourseCategoryLabel(enrollment.courseCategory)
: String(enrollment.id));
export const ATTACHMENT_CATEGORY_OPTIONS = [
{ value: 'id_card', label: '身份证' },
{ value: 'transcript', label: '成绩单' },
{ value: 'certificate', label: '证书' },
{ value: 'contract', label: '合同' },
{ value: 'photo', label: '照片' },
{ value: 'other', label: '其他' },
];
export const formatFileSize = (bytes: number): string => {
if (bytes < 1024) return `${bytes} B`;
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
};
export const ATTENDANCE_STATUS_MAP: Record<string, { text: string; color: string }> = {
present: { text: '出勤', color: 'green' },
late: { text: '迟到', color: 'orange' },
absent: { text: '缺勤', color: 'red' },
leave: { text: '请假', color: 'blue' },
pending: { text: '待确认', color: 'default' },
};
export const SESSION_LABELS: Record<string, string> = {
morning_reading: '早自习',
morning: '上午',
afternoon: '下午',
evening_study: '晚自习',
night_check: '晚寝',
};
export interface TabProps {
studentId: number;
onRefresh: () => void;
}