feat: 学生档案与报告生成
This commit is contained in:
216
apps/admin/src/components/StudentProfileContent/shared.ts
Normal file
216
apps/admin/src/components/StudentProfileContent/shared.ts
Normal file
@@ -0,0 +1,216 @@
|
||||
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;
|
||||
}
|
||||
Reference in New Issue
Block a user