417 lines
9.3 KiB
PHP
417 lines
9.3 KiB
PHP
<?php
|
||
|
||
namespace App\Models\Students;
|
||
|
||
use App\Models\BaseModel;
|
||
use App\Models\Students\StudentClass;
|
||
use App\Models\Schools\School;
|
||
use App\Models\Schools\SchoolClass;
|
||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||
use Illuminate\Notifications\Notifiable;
|
||
use Laravel\Sanctum\HasApiTokens;
|
||
|
||
/**
|
||
* 学生模型
|
||
* @package App\Models\Students
|
||
* @property int $id 主键ID
|
||
* @property string $username 用户名
|
||
* @property string|null $real_name 真实姓名
|
||
* @property string $password 密码
|
||
* @property string $salt 随机串
|
||
* @property int $role 所属角色(2:学生 3:家长)
|
||
* @property int $grade_id 年级ID
|
||
* @property int $parent_id 家长ID
|
||
* @property string|null $email 电子邮件
|
||
* @property string|null $phone_number 手机号
|
||
* @property string $title 头衔
|
||
* @property string $avatar 头像URL
|
||
* @property \Carbon\Carbon|null $reg_time 注册时间
|
||
* @property string|null $reg_ip 注册IP
|
||
* @property int $status 用户状态(0禁用1正常2欠费3未激活)
|
||
* @property int $vip_level 常规VIP等级
|
||
* @property int $sex 性别(1男2女0不填)
|
||
* @property string|null $qq QQ号
|
||
* @property string|null $examing_number 考号
|
||
*/
|
||
class Student extends Authenticatable
|
||
{
|
||
use HasApiTokens, Notifiable;
|
||
|
||
/**
|
||
* 数据表名
|
||
* @var string
|
||
*/
|
||
protected $table = 'student';
|
||
|
||
/**
|
||
* 主键
|
||
* @var string
|
||
*/
|
||
protected $primaryKey = 'id';
|
||
|
||
/**
|
||
* 关闭自动时间戳
|
||
* @var bool
|
||
*/
|
||
public $timestamps = false;
|
||
|
||
/**
|
||
* 可批量赋值的字段
|
||
* @var array
|
||
*/
|
||
protected $fillable = [
|
||
'username',
|
||
'real_name',
|
||
'password',
|
||
'salt',
|
||
'role',
|
||
'grade_id',
|
||
'parent_id',
|
||
'email',
|
||
'phone_number',
|
||
'title',
|
||
'avatar',
|
||
'reg_time',
|
||
'reg_ip',
|
||
'status',
|
||
'vip_level',
|
||
'sex',
|
||
'qq',
|
||
'examing_number'
|
||
];
|
||
|
||
/**
|
||
* 隐藏的字段
|
||
* @var array
|
||
*/
|
||
protected $hidden = [
|
||
'password',
|
||
'salt',
|
||
];
|
||
|
||
/**
|
||
* 字段类型转换
|
||
* @var array
|
||
*/
|
||
protected $casts = [
|
||
'reg_time' => 'datetime',
|
||
'role' => 'integer',
|
||
'grade_id' => 'integer',
|
||
'parent_id' => 'integer',
|
||
'status' => 'integer',
|
||
'vip_level' => 'integer',
|
||
'sex' => 'integer',
|
||
];
|
||
|
||
/**
|
||
* 角色常量
|
||
*/
|
||
const ROLE_STUDENT = 2; // 学生
|
||
const ROLE_PARENT = 3; // 家长
|
||
|
||
/**
|
||
* 状态常量
|
||
*/
|
||
const STATUS_DISABLED = 0; // 禁用
|
||
const STATUS_NORMAL = 1; // 正常
|
||
const STATUS_ARREARS = 2; // 欠费
|
||
const STATUS_INACTIVE = 3; // 未激活
|
||
|
||
/**
|
||
* 性别常量
|
||
*/
|
||
const SEX_UNKNOWN = 0; // 不填
|
||
const SEX_MALE = 1; // 男
|
||
const SEX_FEMALE = 2; // 女
|
||
|
||
/**
|
||
* 角色映射
|
||
* @var array
|
||
*/
|
||
public static $roleMap = [
|
||
self::ROLE_STUDENT => '学生',
|
||
self::ROLE_PARENT => '家长',
|
||
];
|
||
|
||
/**
|
||
* 状态映射
|
||
* @var array
|
||
*/
|
||
public static $statusMap = [
|
||
self::STATUS_DISABLED => '禁用',
|
||
self::STATUS_NORMAL => '正常',
|
||
self::STATUS_ARREARS => '欠费',
|
||
self::STATUS_INACTIVE => '未激活',
|
||
];
|
||
|
||
/**
|
||
* 性别映射
|
||
* @var array
|
||
*/
|
||
public static $sexMap = [
|
||
self::SEX_UNKNOWN => '不填',
|
||
self::SEX_MALE => '男',
|
||
self::SEX_FEMALE => '女',
|
||
];
|
||
|
||
/**
|
||
* 获取学生班级关联
|
||
* @return HasMany
|
||
*/
|
||
public function studentClasses(): HasMany
|
||
{
|
||
return $this->hasMany(StudentClass::class, 'student_id', 'id');
|
||
}
|
||
|
||
/**
|
||
* 获取学生所属班级(多对多)
|
||
* @return BelongsToMany
|
||
*/
|
||
public function classes(): BelongsToMany
|
||
{
|
||
return $this->belongsToMany(SchoolClass::class, 'student_class', 'student_id', 'class_id')
|
||
->withPivot(['join_time', 'leave_time', 'status', 'remark'])
|
||
->withTimestamps();
|
||
}
|
||
|
||
/**
|
||
* 获取家长关联(如果是学生)
|
||
* @return BelongsTo
|
||
*/
|
||
public function parent(): BelongsTo
|
||
{
|
||
return $this->belongsTo(Student::class, 'parent_id', 'id');
|
||
}
|
||
|
||
/**
|
||
* 获取子女关联(如果是家长)
|
||
* @return HasMany
|
||
*/
|
||
public function children(): HasMany
|
||
{
|
||
return $this->hasMany(Student::class, 'parent_id', 'id');
|
||
}
|
||
|
||
/**
|
||
* 只查询学生
|
||
* @param $query
|
||
* @return mixed
|
||
*/
|
||
public function scopeStudents($query)
|
||
{
|
||
return $query->where('role', self::ROLE_STUDENT);
|
||
}
|
||
|
||
/**
|
||
* 只查询家长
|
||
* @param $query
|
||
* @return mixed
|
||
*/
|
||
public function scopeParents($query)
|
||
{
|
||
return $query->where('role', self::ROLE_PARENT);
|
||
}
|
||
|
||
/**
|
||
* 只查询正常状态
|
||
* @param $query
|
||
* @return mixed
|
||
*/
|
||
public function scopeNormal($query)
|
||
{
|
||
return $query->where('status', self::STATUS_NORMAL);
|
||
}
|
||
|
||
/**
|
||
* 按年级过滤
|
||
* @param $query
|
||
* @param int $gradeId
|
||
* @return mixed
|
||
*/
|
||
public function scopeByGrade($query, int $gradeId)
|
||
{
|
||
return $query->where('grade_id', $gradeId);
|
||
}
|
||
|
||
/**
|
||
* 按性别过滤
|
||
* @param $query
|
||
* @param int $sex
|
||
* @return mixed
|
||
*/
|
||
public function scopeBySex($query, int $sex)
|
||
{
|
||
return $query->where('sex', $sex);
|
||
}
|
||
|
||
/**
|
||
* 获取角色名称
|
||
* @return string
|
||
*/
|
||
public function getRoleNameAttribute(): string
|
||
{
|
||
return self::$roleMap[$this->role] ?? '未知';
|
||
}
|
||
|
||
/**
|
||
* 获取状态名称
|
||
* @return string
|
||
*/
|
||
public function getStatusNameAttribute(): string
|
||
{
|
||
return self::$statusMap[$this->status] ?? '未知';
|
||
}
|
||
|
||
/**
|
||
* 获取性别名称
|
||
* @return string
|
||
*/
|
||
public function getSexNameAttribute(): string
|
||
{
|
||
return self::$sexMap[$this->sex] ?? '未知';
|
||
}
|
||
|
||
/**
|
||
* 获取头像URL(如果为空则返回默认头像)
|
||
* @return string
|
||
*/
|
||
public function getAvatarUrlAttribute(): string
|
||
{
|
||
return $this->avatar ?: '/images/default-avatar.png';
|
||
}
|
||
|
||
/**
|
||
* 检查是否为学生
|
||
* @return bool
|
||
*/
|
||
public function isStudent(): bool
|
||
{
|
||
return $this->role === self::ROLE_STUDENT;
|
||
}
|
||
|
||
/**
|
||
* 检查是否为家长
|
||
* @return bool
|
||
*/
|
||
public function isParent(): bool
|
||
{
|
||
return $this->role === self::ROLE_PARENT;
|
||
}
|
||
|
||
/**
|
||
* 检查是否为正常状态
|
||
* @return bool
|
||
*/
|
||
public function isNormal(): bool
|
||
{
|
||
return $this->status === self::STATUS_NORMAL;
|
||
}
|
||
|
||
/**
|
||
* 检查是否为男性
|
||
* @return bool
|
||
*/
|
||
public function isMale(): bool
|
||
{
|
||
return $this->sex === self::SEX_MALE;
|
||
}
|
||
|
||
/**
|
||
* 检查是否为女性
|
||
* @return bool
|
||
*/
|
||
public function isFemale(): bool
|
||
{
|
||
return $this->sex === self::SEX_FEMALE;
|
||
}
|
||
|
||
/**
|
||
* 获取当前所在班级
|
||
* @return SchoolClass|null
|
||
*/
|
||
public function getCurrentClass(): ?SchoolClass
|
||
{
|
||
$studentClass = $this->studentClasses()
|
||
->where('status', StudentClass::STATUS_NORMAL)
|
||
->whereNull('leave_time')
|
||
->first();
|
||
|
||
return $studentClass ? $studentClass->schoolClass : null;
|
||
}
|
||
|
||
/**
|
||
* 获取所有历史班级
|
||
* @return \Illuminate\Database\Eloquent\Collection
|
||
*/
|
||
public function getHistoryClasses()
|
||
{
|
||
return $this->classes()
|
||
->orderBy('student_class.join_time', 'desc')
|
||
->get();
|
||
}
|
||
|
||
/**
|
||
* 密码加密
|
||
* @param string $password
|
||
* @param string $salt
|
||
* @return string
|
||
*/
|
||
public static function encryptPassword(string $password, string $salt): string
|
||
{
|
||
return md5($password . $salt);
|
||
}
|
||
|
||
/**
|
||
* 验证密码
|
||
* @param string $password
|
||
* @return bool
|
||
*/
|
||
public function verifyPassword(string $password): bool
|
||
{
|
||
return $this->password === self::encryptPassword($password, $this->salt);
|
||
}
|
||
|
||
/**
|
||
* 生成随机盐值
|
||
* @return string
|
||
*/
|
||
public static function generateSalt(): string
|
||
{
|
||
return substr(md5(time() . mt_rand()), 0, 6);
|
||
}
|
||
|
||
/**
|
||
* 获取完整信息(包含班级、家长等)
|
||
* @return array
|
||
*/
|
||
public function getFullInfo(): array
|
||
{
|
||
$info = $this->toArray();
|
||
|
||
// 添加角色名称
|
||
$info['role_name'] = $this->role_name;
|
||
$info['status_name'] = $this->status_name;
|
||
$info['sex_name'] = $this->sex_name;
|
||
$info['avatar_url'] = $this->avatar_url;
|
||
|
||
// 添加当前班级信息
|
||
$currentClass = $this->getCurrentClass();
|
||
$info['current_class'] = $currentClass ? $currentClass->toArray() : null;
|
||
|
||
// 添加家长信息(如果是学生)
|
||
if ($this->isStudent() && $this->parent_id) {
|
||
$info['parent'] = $this->parent ? $this->parent->toArray() : null;
|
||
}
|
||
|
||
// 添加子女信息(如果是家长)
|
||
if ($this->isParent()) {
|
||
$info['children'] = $this->children->toArray();
|
||
}
|
||
|
||
return $info;
|
||
}
|
||
}
|