|
|
@ -11,6 +11,7 @@ |
|
|
|
|
|
|
|
|
namespace app\service\api\apiService; |
|
|
namespace app\service\api\apiService; |
|
|
|
|
|
|
|
|
|
|
|
use app\model\student\Student; |
|
|
use core\base\BaseApiService; |
|
|
use core\base\BaseApiService; |
|
|
use think\facade\Db; |
|
|
use think\facade\Db; |
|
|
|
|
|
|
|
|
@ -2434,41 +2435,14 @@ class CourseScheduleService extends BaseApiService |
|
|
// 开启事务 |
|
|
// 开启事务 |
|
|
Db::startTrans(); |
|
|
Db::startTrans(); |
|
|
|
|
|
|
|
|
// 查找学员记录 |
|
|
// 使用内部处理方法 |
|
|
$enrollment = Db::name('person_course_schedule') |
|
|
$result = $this->processSingleStudentSignIn($scheduleId, $personId, 0, $status, $reason); |
|
|
->where('schedule_id', $scheduleId) |
|
|
|
|
|
->where('person_id', $personId) |
|
|
|
|
|
->where('deleted_at', 0) |
|
|
|
|
|
->find(); |
|
|
|
|
|
|
|
|
|
|
|
if (!$enrollment) { |
|
|
if (!$result['success']) { |
|
|
Db::rollback(); |
|
|
Db::rollback(); |
|
|
return [ |
|
|
return [ |
|
|
'code' => 0, |
|
|
'code' => 0, |
|
|
'msg' => '找不到学员记录' |
|
|
'msg' => $result['error'] |
|
|
]; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 准备更新数据 |
|
|
|
|
|
$updateData = [ |
|
|
|
|
|
'status' => $status, |
|
|
|
|
|
'updated_at' => date('Y-m-d H:i:s') |
|
|
|
|
|
]; |
|
|
|
|
|
|
|
|
|
|
|
if ($reason) { |
|
|
|
|
|
$updateData['remark'] = $reason; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 更新学员记录 |
|
|
|
|
|
$result = Db::name('person_course_schedule') |
|
|
|
|
|
->where('id', $enrollment['id']) |
|
|
|
|
|
->update($updateData); |
|
|
|
|
|
|
|
|
|
|
|
if ($result === false) { |
|
|
|
|
|
Db::rollback(); |
|
|
|
|
|
return [ |
|
|
|
|
|
'code' => 0, |
|
|
|
|
|
'msg' => '更新失败' |
|
|
|
|
|
]; |
|
|
]; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -2558,4 +2532,311 @@ class CourseScheduleService extends BaseApiService |
|
|
]; |
|
|
]; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 批量签到 |
|
|
|
|
|
* @param array $data 批量签到数据 |
|
|
|
|
|
* @return array 签到结果 |
|
|
|
|
|
*/ |
|
|
|
|
|
public function batchSignIn(array $data) |
|
|
|
|
|
{ |
|
|
|
|
|
try { |
|
|
|
|
|
// 验证必填字段 |
|
|
|
|
|
if (empty($data['schedule_id'])) { |
|
|
|
|
|
return [ |
|
|
|
|
|
'code' => 0, |
|
|
|
|
|
'msg' => '课程安排ID不能为空' |
|
|
|
|
|
]; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (empty($data['students']) || !is_array($data['students'])) { |
|
|
|
|
|
return [ |
|
|
|
|
|
'code' => 0, |
|
|
|
|
|
'msg' => '学员签到数据不能为空' |
|
|
|
|
|
]; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 开启事务 |
|
|
|
|
|
Db::startTrans(); |
|
|
|
|
|
|
|
|
|
|
|
$scheduleId = $data['schedule_id']; |
|
|
|
|
|
$students = $data['students']; |
|
|
|
|
|
$remark = $data['remark'] ?? ''; |
|
|
|
|
|
$classPhoto = $data['class_photo'] ?? ''; |
|
|
|
|
|
|
|
|
|
|
|
// 验证课程安排是否存在 |
|
|
|
|
|
$schedule = Db::name('course_schedule') |
|
|
|
|
|
->where('id', $scheduleId) |
|
|
|
|
|
->where('deleted_at', 0) |
|
|
|
|
|
->find(); |
|
|
|
|
|
|
|
|
|
|
|
if (empty($schedule)) { |
|
|
|
|
|
Db::rollback(); |
|
|
|
|
|
return [ |
|
|
|
|
|
'code' => 0, |
|
|
|
|
|
'msg' => '课程安排不存在或已被删除' |
|
|
|
|
|
]; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
$successCount = 0; |
|
|
|
|
|
$failedCount = 0; |
|
|
|
|
|
$errors = []; |
|
|
|
|
|
|
|
|
|
|
|
// 批量更新学员签到状态 - 优雅复用单个签到逻辑 |
|
|
|
|
|
foreach ($students as $index => $student) { |
|
|
|
|
|
$studentId = $student['student_id'] ?? 0; |
|
|
|
|
|
$resourceId = $student['resource_id'] ?? 0; |
|
|
|
|
|
$status = $student['status'] ?? 1; // 默认为已到 |
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
|
// 验证学员数据 |
|
|
|
|
|
if (empty($studentId) && empty($resourceId)) { |
|
|
|
|
|
$failedCount++; |
|
|
|
|
|
$errors[] = "第" . ($index + 1) . "条记录:学员ID或资源ID不能为空"; |
|
|
|
|
|
continue; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 使用内部签到处理方法,避免嵌套事务 |
|
|
|
|
|
$result = $this->processSingleStudentSignIn($scheduleId, $studentId, $resourceId, $status, $remark); |
|
|
|
|
|
|
|
|
|
|
|
if ($result['success']) { |
|
|
|
|
|
$successCount++; |
|
|
|
|
|
} else { |
|
|
|
|
|
$failedCount++; |
|
|
|
|
|
$errors[] = "第" . ($index + 1) . "条记录:" . $result['error']; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} catch (\Exception $e) { |
|
|
|
|
|
$failedCount++; |
|
|
|
|
|
$errors[] = "第" . ($index + 1) . "条记录:处理异常 - " . $e->getMessage(); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 如果有课堂照片,保存到课程安排记录 |
|
|
|
|
|
if (!empty($classPhoto)) { |
|
|
|
|
|
// 处理图片上传或保存逻辑 |
|
|
|
|
|
$updateScheduleData = [ |
|
|
|
|
|
'class_photo' => $classPhoto, |
|
|
|
|
|
'updated_at' => date('Y-m-d H:i:s') |
|
|
|
|
|
]; |
|
|
|
|
|
|
|
|
|
|
|
// 如果有签到备注,也保存到课程安排 |
|
|
|
|
|
if (!empty($remark)) { |
|
|
|
|
|
$updateScheduleData['sign_in_remark'] = $remark; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Db::name('course_schedule') |
|
|
|
|
|
->where('id', $scheduleId) |
|
|
|
|
|
->update($updateScheduleData); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 记录签到历史(可选) |
|
|
|
|
|
$this->recordSignInHistory($scheduleId, [ |
|
|
|
|
|
'total_students' => count($students), |
|
|
|
|
|
'success_count' => $successCount, |
|
|
|
|
|
'failed_count' => $failedCount, |
|
|
|
|
|
'remark' => $remark, |
|
|
|
|
|
'class_photo' => $classPhoto, |
|
|
|
|
|
'sign_in_time' => date('Y-m-d H:i:s'), |
|
|
|
|
|
'operator_id' => $this->user_id ?? 0 |
|
|
|
|
|
]); |
|
|
|
|
|
|
|
|
|
|
|
// 检查是否有失败记录 |
|
|
|
|
|
if ($failedCount > 0) { |
|
|
|
|
|
// 如果有失败记录,但也有成功记录,提示部分成功 |
|
|
|
|
|
if ($successCount > 0) { |
|
|
|
|
|
Db::commit(); |
|
|
|
|
|
return [ |
|
|
|
|
|
'code' => 1, |
|
|
|
|
|
'msg' => "批量签到部分成功,成功:{$successCount}人,失败:{$failedCount}人", |
|
|
|
|
|
'data' => [ |
|
|
|
|
|
'success_count' => $successCount, |
|
|
|
|
|
'failed_count' => $failedCount, |
|
|
|
|
|
'errors' => $errors |
|
|
|
|
|
] |
|
|
|
|
|
]; |
|
|
|
|
|
} else { |
|
|
|
|
|
// 全部失败 |
|
|
|
|
|
Db::rollback(); |
|
|
|
|
|
return [ |
|
|
|
|
|
'code' => 0, |
|
|
|
|
|
'msg' => "批量签到失败,失败:{$failedCount}人", |
|
|
|
|
|
'data' => [ |
|
|
|
|
|
'success_count' => $successCount, |
|
|
|
|
|
'failed_count' => $failedCount, |
|
|
|
|
|
'errors' => $errors |
|
|
|
|
|
] |
|
|
|
|
|
]; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 全部成功 |
|
|
|
|
|
Db::commit(); |
|
|
|
|
|
|
|
|
|
|
|
return [ |
|
|
|
|
|
'code' => 1, |
|
|
|
|
|
'msg' => "批量签到成功,共签到{$successCount}人", |
|
|
|
|
|
'data' => [ |
|
|
|
|
|
'success_count' => $successCount, |
|
|
|
|
|
'failed_count' => $failedCount, |
|
|
|
|
|
'schedule_id' => $scheduleId |
|
|
|
|
|
] |
|
|
|
|
|
]; |
|
|
|
|
|
|
|
|
|
|
|
} catch (\Exception $e) { |
|
|
|
|
|
Db::rollback(); |
|
|
|
|
|
return [ |
|
|
|
|
|
'code' => 0, |
|
|
|
|
|
'msg' => '批量签到失败:' . $e->getMessage() |
|
|
|
|
|
]; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 记录签到历史 |
|
|
|
|
|
* @param int $scheduleId 课程安排ID |
|
|
|
|
|
* @param array $signInData 签到数据 |
|
|
|
|
|
* @return void |
|
|
|
|
|
*/ |
|
|
|
|
|
private function recordSignInHistory($scheduleId, $signInData) |
|
|
|
|
|
{ |
|
|
|
|
|
try { |
|
|
|
|
|
// 这里可以记录签到历史到专门的表中 |
|
|
|
|
|
// 如果没有专门的签到历史表,可以记录到日志或其他地方 |
|
|
|
|
|
$historyData = [ |
|
|
|
|
|
'schedule_id' => $scheduleId, |
|
|
|
|
|
'sign_in_data' => json_encode($signInData), |
|
|
|
|
|
'created_at' => date('Y-m-d H:i:s') |
|
|
|
|
|
]; |
|
|
|
|
|
|
|
|
|
|
|
// 假设有一个签到历史表 sign_in_history |
|
|
|
|
|
// Db::name('sign_in_history')->insert($historyData); |
|
|
|
|
|
|
|
|
|
|
|
// 或者记录到系统日志 |
|
|
|
|
|
trace('Batch Sign In: ' . json_encode($historyData)); |
|
|
|
|
|
} catch (\Exception $e) { |
|
|
|
|
|
// 记录日志失败不影响主流程 |
|
|
|
|
|
trace('Record sign in history failed: ' . $e->getMessage()); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 处理试听课签到逻辑 |
|
|
|
|
|
* @param Student $student 学员模型实例 |
|
|
|
|
|
* @throws \Exception |
|
|
|
|
|
*/ |
|
|
|
|
|
private function handleTrialClassCheckin($student) |
|
|
|
|
|
{ |
|
|
|
|
|
try { |
|
|
|
|
|
$currentTrialCount = $student->trial_class_count; |
|
|
|
|
|
|
|
|
|
|
|
// 如果试听课次数为0,不进行任何更新 |
|
|
|
|
|
if ($currentTrialCount <= 0) { |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
$updateData = []; |
|
|
|
|
|
$newTrialCount = $currentTrialCount - 1; |
|
|
|
|
|
$updateData['trial_class_count'] = max(0, $newTrialCount); // 确保最小值为0 |
|
|
|
|
|
|
|
|
|
|
|
// 根据当前试听次数设置对应的签到时间 |
|
|
|
|
|
if ($currentTrialCount === 2) { |
|
|
|
|
|
// 第一次试听课签到 |
|
|
|
|
|
$updateData['first_come'] = date('Y-m-d H:i:s'); |
|
|
|
|
|
} elseif ($currentTrialCount === 1) { |
|
|
|
|
|
// 第二次试听课签到 |
|
|
|
|
|
$updateData['second_come'] = date('Y-m-d H:i:s'); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 更新学员试听信息 |
|
|
|
|
|
$result = Student::where('id', $student->id)->update($updateData); |
|
|
|
|
|
|
|
|
|
|
|
if ($result === false) { |
|
|
|
|
|
throw new \Exception('更新学员试听信息失败'); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 记录日志 |
|
|
|
|
|
trace('Trial class checkin processed', [ |
|
|
|
|
|
'student_id' => $student->id, |
|
|
|
|
|
'old_trial_count' => $currentTrialCount, |
|
|
|
|
|
'new_trial_count' => $updateData['trial_class_count'], |
|
|
|
|
|
'update_fields' => array_keys($updateData) |
|
|
|
|
|
]); |
|
|
|
|
|
|
|
|
|
|
|
} catch (\Exception $e) { |
|
|
|
|
|
// 抛出异常以便外层事务回滚 |
|
|
|
|
|
throw new \Exception('处理试听课签到失败:' . $e->getMessage()); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 处理单个学员签到(内部方法,不管理事务) |
|
|
|
|
|
* @param int $scheduleId 课程安排ID |
|
|
|
|
|
* @param int $studentId 学员ID |
|
|
|
|
|
* @param int $resourceId 资源ID |
|
|
|
|
|
* @param int $status 签到状态 |
|
|
|
|
|
* @param string $reason 备注 |
|
|
|
|
|
* @return array 处理结果 |
|
|
|
|
|
*/ |
|
|
|
|
|
private function processSingleStudentSignIn($scheduleId, $studentId, $resourceId, $status, $reason = '') |
|
|
|
|
|
{ |
|
|
|
|
|
try { |
|
|
|
|
|
// 查找学员课程安排记录 |
|
|
|
|
|
$whereCondition = [ |
|
|
|
|
|
'schedule_id' => $scheduleId, |
|
|
|
|
|
'deleted_at' => 0 |
|
|
|
|
|
]; |
|
|
|
|
|
|
|
|
|
|
|
if (!empty($studentId)) { |
|
|
|
|
|
$whereCondition['student_id'] = $studentId; |
|
|
|
|
|
} elseif (!empty($resourceId)) { |
|
|
|
|
|
$whereCondition['resources_id'] = $resourceId; |
|
|
|
|
|
} else { |
|
|
|
|
|
return ['success' => false, 'error' => '学员ID或资源ID不能为空']; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
$enrollment = Db::name('person_course_schedule') |
|
|
|
|
|
->where($whereCondition) |
|
|
|
|
|
->find(); |
|
|
|
|
|
|
|
|
|
|
|
if (!$enrollment) { |
|
|
|
|
|
return ['success' => false, 'error' => '找不到学员记录']; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 获取学员信息(用于试听课处理) |
|
|
|
|
|
$student = Student::where('id', $enrollment['student_id'])->find(); |
|
|
|
|
|
if (!$student) { |
|
|
|
|
|
return ['success' => false, 'error' => '找不到学员信息']; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 准备更新数据 |
|
|
|
|
|
$updateData = [ |
|
|
|
|
|
'status' => $status, |
|
|
|
|
|
'updated_at' => date('Y-m-d H:i:s') |
|
|
|
|
|
]; |
|
|
|
|
|
|
|
|
|
|
|
if ($reason) { |
|
|
|
|
|
$updateData['remark'] = $reason; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 更新学员签到记录 |
|
|
|
|
|
$result = Db::name('person_course_schedule') |
|
|
|
|
|
->where('id', $enrollment['id']) |
|
|
|
|
|
->update($updateData); |
|
|
|
|
|
|
|
|
|
|
|
if ($result === false) { |
|
|
|
|
|
return ['success' => false, 'error' => '更新签到状态失败']; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 处理试听课签到逻辑(仅在签到成功且学员未付费时处理) |
|
|
|
|
|
if ($status === 1 && $student->pay_status != 1) { |
|
|
|
|
|
$this->handleTrialClassCheckin($student); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return ['success' => true, 'error' => '']; |
|
|
|
|
|
|
|
|
|
|
|
} catch (\Exception $e) { |
|
|
|
|
|
return ['success' => false, 'error' => $e->getMessage()]; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
} |