初始化项目:添加后端代码、ThinkPHP框架、前端资源

This commit is contained in:
amb
2026-09-03 12:42:39 +08:00
commit 482bece22e
3726 changed files with 416708 additions and 0 deletions
+329
View File
@@ -0,0 +1,329 @@
<?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;
}
}