152 lines
5.1 KiB
Python
152 lines
5.1 KiB
Python
"""统计分析模块出入参(需求 2.6)。"""
|
||||
|
|
|
|||
|
|
from __future__ import annotations
|
|||
|
|
|
|||
|
|
from datetime import date
|
|||
|
|
from typing import Any
|
|||
|
|
|
|||
|
|
from pydantic import BaseModel, Field
|
|||
|
|
|
|||
|
|
|
|||
|
|
class ClassOverviewItem(BaseModel):
|
|||
|
|
"""2.6.1 多维度班级统计:每班总人数 + 男女分布。"""
|
|||
|
|
|
|||
|
|
class_id: int
|
|||
|
|
class_no: str
|
|||
|
|
class_name: str
|
|||
|
|
status_text: str | None = None
|
|||
|
|
head_teacher_name: str | None = None
|
|||
|
|
total: int = Field(0, description="总人数")
|
|||
|
|
male: int = Field(0, description="男生数")
|
|||
|
|
female: int = Field(0, description="女生数")
|
|||
|
|
other: int = Field(0, description="未标注性别人数")
|
|||
|
|
|
|||
|
|
|
|||
|
|
class AllAboveItem(BaseModel):
|
|||
|
|
"""2.6.2 每次考试都过线的学生。"""
|
|||
|
|
|
|||
|
|
stu_id: int
|
|||
|
|
stu_no: str
|
|||
|
|
name: str
|
|||
|
|
class_name: str | None = None
|
|||
|
|
exam_count: int = Field(0, description="参加考核次数")
|
|||
|
|
min_score: float = Field(0, description="最低分(就是它决定了过线)")
|
|||
|
|
avg_score: float = Field(0, description="平均分")
|
|||
|
|
scores: list[dict[str, Any]] = Field(default_factory=list, description="各次成绩明细")
|
|||
|
|
|
|||
|
|
|
|||
|
|
class FailDetailItem(BaseModel):
|
|||
|
|
"""2.6.2 不及格明细。"""
|
|||
|
|
|
|||
|
|
stu_id: int
|
|||
|
|
stu_no: str
|
|||
|
|
name: str
|
|||
|
|
class_name: str | None = None
|
|||
|
|
fail_times: int = Field(0, description="不及格次数")
|
|||
|
|
fail_details: list[dict[str, Any]] = Field(default_factory=list, description="不及格场次明细")
|
|||
|
|
|
|||
|
|
|
|||
|
|
class ClassAvgScoreItem(BaseModel):
|
|||
|
|
"""2.6.2 每场考试每个班级的平均分。"""
|
|||
|
|
|
|||
|
|
exam_seq: int
|
|||
|
|
class_id: int | None = None
|
|||
|
|
class_name: str | None = None
|
|||
|
|
student_count: int = Field(0, description="参考人数")
|
|||
|
|
avg_score: float = Field(0, description="平均分")
|
|||
|
|
max_score: float = 0
|
|||
|
|
min_score: float = 0
|
|||
|
|
pass_rate: float = Field(0, description="及格率 %")
|
|||
|
|
|
|||
|
|
|
|||
|
|
class SalaryTopItem(BaseModel):
|
|||
|
|
"""2.6.3 就业薪资 Top N。"""
|
|||
|
|
|
|||
|
|
rank: int
|
|||
|
|
stu_id: int
|
|||
|
|
stu_no: str
|
|||
|
|
name: str
|
|||
|
|
class_name: str | None = None
|
|||
|
|
company: str | None = None
|
|||
|
|
salary: float = 0
|
|||
|
|
salary_wan: float = 0
|
|||
|
|
offer_date: date | None = None
|
|||
|
|
duration_days: int | None = None
|
|||
|
|
|
|||
|
|
|
|||
|
|
class StudentDurationItem(BaseModel):
|
|||
|
|
"""2.6.3 每个学生的就业时长。"""
|
|||
|
|
|
|||
|
|
stu_id: int
|
|||
|
|
stu_no: str
|
|||
|
|
name: str
|
|||
|
|
class_name: str | None = None
|
|||
|
|
company: str | None = None
|
|||
|
|
open_date: date | None = None
|
|||
|
|
offer_date: date | None = None
|
|||
|
|
duration_days: int | None = Field(None, description="offer 时间 - 开放时间(天)")
|
|||
|
|
state: str = Field("", description="就业中 / 已拿到 offer")
|
|||
|
|
|
|||
|
|
|
|||
|
|
class ClassAvgDurationItem(BaseModel):
|
|||
|
|
"""2.6.3 每个班级的平均就业时长。"""
|
|||
|
|
|
|||
|
|
class_id: int | None = None
|
|||
|
|
class_name: str | None = None
|
|||
|
|
student_count: int = Field(0, description="班级总人数")
|
|||
|
|
open_count: int = Field(0, description="已开放就业的人数(统计基数)")
|
|||
|
|
offer_count: int = Field(0, description="已下发 offer 的人数")
|
|||
|
|
avg_duration_days: float | None = Field(None, description="平均就业时长(天)")
|
|||
|
|
min_duration_days: int | None = None
|
|||
|
|
max_duration_days: int | None = None
|
|||
|
|
|
|||
|
|
|
|||
|
|
class VolatilityItem(BaseModel):
|
|||
|
|
"""2.7.2 成绩波动分析。"""
|
|||
|
|
|
|||
|
|
rank: int
|
|||
|
|
stu_id: int
|
|||
|
|
stu_no: str
|
|||
|
|
name: str
|
|||
|
|
class_name: str | None = None
|
|||
|
|
exam_count: int = 0
|
|||
|
|
avg_score: float = 0
|
|||
|
|
stddev: float = Field(0, description="成绩标准差")
|
|||
|
|
score_range: float = Field(0, description="最大分差 max-min")
|
|||
|
|
trend: str = Field("", description="上升 / 下降 / 基本持平(按最小二乘斜率,阈值 ±1 分/场)")
|
|||
|
|
trend_slope: float = Field(0, description="成绩趋势斜率,单位:分/场(对考核序次做最小二乘拟合)")
|
|||
|
|
scores: list[float] = Field(default_factory=list, description="按序次排列的成绩")
|
|||
|
|
|
|||
|
|
|
|||
|
|
class FunnelItem(BaseModel):
|
|||
|
|
"""2.7.2 班级就业漏斗。"""
|
|||
|
|
|
|||
|
|
class_id: int
|
|||
|
|
class_no: str
|
|||
|
|
class_name: str
|
|||
|
|
total: int = Field(0, description="总人数")
|
|||
|
|
employed: int = Field(0, description="已就业人数(拿到 offer)")
|
|||
|
|
high_salary: int = Field(0, description="高薪人数(>= 高薪线)")
|
|||
|
|
employment_rate: float = Field(0, description="就业率 %")
|
|||
|
|
high_salary_rate: float = Field(0, description="高薪占已就业比例 %")
|
|||
|
|
avg_salary: float | None = Field(None, description="已就业学生平均薪资")
|
|||
|
|
avg_duration_days: float | None = Field(None, description="平均就业时长(天)")
|
|||
|
|
|
|||
|
|
|
|||
|
|
class OverviewOut(BaseModel):
|
|||
|
|
"""仪表盘概览。"""
|
|||
|
|
|
|||
|
|
student_total: int = 0
|
|||
|
|
student_by_status: dict[str, int] = Field(default_factory=dict, description="各状态人数")
|
|||
|
|
class_total: int = 0
|
|||
|
|
teacher_total: int = 0
|
|||
|
|
advisor_total: int = 0
|
|||
|
|
employment_total: int = 0
|
|||
|
|
employment_rate: float = Field(0, description="整体就业率 %")
|
|||
|
|
avg_salary: float | None = None
|
|||
|
|
high_salary_count: int = 0
|
|||
|
|
score_record_total: int = 0
|
|||
|
|
score_avg: float | None = None
|
|||
|
|
warning_student_count: int = Field(0, description="存在红线预警的学生数")
|
|||
|
|
top_classes: list[dict[str, Any]] = Field(default_factory=list, description="就业率前 5 班级")
|