1
0
mirror of https://gitee.com/koogua/course-tencent-cloud.git synced 2025-06-24 20:06:09 +08:00

Merge branch 'koogua/v1.7.4' into demo

# Conflicts:
#	CHANGELOG.md
This commit is contained in:
xiaochong0302 2024-12-07 18:24:30 +08:00
commit 4bf963c9ab
32 changed files with 202 additions and 66 deletions

View File

@ -1,3 +1,15 @@
### [v1.7.4](https://gitee.com/koogua/course-tencent-cloud/releases/v1.7.4)(2024-12-10)
- 更新layui-v2.9.20
- 优化编辑器内容自动提交
- 修正课时详情页目录高亮问题
- 修正CommentInfo中点赞判断
- 精简AccountSearchTrait
- 优化kg_h5_index_url()
- 优化CourseUserTrait
- 优化kg_setting()
- 优化CsrfToken
### [v1.7.3](https://gitee.com/koogua/course-tencent-cloud/releases/v1.7.3)(2024-10-10)
- 更新layui-v2.9.16

View File

@ -0,0 +1,29 @@
<?php
/**
* @copyright Copyright (c) 2024 深圳市酷瓜软件有限公司
* @license https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* @link https://www.koogua.com
*/
namespace App\Console\Migrations;
class V20241110191316 extends Migration
{
public function run()
{
$this->handleContactSettings();
}
protected function handleContactSettings()
{
$setting = [
'section' => 'contact',
'item_key' => 'douyin',
'item_value' => '',
];
$this->saveSetting($setting);
}
}

View File

@ -40,7 +40,7 @@ class CourseUser extends Service
$sourceType = CourseUserModel::SOURCE_MANUAL;
return $this->assignUserCourse($course, $user, $expiryTime, $sourceType);
$this->assignUserCourse($course, $user, $expiryTime, $sourceType);
}
public function getUsers($id)

View File

@ -45,7 +45,7 @@ class Resource extends Service
$this->recountCourseResources($course);
return $upload;
return $resource;
}
public function updateResource($id)
@ -67,6 +67,8 @@ class Resource extends Service
$upload->update($data);
$resource->update();
return $resource;
}
public function deleteResource($id)
@ -80,6 +82,8 @@ class Resource extends Service
$resource->delete();
$this->recountCourseResources($course);
return $resource;
}
protected function findOrFail($id)

View File

@ -15,31 +15,28 @@ trait AccountSearchTrait
protected function handleAccountSearchParams($params)
{
$key = null;
if (isset($params['user_id'])) {
$key = 'user_id';
} elseif (isset($params['owner_id'])) {
$key = 'owner_id';
}
if ($key == null) return $params;
$accountRepo = new AccountRepo();
/**
* 兼容用户编号|手机号码|邮箱地址查询
*/
if (!empty($params['user_id'])) {
if (CommonValidator::phone($params['user_id'])) {
$account = $accountRepo->findByPhone($params['user_id']);
$params['user_id'] = $account ? $account->id : -1000;
} elseif (CommonValidator::email($params['user_id'])) {
$account = $accountRepo->findByEmail($params['user_id']);
$params['user_id'] = $account ? $account->id : -1000;
}
}
/**
* 兼容用户编号|手机号码|邮箱地址查询
*/
if (!empty($params['owner_id'])) {
if (CommonValidator::phone($params['owner_id'])) {
$account = $accountRepo->findByPhone($params['owner_id']);
$params['owner_id'] = $account ? $account->id : -1000;
} elseif (CommonValidator::email($params['owner_id'])) {
$account = $accountRepo->findByEmail($params['owner_id']);
$params['owner_id'] = $account ? $account->id : -1000;
if (!empty($params[$key])) {
if (CommonValidator::phone($params[$key])) {
$account = $accountRepo->findByPhone($params[$key]);
$params[$key] = $account ? $account->id : -1000;
} elseif (CommonValidator::email($params[$key])) {
$account = $accountRepo->findByEmail($params[$key]);
$params[$key] = $account ? $account->id : -1000;
}
}

View File

@ -142,7 +142,7 @@ class User extends Service
$this->db->commit();
if ($adminRole > 0) {
$this->updateAdminUserCount($adminRole);
$this->recountRoleUsers($adminRole);
}
$this->rebuildUserCache($user);
@ -225,11 +225,11 @@ class User extends Service
}
if ($oldAdminRole > 0) {
$this->updateAdminUserCount($oldAdminRole);
$this->recountRoleUsers($oldAdminRole);
}
if ($user->admin_role > 0) {
$this->updateAdminUserCount($user->admin_role);
$this->recountRoleUsers($user->admin_role);
}
$this->rebuildUserCache($user);
@ -341,7 +341,7 @@ class User extends Service
$apiAuth->logoutClients($user->id);
}
protected function updateAdminUserCount($roleId)
protected function recountRoleUsers($roleId)
{
$roleRepo = new RoleRepo();

View File

@ -40,6 +40,15 @@
<button class="layui-btn" type="button" id="upload-toutiao">上传</button>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">抖音二维码</label>
<div class="layui-inline" style="width:40%;">
<input class="layui-input" type="text" name="douyin" placeholder="请确保存储已正确配置" value="{{ contact.douyin }}">
</div>
<div class="layui-inline">
<button class="layui-btn" type="button" id="upload-douyin">上传</button>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">微博帐号</label>
<div class="layui-input-block">
@ -138,6 +147,22 @@
}
});
upload.render({
elem: '#upload-douyin',
url: '/admin/upload/icon/img',
exts: 'gif|jpg|png',
before: function () {
layer.load();
},
done: function (res, index, upload) {
$('input[name=douyin]').val(res.data.url);
layer.closeAll('loading');
},
error: function (index, upload) {
layer.msg('上传文件失败', {icon: 2});
}
});
});
</script>

View File

@ -23,7 +23,7 @@
<tr>
<td>{{ client_type(item.client_type) }}</td>
<td><a href="javascript:" class="kg-ip2region" title="查看位置" data-ip="{{ item.client_ip }}">{{ item.client_ip }}</a></td>
<td>{{ date('Y-m-d H:i',item.active_time) }}</td>
<td>{{ date('Y-m-d H:i:s',item.active_time) }}</td>
</tr>
{% endfor %}
</tbody>

View File

@ -15,6 +15,7 @@ use App\Services\Auth\Home as HomeAuth;
use App\Services\Service as AppService;
use App\Traits\Response as ResponseTrait;
use App\Traits\Security as SecurityTrait;
use Phalcon\Config;
use Phalcon\Mvc\Dispatcher;
class Controller extends \Phalcon\Mvc\Controller
@ -46,7 +47,7 @@ class Controller extends \Phalcon\Mvc\Controller
protected $contactInfo;
/**
* @var array
* @var Config
*/
protected $websocketInfo;

View File

@ -1,6 +1,6 @@
{%- macro show_lesson_list(chapter) %}
{%- macro show_lesson_list(parent,chapter) %}
<ul class="sidebar-lesson-list">
{% for lesson in chapter.children %}
{% for lesson in parent.children %}
{% set url = url({'for':'home.chapter.show','id':lesson.id}) %}
{% set active = (chapter.id == lesson.id) ? 'active' : 'normal' %}
<li class="lesson-title layui-elip">
@ -22,13 +22,13 @@
{% for item in catalog %}
<div class="chapter-title layui-elip">{{ item.title }}</div>
<div class="sidebar-lesson-list">
{{ show_lesson_list(item) }}
{{ show_lesson_list(item,chapter) }}
</div>
{% endfor %}
</div>
{% else %}
<div class="sidebar-lesson-list">
{{ show_lesson_list(catalog[0]) }}
{{ show_lesson_list(catalog[0],chapter) }}
</div>
{% endif %}
</div>

View File

@ -33,6 +33,9 @@
{% if contact_info.toutiao %}
<a class="toutiao" href="javascript:" title="头条号"><span class="iconfont icon-toutiao"></span></a>
{% endif %}
{% if contact_info.douyin %}
<a class="douyin" href="javascript:" title="抖音号"><span class="iconfont icon-douyin"></span></a>
{% endif %}
{% if contact_info.weibo %}
{% set link_url = 'https://weibo.com/u/%s'|format(contact_info.weibo) %}
<a class="weibo" href="{{ link_url }}" title="微博主页"><span class="iconfont icon-weibo"></span></a>

View File

@ -13,6 +13,7 @@
qq: '{{ contact_info.qq }}',
wechat: '{{ contact_info.wechat }}',
toutiao: '{{ contact_info.toutiao }}',
douyin: '{{ contact_info.douyin }}',
weibo: '{{ contact_info.weibo }}',
zhihu: '{{ contact_info.zhihu }}',
phone: '{{ contact_info.phone }}',

View File

@ -16,7 +16,7 @@ class AppInfo
protected $link = 'https://www.koogua.com';
protected $version = '1.7.3';
protected $version = '1.7.4';
public function __get($name)
{

View File

@ -36,7 +36,7 @@ class CsrfToken
$content = [
$this->getExpiredTime(),
$this->fixed,
Text::random(8),
Text::random(Text::RANDOM_ALNUM, 8),
];
$text = implode($this->delimiter, $content);

View File

@ -8,6 +8,7 @@
use App\Caches\Setting as SettingCache;
use App\Library\Purifier as HtmlPurifier;
use App\Library\Validators\Common as CommonValidator;
use App\Services\Logic\Url\FullH5Url as FullH5UrlService;
use App\Services\Logic\Url\ShareUrl as ShareUrlService;
use App\Services\Storage as StorageService;
use Phalcon\Config;
@ -189,9 +190,10 @@ function kg_site_url()
*
* @param string $section
* @param string $key
* @param mixed $defaultValue
* @return mixed
*/
function kg_setting($section, $key = null)
function kg_setting($section, $key = null, $defaultValue = null)
{
$cache = new SettingCache();
@ -199,7 +201,9 @@ function kg_setting($section, $key = null)
if (!$key) return $settings;
return $settings[$key] ?? null;
if (isset($settings[$key])) return $settings[$key];
return $defaultValue;
}
/**
@ -768,7 +772,7 @@ function kg_static_url($path, $local = true, $version = null)
$baseUri = rtrim($config->get('static_base_uri'), '/');
$path = ltrim($path, '/');
$url = $local ? $baseUri . '/' . $path : $path;
$version = $version ? $version : $config->get('static_version');
$version = $version ?: $config->get('static_version');
if ($version) {
$url .= '?v=' . $version;
@ -818,5 +822,13 @@ function kg_share_url($type, $id, $referer = 0)
*/
function kg_h5_index_url()
{
return kg_site_url() . '/h5/#/pages/index/index';
$service = new FullH5UrlService();
$url = $service->getHomeUrl();
if ($pos = strpos($url, '?')) {
return substr($url, 0, $pos);
}
return $url;
}

View File

@ -462,7 +462,9 @@ class Course extends Model
3 => '3个月',
6 => '6个月',
12 => '12个月',
24 => '24个月',
36 => '36个月',
48 => '48个月',
];
}
@ -470,11 +472,11 @@ class Course extends Model
{
return [
0 => '0天',
1 => '1天',
3 => '3天',
7 => '7天',
14 => '14天',
30 => '30天',
90 => '90天',
180 => '180天',
];
}

View File

@ -40,6 +40,10 @@ class Chapter extends Repository
$query->andWhere('course_id = :course_id:', ['course_id' => $where['course_id']]);
}
if (isset($where['model'])) {
$query->andWhere('model = :model:', ['model' => $where['model']]);
}
if (isset($where['published'])) {
$query->andWhere('published = :published:', ['published' => $where['published']]);
}

View File

@ -33,6 +33,8 @@ class Admin extends AuthService
];
$this->session->set($authKey, $authInfo);
return $authInfo;
}
public function clearAuthInfo()

View File

@ -39,6 +39,8 @@ class Home extends AuthService
];
$this->session->set($authKey, $authInfo);
return $authInfo;
}
public function clearAuthInfo()

View File

@ -10,7 +10,6 @@ namespace App\Services\Logic\Chapter;
use App\Models\Chapter as ChapterModel;
use App\Models\ChapterUser as ChapterUserModel;
use App\Models\Course as CourseModel;
use App\Models\CourseUser as CourseUserModel;
use App\Models\User as UserModel;
use App\Repos\ChapterLike as ChapterLikeRepo;
use App\Services\Logic\ChapterTrait;
@ -94,15 +93,7 @@ class ChapterInfo extends LogicService
if (!$this->ownedCourse) return;
$sourceType = CourseUserModel::SOURCE_FREE;
if ($course->market_price > 0) {
if ($course->vip_price == 0 && $user->vip == 1) {
$sourceType = CourseUserModel::SOURCE_VIP;
} else {
$sourceType = CourseUserModel::SOURCE_TRIAL;
}
}
$sourceType = $this->getFreeSourceType($course, $user);
$courseUser = $this->createCourseUser($course, $user, 0, $sourceType);
@ -199,7 +190,6 @@ class ChapterInfo extends LogicService
$parent->user_count += 1;
$parent->update();
}
}

View File

@ -9,7 +9,7 @@ namespace App\Services\Logic\Comment;
use App\Models\Comment as CommentModel;
use App\Models\User as UserModel;
use App\Repos\AnswerLike as AnswerLikeRepo;
use App\Repos\CommentLike as CommentLikeRepo;
use App\Services\Logic\CommentTrait;
use App\Services\Logic\Service as LogicService;
use App\Services\Logic\User\ShallowUserInfo;
@ -84,9 +84,9 @@ class CommentInfo extends LogicService
$me['logged'] = 1;
$likeRepo = new AnswerLikeRepo();
$likeRepo = new CommentLikeRepo();
$like = $likeRepo->findAnswerLike($comment->id, $user->id);
$like = $likeRepo->findCommentLike($comment->id, $user->id);
if ($like && $like->deleted == 0) {
$me['liked'] = 1;

View File

@ -50,7 +50,7 @@ trait CourseUserTrait
$this->ownedCourse = true;
} elseif ($course->market_price > 0 && $course->vip_price == 0 && $user->vip == 1) {
} elseif ($course->vip_price == 0 && $user->vip == 1) {
$this->ownedCourse = true;
@ -80,19 +80,22 @@ trait CourseUserTrait
protected function assignUserCourse(CourseModel $course, UserModel $user, int $expiryTime, int $sourceType)
{
if ($this->allowFreeAccess($course, $user)) return;
$courseUserRepo = new CourseUserRepo();
$relation = $courseUserRepo->findCourseUser($course->id, $user->id);
if (!$relation) {
$relation = $this->createCourseUser($course, $user, $expiryTime, $sourceType);
$this->createCourseUser($course, $user, $expiryTime, $sourceType);
} else {
switch ($relation->source_type) {
case CourseUserModel::SOURCE_FREE:
case CourseUserModel::SOURCE_TRIAL:
case CourseUserModel::SOURCE_VIP:
$this->createCourseUser($course, $user, $expiryTime, $sourceType);
$this->deleteCourseUser($relation);
break;
@ -113,8 +116,6 @@ trait CourseUserTrait
$this->recountCourseUsers($course);
$this->recountUserCourses($user);
return $relation;
}
protected function createCourseUser(CourseModel $course, UserModel $user, int $expiryTime, int $sourceType)
@ -160,4 +161,32 @@ trait CourseUserTrait
$user->update();
}
protected function allowFreeAccess(CourseModel $course, UserModel $user)
{
$result = false;
if ($course->market_price == 0) {
$result = true;
} elseif ($course->vip_price == 0 && $user->vip == 1) {
$result = true;
}
return $result;
}
protected function getFreeSourceType(CourseModel $course, UserModel $user)
{
$sourceType = CourseUserModel::SOURCE_FREE;
if ($course->market_price > 0) {
if ($course->vip_price == 0 && $user->vip == 1) {
$sourceType = CourseUserModel::SOURCE_VIP;
} else {
$sourceType = CourseUserModel::SOURCE_TRIAL;
}
}
return $sourceType;
}
}

View File

@ -22,7 +22,7 @@ class Security extends Validator
$postToken = $this->request->getPost('csrf_token');
if (in_array($route->getName(), $this->getCsrfWhitelist())) {
return;
return true;
}
$service = new CsrfTokenService();
@ -38,6 +38,8 @@ class Security extends Validator
if (!$result) {
throw new BadRequestException('security.invalid_csrf_token');
}
return true;
}
public function checkHttpReferer()

View File

@ -55,6 +55,7 @@ layui.use(['jquery'], function () {
*/
setInterval(function () {
editor.sync();
if (!$form.attr('action').includes('update')) return;
if ($textarea.val().length > 30) {
$.ajax({
type: 'POST',

View File

@ -53,6 +53,7 @@ layui.use(['jquery'], function () {
*/
setInterval(function () {
editor.sync();
if (!$form.attr('action').includes('update')) return;
if ($textarea.val().length > 30) {
$.ajax({
type: 'POST',

View File

@ -36,6 +36,17 @@ layui.use(['jquery', 'helper', 'util'], function () {
});
}
var showDouYinCode = function () {
var content = '<div class="qrcode"><img src="' + window.contact.douyin + '" alt="扫码关注"></div>';
layer.open({
type: 1,
title: false,
closeBtn: 0,
shadeClose: true,
content: content,
});
}
var bars = [];
if (window.contact.wechat) {
@ -75,4 +86,8 @@ layui.use(['jquery', 'helper', 'util'], function () {
showTouTiaoCode();
});
$('.icon-douyin').on('click', function () {
showDouYinCode();
});
});

View File

@ -1,18 +1,22 @@
@font-face {
font-family: "iconfont"; /* Project id 2760791 */
src: url('iconfont.woff2?t=1716885700001') format('woff2'),
url('iconfont.woff?t=1716885700001') format('woff'),
url('iconfont.ttf?t=1716885700001') format('truetype');
src: url('iconfont.woff2?t=1731240803792') format('woff2'),
url('iconfont.woff?t=1731240803792') format('woff'),
url('iconfont.ttf?t=1731240803792') format('truetype');
}
.iconfont {
font-family: "iconfont", serif !important;
font-family: "iconfont" !important;
font-size: 16px;
font-style: normal;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.icon-douyin:before {
content: "\e610";
}
.icon-pdf:before {
content: "\e7b8";
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long