智慧教务系统
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.
 
 
 
 
 
 

1595 lines
59 KiB

<?php
// +----------------------------------------------------------------------
// | Niucloud-admin 企业快速开发的多应用管理平台
// +----------------------------------------------------------------------
// | 官方网址:https://www.niucloud.com
// +----------------------------------------------------------------------
// | niucloud团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: Niucloud Team
// +----------------------------------------------------------------------
namespace app\service\api\apiService;
use app\model\campus_person_role\CampusPersonRole;
use app\model\course_schedule\CourseSchedule;
use app\model\person_course_schedule\PersonCourseSchedule;
use app\model\six_speed\SixSpeed;
use app\model\student_course_usage\StudentCourseUsage;
use app\model\student\Student;
use app\model\assignment\Assignment;
use app\model\course\Course;
use app\model\student_courses\StudentCourses;
use core\base\BaseApiService;
use DateTime;
use think\Model;
use think\facade\Db;
/**
* 员工服务层
* Class MemberService
* @package app\service\api\member
*/
class CourseService extends BaseApiService
{
public function __construct()
{
parent::__construct();
$this->model = new Course();
}
//课程列表
public function list($id, $data)
{
$campus_person_role = new CampusPersonRole();
$where = [];
if ($data['schedule_date']) {
$where[] = ['course_date', '=', $data['schedule_date']];
}
$campus_id = $campus_person_role->where(['person_id' => $id])->column('campus_id');
$CourseSchedule = new CourseSchedule();
$search_model = $CourseSchedule
->where('campus_id', 'in', $campus_id)
->where($where)
->with(['course' => function ($query) {
$query->select();
}, 'venue' => function ($query) {
$query->select();
}, 'campus', 'studentCourses']);
$list = $this->pageQuery($search_model);
foreach ($list['data'] as $k => $v) {
$student = Db::name('person_course_schedule')
->alias('pcs')
->where('pcs.schedule_id', $v['id']) // 建议加上表别名避免冲突
->join('school_student st', 'pcs.student_id = st.id')
->join('school_customer_resources cr', 'st.user_id = cr.id')
->join('school_member sm', 'cr.member_id = sm.member_id')
->field('st.name, sm.headimg as avatar') // 👈 正确方式取字段
->select();
$list['data'][$k]['student'] = $student;
}
return $list;
}
//获取课程详情
public function info($data)
{
$school_six_speed = new SixSpeed();
$CourseSchedule = new CourseSchedule();
$search_model = $CourseSchedule
->where('id', $data)
->with(['course' => function ($query) {
$query->select();
}, 'venue' => function ($query) {
$query->select();
}, 'coach' => function ($query) {
$query->select();
}]);
$list = $search_model->find();
$student = Db::name('person_course_schedule')
->alias('pcs')
->where('pcs.schedule_id', $list['id'])
->join('school_student st', 'pcs.student_id = st.id')
->join('school_customer_resources cr', 'st.user_id = cr.id')
->join('school_member sm', 'cr.member_id = sm.member_id')
->field('st.name, sm.headimg as avatar')
->select();
$list['student'] = $student;
$student_courses = Db::name('student_courses')
->alias('sc')
->where('sc.course_id', $list['id'])
->join('school_student_course_usage sscu', 'sc.id = sscu.student_course_id')
->field('sc.student_id,sc.end_date,sc.end_date,sc.start_date,sc.course_id')
->select()->toArray();
foreach ($student_courses as &$v) {
$student = Db::name('student')
->alias('st')
->where('st.id', $v['student_id'])
->join('school_customer_resources cr', 'st.user_id = cr.id')
->join('school_member sm', 'cr.member_id = sm.member_id')
->field('st.name, sm.headimg as avatar,cr.id as resources_id,cr.source')
->find();
if ($student) {
$v['school_six_speed'] = $school_six_speed->where(['staff_id' => $student['resources_id']])->find();
} else {
$v['school_six_speed'] = [];
}
$v['source'] = get_dict_value("source", $student['source']);
$v['name'] = $student['name'];
$v['avatar'] = $student['avatar'];
}
$list['student_courses'] = $student_courses;
$Assignment = new Assignment();
$search_model = $Assignment->where('course_id', $data)
->with(['student' => function ($query) {
$query->with(['customerResources' => function ($query) {
$query->with(['member' => function ($query) {
$query->select();
}]);
}]);
}]);
$search_model_res = $search_model->select()->toArray();
$groupedByStatus1 = [];
$groupedByStatus2 = [];
$groupedByStatus3 = [];
foreach ($search_model_res as $item) {
if ($item['status'] == 1) {
array_push($groupedByStatus1, $item);
} else if ($item['status'] == 2) {
array_push($groupedByStatus2, $item);
} else if ($item['status'] == 3) {
array_push($groupedByStatus3, $item);
}
}
$list['groupedByStatus1'] = $groupedByStatus1;
$list['groupedByStatus2'] = $groupedByStatus2;
$list['groupedByStatus3'] = $groupedByStatus3;
return $list;
}
public function classList($data)
{
$CourseSchedule = new CourseSchedule();
$search_model = $CourseSchedule
->where('coach_id', $data)
->with(['course' => function ($query) {
$query->with(['studentCourses' => function ($query) {
$query->select();
}]);
}, 'venue' => function ($query) {
$query->select();
}, 'coach' => function ($query) {
$query->select();
}, 'campus']);
$list = $this->pageQuery($search_model);
foreach ($list['data'] as &$v) {
$student = Db::name('person_course_schedule')
->alias('pcs')
->where('pcs.schedule_id', $v['id'])
->join('school_student st', 'pcs.student_id = st.id')
->join('school_customer_resources cr', 'st.user_id = cr.id')
->join('school_member sm', 'cr.member_id = sm.member_id')
->field('st.name, sm.headimg as avatar')
->select();
$v['student'] = $student;
}
foreach ($list['data'] as &$v) {
$student_courses = Db::name('student_courses')
->alias('sc')
->where('sc.course_id', $v['id'])
->join('school_student_course_usage sscu', 'sc.id = sscu.student_course_id')
->field('sc.student_id,sc.end_date,sc.end_date,sc.start_date,sc.course_id')
->select()->toArray();
$v['student_courses'] = $student_courses;
}
return $list;
}
//获取添加学员列表
public function StudentList($id)
{
$StudentCourses = new StudentCourses();
$PersonCourseSchedule = new PersonCourseSchedule();
$student_arr = $PersonCourseSchedule->where('schedule_id', $id)->column('student_id');
// 获取当前时间
$now = date('Y-m-d H:i:s');
// 查询end_date大于当前时间的课程记录
$query = $StudentCourses->where('course_id', $id)
->where('end_date', '>', $now);
if (!empty($student_arr)) {
$query->whereNotIn('student_id', $student_arr);
}
$studentCourses = $query->field('student_id as value, resource_id')->select()->toArray();
// 如果没有符合条件的记录,直接返回空数组
if (empty($studentCourses)) {
return [];
}
// 收集所有的resource_id
$resourceIds = array_column($studentCourses, 'resource_id');
$resourceIds = array_filter($resourceIds); // 过滤掉空值
if (empty($resourceIds)) {
return [];
}
// 查询客户资源表获取详细信息
$resources = Db::name('customer_resources')
->whereIn('id', $resourceIds)
->field('id, name, source_channel, source, age')
->select()
->toArray();
// 将资源信息与学生ID关联
$result = [];
foreach ($resources as $resource) {
// 查找对应的学生ID
foreach ($studentCourses as $course) {
if ($course['resource_id'] == $resource['id']) {
// 源和来源渠道转换为字典值
$source = get_dict_value("source", $resource['source']);
$sourceChannel = get_dict_value("source_channel", $resource['source_channel']);
$result[] = [
'value' => $course['value'], // 学生ID
'resource_id' => $resource['id'],
'text' => $resource['name'], // 学生姓名
'name' => $resource['name'],
'age' => $resource['age'],
'source' => $source,
'source_channel' => $sourceChannel,
'source_raw' => $resource['source'],
'source_channel_raw' => $resource['source_channel']
];
break;
}
}
}
return $result;
}
public function addStudent($data)
{
$PersonCourseSchedule = new PersonCourseSchedule();
$res = $PersonCourseSchedule->create($data);
return $res;
}
public function delStudentCourse($data)
{
$StudentCourseUsage = new StudentCourseUsage();
$StudentCourses = new StudentCourses();
$StudentCourses_id = $StudentCourses->where('student_id', $data['student_id'])->where('course_id', $data['course_id'])->value('id');
$PersonCourseSchedule_id = $StudentCourseUsage->where('student_course_id', $StudentCourses_id)->value('id');
if ($PersonCourseSchedule_id) {
$StudentCourseUsage->where('student_course_id', $StudentCourses_id)->delete();
return true;
} else {
return false;
}
}
public function getDate(array $baseDate)
{
$dates = [];
$this_date = $baseDate['date'] ?: date('Y-m-d');
$date = new DateTime($this_date);
for ($i = -2; $i <= 4; $i++) {
$tempDate = clone $date; // 避免修改原始对象
$tempDate->modify("$i days");
$status = false;
if ($baseDate['day'] == $tempDate->format('d')) {
$status = true;
} else if (empty($baseDate['day'])) {
if ($tempDate->format('Y-m-d') === date('Y-m-d')) {
$status = true;
}
}
$dates[] = [
'date' => $tempDate->format('Y-m-d'),
'day' => $tempDate->format('d'),
'week' => getChineseWeekday($tempDate),
'status' => $status
];
}
return ['dates' => $dates, 'date' => $this_date];
}
public function listAll($data)
{
$where = [];
// 基础日期查询
if ($data['schedule_date']) {
$where[] = ['course_date', '=', $data['schedule_date']];
}
// 日期范围查询
if (!empty($data['start_date'])) {
$where[] = ['course_date', '>=', $data['start_date']];
}
if (!empty($data['end_date'])) {
$where[] = ['course_date', '<=', $data['end_date']];
}
// 场地编号筛选 - 根据venue表的id或venue_name进行筛选
if (!empty($data['venue_number'])) {
// 先查询匹配的场地ID
$venue_ids = Db::name('venue')->where('id', $data['venue_number'])->column('id');
if (empty($venue_ids)) {
// 如果根据ID查不到,可能是根据场地名称查询
$venue_ids = Db::name('venue')->where('venue_name', 'like', '%' . $data['venue_number'] . '%')->column('id');
}
if (empty($venue_ids)) {
// 如果没有找到匹配的场地,返回空结果
return [];
}
$where[] = ['venue_id', 'in', $venue_ids];
}
// 教练姓名筛选 - 需要关联personnel表
if (!empty($data['teacher_name'])) {
// 先查询匹配的教练ID
$coach_ids = Db::name('personnel')->where('name', 'like', '%' . $data['teacher_name'] . '%')->column('id');
if (!empty($coach_ids)) {
$where[] = ['coach_id', 'in', $coach_ids];
} else {
// 如果找不到匹配的教练,返回空结果
return [];
}
}
$CourseSchedule = new CourseSchedule();
$query = $CourseSchedule->where($where);
// 时间段筛选 - 根据time_slot字段和传入的时间范围
if (!empty($data['time_hour']) && $data['time_hour'] !== '全部时间') {
$time_condition = $this->getTimeSlotCondition($data['time_hour']);
if ($time_condition) {
[$start_time, $end_time] = $time_condition;
// 查询time_slot字段中包含在指定时间范围内的课程
// time_slot格式为"HH:MM-HH:MM",我们需要检查时间段是否有重叠
$query = $query->where(function ($subQuery) use ($start_time, $end_time) {
$subQuery->where('time_slot', 'like', $start_time . '%')
->whereOr('time_slot', 'like', '%' . $start_time . '%')
->whereOr('time_slot', 'like', '%' . $end_time . '%')
->whereOr(function ($subQuery2) use ($start_time, $end_time) {
// 检查开始时间是否在范围内
$subQuery2->whereRaw("TIME(SUBSTRING_INDEX(time_slot, '-', 1)) >= ?", [$start_time])
->whereRaw("TIME(SUBSTRING_INDEX(time_slot, '-', 1)) < ?", [$end_time]);
})
->whereOr(function ($subQuery3) use ($start_time, $end_time) {
// 检查结束时间是否在范围内
$subQuery3->whereRaw("TIME(SUBSTRING_INDEX(time_slot, '-', -1)) > ?", [$start_time])
->whereRaw("TIME(SUBSTRING_INDEX(time_slot, '-', -1)) <= ?", [$end_time]);
});
});
}
}
$list = $query
->with(['course', 'venue', 'campus', 'coach'])
->select()->toArray();
foreach ($list as $k => $v) {
// 修复:通过resources_id查询学员信息,使用LEFT JOIN处理member_id为0的情况
$student = Db::name('person_course_schedule')
->alias('pcs')
->where('pcs.schedule_id', $v['id'])
->leftJoin('school_customer_resources cr', 'pcs.resources_id = cr.id')
->leftJoin('school_member sm', 'cr.member_id = sm.member_id AND cr.member_id > 0')
->field('cr.name, COALESCE(sm.headimg, "") as avatar, pcs.schedule_type, pcs.course_type, pcs.status')
->select();
$list[$k]['student'] = $student;
}
return $list;
}
/**
* 根据时间选择器的值获取时间段查询条件
* @param string $timeHour
* @return array|null 返回时间范围数组 [start_hour, end_hour] 或 null
*/
private function getTimeSlotCondition($timeHour)
{
switch ($timeHour) {
case '上午(8:00-12:00)':
return ['08:00', '12:00']; // 上午时间范围
case '下午(12:00-18:00)':
return ['12:00', '18:00']; // 下午时间范围
case '晚上(18:00-22:00)':
return ['18:00', '22:00']; // 晚上时间范围
default:
return null;
}
}
public function addSchedule(array $data)
{
$CourseSchedule = new CourseSchedule();
$personCourseSchedule = new PersonCourseSchedule();
$student = Student::where('id', $data['student_id'])->find();
if (!$student) {
return fail("学员不存在");
}
$studentCourse = StudentCourses::where('student_id', $student->id)
->order('id', 'desc')
->find();
$student_status = $studentCourse && $this->handeStudentStatus($studentCourse);
if ($student_status) {
$person_type = 'student';
} else {
$person_type = 'customer_resource';
}
// 检查重复添加 - 根据person_type使用不同的检查逻辑
$checkWhere = [
'schedule_id' => $data['schedule_id'],
'student_id' => $student->id,
'resources_id' => $data['resources_id'],
'status' => 0
];
$course = $personCourseSchedule->where($checkWhere)->find();
if ($course) {
return fail("重复添加");
}
$insertData = [
'student_id' => $student->id, // 正确设置student_id
'resources_id' => $data['resources_id'], // 正确设置resources_id
'person_id' => $this->member_id,
'person_type' => $person_type,
'schedule_id' => $data['schedule_id'],
'course_date' => $data['course_date'],
'time_slot' => $data['time_slot'],
'schedule_type' => $data['schedule_type'] ?? 1, // 1=正式位, 2=等待位
'course_type' => $data['course_type'], // 根据上面的逻辑设置课程类型
'remark' => $data['remark'] ?? '', // 备注
'student_course_id' => $studentCourse->id ?? 0
];
$personCourseSchedule->insert($insertData);
$student_ids = $personCourseSchedule->where(['schedule_id' => $data['schedule_id']])->column('student_id');
$CourseSchedule->where(['id' => $data['schedule_id']])->update([
'student_ids' => $student_ids,
'available_capacity' => count($student_ids)
]);
return success("添加成功");
}
public function schedule_list(array $data)
{
$personCourseSchedule = new PersonCourseSchedule();
$list = $personCourseSchedule
->alias('a')
->leftJoin(['school_student' => 'st'], 'a.student_id = st.id AND a.person_type = "student"')
->leftJoin(['school_customer_resources' => 'b'], 'a.resources_id = b.id')
->leftJoin(['school_course_schedule' => 'c'], 'c.id = a.schedule_id')
->where('a.schedule_id', $data['schedule_id'])
->field([
'COALESCE(st.name, b.name) as name', // 优先显示学员姓名,否则客户资源姓名
'a.status',
'a.person_type',
'c.campus_id',
'a.student_id',
'a.resources_id',
'a.schedule_type',
'a.course_type',
'a.id as person_schedule_id'
])
->select()
->toArray();
return $list;
}
public function schedule_del(array $data)
{
$personCourseSchedule = new PersonCourseSchedule();
// 查询记录
$record = $personCourseSchedule->where([
'schedule_id' => $data['id'],
'resources_id' => $data['resources_id'],
'student_id' => $data['student_id']
])->find();
if (!$record) {
return fail('未找到相关记录');
}
// 根据person_type执行不同操作
if ($record['person_type'] == 'customer_resource') {
// 如果是客户资源类型,直接删除记录
$personCourseSchedule->where([
'id' => $record->id,
'resources_id' => $data['resources_id']
])->delete();
return success('删除成功');
} else if ($record['person_type'] == 'student') {
// 如果是学生类型,更新状态为2并更新备注
$personCourseSchedule->where([
'id' => $record->id
])->update([
'status' => 2,
'remark' => $data['remark']
]);
return success('更新成功');
} else {
return fail('未知的人员类型');
}
}
/**
* 更新学员课程人员配置
* @param array $data
* @return array
*/
public function updateStudentCoursePersonnel(array $data)
{
$res = [
'code' => 0,
'msg' => '更新失败',
'data' => []
];
try {
// 开启事务
Db::startTrans();
$studentCourseId = $data['student_course_id'];
$mainCoachId = $data['main_coach_id'] ?? null;
$educationId = $data['education_id'] ?? null;
$assistantIds = $data['assistant_ids'] ?? '';
$classId = $data['class_id'] ?? null;
// 获取学员课程信息(需要 student_id 和 resource_id 来处理班级关联)
$studentCourse = Db::name('student_courses')
->where('id', $studentCourseId)
->field('student_id, resource_id')
->find();
if (!$studentCourse) {
Db::rollback();
$res['msg'] = '学员课程记录不存在';
return $res;
}
// 更新学员课程表
$updateData = [
'updated_at' => date('Y-m-d H:i:s')
];
if ($mainCoachId !== null) {
$updateData['main_coach_id'] = $mainCoachId;
}
if ($educationId !== null) {
$updateData['education_id'] = $educationId;
}
if ($assistantIds !== '') {
$updateData['assistant_ids'] = $assistantIds;
}
// 更新学员课程表
$updateResult = Db::name('student_courses')
->where('id', $studentCourseId)
->update($updateData);
if (!$updateResult) {
Db::rollback();
$res['msg'] = '更新学员课程配置失败';
return $res;
}
// 处理班级关联逻辑
if ($classId !== null && $studentCourse['resource_id']) {
// 先删除现有的班级关联
Db::name('class_resources_rel')
->where('resource_id', $studentCourse['resource_id'])
->delete();
// 如果选择了新的班级,创建新的关联记录
if ($classId > 0) {
$classRelData = [
'class_id' => $classId,
'resource_id' => $studentCourse['resource_id'],
'campus_id' => 0, // 可根据实际需求设置
'source_id' => $studentCourse['student_id'],
'source_type' => 'student',
'join_time' => time(),
'status' => 1,
'create_time' => date('Y-m-d H:i:s'),
'update_time' => date('Y-m-d H:i:s')
];
$classRelResult = Db::name('class_resources_rel')->insert($classRelData);
if (!$classRelResult) {
Db::rollback();
$res['msg'] = '更新班级关联失败';
return $res;
}
}
}
// 提交事务
Db::commit();
$res = [
'code' => 1,
'msg' => '更新成功',
'data' => [
'student_course_id' => $studentCourseId,
'main_coach_id' => $mainCoachId,
'education_id' => $educationId,
'assistant_ids' => $assistantIds,
'class_id' => $classId
]
];
} catch (\Exception $e) {
Db::rollback();
$res['msg'] = '更新学员课程人员配置异常:' . $e->getMessage();
}
return $res;
}
/**
* 获取课程列表(用于添加课程安排)
* @param array $data
* @return array
*/
public function getCourseListForSchedule(array $data)
{
try {
$where = [];
// 课程名称关键词搜索
if (!empty($data['keyword'])) {
$where[] = ['course_name', 'like', '%' . $data['keyword'] . '%'];
}
// 课程类型筛选
if (!empty($data['course_type'])) {
$where[] = ['course_type', '=', $data['course_type']];
}
// 只获取有效课程(未逻辑删除)
// 注意:Course模型使用软删除,保留deleted_at条件
$courseList = $this->model
->where($where)
->field('id, course_name, course_type, duration, session_count, single_session_count, price')
->order('created_at DESC')
->select()
->toArray();
return [
'code' => 1,
'msg' => '获取成功',
'data' => $courseList
];
} catch (\Exception $e) {
return [
'code' => 0,
'msg' => '获取课程列表失败:' . $e->getMessage(),
'data' => []
];
}
}
/**
* 获取课程安排详情
* @param int $scheduleId 课程安排ID
* @return array
*/
public function getScheduleDetail($scheduleId)
{
try {
$CourseSchedule = new CourseSchedule();
$PersonCourseSchedule = new PersonCourseSchedule();
// 获取课程安排基本信息
$schedule = $CourseSchedule
->where('id', $scheduleId)
->with(['course', 'venue', 'campus'])
->find();
if (!$schedule) {
return [
'code' => 0,
'msg' => '课程安排不存在',
'data' => []
];
}
// 获取已安排的学员列表(包括正式学员和等待位),排除请假的学员(status!=2)
$students = $PersonCourseSchedule
->where('schedule_id', $scheduleId)
->where('status', '<>', 2) // 排除请假的学员,包含待上课(0)和已上课(1)
->where(function ($query) {
$query->where('deleted_at', 0)->whereOr('deleted_at', null);
})
->with(['student', 'resources'])
->order('course_type ASC, created_at ASC')
->select()
->toArray();
// 分组学员数据
$formalStudents = []; // 正式学员
$waitingStudents = []; // 等待位学员
foreach ($students as $student) {
// 获取学员信息
$name = '';
$age = 0;
$phone = '';
$trialClassCount = 0;
$studentCourseInfo = null;
$courseUsageInfo = null;
if ($student['person_type'] == 'student' && !empty($student['student'])) {
// 正式学员
$name = $student['student']['name'] ?: '';
$age = $student['student']['age'] ?: 0;
$phone = $student['student']['contact_phone'] ?: '';
$trialClassCount = $student['student']['trial_class_count'] ?: 0;
// 获取学员最新的付费课程信息
$studentCourseInfo = Db::name('student_courses')
->where('student_id', $student['student_id'])
->order('created_at DESC')
->find();
// 如果有付费课程,获取使用情况
if ($studentCourseInfo) {
$courseUsageInfo = Db::name('student_course_usage')
->where('student_course_id', $studentCourseInfo['id'])
->select()
->toArray();
}
} elseif ($student['person_type'] == 'customer_resource') {
// 客户资源 - 现在我们有正确的student_id,应该从学生表获取信息
if ($student['student_id'] > 0) {
// 从学生表获取学员信息
$studentInfo = Db::name('student')
->where('id', $student['student_id'])
->find();
if ($studentInfo) {
$name = $studentInfo['name'] ?: '';
$age = $studentInfo['age'] ?: 0;
$phone = $studentInfo['contact_phone'] ?: '';
$trialClassCount = $studentInfo['trial_class_count'] ?: 0;
} else {
// 如果学生信息不存在,使用客户资源信息作为后备
$name = !empty($student['resources']) ? $student['resources']['name'] : '';
$age = !empty($student['resources']) ? $student['resources']['age'] : 0;
$phone = !empty($student['resources']) ? $student['resources']['phone_number'] : '';
}
} else {
// 如果没有student_id,使用客户资源信息
$name = !empty($student['resources']) ? $student['resources']['name'] : '';
$age = !empty($student['resources']) ? $student['resources']['age'] : 0;
$phone = !empty($student['resources']) ? $student['resources']['phone_number'] : '';
}
}
// 计算剩余课时和续费状态
$remainingHours = 0;
$totalHours = 0;
$usedHours = 0;
$needsRenewal = false;
$isTrialStudent = false; // 是否为体验课学员
if ($studentCourseInfo) {
// 付费学员
$totalRegularHours = intval($studentCourseInfo['total_hours'] ?: 0);
$totalGiftHours = intval($studentCourseInfo['gift_hours'] ?: 0);
$usedRegularHours = intval($studentCourseInfo['use_total_hours'] ?: 0);
$usedGiftHours = intval($studentCourseInfo['use_gift_hours'] ?: 0);
$totalHours = $totalRegularHours + $totalGiftHours;
$usedHours = $usedRegularHours + $usedGiftHours;
$remainingHours = $totalHours - $usedHours;
// 判断是否需要续费
// 条件1:end_date距离今天不足10天
$endDate = $studentCourseInfo['end_date'];
if ($endDate) {
$daysUntilExpiry = (strtotime($endDate) - time()) / (24 * 3600);
if ($daysUntilExpiry <= 10) {
$needsRenewal = true;
}
}
// 条件2:剩余课时少于4节
if ($remainingHours < 4) {
$needsRenewal = true;
}
} else {
// 体验课学员(没有付费课程记录)
$isTrialStudent = true;
$totalHours = $trialClassCount;
$usedHours = 0; // 这里可以根据实际需求统计体验课使用情况
$remainingHours = $trialClassCount;
}
$studentInfo = [
'id' => $student['id'], // 人员课程安排关系ID
'student_id' => $student['student_id'] ?: 0,
'resources_id' => $student['resources_id'] ?: 0,
'name' => $name,
'age' => $age,
'phone' => $phone,
'courseStatus' => $this->getCourseTypeText($student['course_type']),
'courseType' => $student['schedule_type'] == 2 ? 'fixed' : 'temporary',
'remainingHours' => $remainingHours,
'totalHours' => $totalHours,
'usedHours' => $usedHours,
'expiryDate' => $studentCourseInfo ? ($studentCourseInfo['end_date'] ?: '') : '',
'needsRenewal' => $needsRenewal,
'isTrialStudent' => $isTrialStudent,
'trialClassCount' => $trialClassCount,
'status' => $student['status'] ?: 0,
'remark' => $student['remark'] ?: '',
'person_type' => $student['person_type'],
'schedule_type' => $student['schedule_type'] ?: 1,
'course_type' => $student['course_type'] ?: 1,
// 添加课程购买和使用信息
'student_course_info' => $studentCourseInfo,
'course_usage_info' => $courseUsageInfo,
'course_progress' => [
'total' => $totalHours,
'used' => $usedHours,
'remaining' => $remainingHours,
'percentage' => $totalHours > 0 ? round(($usedHours / $totalHours) * 100, 1) : 0
]
];
if ($student['course_type'] == 3) {
// 等待位学员
$waitingStudents[] = $studentInfo;
} else {
// 正式学员
$formalStudents[] = $studentInfo;
}
}
// 计算可用位置
$maxStudents = $schedule['max_students'] ?: 0;
$availableSlots = 0;
if ($maxStudents > 0) {
$availableSlots = max(0, $maxStudents - count($formalStudents));
} else {
// 如果没有限制,总是显示至少1个可用位置
$availableSlots = max(1, 6 - count($formalStudents));
}
$result = [
'schedule_info' => [
'id' => $schedule['id'],
'course_name' => $schedule['course']['course_name'] ?? '',
'course_date' => $schedule['course_date'],
'time_slot' => $schedule['time_slot'],
'venue_name' => $schedule['venue']['venue_name'] ?? '',
'campus_name' => $schedule['campus']['campus_name'] ?? '',
'available_capacity' => $schedule['available_capacity'] ?: 0,
'max_students' => $maxStudents,
'available_slots' => $availableSlots,
'status' => $schedule['status'] ?: 0
],
'formal_students' => $formalStudents,
'waiting_students' => $waitingStudents
];
return [
'code' => 1,
'msg' => '获取成功',
'data' => $result
];
} catch (\Exception $e) {
return [
'code' => 0,
'msg' => '获取课程安排详情失败:' . $e->getMessage(),
'data' => []
];
}
}
/**
* 搜索可添加的学员
* @param array $data
* @return array
*/
public function searchAvailableStudents($data)
{
try {
$keyword = trim($data['keyword']);
$searchType = $data['search_type'] ?: 'auto';
$scheduleId = $data['schedule_id'] ?: 0;
if (empty($keyword)) {
return [
'code' => 1,
'msg' => '搜索成功',
'data' => []
];
}
// 获取已安排的学员ID和资源ID,用于排除
$PersonCourseSchedule = new PersonCourseSchedule();
$existingRecords = $PersonCourseSchedule
->where('schedule_id', $scheduleId)
->where(function ($query) {
$query->where('deleted_at', 0)->whereOr('deleted_at', null);
})
->field('student_id, resources_id')
->select()
->toArray();
$existingStudentIds = array_filter(array_column($existingRecords, 'student_id'));
$existingResourceIds = array_filter(array_column($existingRecords, 'resources_id'));
$results = [];
// 搜索正式学员
$Student = new Student();
$studentWhere = [];
$studentWhere[] = ['deleted_at', '=', 0];
if ($searchType == 'phone' || ($searchType == 'auto' && preg_match('/^1[3-9]\d{9}$/', $keyword))) {
// 搜索手机号 - 通过关联客户资源表
$students = $Student
->alias('s')
->leftJoin('customer_resources cr', 's.user_id = cr.id')
->where('cr.phone_number', 'like', "%{$keyword}%")
->where('s.deleted_at', 0)
->field('s.id as student_id, s.name, s.gender, s.status, cr.age, cr.phone_number, s.user_id as resource_id, "student" as person_type')
->select()
->toArray();
} else {
// 搜索姓名
$students = $Student
->alias('s')
->leftJoin('customer_resources cr', 's.user_id = cr.id')
->where('s.name', 'like', "%{$keyword}%")
->where('s.deleted_at', 0)
->field('s.id as student_id, s.name, s.gender, s.status, cr.age, cr.phone_number, s.user_id as resource_id, "student" as person_type')
->select()
->toArray();
}
// 过滤已安排的学员
foreach ($students as $student) {
if (!in_array($student['student_id'], $existingStudentIds)) {
$results[] = [
'id' => $student['student_id'],
'student_id' => $student['student_id'],
'resources_id' => $student['resource_id'],
'name' => $student['name'],
'age' => $student['age'] ?: 0,
'phone' => $student['phone_number'] ?: '',
'gender' => $student['gender'],
'status' => $student['status'], // 添加学员状态
'person_type' => 'student',
'type_label' => '正式学员'
];
}
}
// 搜索客户资源(非正式学员)
$customerWhere = [];
$customerWhere[] = ['deleted_at', '=', 0];
if ($searchType == 'phone' || ($searchType == 'auto' && preg_match('/^1[3-9]\d{9}$/', $keyword))) {
$customerWhere[] = ['phone_number', 'like', "%{$keyword}%"];
} else {
$customerWhere[] = ['name', 'like', "%{$keyword}%"];
}
$customers = Db::name('customer_resources')
->where($customerWhere)
->field('id as resources_id, name, age, phone_number, gender')
->select()
->toArray();
// 过滤已安排的客户资源
foreach ($customers as $customer) {
if (!in_array($customer['resources_id'], $existingResourceIds)) {
$results[] = [
'id' => $customer['resources_id'],
'student_id' => 0,
'resources_id' => $customer['resources_id'],
'name' => $customer['name'],
'age' => $customer['age'] ?: 0,
'phone' => $customer['phone_number'] ?: '',
'gender' => $customer['gender'],
'person_type' => 'customer_resource',
'type_label' => '客户资源'
];
}
}
return [
'code' => 1,
'msg' => '搜索成功',
'data' => $results
];
} catch (\Exception $e) {
return [
'code' => 0,
'msg' => '搜索学员失败:' . $e->getMessage(),
'data' => []
];
}
}
/**
* 添加学员到课程安排
* @param array $data
* @return array
*/
public function addStudentToSchedule($data)
{
try {
$scheduleId = $data['schedule_id'];
$studentId = $data['student_id'] ?: null;
$resourcesId = $data['resources_id'] ?: null;
$personType = $data['person_type'];
$scheduleType = $data['schedule_type'] ?: 1;
$courseType = $data['course_type'] ?: 1;
$remarks = $data['remarks'] ?: '';
// 获取课程安排信息
$CourseSchedule = new CourseSchedule();
$schedule = $CourseSchedule
->where('id', $scheduleId)
->find();
if (!$schedule) {
return [
'code' => 0,
'msg' => '课程安排不存在',
'data' => []
];
}
// 检查是否已经添加过
$PersonCourseSchedule = new PersonCourseSchedule();
$existingWhere = [
['schedule_id', '=', $scheduleId],
function ($query) {
$query->where('deleted_at', 0)->whereOr('deleted_at', null);
}
];
if ($studentId) {
$existingWhere[] = ['student_id', '=', $studentId];
} else {
$existingWhere[] = ['resources_id', '=', $resourcesId];
}
$existing = $PersonCourseSchedule->where($existingWhere)->find();
if ($existing) {
return [
'code' => 0,
'msg' => '该学员已经在此课程安排中',
'data' => []
];
}
// 验证学员状态 - 只有status=1的学员才能预约固定课
if ($scheduleType == 2 && $studentId) { // 固定课且是正式学员
$Student = new Student();
$student = $Student->where('id', $studentId)->find();
if (!$student) {
return [
'code' => 0,
'msg' => '学员不存在',
'data' => []
];
}
if ($student['status'] != 1) {
return [
'code' => 0,
'msg' => '只有有效状态的学员才能预约固定课,该学员只能预约临时课',
'data' => []
];
}
}
// 如果是正式学员位置,检查容量限制
if ($courseType != 3) { // 不是等待位
$maxStudents = $schedule['max_students'] ?: 0;
if ($maxStudents > 0) {
$currentCount = $PersonCourseSchedule
->where('schedule_id', $scheduleId)
->where('course_type', '<>', 3) // 不包括等待位
->where(function ($query) {
$query->where('deleted_at', 0)->whereOr('deleted_at', null);
})
->count();
if ($currentCount >= $maxStudents) {
return [
'code' => 0,
'msg' => '课程安排已满,请添加到等待位',
'data' => []
];
}
}
}
// 准备插入数据
$insertData = [
'resources_id' => $resourcesId,
'person_id' => null, // 这个字段根据实际业务需求设置
'student_id' => $studentId,
'person_type' => $personType,
'schedule_id' => $scheduleId,
'course_date' => $schedule['course_date'],
'schedule_type' => $scheduleType,
'course_type' => $courseType,
'time_slot' => $schedule['time_slot'],
'status' => 0, // 待上课
'remark' => $remarks,
'created_at' => date('Y-m-d H:i:s'),
'updated_at' => date('Y-m-d H:i:s')
];
$result = $PersonCourseSchedule->create($insertData);
if ($result) {
// 更新课程安排表的参与人员信息
$this->updateScheduleParticipants($scheduleId);
return [
'code' => 1,
'msg' => '添加成功',
'data' => $result->toArray()
];
} else {
return [
'code' => 0,
'msg' => '添加失败',
'data' => []
];
}
} catch (\Exception $e) {
return [
'code' => 0,
'msg' => '添加学员失败:' . $e->getMessage(),
'data' => []
];
}
}
/**
* 从课程安排中移除学员
* @param array $data
* @return array
*/
public function removeStudentFromSchedule($data)
{
try {
$personScheduleId = $data['person_schedule_id'];
$reason = $data['reason'] ?: '';
$remark = $data['remark'] ?: '';
$PersonCourseSchedule = new PersonCourseSchedule();
$record = $PersonCourseSchedule
->where('id', $personScheduleId)
->find();
if (!$record) {
return [
'code' => 0,
'msg' => '记录不存在',
'data' => []
];
}
// 软删除记录
$updateData = [
'deleted_at' => time(),
'remark' => $remark ? ($record['remark'] . '; 移除原因:' . $remark) : $record['remark'],
'updated_at' => date('Y-m-d H:i:s')
];
$result = $PersonCourseSchedule
->where('id', $personScheduleId)
->update($updateData);
if ($result) {
// 更新课程安排表的参与人员信息
$this->updateScheduleParticipants($record['schedule_id']);
return [
'code' => 1,
'msg' => '移除成功',
'data' => []
];
} else {
return [
'code' => 0,
'msg' => '移除失败',
'data' => []
];
}
} catch (\Exception $e) {
return [
'code' => 0,
'msg' => '移除学员失败:' . $e->getMessage(),
'data' => []
];
}
}
/**
* 更新学员课程状态
* @param array $data
* @return array
*/
public function updateStudentStatus($data)
{
try {
$personScheduleId = $data['person_schedule_id'];
$status = $data['status'];
$remark = $data['remark'] ?: '';
$PersonCourseSchedule = new PersonCourseSchedule();
$record = $PersonCourseSchedule
->where('id', $personScheduleId)
->find();
if (!$record) {
return [
'code' => 0,
'msg' => '记录不存在',
'data' => []
];
}
$updateData = [
'status' => $status,
'updated_at' => date('Y-m-d H:i:s')
];
if ($remark) {
$updateData['remark'] = $remark;
}
$result = $PersonCourseSchedule
->where('id', $personScheduleId)
->update($updateData);
if ($result) {
return [
'code' => 1,
'msg' => '更新成功',
'data' => []
];
} else {
return [
'code' => 0,
'msg' => '更新失败',
'data' => []
];
}
} catch (\Exception $e) {
return [
'code' => 0,
'msg' => '更新学员状态失败:' . $e->getMessage(),
'data' => []
];
}
}
/**
* 更新课程安排的参与人员信息
* @param int $scheduleId
*/
private function updateScheduleParticipants($scheduleId)
{
try {
$PersonCourseSchedule = new PersonCourseSchedule();
// 获取当前安排的所有人员
$participants = $PersonCourseSchedule
->where('schedule_id', $scheduleId)
->where(function ($query) {
$query->where('deleted_at', 0)->whereOr('deleted_at', null);
})
->field('resources_id, student_id')
->select()
->toArray();
$resourceIds = array_filter(array_column($participants, 'resources_id'));
$studentIds = array_filter(array_column($participants, 'student_id'));
$CourseSchedule = new CourseSchedule();
$CourseSchedule
->where('id', $scheduleId)
->update([
'participants' => json_encode($resourceIds),
'student_ids' => json_encode($studentIds),
'updated_at' => date('Y-m-d H:i:s')
]);
} catch (\Exception $e) {
// 记录日志但不影响主流程
error_log('更新课程安排参与人员信息失败:' . $e->getMessage());
}
}
/**
* 获取教练列表
* @param int $campus_id
* @return array
*/
public function getCoachList($campus_id = 0)
{
try {
// 查询dept_id=23的教练角色
$roleIds = \app\model\sys_role\SysRole::where('dept_id', 23)
->where('status', 1)
->column('role_id');
if (empty($roleIds)) {
return ['code' => 0, 'msg' => '没有找到教练角色'];
}
// 查询校区人员角色关系表
$query = \app\model\campus_person_role\CampusPersonRole::alias('cpr')
->join(['school_personnel' => 'p'], 'cpr.person_id = p.id', 'inner')
->whereIn('cpr.role_id', $roleIds)
->where('cpr.deleted_at', 0)
->where('p.status', 1); // 只查询状态正常的人员
// 如果指定了校区,添加校区筛选
if ($campus_id > 0) {
$query->where('cpr.campus_id', $campus_id);
}
$list = $query->field([
'p.id',
'p.name',
'p.phone',
'p.status',
'cpr.campus_id',
'cpr.role_id'
])->select();
return ['code' => 1, 'data' => $list ? $list->toArray() : []];
} catch (\Exception $e) {
return ['code' => 0, 'msg' => '获取教练列表失败: ' . $e->getMessage()];
}
}
/**
* 获取教务人员列表
* @param int $campus_id
* @return array
*/
public function getEducationList($campus_id = 0)
{
try {
// 查询dept_id=2的教务角色
$roleIds = \app\model\sys_role\SysRole::where('dept_id', 2)
->where('status', 1)
->column('role_id');
if (empty($roleIds)) {
return ['code' => 0, 'msg' => '没有找到教务角色'];
}
// 查询校区人员角色关系表
$query = \app\model\campus_person_role\CampusPersonRole::alias('cpr')
->join(['school_personnel' => 'p'], 'cpr.person_id = p.id', 'inner')
->whereIn('cpr.role_id', $roleIds)
->where('cpr.deleted_at', 0)
->where('p.status', 1); // 只查询状态正常的人员
// 如果指定了校区,添加校区筛选
if ($campus_id > 0) {
$query->where('cpr.campus_id', $campus_id);
}
$list = $query->field([
'p.id',
'p.name',
'p.phone',
'p.status',
'cpr.campus_id',
'cpr.role_id'
])->select();
return ['code' => 1, 'data' => $list ? $list->toArray() : []];
} catch (\Exception $e) {
return ['code' => 0, 'msg' => '获取教务人员列表失败: ' . $e->getMessage()];
}
}
/**
* 更新学员课程信息
* @param array $data
* @return array
*/
public function updateCourseInfo($data)
{
try {
$studentCourseId = $data['student_course_id'];
$mainCoachId = $data['main_coach_id'] ?? 0;
$assistantIds = $data['assistant_ids'] ?? '';
$educationId = $data['education_id'] ?? 0;
$classId = $data['class_id'] ?? 0;
// 1. 更新学员课程表
$updateData = [];
if ($mainCoachId > 0) {
$updateData['main_coach_id'] = $mainCoachId;
}
if (!empty($assistantIds)) {
$updateData['assistant_ids'] = $assistantIds;
}
if ($educationId > 0) {
$updateData['education_id'] = $educationId;
}
if (!empty($updateData)) {
$updateData['updated_at'] = date('Y-m-d H:i:s');
$result = StudentCourses::where('id', $studentCourseId)->update($updateData);
if (!$result) {
return ['code' => 0, 'msg' => '更新学员课程信息失败'];
}
}
// 2. 如果需要更新班级关联
if ($classId > 0) {
// 先获取学员的resource_id
$studentCourse = StudentCourses::where('id', $studentCourseId)->find();
if (!$studentCourse) {
return ['code' => 0, 'msg' => '学员课程不存在'];
}
$resourceId = $studentCourse->resource_id;
// 检查是否已存在班级关联
$existingRel = \app\model\class_resources_rel\ClassResourcesRel::where([
'resource_id' => $resourceId,
'status' => 1
])->find();
if ($existingRel) {
// 更新现有关联
$existingRel->class_id = $classId;
$existingRel->update_time = date('Y-m-d H:i:s');
$existingRel->save();
} else {
// 创建新的班级关联
$classRel = new \app\model\class_resources_rel\ClassResourcesRel();
$classRel->class_id = $classId;
$classRel->resource_id = $resourceId;
$classRel->campus_id = $studentCourse->campus_id ?? 1; // 默认校区ID
$classRel->source_type = 'student';
$classRel->join_time = time();
$classRel->status = 1;
$classRel->save();
}
}
return ['code' => 1, 'data' => ['id' => $studentCourseId], 'msg' => '更新成功'];
} catch (\Exception $e) {
return ['code' => 0, 'msg' => '更新失败: ' . $e->getMessage()];
}
}
/**
* 检查学员班级关联情况
* @param int $resource_id
* @return array
*/
public function checkClassRelation($resource_id)
{
try {
$classRel = \app\model\class_resources_rel\ClassResourcesRel::alias('crr')
->join(['school_class' => 'c'], 'crr.class_id = c.id', 'left')
->where([
'crr.resource_id' => $resource_id,
'crr.status' => 1
])
->field([
'crr.id',
'crr.class_id',
'c.class_name',
'c.head_coach',
'c.educational_id'
])
->find();
$hasClass = !empty($classRel);
$classInfo = $hasClass ? $classRel->toArray() : null;
return [
'code' => 1,
'data' => [
'has_class' => $hasClass,
'class_info' => $classInfo
]
];
} catch (\Exception $e) {
return ['code' => 0, 'msg' => '检查班级关联失败: ' . $e->getMessage()];
}
}
/**
* 获取课程类型文本
* @param int $courseType
* @return string
*/
private function getCourseTypeText($courseType)
{
$courseTypeMap = [
1 => '临时课',
2 => '固定课',
3 => '等待位',
4 => '试听课'
];
return $courseTypeMap[$courseType] ?? '未知';
}
private function handeStudentStatus($studentCourse)
{
$now = time();
if (strtotime($studentCourse->end_date) > $now) {
$total = $studentCourse->total_hours + $studentCourse->gift_hours - $studentCourse->use_total_hours - $studentCourse->use_gift_hours;
if ($total > 0) {
return true;
}
}
return false;
}
}