智慧教务系统
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

436 lines
16 KiB

<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的多应用管理平台
// +----------------------------------------------------------------------
// | 官方网址:https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\service\api\apiService;
use core\base\BaseApiService;
use think\facade\Db;
/**
* 教练端学员服务层
* Class CoachStudentService
* @package app\service\api\apiService
*/
class CoachStudentService extends BaseApiService
{
public function __construct()
{
parent::__construct();
}
/**
* 获取教练端学员列表
* @param array $data
* @return array
*/
public function getMyStudents(array $data)
{
$res = [
'code' => 0,
'msg' => '操作失败',
'data' => []
];
try {
// 获取当前登录教练的ID
$coachId = $this->getCurrentCoachId();
if (empty($coachId)) {
$res['code'] = 1;
$res['data'] = [
'list' => [],
'total' => 0,
'page' => 1,
'limit' => 10,
'pages' => 0,
'has_more' => false
];
$res['msg'] = '获取成功';
return $res;
}
// 查询教练负责的所有学员ID
$studentIds = $this->getCoachStudentIds($coachId, $data);
if (empty($studentIds)) {
$res['code'] = 1;
$res['data'] = [
'list' => [],
'total' => 0,
'page' => 1,
'limit' => 10,
'pages' => 0,
'has_more' => false
];
$res['msg'] = '获取成功';
return $res;
}
// 构建学员基础查询条件
$where = [];
$where[] = ['s.deleted_at', '=', 0];
$where[] = ['s.id', 'in', $studentIds];
// 支持搜索参数
if (!empty($data['name'])) {
$where[] = ['s.name', 'like', '%' . $data['name'] . '%'];
}
if (!empty($data['phone'])) {
$where[] = ['s.contact_phone', 'like', '%' . $data['phone'] . '%'];
}
if (!empty($data['campus_id'])) {
$where[] = ['s.campus_id', '=', $data['campus_id']];
}
if (!empty($data['status'])) {
$where[] = ['s.status', '=', $data['status']];
}
// 分页参数处理
$page = max(1, intval($data['page'] ?? 1));
$limit = max(1, min(50, intval($data['limit'] ?? 10))); // 限制每页最多50条
// 查询总数
$total = Db::table('school_student s')
->leftJoin('school_campus c', 's.campus_id = c.id')
->where($where)
->count();
// 查询学员基础信息(分页)
$list = Db::table('school_student s')
->leftJoin('school_campus c', 's.campus_id = c.id')
->where($where)
->field('s.*, c.campus_name as campus')
->order('s.created_at', 'desc')
->page($page, $limit)
->select()
->toArray();
// 为每个学员添加教练专属信息
foreach ($list as &$student) {
// 获取学员最新有效的课程信息
$courseInfo = $this->getStudentLatestCourse($student['id']);
$student = array_merge($student, $courseInfo);
// 获取教练与学员的关系信息
$coachRelation = $this->getCoachStudentRelation($coachId, $student['id']);
$student = array_merge($student, $coachRelation);
// 查询该学员的课程安排记录,按日期排序获取一访和二访信息
$visitRecords = Db::table('school_person_course_schedule pcs')
->leftJoin('school_course_schedule cs', 'pcs.schedule_id = cs.id')
->where([
['pcs.student_id', '=', $student['id']],
['pcs.person_type', '=', 'student'],
['pcs.deleted_at', '=', 0],
['cs.deleted_at', '=', 0]
])
->where(function($query) use ($coachId) {
$query->where('cs.coach_id', $coachId)
->whereOr('cs.education_id', $coachId);
})
->field('pcs.*, cs.course_date, cs.start_time, cs.end_time')
->order('cs.course_date', 'asc')
->select()
->toArray();
// 初始化到访信息
$student['first_visit_time'] = '';
$student['second_visit_time'] = '';
$student['first_visit_status'] = '未到访';
$student['second_visit_status'] = '未到访';
// 设置一访和二访信息
if (!empty($visitRecords)) {
if (isset($visitRecords[0])) {
$student['first_visit_time'] = $visitRecords[0]['course_date'];
$student['first_visit_status'] = '已到访';
}
if (isset($visitRecords[1])) {
$student['second_visit_time'] = $visitRecords[1]['course_date'];
$student['second_visit_status'] = '已到访';
}
}
// 保留原始访问记录数据供前端使用
$student['visit_records'] = $visitRecords;
// 计算教练相关的课时统计
$student['coach_class_count'] = count($visitRecords);
$student['total_class_hours'] = array_sum(array_column($visitRecords, 'class_hours'));
}
$res['code'] = 1;
$res['data'] = [
'list' => $list,
'total' => $total,
'page' => $page,
'limit' => $limit,
'pages' => ceil($total / $limit),
'has_more' => $page * $limit < $total
];
} catch (\Exception $e) {
$res['msg'] = '获取失败:' . $e->getMessage();
}
return $res;
}
/**
* 获取教练负责的学员ID集合(带缓存)
* @param int $coachId 教练ID
* @param array $data 查询条件
* @return array
*/
private function getCoachStudentIds($coachId, $data = [])
{
// 检查缓存
$cacheKey = "coach_student_ids:{$coachId}";
$cachedIds = cache($cacheKey);
if ($cachedIds !== null && is_array($cachedIds)) {
return $cachedIds;
}
// 1. 从 school_student_courses 表中查询相关学员
$courseStudentIds = Db::table('school_student_courses')
->where(function($query) use ($coachId) {
$query->where('main_coach_id', $coachId)
->whereOr('education_id', $coachId)
->whereOr(function($q) use ($coachId) {
// 查询 assistant_ids 字段中包含当前教练ID的记录
$q->whereNotNull('assistant_ids')
->where('assistant_ids', '<>', '')
->whereRaw("FIND_IN_SET(?, assistant_ids)", [$coachId]);
});
})
->column('student_id');
// 2. 从 school_person_course_schedule 和 school_course_schedule 表联查,获取教练负责的学员
$scheduleStudentIds = Db::table('school_person_course_schedule pcs')
->leftJoin('school_course_schedule cs', 'pcs.schedule_id = cs.id')
->where(function($query) use ($coachId) {
$query->where('cs.education_id', $coachId)
->whereOr('cs.coach_id', $coachId)
->whereOr(function($q) use ($coachId) {
// 查询 assistant_ids 字段中包含当前教练ID的记录
$q->whereNotNull('cs.assistant_ids')
->where('cs.assistant_ids', '<>', '')
->whereRaw("FIND_IN_SET(?, cs.assistant_ids)", [$coachId]);
});
})
->where('pcs.person_type', 'student')
->where('pcs.deleted_at', 0)
->where('cs.deleted_at', 0)
->column('pcs.student_id');
// 3. 合并并去重学生ID
$allStudentIds = array_merge($courseStudentIds, $scheduleStudentIds);
$uniqueStudentIds = array_unique($allStudentIds);
$result = array_values($uniqueStudentIds);
// 4. 缓存结果(1小时 = 3600秒)
cache($cacheKey, $result, 3600);
return $result;
}
/**
* 获取学员最新有效的课程信息
* @param int $studentId 学员ID
* @return array
*/
private function getStudentLatestCourse($studentId)
{
// 先从学员课程表获取课程信息
$courseInfo = Db::table('school_student_courses sc')
->leftJoin('school_course c', 'sc.course_id = c.id')
->where([
['sc.student_id', '=', $studentId]
])
->field('sc.total_hours, sc.gift_hours, sc.use_total_hours, sc.use_gift_hours, sc.end_date, sc.resource_id, c.course_name')
->order('sc.created_at', 'desc')
->find();
// 获取学员对应的资源分配ID (resource_sharing_id)
$resourceSharingId = 0;
// 获取学员的user_id
$student = Db::table('school_student')
->where('id', $studentId)
->field('user_id')
->find();
if (!empty($student['user_id'])) {
// 通过学员的user_id查找客户资源记录
$customerResource = Db::table('school_customer_resources')
->where('member_id', $student['user_id'])
->where('deleted_at', 0)
->field('id')
->order('created_at', 'desc')
->find();
if (!empty($customerResource)) {
// 通过客户资源ID查找资源分配记录
// resource_sharing_id 是 school_resource_assignment 表的 id
$resourceAssignment = Db::table('school_resource_assignment')
->where('resource_id', $customerResource['id'])
->field('id')
->order('assigned_at', 'desc')
->find();
if (!empty($resourceAssignment)) {
$resourceSharingId = $resourceAssignment['id'];
}
}
}
if (empty($courseInfo)) {
return [
'total_hours' => 0,
'gift_hours' => 0,
'use_total_hours' => 0,
'use_gift_hours' => 0,
'end_date' => '',
'resource_sharing_id' => $resourceSharingId,
'course_name' => ''
];
}
// 返回课程信息,包含resource_sharing_id
return [
'total_hours' => $courseInfo['total_hours'] ?? 0,
'gift_hours' => $courseInfo['gift_hours'] ?? 0,
'use_total_hours' => $courseInfo['use_total_hours'] ?? 0,
'use_gift_hours' => $courseInfo['use_gift_hours'] ?? 0,
'end_date' => $courseInfo['end_date'] ?? '',
'resource_sharing_id' => $resourceSharingId,
'course_name' => $courseInfo['course_name'] ?? ''
];
}
/**
* 获取教练与学员的关系信息
* @param int $coachId 教练ID
* @param int $studentId 学员ID
* @return array
*/
private function getCoachStudentRelation($coachId, $studentId)
{
// 检查教练在学员课程中的角色
$courseRelation = Db::table('school_student_courses')
->where('student_id', $studentId)
->where(function($query) use ($coachId) {
$query->where('main_coach_id', $coachId)
->whereOr('education_id', $coachId);
})
->field('main_coach_id, education_id')
->find();
$relation_type = '';
if (!empty($courseRelation)) {
if ($courseRelation['main_coach_id'] == $coachId) {
$relation_type = '主教练';
} elseif ($courseRelation['education_id'] == $coachId) {
$relation_type = '教务';
}
}
// 如果没有在课程表中找到关系,检查课程安排表
if (empty($relation_type)) {
$scheduleRelation = Db::table('school_person_course_schedule pcs')
->leftJoin('school_course_schedule cs', 'pcs.schedule_id = cs.id')
->where('pcs.student_id', $studentId)
->where('pcs.person_type', 'student')
->where('pcs.deleted_at', 0)
->where('cs.deleted_at', 0)
->where(function($query) use ($coachId) {
$query->where('cs.coach_id', $coachId)
->whereOr('cs.education_id', $coachId);
})
->field('cs.coach_id, cs.education_id')
->find();
if (!empty($scheduleRelation)) {
if ($scheduleRelation['coach_id'] == $coachId) {
$relation_type = '授课教练';
} elseif ($scheduleRelation['education_id'] == $coachId) {
$relation_type = '教务';
}
}
}
return [
'coach_relation_type' => $relation_type ?: '相关教练'
];
}
/**
* 获取当前登录教练ID
* @return int
*/
private function getCurrentCoachId()
{
try {
// 从请求头获取token
$token = request()->header('token') ?: request()->header('Authorization');
if (empty($token)) {
return 0;
}
// 去掉Bearer前缀
$token = str_replace('Bearer ', '', $token);
// 使用项目的TokenAuth类解析token,类型为personnel(员工端)
$tokenInfo = \core\util\TokenAuth::parseToken($token, 'personnel');
if (!empty($tokenInfo)) {
// 从jti中提取用户ID(格式:用户ID_类型)
$jti = $tokenInfo['jti'] ?? '';
if (!empty($jti)) {
$parts = explode('_', $jti);
if (count($parts) >= 2) {
return (int)$parts[0];
}
}
}
return 0;
} catch (\Exception $e) {
return 0;
}
}
/**
* 清除教练学员关系缓存
* @param int|array $coachId 教练ID或教练ID数组
* @return bool
*/
public static function clearCoachStudentCache($coachId)
{
try {
if (is_array($coachId)) {
// 批量清除缓存
foreach ($coachId as $id) {
cache("coach_student_ids:{$id}", null);
}
} else {
// 清除单个教练缓存
cache("coach_student_ids:{$coachId}", null);
}
return true;
} catch (\Exception $e) {
return false;
}
}
}