15 changed files with 530 additions and 52 deletions
@ -0,0 +1,53 @@ |
|||||
|
<?php |
||||
|
// +---------------------------------------------------------------------- |
||||
|
// | Niucloud-admin 企业快速开发的多应用管理平台 |
||||
|
// +---------------------------------------------------------------------- |
||||
|
// | 官方网址:https://www.niucloud.com |
||||
|
// +---------------------------------------------------------------------- |
||||
|
// | niucloud团队 版权所有 开源版本可自由商用 |
||||
|
// +---------------------------------------------------------------------- |
||||
|
// | Author: Niucloud Team |
||||
|
// +---------------------------------------------------------------------- |
||||
|
|
||||
|
namespace app\api\controller\apiController; |
||||
|
|
||||
|
use app\Request; |
||||
|
use app\service\api\apiService\CoachStudentService; |
||||
|
use core\base\BaseApiService; |
||||
|
|
||||
|
/** |
||||
|
* 教练端学员管理相关接口 |
||||
|
* Class CoachStudent |
||||
|
* @package app\api\controller\apiController |
||||
|
*/ |
||||
|
class CoachStudent extends BaseApiService |
||||
|
{ |
||||
|
/** |
||||
|
* 获取教练端学员列表 |
||||
|
* @param Request $request |
||||
|
* @return \think\Response |
||||
|
*/ |
||||
|
public function getMyStudents(Request $request) |
||||
|
{ |
||||
|
try { |
||||
|
$data = $this->request->params([ |
||||
|
["name", ""], // 学员姓名搜索 |
||||
|
["phone", ""], // 联系电话搜索 |
||||
|
["campus_id", 0], // 校区ID |
||||
|
["status", 0], // 学员状态 |
||||
|
["course_id", 0], // 课程ID搜索 |
||||
|
["class_id", 0], // 班级ID搜索 |
||||
|
["debug", false] // 调试模式 |
||||
|
]); |
||||
|
|
||||
|
$result = (new CoachStudentService())->getMyStudents($data); |
||||
|
if ($result['code'] === 1) { |
||||
|
return success('获取成功', $result['data']); |
||||
|
} else { |
||||
|
return fail($result['msg']); |
||||
|
} |
||||
|
} catch (\Exception $e) { |
||||
|
return fail('获取我的学员列表失败:' . $e->getMessage()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,381 @@ |
|||||
|
<?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'] = []; |
||||
|
$res['msg'] = '获取成功'; |
||||
|
return $res; |
||||
|
} |
||||
|
|
||||
|
// 查询教练负责的所有学员ID |
||||
|
$studentIds = $this->getCoachStudentIds($coachId, $data); |
||||
|
|
||||
|
if (empty($studentIds)) { |
||||
|
$res['code'] = 1; |
||||
|
$res['data'] = []; |
||||
|
$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']]; |
||||
|
} |
||||
|
|
||||
|
// 查询学员基础信息 |
||||
|
$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') |
||||
|
->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; |
||||
|
} catch (\Exception $e) { |
||||
|
$res['msg'] = '获取失败:' . $e->getMessage(); |
||||
|
} |
||||
|
|
||||
|
return $res; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取教练负责的学员ID集合 |
||||
|
* @param int $coachId 教练ID |
||||
|
* @param array $data 查询条件 |
||||
|
* @return array |
||||
|
*/ |
||||
|
private function getCoachStudentIds($coachId, $data = []) |
||||
|
{ |
||||
|
// 1. 从 school_student_courses 表中查询 main_coach_id 或 education_id 是当前教练的学员 |
||||
|
$courseStudentIds = Db::table('school_student_courses') |
||||
|
->where(function($query) use ($coachId) { |
||||
|
$query->where('main_coach_id', $coachId) |
||||
|
->whereOr('education_id', $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); |
||||
|
}) |
||||
|
->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); |
||||
|
|
||||
|
return array_values($uniqueStudentIds); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取学员最新有效的课程信息 |
||||
|
* @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 |
||||
|
$resourceSharingId = 0; |
||||
|
if (!empty($courseInfo) && !empty($courseInfo['resource_id'])) { |
||||
|
// 通过resource_id查找对应的资源共享记录,获取最新的一条 |
||||
|
$resourceSharing = Db::table('school_resource_sharing') |
||||
|
->where('resource_id', $courseInfo['resource_id']) |
||||
|
->field('id') |
||||
|
->order('shared_at', 'desc') |
||||
|
->find(); |
||||
|
|
||||
|
if (!empty($resourceSharing)) { |
||||
|
$resourceSharingId = $resourceSharing['id']; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 如果没有找到资源共享ID,尝试通过学员的user_id查找 |
||||
|
if (empty($resourceSharingId)) { |
||||
|
$student = Db::table('school_student') |
||||
|
->where('id', $studentId) |
||||
|
->field('user_id') |
||||
|
->find(); |
||||
|
|
||||
|
if (!empty($student['user_id'])) { |
||||
|
// 方法1:先尝试直接用user_id作为resource_id查找 |
||||
|
$resourceSharing = Db::table('school_resource_sharing') |
||||
|
->where('resource_id', $student['user_id']) |
||||
|
->field('id') |
||||
|
->order('shared_at', 'desc') |
||||
|
->find(); |
||||
|
|
||||
|
if (!empty($resourceSharing)) { |
||||
|
$resourceSharingId = $resourceSharing['id']; |
||||
|
} else { |
||||
|
// 方法2:通过客户资源表查找 |
||||
|
$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查找资源共享记录 |
||||
|
$resourceSharing = Db::table('school_resource_sharing') |
||||
|
->where('resource_id', $customerResource['id']) |
||||
|
->field('id') |
||||
|
->order('shared_at', 'desc') |
||||
|
->find(); |
||||
|
|
||||
|
if (!empty($resourceSharing)) { |
||||
|
$resourceSharingId = $resourceSharing['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; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue