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']) ->where('assignee_type', 'user') ->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; } } }