329 lines
9.0 KiB
PHP
329 lines
9.0 KiB
PHP
<?php
|
|
|
|
namespace app\common\model\user;
|
|
|
|
use think\Model;
|
|
use think\Db;
|
|
//use think\Query;
|
|
use think\Cache;
|
|
/**
|
|
* 商品-课程
|
|
*/
|
|
class Study extends Model
|
|
{
|
|
// 表名
|
|
protected $name = 'study';
|
|
|
|
public $timeStep = 10;
|
|
|
|
|
|
|
|
|
|
public function course()
|
|
{
|
|
return $this->belongsTo('\app\common\model\course\Course', 'course_id', 'id', [], 'RIGHT')->setEagerlyType(0);
|
|
}
|
|
|
|
public function user()
|
|
{
|
|
return $this->belongsTo('\app\admin\model\User', 'user_id', 'id', [], 'RIGHT')->setEagerlyType(0);
|
|
}
|
|
|
|
/**
|
|
* 获取统计信息
|
|
* @param $userId
|
|
* @param $time
|
|
* @return int[]
|
|
*/
|
|
public function getTotal($userId,$time=null){
|
|
$where = [];
|
|
|
|
$fields = ["sum(total_time) as time","COUNT(DISTINCT `course_id`) as course"];
|
|
|
|
if($userId != 0){
|
|
$where['user_id'] = $userId;
|
|
}else{
|
|
$fields[] = "COUNT(DISTINCT `user_id`) as user";
|
|
}
|
|
if($time){
|
|
$where['end_time'] = ['between',[$time['start'],$time['end']]];
|
|
}
|
|
|
|
|
|
|
|
$data = self::where($where)
|
|
->field($fields)
|
|
->find();
|
|
|
|
if(!$data){
|
|
$empty = [
|
|
'time'=>0,
|
|
'course'=>0
|
|
];
|
|
if($userId == 0){
|
|
$empty['user'] = 0;
|
|
}
|
|
|
|
return $empty;
|
|
}
|
|
$data['time'] = floor($data['time']/ 60 / 60 * 10 )/10;
|
|
return $data;
|
|
}
|
|
|
|
|
|
/**
|
|
* 获取课程列表
|
|
* @param $userId 分组ID
|
|
* @param $params 分页信息 page页码 limit获取数量
|
|
* @return array
|
|
*/
|
|
public function getStudyLog($userId = 0,$params = []){
|
|
$rows = self::with(['course']);
|
|
|
|
$where = [
|
|
'user_id'=>$userId,
|
|
'course.status'=>1
|
|
];
|
|
|
|
$buildSql = self::where($where)->order('end_time','desc')->limit($params['limit'])->page($params['page'])->buildSql();
|
|
|
|
$list = $rows->table($buildSql . ' as t')
|
|
->group('t.course_id')
|
|
->order('end_time','desc')
|
|
->field('sum(t.total_time) as total_time,count(*) as count,course__name,course__type,course__cover,course__id,end_time')
|
|
->select();
|
|
|
|
|
|
$data = [];
|
|
if(!empty($list)){
|
|
foreach ($list as $item){
|
|
$item['course'] = [
|
|
'id'=>$item['course__id'],
|
|
'name'=>$item['course__name'],
|
|
'type'=>$item['course__type'],
|
|
'cover'=>$item['course__cover'],
|
|
];
|
|
$data[] = $item;
|
|
}
|
|
}
|
|
return $data;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* 设置学习记录
|
|
* @param $userId 用户ID
|
|
* @param $courseId 课程ID
|
|
* @param $mediaProgress 媒体播放进度
|
|
* @param $finish 是否播放完成
|
|
* @return void
|
|
*/
|
|
public function setLog($userId, $courseId, $columnId, $mediaProgress = 0, $finish = 0)
|
|
{
|
|
$cacheKey = \app\common\constant\cache\Keys::STUDY_LOG . ':' . $userId . ':' . $courseId;
|
|
$log = Cache::get($cacheKey);
|
|
|
|
$now = time();
|
|
|
|
if (!$log) {
|
|
// 新建日志
|
|
$log = [
|
|
'user_id' => $userId,
|
|
'course_id' => $courseId,
|
|
'column_id' => $columnId,
|
|
'media_progress' => $mediaProgress,
|
|
'start_time' => $now - $this->timeStep,
|
|
'end_time' => $now,
|
|
'finish' => $finish,
|
|
'uniacid' => UNIACID,
|
|
'total_time' => $this->timeStep
|
|
];
|
|
} else {
|
|
// 合并已有日志,避免覆盖
|
|
$log['end_time'] = $now;
|
|
$log['media_progress'] = $mediaProgress;
|
|
$log['total_time'] = ($log['total_time'] ?? 0) + ($now - ($log['end_time'] ?? $now));
|
|
|
|
if(isset($log['finish']) && $log['finish'] == 1){
|
|
$log['finish'] = $finish; // 如果已完成,可以覆盖
|
|
}
|
|
|
|
// 保留 start_time 最早值
|
|
if(!isset($log['start_time'])){
|
|
$log['start_time'] = $now - $this->timeStep;
|
|
}
|
|
}
|
|
|
|
// 写入缓存
|
|
Cache::set($cacheKey, $log, \app\common\constant\cache\Timeout::STUDY_LOG_CACHE_SYNC);
|
|
|
|
// 维护缓存列表
|
|
$this->updateCacheKeyList($cacheKey);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/**
|
|
* 批量同步学习缓存数据到数据库
|
|
* @return void
|
|
*/
|
|
public function batchSyncStudyCache()
|
|
{
|
|
// 获取缓存键列表
|
|
$cacheKeyList = Cache::get(\app\common\constant\cache\Keys::STUDY_LOG_CACHE_KEYS, []);
|
|
if (!$cacheKeyList) {
|
|
return; // 如果没有缓存键,直接返回
|
|
}
|
|
// 遍历缓存键列表,将数据同步到数据库
|
|
foreach ($cacheKeyList as $cacheKey) {
|
|
$this->syncCacheToDatabase($cacheKey);
|
|
}
|
|
// 清理缓存键列表
|
|
Cache::rm(\app\common\constant\cache\Keys::STUDY_LOG_CACHE_KEYS);
|
|
}
|
|
|
|
|
|
/**
|
|
* 同步单个缓存数据到数据库
|
|
* @param $userId
|
|
* @param $courseId
|
|
* @return void
|
|
*/
|
|
public function singleSyncCache($userId, $courseId){
|
|
// 生成缓存键
|
|
$cacheKey = \app\common\constant\cache\Keys::STUDY_LOG.':' . $userId . ':' . $courseId;
|
|
|
|
$log = Cache::get($cacheKey);
|
|
if($log){
|
|
$this->syncCacheToDatabase($cacheKey);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* 同步缓存到数据库
|
|
* @param $cacheKey
|
|
* @return void
|
|
*/
|
|
public function syncCacheToDatabase($cacheKey){
|
|
$log = Cache::get($cacheKey); // 获取缓存数据
|
|
if ($log) {
|
|
// 判断缓存中的数据是否需要同步到数据库
|
|
$logExists = self::where([
|
|
'user_id' => $log['user_id'],
|
|
'course_id' => $log['course_id'],
|
|
'column_id' => $log['column_id'],
|
|
])->order('id','desc')->find();
|
|
|
|
if ($logExists) {
|
|
// 如果记录存在,更新数据库
|
|
|
|
$data = [
|
|
'end_time' => $log['end_time'],
|
|
'media_progress'=>$log['media_progress'],
|
|
'total_time' => $log['total_time'] + $logExists['total_time']
|
|
];
|
|
|
|
if(isset($log['finish']) && $log['finish'] == 1){
|
|
$data['finish'] = $log['finish'];
|
|
}
|
|
|
|
self::where(['id' => $logExists['id']])->update($data);
|
|
} else {
|
|
// 插入新的记录
|
|
self::insert($log);
|
|
}
|
|
|
|
// 同步完后,清除缓存
|
|
Cache::rm($cacheKey);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 维护缓存键列表
|
|
* 用于跟踪所有缓存的日志键,供后台任务使用
|
|
*/
|
|
private function updateCacheKeyList($cacheKey)
|
|
{
|
|
// 获取现有的缓存键列表
|
|
$cacheKeyList = Cache::get(\app\common\constant\cache\Keys::STUDY_LOG_CACHE_KEYS, []);
|
|
|
|
// 如果缓存键列表为空,则初始化为空数组
|
|
if (!$cacheKeyList) {
|
|
$cacheKeyList = [];
|
|
}
|
|
|
|
// 如果缓存键不在列表中,则添加
|
|
if (!in_array($cacheKey, $cacheKeyList)) {
|
|
$cacheKeyList[] = $cacheKey;
|
|
}
|
|
|
|
// 更新缓存键列表
|
|
Cache::set(\app\common\constant\cache\Keys::STUDY_LOG_CACHE_KEYS, $cacheKeyList, (\app\common\constant\cache\Timeout::STUDY_LOG_CACHE_SYNC + 60));
|
|
}
|
|
|
|
|
|
/**
|
|
* 获取课程学习数量
|
|
* @param $courseId
|
|
* @return void
|
|
*/
|
|
public function getCourseStudyNum($courseId){
|
|
return self::where([
|
|
'course_id'=>$courseId
|
|
])->count();
|
|
}
|
|
|
|
/**
|
|
* 获取连续学习天数
|
|
* @param $userId
|
|
* @return int
|
|
*/
|
|
public function getContinuousStudyDays($userId)
|
|
{
|
|
// 获取当前时间
|
|
$today = strtotime('today');
|
|
|
|
// 获取用户的学习记录,并按日期分组
|
|
$records = self::where('user_id', $userId)
|
|
->field("FROM_UNIXTIME(start_time, '%Y-%m-%d') as date")
|
|
->group('date')
|
|
->order('date', 'desc')
|
|
->select();
|
|
|
|
if (empty($records)) {
|
|
return 0;
|
|
}
|
|
|
|
$records = collection($records)->toArray();
|
|
|
|
// 计算连续学习天数
|
|
$continuousDays = 0;
|
|
$previousDate = $today;
|
|
|
|
foreach ($records as $record) {
|
|
$recordDate = strtotime($record['date']);
|
|
// 检查是否是连续日期
|
|
if ($recordDate == $previousDate || $recordDate == strtotime('-1 day', $previousDate)) {
|
|
$continuousDays++;
|
|
$previousDate = $recordDate;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
// 检查今天是否有学习记录
|
|
$todayRecord = self::where('user_id', $userId)
|
|
->where('start_time', '>=', strtotime('today'))
|
|
->find();
|
|
|
|
if ($todayRecord) {
|
|
$continuousDays++;
|
|
}
|
|
|
|
return $continuousDays;
|
|
}
|
|
} |