mirror of
https://gitee.com/koogua/course-tencent-cloud.git
synced 2025-06-28 05:11:39 +08:00
完成同一课程多次购买学习逻辑
This commit is contained in:
parent
cf5cd3ea51
commit
533b0eaad5
@ -32,10 +32,7 @@ abstract class Cache extends Component
|
|||||||
|
|
||||||
$content = $this->getContent($id);
|
$content = $this->getContent($id);
|
||||||
|
|
||||||
/**
|
$lifetime = $this->getLifetime();
|
||||||
* 原始内容为空,设置较短的生存时间,简单防止穿透
|
|
||||||
*/
|
|
||||||
$lifetime = $content ? $this->getLifetime() : 5 * 60;
|
|
||||||
|
|
||||||
$this->cache->save($key, $content, $lifetime);
|
$this->cache->save($key, $content, $lifetime);
|
||||||
|
|
||||||
|
@ -40,11 +40,9 @@ abstract class Counter extends Component
|
|||||||
if (!$this->cache->exists($key)) {
|
if (!$this->cache->exists($key)) {
|
||||||
|
|
||||||
$content = $this->getContent($id);
|
$content = $this->getContent($id);
|
||||||
|
|
||||||
$lifetime = $this->getLifetime();
|
$lifetime = $this->getLifetime();
|
||||||
|
|
||||||
$this->redis->hMSet($key, $content);
|
$this->redis->hMSet($key, $content);
|
||||||
|
|
||||||
$this->redis->expire($key, $lifetime);
|
$this->redis->expire($key, $lifetime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
33
app/Caches/CourseUser.php
Normal file
33
app/Caches/CourseUser.php
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Caches;
|
||||||
|
|
||||||
|
use App\Repos\CourseUser as CourseUserRepo;
|
||||||
|
|
||||||
|
class CourseUser extends Cache
|
||||||
|
{
|
||||||
|
|
||||||
|
protected $lifetime = 1 * 86400;
|
||||||
|
|
||||||
|
public function getLifetime()
|
||||||
|
{
|
||||||
|
return $this->lifetime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getKey($id = null)
|
||||||
|
{
|
||||||
|
return "course_user:{$id}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getContent($id = null)
|
||||||
|
{
|
||||||
|
list($courseId, $userId) = explode('_', $id);
|
||||||
|
|
||||||
|
$repo = new CourseUserRepo();
|
||||||
|
|
||||||
|
$courseUser = $repo->findCourseUser($courseId, $userId);
|
||||||
|
|
||||||
|
return $courseUser ?: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -2,14 +2,11 @@
|
|||||||
|
|
||||||
namespace App\Console\Tasks;
|
namespace App\Console\Tasks;
|
||||||
|
|
||||||
use App\Models\ChapterUser as ChapterUserModel;
|
|
||||||
use App\Models\CourseUser as CourseUserModel;
|
use App\Models\CourseUser as CourseUserModel;
|
||||||
use App\Models\Learning as LearningModel;
|
|
||||||
use App\Models\Order as OrderModel;
|
use App\Models\Order as OrderModel;
|
||||||
use App\Models\Refund as RefundModel;
|
use App\Models\Refund as RefundModel;
|
||||||
use App\Models\Task as TaskModel;
|
use App\Models\Task as TaskModel;
|
||||||
use App\Models\Trade as TradeModel;
|
use App\Models\Trade as TradeModel;
|
||||||
use App\Repos\CourseUser as CourseUserRepo;
|
|
||||||
use App\Repos\Order as OrderRepo;
|
use App\Repos\Order as OrderRepo;
|
||||||
use App\Repos\User as UserRepo;
|
use App\Repos\User as UserRepo;
|
||||||
use App\Services\Smser\Order as OrderSmser;
|
use App\Services\Smser\Order as OrderSmser;
|
||||||
@ -116,8 +113,6 @@ class OrderTask extends Task
|
|||||||
if ($courseUser->create($data) === false) {
|
if ($courseUser->create($data) === false) {
|
||||||
throw new \RuntimeException('Create CourseQuery User Failed');
|
throw new \RuntimeException('Create CourseQuery User Failed');
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->handleCourseHistory($data['course_id'], $data['user_id']);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function handlePackageOrder(OrderModel $order)
|
protected function handlePackageOrder(OrderModel $order)
|
||||||
@ -140,10 +135,8 @@ class OrderTask extends Task
|
|||||||
$courseUser = new CourseUserModel();
|
$courseUser = new CourseUserModel();
|
||||||
|
|
||||||
if ($courseUser->create($data) === false) {
|
if ($courseUser->create($data) === false) {
|
||||||
throw new \RuntimeException('Create CourseQuery User Failed');
|
throw new \RuntimeException('Create Course User Failed');
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->handleCourseHistory($data['course_id'], $data['user_id']);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,57 +189,6 @@ class OrderTask extends Task
|
|||||||
$refund->create();
|
$refund->create();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function handleCourseHistory($courseId, $userId)
|
|
||||||
{
|
|
||||||
$courseUserRepo = new CourseUserRepo();
|
|
||||||
|
|
||||||
$courseUser = $courseUserRepo->findCourseStudent($courseId, $userId);
|
|
||||||
|
|
||||||
if ($courseUser) {
|
|
||||||
$courseUser->update(['deleted' => 1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
$chapterUsers = $this->findPlanChapterUsers($courseId, $userId);
|
|
||||||
|
|
||||||
if ($chapterUsers->count() > 0) {
|
|
||||||
$chapterUsers->update(['deleted' => 1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
$learnings = $this->findPlanLearnings($courseId, $userId);
|
|
||||||
|
|
||||||
if ($learnings->count() > 0) {
|
|
||||||
$learnings->update(['deleted' => 1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param int $courseId
|
|
||||||
* @param int $userId
|
|
||||||
* @return ResultsetInterface|Resultset|CourseUserModel[]
|
|
||||||
*/
|
|
||||||
protected function findPlanChapterUsers($courseId, $userId)
|
|
||||||
{
|
|
||||||
return ChapterUserModel::query()
|
|
||||||
->where('course_id = :course_id:', ['course_id' => $courseId])
|
|
||||||
->andWhere('user_id = :user_id:', ['user_id' => $userId])
|
|
||||||
->andWhere('deleted = 0')
|
|
||||||
->execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param int $courseId
|
|
||||||
* @param int $userId
|
|
||||||
* @return ResultsetInterface|Resultset|CourseUserModel[]
|
|
||||||
*/
|
|
||||||
protected function findPlanLearnings($courseId, $userId)
|
|
||||||
{
|
|
||||||
return LearningModel::query()
|
|
||||||
->where('course_id = :course_id:', ['course_id' => $courseId])
|
|
||||||
->andWhere('user_id = :user_id:', ['user_id' => $userId])
|
|
||||||
->andWhere('deleted = 0')
|
|
||||||
->execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param int $orderId
|
* @param int $orderId
|
||||||
* @return Model|TradeModel
|
* @return Model|TradeModel
|
||||||
|
@ -153,21 +153,34 @@ class SyncLearningTask extends Task
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$userLearnings = $courseRepo->findConsumedUserLearnings($courseId, $userId);
|
$userLearnings = $courseRepo->findUserLearnings($courseId, $userId, $courseUser->plan_id);
|
||||||
|
|
||||||
if ($userLearnings->count() == 0) {
|
if ($userLearnings->count() == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array $consumedUserLearnings
|
||||||
|
*/
|
||||||
|
$consumedUserLearnings = $userLearnings->filter(function ($item) {
|
||||||
|
if ($item->consumed == 1) {
|
||||||
|
return $item;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (count($consumedUserLearnings) == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
$duration = 0;
|
$duration = 0;
|
||||||
|
|
||||||
foreach ($userLearnings as $learning) {
|
foreach ($consumedUserLearnings as $learning) {
|
||||||
$duration += $learning->duration;
|
$duration += $learning['duration'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$courseLessonIds = kg_array_column($courseLessons->toArray(), 'id');
|
$courseLessonIds = kg_array_column($courseLessons->toArray(), 'id');
|
||||||
$userLessonIds = kg_array_column($userLearnings->toArray(), 'chapter_id');
|
$consumedUserLessonIds = kg_array_column($consumedUserLearnings, 'chapter_id');
|
||||||
$consumedLessonIds = array_intersect($courseLessonIds, $userLessonIds);
|
$consumedLessonIds = array_intersect($courseLessonIds, $consumedUserLessonIds);
|
||||||
|
|
||||||
$totalCount = count($courseLessonIds);
|
$totalCount = count($courseLessonIds);
|
||||||
$consumedCount = count($consumedLessonIds);
|
$consumedCount = count($consumedLessonIds);
|
||||||
|
@ -10,6 +10,14 @@ use App\Http\Admin\Services\Package as PackageService;
|
|||||||
class PackageController extends Controller
|
class PackageController extends Controller
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Get("/search", name="admin.package.search")
|
||||||
|
*/
|
||||||
|
public function searchAction()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Get("/guiding", name="admin.package.guiding")
|
* @Get("/guiding", name="admin.package.guiding")
|
||||||
*/
|
*/
|
||||||
|
@ -105,18 +105,24 @@ class AuthNode extends Service
|
|||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => '1-3-2',
|
'id' => '1-3-2',
|
||||||
|
'title' => '搜索套餐',
|
||||||
|
'type' => 'menu',
|
||||||
|
'route' => 'admin.package.search',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => '1-3-3',
|
||||||
'title' => '添加套餐',
|
'title' => '添加套餐',
|
||||||
'type' => 'menu',
|
'type' => 'menu',
|
||||||
'route' => 'admin.package.add',
|
'route' => 'admin.package.add',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => '1-3-3',
|
'id' => '1-3-4',
|
||||||
'title' => '编辑套餐',
|
'title' => '编辑套餐',
|
||||||
'type' => 'button',
|
'type' => 'button',
|
||||||
'route' => 'admin.package.edit',
|
'route' => 'admin.package.edit',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => '1-3-4',
|
'id' => '1-3-5',
|
||||||
'title' => '删除套餐',
|
'title' => '删除套餐',
|
||||||
'type' => 'button',
|
'type' => 'button',
|
||||||
'route' => 'admin.package.delete',
|
'route' => 'admin.package.delete',
|
||||||
|
@ -358,7 +358,7 @@ class Course extends Service
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$newTeacherIds = explode(',', $teacherIds);
|
$newTeacherIds = $teacherIds ? explode(',', $teacherIds) : [];
|
||||||
$addedTeacherIds = array_diff($newTeacherIds, $originTeacherIds);
|
$addedTeacherIds = array_diff($newTeacherIds, $originTeacherIds);
|
||||||
|
|
||||||
if ($addedTeacherIds) {
|
if ($addedTeacherIds) {
|
||||||
@ -412,7 +412,7 @@ class Course extends Service
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$newCategoryIds = explode(',', $categoryIds);
|
$newCategoryIds = $categoryIds ? explode(',', $categoryIds) : [];
|
||||||
$addedCategoryIds = array_diff($newCategoryIds, $originCategoryIds);
|
$addedCategoryIds = array_diff($newCategoryIds, $originCategoryIds);
|
||||||
|
|
||||||
if ($addedCategoryIds) {
|
if ($addedCategoryIds) {
|
||||||
@ -463,7 +463,7 @@ class Course extends Service
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$newRelatedIds = explode(',', $courseIds);
|
$newRelatedIds = $courseIds ? explode(',', $courseIds) : [];
|
||||||
$addedRelatedIds = array_diff($newRelatedIds, $originRelatedIds);
|
$addedRelatedIds = array_diff($newRelatedIds, $originRelatedIds);
|
||||||
|
|
||||||
$courseRelatedRepo = new CourseRelatedRepo();
|
$courseRelatedRepo = new CourseRelatedRepo();
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Admin\Services;
|
namespace App\Http\Admin\Services;
|
||||||
|
|
||||||
|
use App\Caches\CoursePackageList as CoursePackageListCache;
|
||||||
use App\Caches\Package as PackageCache;
|
use App\Caches\Package as PackageCache;
|
||||||
use App\Caches\PackageCourseList as PackageCourseListCache;
|
use App\Caches\PackageCourseList as PackageCourseListCache;
|
||||||
use App\Library\Paginator\Query as PagerQuery;
|
use App\Library\Paginator\Query as PagerQuery;
|
||||||
@ -93,7 +94,7 @@ class Package extends Service
|
|||||||
|
|
||||||
$package->update($data);
|
$package->update($data);
|
||||||
|
|
||||||
$this->updateCourseCount($package);
|
$this->updatePackageCourseCount($package);
|
||||||
|
|
||||||
$this->rebuildPackageCache($package);
|
$this->rebuildPackageCache($package);
|
||||||
|
|
||||||
@ -193,7 +194,7 @@ class Package extends Service
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$newCourseIds = explode(',', $courseIds);
|
$newCourseIds = $courseIds ? explode(',', $courseIds) : [];
|
||||||
$addedCourseIds = array_diff($newCourseIds, $originCourseIds);
|
$addedCourseIds = array_diff($newCourseIds, $originCourseIds);
|
||||||
|
|
||||||
if ($addedCourseIds) {
|
if ($addedCourseIds) {
|
||||||
@ -203,6 +204,8 @@ class Package extends Service
|
|||||||
'course_id' => $courseId,
|
'course_id' => $courseId,
|
||||||
'package_id' => $package->id,
|
'package_id' => $package->id,
|
||||||
]);
|
]);
|
||||||
|
$this->updateCoursePackageCount($courseId);
|
||||||
|
$this->rebuildCoursePackageCache($courseId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,14 +215,14 @@ class Package extends Service
|
|||||||
$coursePackageRepo = new CoursePackageRepo();
|
$coursePackageRepo = new CoursePackageRepo();
|
||||||
foreach ($deletedCourseIds as $courseId) {
|
foreach ($deletedCourseIds as $courseId) {
|
||||||
$coursePackage = $coursePackageRepo->findCoursePackage($courseId, $package->id);
|
$coursePackage = $coursePackageRepo->findCoursePackage($courseId, $package->id);
|
||||||
if ($coursePackage) {
|
$coursePackage->delete();
|
||||||
$coursePackage->delete();
|
$this->updateCoursePackageCount($courseId);
|
||||||
}
|
$this->rebuildCoursePackageCache($courseId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function updateCourseCount(PackageModel $package)
|
protected function updatePackageCourseCount(PackageModel $package)
|
||||||
{
|
{
|
||||||
$packageRepo = new PackageRepo();
|
$packageRepo = new PackageRepo();
|
||||||
|
|
||||||
@ -230,6 +233,19 @@ class Package extends Service
|
|||||||
$package->update();
|
$package->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function updateCoursePackageCount($courseId)
|
||||||
|
{
|
||||||
|
$courseRepo = new CourseRepo();
|
||||||
|
|
||||||
|
$course = $courseRepo->findById($courseId);
|
||||||
|
|
||||||
|
$packageCount = $courseRepo->countPackages($courseId);
|
||||||
|
|
||||||
|
$course->package_count = $packageCount;
|
||||||
|
|
||||||
|
$course->update();
|
||||||
|
}
|
||||||
|
|
||||||
protected function rebuildPackageCache(PackageModel $package)
|
protected function rebuildPackageCache(PackageModel $package)
|
||||||
{
|
{
|
||||||
$cache = new PackageCache();
|
$cache = new PackageCache();
|
||||||
@ -241,6 +257,13 @@ class Package extends Service
|
|||||||
$cache->rebuild($package->id);
|
$cache->rebuild($package->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function rebuildCoursePackageCache($courseId)
|
||||||
|
{
|
||||||
|
$cache = new CoursePackageListCache();
|
||||||
|
|
||||||
|
$cache->rebuild($courseId);
|
||||||
|
}
|
||||||
|
|
||||||
protected function findOrFail($id)
|
protected function findOrFail($id)
|
||||||
{
|
{
|
||||||
$validator = new PackageValidator();
|
$validator = new PackageValidator();
|
||||||
|
@ -5,9 +5,9 @@
|
|||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<div class="layui-form-item">
|
<div class="layui-form-item">
|
||||||
<label class="layui-form-label">课程编号</label>
|
<label class="layui-form-label">编号</label>
|
||||||
<div class="layui-input-block">
|
<div class="layui-input-block">
|
||||||
<input class="layui-input" type="text" name="id" placeholder="课程编号精确匹配">
|
<input class="layui-input" type="text" name="id" placeholder="编号精确匹配">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
45
app/Http/Admin/Views/package/search.volt
Normal file
45
app/Http/Admin/Views/package/search.volt
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
<form class="layui-form kg-form" method="GET" action="{{ url({'for':'admin.package.list'}) }}">
|
||||||
|
|
||||||
|
<fieldset class="layui-elem-field layui-field-title">
|
||||||
|
<legend>搜索套餐</legend>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<label class="layui-form-label">编号</label>
|
||||||
|
<div class="layui-input-block">
|
||||||
|
<input class="layui-input" type="text" name="id" placeholder="编号精确匹配">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<label class="layui-form-label">标题</label>
|
||||||
|
<div class="layui-input-block">
|
||||||
|
<input class="layui-input" type="text" name="title" placeholder="标题模糊匹配">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<label class="layui-form-label">发布</label>
|
||||||
|
<div class="layui-input-block">
|
||||||
|
<input type="radio" name="published" value="1" title="是">
|
||||||
|
<input type="radio" name="published" value="0" title="否">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<label class="layui-form-label">删除</label>
|
||||||
|
<div class="layui-input-block">
|
||||||
|
<input type="radio" name="deleted" value="1" title="是">
|
||||||
|
<input type="radio" name="deleted" value="0" title="否">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<label class="layui-form-label"></label>
|
||||||
|
<div class="layui-input-block">
|
||||||
|
<button class="layui-btn" lay-submit="true">提交</button>
|
||||||
|
<button type="button" class="kg-back layui-btn layui-btn-primary">返回</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</form>
|
@ -23,6 +23,9 @@
|
|||||||
<div class="cover"><img src="{{ course.cover }}!cover_270" alt="{{ course.title }}"></div>
|
<div class="cover"><img src="{{ course.cover }}!cover_270" alt="{{ course.title }}"></div>
|
||||||
<div class="title"><a href="{{ course_url }}">{{ course.title }}</a></div>
|
<div class="title"><a href="{{ course_url }}">{{ course.title }}</a></div>
|
||||||
</div>
|
</div>
|
||||||
|
{% if loop.first %}
|
||||||
|
<div class="separator"><i class="layui-icon layui-icon-add-1"></i></div>
|
||||||
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
<div class="layout-main clearfix">
|
<div class="layout-main clearfix">
|
||||||
|
|
||||||
{% set show_tab_packages = 1 %}
|
{% set show_tab_packages = course.package_count > 0 ? 1 : 0 %}
|
||||||
{% set show_tab_consults = course.consult_count > 0 ? 1 : 0 %}
|
{% set show_tab_consults = course.consult_count > 0 ? 1 : 0 %}
|
||||||
{% set show_tab_reviews = course.review_count > 0 ? 1 : 0 %}
|
{% set show_tab_reviews = course.review_count > 0 ? 1 : 0 %}
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ class ChapterUser extends Model
|
|||||||
public $id;
|
public $id;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 计划编号(course_user主键)
|
* 计划编号
|
||||||
*
|
*
|
||||||
* @var int
|
* @var int
|
||||||
*/
|
*/
|
||||||
|
@ -178,6 +178,13 @@ class Course extends Model
|
|||||||
*/
|
*/
|
||||||
public $lesson_count;
|
public $lesson_count;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 套餐数
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
public $package_count;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 评论数
|
* 评论数
|
||||||
*
|
*
|
||||||
@ -349,6 +356,7 @@ class Course extends Model
|
|||||||
'rating' => '评价',
|
'rating' => '评价',
|
||||||
'latest' => '最新',
|
'latest' => '最新',
|
||||||
'popular' => '最热',
|
'popular' => '最热',
|
||||||
|
'free' => '免费',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,6 +27,13 @@ class CourseUser extends Model
|
|||||||
*/
|
*/
|
||||||
public $id;
|
public $id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计划编号
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
public $plan_id;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 课程编号
|
* 课程编号
|
||||||
*
|
*
|
||||||
@ -123,6 +130,8 @@ class CourseUser extends Model
|
|||||||
|
|
||||||
public function beforeCreate()
|
public function beforeCreate()
|
||||||
{
|
{
|
||||||
|
$this->plan_id = (int)date('Y-m-d');
|
||||||
|
|
||||||
$this->create_time = time();
|
$this->create_time = time();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ class Learning extends Model
|
|||||||
public $request_id;
|
public $request_id;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 计划编号(course_user主键)
|
* 计划编号
|
||||||
*
|
*
|
||||||
* @var int
|
* @var int
|
||||||
*/
|
*/
|
||||||
|
@ -45,6 +45,7 @@ class ChapterUser extends Repository
|
|||||||
return ChapterUserModel::findFirst([
|
return ChapterUserModel::findFirst([
|
||||||
'conditions' => 'chapter_id = ?1 AND user_id = ?2 AND deleted = 0',
|
'conditions' => 'chapter_id = ?1 AND user_id = ?2 AND deleted = 0',
|
||||||
'bind' => [1 => $chapterId, 2 => $userId],
|
'bind' => [1 => $chapterId, 2 => $userId],
|
||||||
|
'order' => 'id DESC',
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,6 +60,10 @@ class Course extends Repository
|
|||||||
$builder->andWhere('level = :level:', ['level' => $where['level']]);
|
$builder->andWhere('level = :level:', ['level' => $where['level']]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($sort == 'free') {
|
||||||
|
$where['free'] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (isset($where['free'])) {
|
if (isset($where['free'])) {
|
||||||
if ($where['free'] == 1) {
|
if ($where['free'] == 1) {
|
||||||
$builder->andWhere('market_price = 0');
|
$builder->andWhere('market_price = 0');
|
||||||
@ -215,28 +219,15 @@ class Course extends Repository
|
|||||||
/**
|
/**
|
||||||
* @param int $courseId
|
* @param int $courseId
|
||||||
* @param int $userId
|
* @param int $userId
|
||||||
|
* @param int $planId
|
||||||
* @return ResultsetInterface|Resultset|ChapterUserModel[]
|
* @return ResultsetInterface|Resultset|ChapterUserModel[]
|
||||||
*/
|
*/
|
||||||
public function findUserLearnings($courseId, $userId)
|
public function findUserLearnings($courseId, $userId, $planId)
|
||||||
{
|
{
|
||||||
return ChapterUserModel::query()
|
return ChapterUserModel::query()
|
||||||
->where('course_id = :course_id:', ['course_id' => $courseId])
|
->where('course_id = :course_id:', ['course_id' => $courseId])
|
||||||
->andWhere('user_id = :user_id:', ['user_id' => $userId])
|
->andWhere('user_id = :user_id:', ['user_id' => $userId])
|
||||||
->andWhere('deleted = 0')
|
->andWhere('plan_id = :plan_id:', ['plan_id' => $planId])
|
||||||
->execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param int $courseId
|
|
||||||
* @param int $userId
|
|
||||||
* @return ResultsetInterface|Resultset|ChapterUserModel[]
|
|
||||||
*/
|
|
||||||
public function findConsumedUserLearnings($courseId, $userId)
|
|
||||||
{
|
|
||||||
return ChapterUserModel::query()
|
|
||||||
->where('course_id = :course_id:', ['course_id' => $courseId])
|
|
||||||
->andWhere('user_id = :user_id:', ['user_id' => $userId])
|
|
||||||
->andWhere('consumed = 1 AND deleted = 0')
|
|
||||||
->execute();
|
->execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -280,6 +271,14 @@ class Course extends Repository
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function countPackages($courseId)
|
||||||
|
{
|
||||||
|
return CoursePackageModel::count([
|
||||||
|
'conditions' => 'course_id = :course_id:',
|
||||||
|
'bind' => ['course_id' => $courseId],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
public function countUsers($courseId)
|
public function countUsers($courseId)
|
||||||
{
|
{
|
||||||
return CourseUserModel::count([
|
return CourseUserModel::count([
|
||||||
|
@ -21,8 +21,12 @@ class Package extends Repository
|
|||||||
|
|
||||||
$builder->where('1 = 1');
|
$builder->where('1 = 1');
|
||||||
|
|
||||||
if (!empty($where['user_id'])) {
|
if (!empty($where['id'])) {
|
||||||
$builder->andWhere('user_id = :user_id:', ['user_id' => $where['user_id']]);
|
$builder->andWhere('id = :id:', ['id' => $where['id']]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($where['title'])) {
|
||||||
|
$builder->andWhere('title LIKE :title:', ['title' => "%{$where['title']}%"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($where['published'])) {
|
if (isset($where['published'])) {
|
||||||
|
@ -170,7 +170,7 @@ class ChapterInfo extends FrontendService
|
|||||||
|
|
||||||
protected function handleCourseUser(CourseModel $course, UserModel $user)
|
protected function handleCourseUser(CourseModel $course, UserModel $user)
|
||||||
{
|
{
|
||||||
if (empty($user->id)) return;
|
if ($user->id == 0) return;
|
||||||
|
|
||||||
if ($this->joinedCourse) return;
|
if ($this->joinedCourse) return;
|
||||||
|
|
||||||
@ -182,7 +182,6 @@ class ChapterInfo extends FrontendService
|
|||||||
$courseUser->user_id = $user->id;
|
$courseUser->user_id = $user->id;
|
||||||
$courseUser->source_type = CourseUserModel::SOURCE_FREE;
|
$courseUser->source_type = CourseUserModel::SOURCE_FREE;
|
||||||
$courseUser->role_type = CourseUserModel::ROLE_STUDENT;
|
$courseUser->role_type = CourseUserModel::ROLE_STUDENT;
|
||||||
$courseUser->expiry_time = strtotime('+3 years');
|
|
||||||
|
|
||||||
$courseUser->create();
|
$courseUser->create();
|
||||||
|
|
||||||
@ -191,14 +190,22 @@ class ChapterInfo extends FrontendService
|
|||||||
|
|
||||||
protected function handleChapterUser(ChapterModel $chapter, UserModel $user)
|
protected function handleChapterUser(ChapterModel $chapter, UserModel $user)
|
||||||
{
|
{
|
||||||
if (empty($user->id)) return;
|
if ($user->id == 0) return;
|
||||||
|
|
||||||
if ($this->joinedChapter) return;
|
/**
|
||||||
|
* 一个课程可能购买学习多次
|
||||||
|
*/
|
||||||
|
if ($this->chapterUser && $this->courseUser) {
|
||||||
|
if ($this->chapterUser->plan_id == $this->courseUser->plan_id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!$this->ownedChapter) return;
|
if (!$this->ownedChapter) return;
|
||||||
|
|
||||||
$chapterUser = new ChapterUserModel();
|
$chapterUser = new ChapterUserModel();
|
||||||
|
|
||||||
|
$chapterUser->plan_id = $this->courseUser->plan_id;
|
||||||
$chapterUser->course_id = $chapter->course_id;
|
$chapterUser->course_id = $chapter->course_id;
|
||||||
$chapterUser->chapter_id = $chapter->id;
|
$chapterUser->chapter_id = $chapter->id;
|
||||||
$chapterUser->user_id = $user->id;
|
$chapterUser->user_id = $user->id;
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
namespace App\Services\Frontend;
|
namespace App\Services\Frontend;
|
||||||
|
|
||||||
use App\Models\Chapter as ChapterModel;
|
use App\Models\Chapter as ChapterModel;
|
||||||
|
use App\Models\ChapterUser as ChapterUserModel;
|
||||||
use App\Models\User as UserModel;
|
use App\Models\User as UserModel;
|
||||||
use App\Repos\ChapterUser as ChapterUserRepo;
|
use App\Repos\ChapterUser as ChapterUserRepo;
|
||||||
use App\Validators\Chapter as ChapterValidator;
|
use App\Validators\Chapter as ChapterValidator;
|
||||||
@ -20,6 +21,11 @@ trait ChapterTrait
|
|||||||
*/
|
*/
|
||||||
protected $joinedChapter = false;
|
protected $joinedChapter = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var ChapterUserModel
|
||||||
|
*/
|
||||||
|
protected $chapterUser;
|
||||||
|
|
||||||
public function checkChapter($id)
|
public function checkChapter($id)
|
||||||
{
|
{
|
||||||
$validator = new ChapterValidator();
|
$validator = new ChapterValidator();
|
||||||
@ -41,6 +47,7 @@ trait ChapterTrait
|
|||||||
$chapterUser = $chapterUserRepo->findChapterUser($chapter->id, $user->id);
|
$chapterUser = $chapterUserRepo->findChapterUser($chapter->id, $user->id);
|
||||||
|
|
||||||
if ($chapterUser) {
|
if ($chapterUser) {
|
||||||
|
$this->chapterUser = $chapterUser;
|
||||||
$this->joinedChapter = true;
|
$this->joinedChapter = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ class ChapterList extends FrontendService
|
|||||||
|
|
||||||
$chapters = $cache->get($course->id);
|
$chapters = $cache->get($course->id);
|
||||||
|
|
||||||
if (empty($chapters)) {
|
if (count($chapters) == 0) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,7 +46,7 @@ class ChapterList extends FrontendService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$mappings = $this->getLearningMappings($course, $user);
|
$mappings = $this->getLearningMappings($course->id, $user->id, $this->courseUser->plan_id);
|
||||||
foreach ($chapters as &$chapter) {
|
foreach ($chapters as &$chapter) {
|
||||||
foreach ($chapter['children'] as &$lesson) {
|
foreach ($chapter['children'] as &$lesson) {
|
||||||
$lesson['me'] = [
|
$lesson['me'] = [
|
||||||
@ -61,11 +61,11 @@ class ChapterList extends FrontendService
|
|||||||
return $chapters;
|
return $chapters;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getLearningMappings(CourseModel $course, UserModel $user)
|
protected function getLearningMappings($courseId, $userId, $planId)
|
||||||
{
|
{
|
||||||
$courseRepo = new CourseRepo();
|
$courseRepo = new CourseRepo();
|
||||||
|
|
||||||
$userLearnings = $courseRepo->findUserLearnings($course->id, $user->id);
|
$userLearnings = $courseRepo->findUserLearnings($courseId, $userId, $planId);
|
||||||
|
|
||||||
if ($userLearnings->count() == 0) {
|
if ($userLearnings->count() == 0) {
|
||||||
return [];
|
return [];
|
||||||
|
@ -45,6 +45,7 @@ class CourseInfo extends FrontendService
|
|||||||
'attrs' => $course->attrs,
|
'attrs' => $course->attrs,
|
||||||
'user_count' => $course->user_count,
|
'user_count' => $course->user_count,
|
||||||
'lesson_count' => $course->lesson_count,
|
'lesson_count' => $course->lesson_count,
|
||||||
|
'package_count' => $course->package_count,
|
||||||
'review_count' => $course->review_count,
|
'review_count' => $course->review_count,
|
||||||
'comment_count' => $course->comment_count,
|
'comment_count' => $course->comment_count,
|
||||||
'consult_count' => $course->consult_count,
|
'consult_count' => $course->consult_count,
|
||||||
|
@ -28,18 +28,21 @@ class PackageList extends FrontendService
|
|||||||
|
|
||||||
$result = [];
|
$result = [];
|
||||||
|
|
||||||
|
$firstCourseId = $course->id;
|
||||||
|
|
||||||
foreach ($packages as $package) {
|
foreach ($packages as $package) {
|
||||||
|
|
||||||
$courses = $cache->get($package['id']);
|
$courses = $cache->get($package['id']);
|
||||||
|
|
||||||
$package['origin_price'] = 0.00;
|
$package['origin_price'] = 0.00;
|
||||||
|
|
||||||
$package['courses'] = [];
|
$package['courses'] = [];
|
||||||
|
|
||||||
if ($courses) {
|
if ($courses) {
|
||||||
foreach ($courses as $course) {
|
foreach ($courses as $course) {
|
||||||
$package['origin_price'] += $course['market_price'];
|
$package['origin_price'] += $course['market_price'];
|
||||||
}
|
}
|
||||||
$package['courses'] = $courses;
|
$package['courses'] = $this->sortCourses($courses, $firstCourseId);
|
||||||
}
|
}
|
||||||
|
|
||||||
$result[] = $package;
|
$result[] = $package;
|
||||||
@ -48,4 +51,36 @@ class PackageList extends FrontendService
|
|||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 把特定课程排在第一位
|
||||||
|
*
|
||||||
|
* @param array $courses
|
||||||
|
* @param int $firstCourseId
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function sortCourses(array $courses, $firstCourseId)
|
||||||
|
{
|
||||||
|
$firstCourse = [];
|
||||||
|
|
||||||
|
foreach ($courses as $course) {
|
||||||
|
if ($course['id'] == $firstCourseId) {
|
||||||
|
$firstCourse = $course;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = [];
|
||||||
|
|
||||||
|
if ($firstCourse) {
|
||||||
|
$result[] = $firstCourse;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($courses as $course) {
|
||||||
|
if ($course['id'] != $firstCourseId) {
|
||||||
|
$result[] = $course;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ trait CourseTrait
|
|||||||
protected $joinedCourse = false;
|
protected $joinedCourse = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var CourseUserModel
|
* @var CourseUserModel|null
|
||||||
*/
|
*/
|
||||||
protected $courseUser;
|
protected $courseUser;
|
||||||
|
|
||||||
@ -42,12 +42,16 @@ trait CourseTrait
|
|||||||
|
|
||||||
public function setCourseUser(CourseModel $course, UserModel $user)
|
public function setCourseUser(CourseModel $course, UserModel $user)
|
||||||
{
|
{
|
||||||
$courseUserRepo = new CourseUserRepo();
|
$courseUser = null;
|
||||||
|
|
||||||
$courseUser = $courseUserRepo->findCourseUser($course->id, $user->id);
|
if ($user->id > 0) {
|
||||||
|
$courseUserRepo = new CourseUserRepo();
|
||||||
|
$courseUser = $courseUserRepo->findCourseUser($course->id, $user->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->courseUser = $courseUser;
|
||||||
|
|
||||||
if ($courseUser) {
|
if ($courseUser) {
|
||||||
$this->courseUser = $courseUser;
|
|
||||||
$this->joinedCourse = true;
|
$this->joinedCourse = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ namespace App\Services;
|
|||||||
|
|
||||||
use App\Models\Order as OrderModel;
|
use App\Models\Order as OrderModel;
|
||||||
use App\Repos\Course as CourseRepo;
|
use App\Repos\Course as CourseRepo;
|
||||||
|
use App\Repos\CourseUser as CourseUserRepo;
|
||||||
|
|
||||||
class Refund extends Service
|
class Refund extends Service
|
||||||
{
|
{
|
||||||
@ -104,15 +105,36 @@ class Refund extends Service
|
|||||||
return 1.00;
|
return 1.00;
|
||||||
}
|
}
|
||||||
|
|
||||||
$userLearnings = $courseRepo->findConsumedUserLearnings($courseId, $userId);
|
$courseUserRepo = new CourseUserRepo();
|
||||||
|
|
||||||
|
$courseUser = $courseUserRepo->findCourseUser($courseId, $userId);
|
||||||
|
|
||||||
|
if (!$courseUser) {
|
||||||
|
return 1.00;
|
||||||
|
}
|
||||||
|
|
||||||
|
$userLearnings = $courseRepo->findUserLearnings($courseId, $userId, $courseUser->plan_id);
|
||||||
|
|
||||||
if ($userLearnings->count() == 0) {
|
if ($userLearnings->count() == 0) {
|
||||||
return 1.00;
|
return 1.00;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array $consumedUserLearnings
|
||||||
|
*/
|
||||||
|
$consumedUserLearnings = $userLearnings->filter(function ($item) {
|
||||||
|
if ($item->consumed == 1) {
|
||||||
|
return $item;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (count($consumedUserLearnings) == 0) {
|
||||||
|
return 1.00;
|
||||||
|
}
|
||||||
|
|
||||||
$courseLessonIds = kg_array_column($courseLessons->toArray(), 'id');
|
$courseLessonIds = kg_array_column($courseLessons->toArray(), 'id');
|
||||||
$userLessonIds = kg_array_column($userLearnings->toArray(), 'chapter_id');
|
$consumedUserLessonIds = kg_array_column($consumedUserLearnings, 'chapter_id');
|
||||||
$consumedLessonIds = array_intersect($courseLessonIds, $userLessonIds);
|
$consumedLessonIds = array_intersect($courseLessonIds, $consumedUserLessonIds);
|
||||||
|
|
||||||
$totalCount = count($courseLessonIds);
|
$totalCount = count($courseLessonIds);
|
||||||
$consumedCount = count($consumedLessonIds);
|
$consumedCount = count($consumedLessonIds);
|
||||||
|
@ -4,7 +4,6 @@ namespace App\Traits;
|
|||||||
|
|
||||||
use App\Caches\User as UserCache;
|
use App\Caches\User as UserCache;
|
||||||
use App\Models\User as UserModel;
|
use App\Models\User as UserModel;
|
||||||
use App\Repos\User as UserRepo;
|
|
||||||
use App\Services\Auth as AuthService;
|
use App\Services\Auth as AuthService;
|
||||||
use App\Validators\Validator as AppValidator;
|
use App\Validators\Validator as AppValidator;
|
||||||
use Phalcon\Di;
|
use Phalcon\Di;
|
||||||
@ -33,10 +32,6 @@ trait Auth
|
|||||||
*/
|
*/
|
||||||
public function getLoginUser()
|
public function getLoginUser()
|
||||||
{
|
{
|
||||||
$userRepo = new UserRepo();
|
|
||||||
|
|
||||||
return $userRepo->findById(100015);
|
|
||||||
|
|
||||||
$authUser = $this->getAuthUser();
|
$authUser = $this->getAuthUser();
|
||||||
|
|
||||||
$validator = new AppValidator();
|
$validator = new AppValidator();
|
||||||
|
@ -419,7 +419,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.package-item {
|
.package-item {
|
||||||
margin-bottom: 15px;
|
margin-bottom: 25px;
|
||||||
border-bottom: 1px dashed #ccc;
|
border-bottom: 1px dashed #ccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -468,16 +468,24 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.package-course-list {
|
.package-course-list {
|
||||||
width: 560px;
|
width: 580px;
|
||||||
height: 170px;
|
height: 170px;
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.separator {
|
||||||
|
color: #666;
|
||||||
|
display: inline-block;
|
||||||
|
padding-top: 35px;
|
||||||
|
margin-left: -5px;
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
.package-course-card {
|
.package-course-card {
|
||||||
width: 175px;
|
width: 175px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin-right: 5px;
|
margin-right: 8px;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
2
storage/cache/annotations/.gitignore
vendored
Normal file
2
storage/cache/annotations/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
*
|
||||||
|
!.gitignore
|
Loading…
x
Reference in New Issue
Block a user