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.
372 lines
13 KiB
372 lines
13 KiB
<?php
|
|
// +----------------------------------------------------------------------
|
|
// | Niucloud-admin 企业快速开发的多应用管理平台
|
|
// +----------------------------------------------------------------------
|
|
// | 官方网址:https://www.niucloud.com
|
|
// +----------------------------------------------------------------------
|
|
// | niucloud团队 版权所有 开源版本可自由商用
|
|
// +----------------------------------------------------------------------
|
|
// | Author: Niucloud Team
|
|
// +----------------------------------------------------------------------
|
|
|
|
namespace app\job\transfer\schedule;
|
|
|
|
use app\model\member\Member;
|
|
use app\model\course\Course;
|
|
use app\model\course_booking\CourseBooking;
|
|
use app\model\notification\Notification;
|
|
use core\base\BaseJob;
|
|
use think\facade\Log;
|
|
|
|
/**
|
|
* 定时检查学员课程有效期和课时数量发送提醒任务
|
|
* 监控学员课程状态,及时发送相关提醒通知
|
|
*/
|
|
class StudentCourseReminderJob extends BaseJob
|
|
{
|
|
/**
|
|
* 执行定时任务
|
|
* @param mixed ...$data 任务参数
|
|
* @return bool 处理结果
|
|
*/
|
|
public function doJob(...$data)
|
|
{
|
|
Log::write('开始执行学员课程提醒任务');
|
|
|
|
try {
|
|
// 检查课程有效期提醒
|
|
$expiryResult = $this->checkCourseExpiryReminders();
|
|
|
|
// 检查课时余量提醒
|
|
$hoursResult = $this->checkRemainingHoursReminders();
|
|
|
|
// 检查预约课程提醒
|
|
$bookingResult = $this->checkUpcomingBookingReminders();
|
|
|
|
// 检查长期未上课提醒
|
|
$inactiveResult = $this->checkInactiveStudentReminders();
|
|
|
|
// 检查课程完成祝贺
|
|
$completionResult = $this->checkCourseCompletionCongratulations();
|
|
|
|
Log::write('学员课程提醒任务执行完成', [
|
|
'expiry_reminders' => $expiryResult['count'],
|
|
'hours_reminders' => $hoursResult['count'],
|
|
'booking_reminders' => $bookingResult['count'],
|
|
'inactive_reminders' => $inactiveResult['count'],
|
|
'completion_congratulations' => $completionResult['count']
|
|
]);
|
|
|
|
return true;
|
|
|
|
} catch (\Exception $e) {
|
|
Log::write('学员课程提醒任务执行失败:' . $e->getMessage());
|
|
throw $e;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 检查课程有效期提醒
|
|
* @return array 处理结果
|
|
*/
|
|
protected function checkCourseExpiryReminders()
|
|
{
|
|
$currentDate = date('Y-m-d');
|
|
|
|
// 查找7天内即将过期的课程
|
|
$expiringCourses = Course::where('valid_until', '>', $currentDate)
|
|
->where('valid_until', '<=', date('Y-m-d', strtotime('+7 days')))
|
|
->where('status', 1)
|
|
->select();
|
|
|
|
$count = 0;
|
|
foreach ($expiringCourses as $course) {
|
|
// 检查是否已发送过提醒
|
|
$reminderSent = $this->checkReminderSent($course->member_id, 'course_expiry', $course->id);
|
|
|
|
if (!$reminderSent) {
|
|
$daysLeft = ceil((strtotime($course->valid_until) - strtotime($currentDate)) / 86400);
|
|
|
|
$this->sendCourseExpiryReminder($course, $daysLeft);
|
|
$this->recordReminderSent($course->member_id, 'course_expiry', $course->id);
|
|
|
|
$count++;
|
|
Log::write("发送课程过期提醒:学员ID {$course->member_id}, 课程ID {$course->id}, 剩余 {$daysLeft} 天");
|
|
}
|
|
}
|
|
|
|
return ['count' => $count];
|
|
}
|
|
|
|
/**
|
|
* 检查课时余量提醒
|
|
* @return array 处理结果
|
|
*/
|
|
protected function checkRemainingHoursReminders()
|
|
{
|
|
// 查找剩余课时少于3节的有效课程
|
|
$lowHoursCourses = Course::where('remaining_hours', '>', 0)
|
|
->where('remaining_hours', '<=', 3)
|
|
->where('status', 1)
|
|
->select();
|
|
|
|
$count = 0;
|
|
foreach ($lowHoursCourses as $course) {
|
|
// 检查是否已发送过提醒
|
|
$reminderSent = $this->checkReminderSent($course->member_id, 'low_hours', $course->id);
|
|
|
|
if (!$reminderSent) {
|
|
$this->sendLowHoursReminder($course);
|
|
$this->recordReminderSent($course->member_id, 'low_hours', $course->id);
|
|
|
|
$count++;
|
|
Log::write("发送课时不足提醒:学员ID {$course->member_id}, 课程ID {$course->id}, 剩余 {$course->remaining_hours} 课时");
|
|
}
|
|
}
|
|
|
|
return ['count' => $count];
|
|
}
|
|
|
|
/**
|
|
* 检查预约课程提醒
|
|
* @return array 处理结果
|
|
*/
|
|
protected function checkUpcomingBookingReminders()
|
|
{
|
|
$tomorrow = date('Y-m-d', strtotime('+1 day'));
|
|
|
|
// 查找明天的预约课程
|
|
$tomorrowBookings = CourseBooking::where('booking_date', $tomorrow)
|
|
->where('status', 1)
|
|
->select();
|
|
|
|
$count = 0;
|
|
foreach ($tomorrowBookings as $booking) {
|
|
// 检查是否已发送过提醒
|
|
$reminderSent = $this->checkReminderSent($booking->member_id, 'booking_reminder', $booking->id);
|
|
|
|
if (!$reminderSent) {
|
|
$this->sendBookingReminder($booking);
|
|
$this->recordReminderSent($booking->member_id, 'booking_reminder', $booking->id);
|
|
|
|
$count++;
|
|
Log::write("发送预约提醒:学员ID {$booking->member_id}, 预约ID {$booking->id}");
|
|
}
|
|
}
|
|
|
|
return ['count' => $count];
|
|
}
|
|
|
|
/**
|
|
* 检查长期未上课提醒
|
|
* @return array 处理结果
|
|
*/
|
|
protected function checkInactiveStudentReminders()
|
|
{
|
|
$thirtyDaysAgo = date('Y-m-d', strtotime('-30 days'));
|
|
|
|
// 查找有有效课程但30天内没有上课的学员
|
|
$inactiveMembers = Member::whereHas('courses', function($query) {
|
|
$query->where('status', 1)->where('remaining_hours', '>', 0);
|
|
})->whereDoesntHave('courseBookings', function($query) use ($thirtyDaysAgo) {
|
|
$query->where('booking_date', '>=', $thirtyDaysAgo)
|
|
->where('status', 'completed');
|
|
})->select();
|
|
|
|
$count = 0;
|
|
foreach ($inactiveMembers as $member) {
|
|
// 检查是否已发送过提醒
|
|
$reminderSent = $this->checkReminderSent($member->id, 'inactive_student', $member->id);
|
|
|
|
if (!$reminderSent) {
|
|
$this->sendInactiveStudentReminder($member);
|
|
$this->recordReminderSent($member->id, 'inactive_student', $member->id);
|
|
|
|
$count++;
|
|
Log::write("发送长期未上课提醒:学员ID {$member->id}");
|
|
}
|
|
}
|
|
|
|
return ['count' => $count];
|
|
}
|
|
|
|
/**
|
|
* 检查课程完成祝贺
|
|
* @return array 处理结果
|
|
*/
|
|
protected function checkCourseCompletionCongratulations()
|
|
{
|
|
// 查找今日刚完成的课程(剩余课时为0且今日有完成的预约)
|
|
$today = date('Y-m-d');
|
|
|
|
$completedCourses = Course::where('remaining_hours', 0)
|
|
->where('status', 1)
|
|
->whereHas('courseBookings', function($query) use ($today) {
|
|
$query->where('booking_date', $today)
|
|
->where('status', 'completed');
|
|
})->select();
|
|
|
|
$count = 0;
|
|
foreach ($completedCourses as $course) {
|
|
// 检查是否已发送过祝贺
|
|
$congratsSent = $this->checkReminderSent($course->member_id, 'course_completion', $course->id);
|
|
|
|
if (!$congratsSent) {
|
|
$this->sendCourseCompletionCongratulations($course);
|
|
$this->recordReminderSent($course->member_id, 'course_completion', $course->id);
|
|
|
|
// 更新课程状态为已完成
|
|
$course->status = 3; // 假设3为已完成状态
|
|
$course->completed_at = date('Y-m-d H:i:s');
|
|
$course->save();
|
|
|
|
$count++;
|
|
Log::write("发送课程完成祝贺:学员ID {$course->member_id}, 课程ID {$course->id}");
|
|
}
|
|
}
|
|
|
|
return ['count' => $count];
|
|
}
|
|
|
|
/**
|
|
* 发送课程过期提醒
|
|
* @param Course $course 课程对象
|
|
* @param int $daysLeft 剩余天数
|
|
*/
|
|
protected function sendCourseExpiryReminder($course, $daysLeft)
|
|
{
|
|
$member = Member::find($course->member_id);
|
|
if (!$member) return;
|
|
|
|
$message = "亲爱的{$member->nickname},您的课程《{$course->course_name}》将在{$daysLeft}天后过期,请尽快安排上课时间。";
|
|
|
|
$this->createNotification($member->id, 'course_expiry', '课程即将过期提醒', $message, [
|
|
'course_id' => $course->id,
|
|
'days_left' => $daysLeft
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* 发送课时不足提醒
|
|
* @param Course $course 课程对象
|
|
*/
|
|
protected function sendLowHoursReminder($course)
|
|
{
|
|
$member = Member::find($course->member_id);
|
|
if (!$member) return;
|
|
|
|
$message = "亲爱的{$member->nickname},您的课程《{$course->course_name}》还剩{$course->remaining_hours}节课,建议及时续费以确保学习连续性。";
|
|
|
|
$this->createNotification($member->id, 'low_hours', '课时不足提醒', $message, [
|
|
'course_id' => $course->id,
|
|
'remaining_hours' => $course->remaining_hours
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* 发送预约课程提醒
|
|
* @param CourseBooking $booking 预约对象
|
|
*/
|
|
protected function sendBookingReminder($booking)
|
|
{
|
|
$member = Member::find($booking->member_id);
|
|
$course = Course::find($booking->course_id);
|
|
if (!$member || !$course) return;
|
|
|
|
$message = "亲爱的{$member->nickname},您预约的课程《{$course->course_name}》将在明天{$booking->time_slot}开始,请准时参加。";
|
|
|
|
$this->createNotification($member->id, 'booking_reminder', '课程预约提醒', $message, [
|
|
'booking_id' => $booking->id,
|
|
'course_id' => $booking->course_id,
|
|
'booking_date' => $booking->booking_date,
|
|
'time_slot' => $booking->time_slot
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* 发送长期未上课提醒
|
|
* @param Member $member 学员对象
|
|
*/
|
|
protected function sendInactiveStudentReminder($member)
|
|
{
|
|
$message = "亲爱的{$member->nickname},您已经很久没有上课了。坚持学习才能看到更好的效果,快来预约课程吧!";
|
|
|
|
$this->createNotification($member->id, 'inactive_student', '久未上课提醒', $message, [
|
|
'member_id' => $member->id
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* 发送课程完成祝贺
|
|
* @param Course $course 课程对象
|
|
*/
|
|
protected function sendCourseCompletionCongratulations($course)
|
|
{
|
|
$member = Member::find($course->member_id);
|
|
if (!$member) return;
|
|
|
|
$message = "恭喜{$member->nickname}!您已成功完成《{$course->course_name}》课程的全部学习,感谢您的坚持和努力!";
|
|
|
|
$this->createNotification($member->id, 'course_completion', '课程完成祝贺', $message, [
|
|
'course_id' => $course->id,
|
|
'completion_date' => date('Y-m-d')
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* 检查是否已发送过提醒
|
|
* @param int $memberId 学员ID
|
|
* @param string $type 提醒类型
|
|
* @param int $relatedId 相关ID
|
|
* @return bool
|
|
*/
|
|
protected function checkReminderSent($memberId, $type, $relatedId)
|
|
{
|
|
$today = date('Y-m-d');
|
|
|
|
$exists = Notification::where('member_id', $memberId)
|
|
->where('type', $type)
|
|
->where('related_id', $relatedId)
|
|
->where('created_at', '>=', $today . ' 00:00:00')
|
|
->count();
|
|
|
|
return $exists > 0;
|
|
}
|
|
|
|
/**
|
|
* 记录已发送的提醒
|
|
* @param int $memberId 学员ID
|
|
* @param string $type 提醒类型
|
|
* @param int $relatedId 相关ID
|
|
*/
|
|
protected function recordReminderSent($memberId, $type, $relatedId)
|
|
{
|
|
// 这个方法可以用于记录提醒发送日志,避免重复发送
|
|
Log::write("记录提醒发送:学员ID {$memberId}, 类型: {$type}, 相关ID: {$relatedId}");
|
|
}
|
|
|
|
/**
|
|
* 创建通知记录
|
|
* @param int $memberId 学员ID
|
|
* @param string $type 通知类型
|
|
* @param string $title 标题
|
|
* @param string $message 消息内容
|
|
* @param array $extra 额外数据
|
|
*/
|
|
protected function createNotification($memberId, $type, $title, $message, $extra = [])
|
|
{
|
|
$notification = new Notification();
|
|
$notification->member_id = $memberId;
|
|
$notification->type = $type;
|
|
$notification->title = $title;
|
|
$notification->message = $message;
|
|
$notification->extra_data = json_encode($extra);
|
|
$notification->status = 'sent';
|
|
$notification->created_at = date('Y-m-d H:i:s');
|
|
$notification->save();
|
|
|
|
// 这里可以扩展实际的通知发送逻辑
|
|
// 比如调用短信服务、邮件服务、推送服务等
|
|
Log::write("创建通知:学员ID {$memberId}, 类型: {$type}, 标题: {$title}");
|
|
}
|
|
}
|