buildScheduleWhere($data); // 分页参数 $page = intval($data['page'] ?? 1); $limit = intval($data['limit'] ?? 20); $offset = ($page - 1) * $limit; // 基础查询 $query = Db::name($this->prefix . 'course_schedule') ->alias('cs') ->leftJoin($this->prefix . 'course c', 'cs.course_id = c.id') ->leftJoin($this->prefix . 'venue v', 'cs.venue_id = v.id') ->leftJoin($this->prefix . 'campus cap', 'cs.campus_id = cap.id') ->leftJoin($this->prefix . 'personnel coach', 'cs.coach_id = coach.id') ->leftJoin($this->prefix . 'personnel edu', 'cs.education_id = edu.id') ->where($where) ->where('cs.deleted_at', 0); // 获取总数 $total = $query->count(); // 获取列表数据 $list = $query->field([ 'cs.*', 'c.course_name', 'c.course_type', 'c.duration as course_duration', 'c.session_count', 'c.single_session_count', 'v.venue_name', 'v.capacity as venue_capacity', 'cap.campus_name', 'coach.name as coach_name', 'coach.head_img as coach_avatar', 'edu.name as education_name' ]) ->order('cs.course_date DESC, cs.time_slot ASC') ->limit($offset, $limit) ->select() ->toArray(); // 处理列表数据 foreach ($list as &$item) { // 解析时间段 $item['time_info'] = $this->parseTimeSlot($item['time_slot']); // 获取参与学员信息 $item['students'] = $this->getScheduleStudents($item['id']); // 获取助教信息 $item['assistants'] = $this->getScheduleAssistants($item['assistant_ids']); // 计算已报名人数 $item['enrolled_count'] = count($item['students']); // 计算剩余容量 $item['remaining_capacity'] = max(0, ($item['available_capacity'] ?? $item['venue_capacity']) - $item['enrolled_count']); // 格式化状态 $item['status_text'] = $this->getStatusText($item['status']); // 格式化创建方式 $item['created_by_text'] = $item['created_by'] == 'manual' ? '手动安排' : '系统创建'; // 处理图片路径 $item['coach_avatar'] = $item['coach_avatar'] ? $this->formatImageUrl($item['coach_avatar']) : ''; } return [ 'list' => $list, 'total' => $total, 'page' => $page, 'limit' => $limit, 'pages' => ceil($total / $limit) ]; } catch (\Exception $e) { return [ 'list' => [], 'total' => 0, 'page' => 1, 'limit' => $limit ?? 20, 'pages' => 0, 'error' => $e->getMessage() ]; } } /** * 构建查询条件 * @param array $data 筛选参数 * @return array 条件数组 */ private function buildScheduleWhere($data) { $where = []; // 日期范围筛选 if (!empty($data['start_date'])) { $where[] = ['cs.course_date', '>=', $data['start_date']]; } if (!empty($data['end_date'])) { $where[] = ['cs.course_date', '<=', $data['end_date']]; } // 校区筛选 if (!empty($data['campus_id'])) { if (is_array($data['campus_id'])) { $where[] = ['cs.campus_id', 'in', $data['campus_id']]; } else { $where[] = ['cs.campus_id', '=', $data['campus_id']]; } } // 场地筛选 if (!empty($data['venue_id'])) { if (is_array($data['venue_id'])) { $where[] = ['cs.venue_id', 'in', $data['venue_id']]; } else { $where[] = ['cs.venue_id', '=', $data['venue_id']]; } } // 教练筛选 if (!empty($data['coach_id'])) { if (is_array($data['coach_id'])) { $where[] = ['cs.coach_id', 'in', $data['coach_id']]; } else { $where[] = ['cs.coach_id', '=', $data['coach_id']]; } } // 课程筛选 if (!empty($data['course_id'])) { if (is_array($data['course_id'])) { $where[] = ['cs.course_id', 'in', $data['course_id']]; } else { $where[] = ['cs.course_id', '=', $data['course_id']]; } } // 状态筛选 if (!empty($data['status'])) { if (is_array($data['status'])) { $where[] = ['cs.status', 'in', $data['status']]; } else { $where[] = ['cs.status', '=', $data['status']]; } } // 教务筛选 if (!empty($data['education_id'])) { $where[] = ['cs.education_id', '=', $data['education_id']]; } // 时间段筛选 if (!empty($data['time_range'])) { switch ($data['time_range']) { case 'morning': $where[] = ['cs.time_slot', 'like', '0%']; break; case 'afternoon': $where[] = ['cs.time_slot', 'like', '1%']; break; case 'evening': $where[] = ['cs.time_slot', 'like', '1[8-9]%']; break; } } // 自动排课筛选 if (isset($data['auto_schedule'])) { $where[] = ['cs.auto_schedule', '=', $data['auto_schedule']]; } // 创建方式筛选 if (!empty($data['created_by'])) { $where[] = ['cs.created_by', '=', $data['created_by']]; } return $where; } /** * 解析时间段 * @param string $timeSlot 时间段字符串(格式如:09:00-10:30) * @return array 解析后的时间段信息 */ private function parseTimeSlot($timeSlot) { if (strpos($timeSlot, '-') !== false) { list($startTime, $endTime) = explode('-', $timeSlot); return [ 'start_time' => trim($startTime), 'end_time' => trim($endTime), 'duration' => $this->calculateDuration(trim($startTime), trim($endTime)) ]; } return [ 'start_time' => $timeSlot, 'end_time' => '', 'duration' => 60 // 默认1小时 ]; } /** * 计算时长(分钟) * @param string $startTime 开始时间 * @param string $endTime 结束时间 * @return int 时长(分钟) */ private function calculateDuration($startTime, $endTime) { try { $start = strtotime($startTime); $end = strtotime($endTime); return ($end - $start) / 60; } catch (\Exception $e) { return 60; // 默认1小时 } } /** * 获取课程安排的学员信息 * @param int $scheduleId 课程安排ID * @return array 学员信息数组 */ private function getScheduleStudents($scheduleId) { try { $students = Db::name($this->prefix . 'person_course_schedule') ->alias('pcs') ->leftJoin($this->prefix . 'student s', 'pcs.student_id = s.id') ->leftJoin($this->prefix . 'customer_resources cr', 'pcs.resources_id = cr.id') ->leftJoin($this->prefix . 'member m', 'cr.member_id = m.member_id') ->where('pcs.schedule_id', $scheduleId) ->where('pcs.deleted_at', 0) ->field([ 'pcs.*', 's.name as student_name', 'cr.name as resource_name', 'cr.phone_number', 'cr.age', 'cr.gender', 'm.headimg as avatar' ]) ->select() ->toArray(); foreach ($students as &$student) { $student['name'] = $student['student_name'] ?: $student['resource_name']; $student['avatar'] = $student['avatar'] ? $this->formatImageUrl($student['avatar']) : ''; $student['status_text'] = $this->getStudentStatusText($student['status']); $student['person_type_text'] = $student['person_type'] == 'student' ? '正式学员' : '体验学员'; $student['course_type_text'] = $this->getCourseTypeText($student['course_type']); } return $students; } catch (\Exception $e) { return []; } } /** * 获取助教信息 * @param string $assistantIds 助教ID字符串,使用逗号分隔 * @return array 助教信息数组 */ private function getScheduleAssistants($assistantIds) { if (empty($assistantIds)) { return []; } try { $ids = explode(',', $assistantIds); $assistants = Db::name($this->prefix . 'personnel') ->whereIn('id', $ids) ->field('id, name, head_img, phone') ->select() ->toArray(); foreach ($assistants as &$assistant) { $assistant['head_img'] = $assistant['head_img'] ? $this->formatImageUrl($assistant['head_img']) : ''; } return $assistants; } catch (\Exception $e) { return []; } } /** * 获取状态文本 * @param string $status 状态码 * @return string 状态文本描述 */ private function getStatusText($status) { $statusMap = [ 'pending' => '待开始', 'upcoming' => '即将开始', 'ongoing' => '进行中', 'completed' => '已结束' ]; return $statusMap[$status] ?? $status; } /** * 获取学员状态文本 * @param int $status 学员状态码 * @return string 学员状态文本描述 */ private function getStudentStatusText($status) { $statusMap = [ 0 => '待上课', 1 => '已上课', 2 => '请假' ]; return $statusMap[$status] ?? '未知'; } /** * 获取课程类型文本 * @param int $courseType 课程类型码 * @return string 课程类型文本描述 */ private function getCourseTypeText($courseType) { $typeMap = [ 1 => '加课', 2 => '补课', 3 => '等待位' ]; return $typeMap[$courseType] ?? '正常课程'; } /** * 格式化图片URL * @param string $imagePath 图片路径 * @return string 格式化后的图片URL */ private function formatImageUrl($imagePath) { if (empty($imagePath)) { return ''; } // 如果已经是完整URL,直接返回 if (strpos($imagePath, 'http') === 0) { return $imagePath; } // 拼接域名 $domain = request()->domain(); return $domain . '/' . ltrim($imagePath, '/'); } /** * 获取筛选选项(教练、课程、班级等) * @param array $data 请求参数 * @return array 筛选选项数据 */ public function getFilterOptions($data = []) { try { $result = [ 'coaches' => [], // 教练列表 'courses' => [], // 课程列表 'classes' => [], // 班级列表 'venues' => [], // 场地列表 'campuses' => [], // 校区列表 'status_options' => [] // 状态选项 ]; // 获取教练列表 $result['coaches'] = Db::name($this->prefix . 'personnel') ->where('is_coach', 1) ->where('deleted_at', 0) ->field('id, name, head_img as avatar, phone') ->select() ->toArray(); foreach ($result['coaches'] as &$coach) { $coach['avatar'] = $coach['avatar'] ? $this->formatImageUrl($coach['avatar']) : ''; } // 获取课程列表 $result['courses'] = Db::name($this->prefix . 'course') ->where('deleted_at', 0) ->field('id, course_name, course_type, duration') ->select() ->toArray(); // 获取班级列表 $result['classes'] = Db::name($this->prefix . 'class') ->where('deleted_at', 0) ->field('id, class_name, class_level, total_students') ->select() ->toArray(); // 获取场地列表 $result['venues'] = Db::name($this->prefix . 'venue') ->where('deleted_at', 0) ->field('id, venue_name, capacity, description') ->select() ->toArray(); // 获取校区列表 $result['campuses'] = Db::name($this->prefix . 'campus') ->where('deleted_at', 0) ->field('id, campus_name, address') ->select() ->toArray(); // 状态选项 $result['status_options'] = [ ['value' => 'pending', 'label' => '待开始'], ['value' => 'upcoming', 'label' => '即将开始'], ['value' => 'ongoing', 'label' => '进行中'], ['value' => 'completed', 'label' => '已结束'] ]; return $result; } catch (\Exception $e) { return [ 'coaches' => [], 'courses' => [], 'classes' => [], 'venues' => [], 'campuses' => [], 'status_options' => [], 'error' => $e->getMessage() ]; } } /** * 获取课程安排详情 * @param int $scheduleId 课程安排ID * @return array 课程安排详细信息或错误信息 */ public function getScheduleInfo($scheduleId) { try { // 查询课程安排信息 $schedule = Db::name($this->prefix . 'course_schedule') ->alias('cs') ->leftJoin($this->prefix . 'course c', 'cs.course_id = c.id') ->leftJoin($this->prefix . 'venue v', 'cs.venue_id = v.id') ->leftJoin($this->prefix . 'campus cap', 'cs.campus_id = cap.id') ->leftJoin($this->prefix . 'personnel coach', 'cs.coach_id = coach.id') ->leftJoin($this->prefix . 'personnel edu', 'cs.education_id = edu.id') ->where('cs.id', $scheduleId) ->where('cs.deleted_at', 0) ->field([ 'cs.*', 'c.course_name', 'c.course_type', 'c.duration as course_duration', 'c.session_count', 'c.single_session_count', 'v.venue_name', 'v.capacity as venue_capacity', 'cap.campus_name', 'coach.name as coach_name', 'coach.head_img as coach_avatar', 'edu.name as education_name' ]) ->find(); if (empty($schedule)) { return ['code' => 0, 'msg' => '课程安排不存在或已被删除']; } // 解析时间段 $schedule['time_info'] = $this->parseTimeSlot($schedule['time_slot']); // 获取参与学员信息 $schedule['students'] = $this->getScheduleStudents($schedule['id']); // 获取助教信息 $schedule['assistants'] = $this->getScheduleAssistants($schedule['assistant_ids']); // 计算已报名人数 $schedule['enrolled_count'] = count($schedule['students']); // 计算剩余容量 $schedule['remaining_capacity'] = max(0, ($schedule['available_capacity'] ?? $schedule['venue_capacity']) - $schedule['enrolled_count']); // 格式化状态 $schedule['status_text'] = $this->getStatusText($schedule['status']); // 格式化创建方式 $schedule['created_by_text'] = $schedule['created_by'] == 'manual' ? '手动安排' : '系统创建'; // 处理图片路径 $schedule['coach_avatar'] = $schedule['coach_avatar'] ? $this->formatImageUrl($schedule['coach_avatar']) : ''; // 获取班级相关信息 if (!empty($schedule['class_id'])) { $schedule['class_info'] = Db::name($this->prefix . 'class') ->where('id', $schedule['class_id']) ->field('id, class_name, class_level, total_students') ->find(); } else { $schedule['class_info'] = null; } // 获取历史变更记录 $schedule['change_history'] = Db::name($this->prefix . 'course_schedule_changes') ->where('schedule_id', $scheduleId) ->order('created_at DESC') ->select() ->toArray(); return $schedule; } catch (\Exception $e) { return ['code' => 0, 'msg' => $e->getMessage()]; } } }