where('id', $student_id) ->find(); $resources_id = $student->user_id; $person_id = $this->member_id; if (empty($schedule_id)) { throw new \Exception('参数错误:缺少课程安排ID'); } // 开启事务 Db::startTrans(); try { // 1. 查询课程安排记录 - 支持学员和客户资源两种类型 $where = [ ['schedule_id', '=', $schedule_id], ['student_id', '=', $student_id], ['resources_id', '=', $resources_id], ['deleted_at', '=', 0] ]; $schedule = (new SchoolPersonCourseSchedule()) ->where($where) ->find(); if (!$schedule) { throw new \Exception('课程安排记录不存在'); } if ($schedule['status'] == 1) { throw new \Exception('该学员已经签到过了'); } // 2. 更新课程安排状态为已上课 $schedule->save([ 'status' => 1, 'updated_at' => time() ]); $student_course_id = $schedule['student_course_id']; $person_type = $schedule['person_type']; if (!empty($student_course_id)) { // 正式学员处理逻辑 $this->handleFormalStudentCheckin($student_course_id, $student_id, $schedule); } elseif ($person_type == 'student' && !empty($student_id)) { // 体验课学员处理逻辑 $this->handleTrialStudentCheckin($student_id, $schedule); } elseif ($person_type == 'customer_resource') { // 客户资源处理逻辑 - 只更新状态,不扣除课时 $this->handleCustomerResourceCheckin($schedule); } else { throw new \Exception('无法确定人员类型,签到失败'); } Db::commit(); return [ 'schedule_id' => $schedule_id, 'student_id' => $student_id, 'status' => 1, 'message' => '签到成功' ]; } catch (\Exception $e) { Db::rollback(); throw new \Exception('签到失败:' . $e->getMessage()); } } /** * 处理正式学员签到 * @param int $student_course_id * @param int $student_id * @param object $schedule */ private function handleFormalStudentCheckin($student_course_id, $student_id, $schedule) { // 查询学员课程信息 $studentCourse = (new SchoolStudentCourses()) ->where('id', $student_course_id) ->find(); if (!$studentCourse) { throw new \Exception('学员课程记录不存在'); } $single_session_count = $studentCourse['single_session_count'] ?: 1; $total_hours = $studentCourse['total_hours']; $gift_hours = $studentCourse['gift_hours']; $use_total_hours = $studentCourse['use_total_hours']; $use_gift_hours = $studentCourse['use_gift_hours']; // 计算课时扣减逻辑 $remaining_total_hours = $total_hours - $use_total_hours; $remaining_gift_hours = $gift_hours - $use_gift_hours; $new_use_total_hours = $use_total_hours; $new_use_gift_hours = $use_gift_hours; if ($remaining_total_hours > 0) { // 优先扣减正式课时 $deduct_from_total = min($remaining_total_hours, $single_session_count); $new_use_total_hours += $deduct_from_total; $remaining_to_deduct = $single_session_count - $deduct_from_total; if ($remaining_to_deduct > 0 && $remaining_gift_hours > 0) { // 剩余部分从赠送课时扣减 $deduct_from_gift = min($remaining_gift_hours, $remaining_to_deduct); $new_use_gift_hours += $deduct_from_gift; } } else if ($remaining_gift_hours > 0) { // 没有正式课时,直接扣减赠送课时 $deduct_from_gift = min($remaining_gift_hours, $single_session_count); $new_use_gift_hours += $deduct_from_gift; } // 更新学员课程表 $studentCourse->save([ 'use_total_hours' => $new_use_total_hours, 'use_gift_hours' => $new_use_gift_hours, 'updated_at' => time() ]); // 插入消课记录 $this->insertUsageRecord($student_course_id, $student_id, $single_session_count, $schedule); } /** * 处理体验课学员签到 * @param int $student_id * @param object $schedule */ private function handleTrialStudentCheckin($student_id, $schedule) { // 查询学员信息 $student = (new SchoolStudent()) ->where('id', $student_id) ->find(); if (!$student) { throw new \Exception('学员信息不存在'); } $updateData = []; $current_time = time(); // 更新到校时间逻辑 if (empty($student['first_come']) || $student['first_come'] == '0000-00-00 00:00:00') { $updateData['first_come'] = date('Y-m-d H:i:s', $current_time); } else if (empty($student['second_come']) || $student['second_come'] == '0000-00-00 00:00:00') { $updateData['second_come'] = date('Y-m-d H:i:s', $current_time); } // 扣减体验课次数 $trial_class_count = $student['trial_class_count'] ?: 0; if ($trial_class_count > 0) { $updateData['trial_class_count'] = $trial_class_count - 1; } if (!empty($updateData)) { $updateData['updated_at'] = date('Y-m-d H:i:s'); $student->save($updateData); } // 插入消课记录(体验课也需要记录) $this->insertUsageRecord(0, $student_id, 1, $schedule); } /** * 插入消课记录 * @param int $student_course_id * @param int $student_id * @param float $used_hours * @param object $schedule */ private function insertUsageRecord($student_course_id, $student_id, $used_hours, $schedule) { // 获取资源ID $resource_id = $schedule['resources_id']; (new SchoolStudentCourseUsage())->save([ 'student_course_id' => $student_course_id, 'used_hours' => $used_hours, 'usage_date' => date('Y-m-d'), 'student_id' => $student_id, 'resource_id' => $resource_id, 'created_at' => time(), 'updated_at' => time() ]); } /** * 学员请假 * @param array $data * @return array */ public function leaveStudent($data) { $schedule_id = $data['schedule_id']; $student_id = $data['student_id']; $resources_id = $data['resources_id'] ?? 0; $person_id = $data['person_id']; $remark = $data['remark'] ?? ''; if (empty($schedule_id)) { throw new \Exception('参数错误:缺少课程安排ID'); } // 查询课程安排记录 - 支持学员和客户资源两种类型 $where = [ ['schedule_id', '=', $schedule_id], ['person_id', '=', $person_id], ['deleted_at', '=', 0] ]; // 根据传入的参数决定查询条件 if (!empty($student_id) && $student_id > 0) { // 正式学员 $where[] = ['student_id', '=', $student_id]; $where[] = ['person_type', '=', 'student']; } elseif (!empty($resources_id) && $resources_id > 0) { // 客户资源 $where[] = ['resources_id', '=', $resources_id]; $where[] = ['person_type', '=', 'customer_resource']; } else { throw new \Exception('参数错误:必须提供学员ID或资源ID'); } $schedule = (new SchoolPersonCourseSchedule()) ->where($where) ->find(); if (!$schedule) { throw new \Exception('课程安排记录不存在'); } if ($schedule['status'] == 2) { throw new \Exception('该学员已经请假了'); } // 更新状态为请假 $schedule->save([ 'status' => 2, 'remark' => $remark, 'updated_at' => time() ]); return [ 'schedule_id' => $schedule_id, 'student_id' => $student_id, 'status' => 2, 'message' => '请假成功' ]; } /** * 学员取消 * @param array $data * @return array */ public function cancelStudent($data) { $schedule_id = $data['schedule_id']; $student_id = $data['student_id']; $resources_id = $data['resources_id'] ?? 0; $person_id = $data['person_id']; $cancel_scope = $data['cancel_scope'] ?? 'single'; // single: 单节课, all: 全部课程 $cancel_reason = $data['cancel_reason'] ?? ''; if (empty($schedule_id)) { throw new \Exception('参数错误:缺少课程安排ID'); } // 开启事务 Db::startTrans(); try { // 查询课程安排记录 - 支持学员和客户资源两种类型 $where = [ ['schedule_id', '=', $schedule_id], ['person_id', '=', $person_id], ['deleted_at', '=', 0] ]; // 根据传入的参数决定查询条件 if (!empty($student_id) && $student_id > 0) { // 正式学员 $where[] = ['student_id', '=', $student_id]; $where[] = ['person_type', '=', 'student']; } elseif (!empty($resources_id) && $resources_id > 0) { // 客户资源 $where[] = ['resources_id', '=', $resources_id]; $where[] = ['person_type', '=', 'customer_resource']; } else { throw new \Exception('参数错误:必须提供学员ID或资源ID'); } $schedule = (new SchoolPersonCourseSchedule()) ->where($where) ->find(); if (!$schedule) { throw new \Exception('课程安排记录不存在'); } $schedule_type = $schedule['schedule_type']; $course_date = $schedule['course_date']; $current_time = time(); if ($cancel_scope === 'all' && $schedule_type == 1) { // 批量取消固定课程 $cancelCount = (new SchoolPersonCourseSchedule()) ->where([ ['student_id', '=', $student_id], ['schedule_id', '=', $schedule_id], ['course_date', '>=', $course_date], ['deleted_at', '=', 0] ]) ->update([ 'deleted_at' => $current_time, 'cancel_reason' => $cancel_reason, 'updated_at' => $current_time ]); $message = "成功取消{$cancelCount}节固定课程"; } else { // 单节课取消 $schedule->save([ 'deleted_at' => $current_time, 'cancel_reason' => $cancel_reason, 'updated_at' => $current_time ]); $message = '成功取消单节课程'; } Db::commit(); return [ 'schedule_id' => $schedule_id, 'student_id' => $student_id, 'cancel_scope' => $cancel_scope, 'message' => $message ]; } catch (\Exception $e) { Db::rollback(); throw new \Exception('取消失败:' . $e->getMessage()); } } /** * 处理客户资源签到 * @param object $schedule */ private function handleCustomerResourceCheckin($schedule) { // 客户资源签到,需要检查是否为体验课学员并更新相关字段 $student_id = $schedule['student_id']; $current_time = time(); if (!empty($student_id)) { // 查询学员信息 $student = (new SchoolStudent()) ->where('id', $student_id) ->find(); if ($student) { $updateData = []; // 更新到校时间逻辑 if (empty($student['first_come']) || $student['first_come'] == '0000-00-00 00:00:00') { $updateData['first_come'] = date('Y-m-d H:i:s', $current_time); } else if (empty($student['second_come']) || $student['second_come'] == '0000-00-00 00:00:00') { $updateData['second_come'] = date('Y-m-d H:i:s', $current_time); } // 扣减体验课次数 $trial_class_count = $student['trial_class_count'] ?: 0; if ($trial_class_count > 0) { $updateData['trial_class_count'] = $trial_class_count - 1; } if (!empty($updateData)) { $updateData['updated_at'] = date('Y-m-d H:i:s'); $student->save($updateData); } // 插入消课记录(体验课也需要记录) $this->insertUsageRecord(0, $student_id, 1, $schedule); } } return true; } }