1
0
mirror of https://gitee.com/koogua/course-tencent-cloud.git synced 2025-06-17 15:55:31 +08:00

Merge branch 'koogua/v1.3.8'

This commit is contained in:
koogua 2021-07-11 16:14:50 +08:00
commit bf5686f6d9
67 changed files with 356 additions and 267 deletions

View File

@ -1,3 +1,24 @@
### [v1.3.8](https://gitee.com/koogua/course-tencent-cloud/releases/v1.3.8)(2021-07-11)
### 更新
- 更正readme中github仓库信息
- 增加清除点播地址缓存命令
- 若干缓存键名重命名 后台站点名称修改为用户站点名称
- 标签名称比较忽略大小写
- 重新设计前后台登录界面
- 更正后台存储设置中图片样式的参数描述
- 记录逻辑删除后浏览重定向到404
- 修正图文类型的章节markdown解析问题
- 优化文章和提问不必要的标签数据提交
- 图文中图片增加点击放大预览功能
- 各数据结构中增加若干业务字段
- COS存储中去除多余的年月目录结构
- 清理优化css
- 修正直播地址问题
- 修正评论审核路由问题
- 修正取消收藏问题
### [v1.3.7](https://gitee.com/koogua/course-tencent-cloud/releases/v1.3.7)(2021-06-14)
### 更新

View File

@ -4,17 +4,17 @@
### 项目介绍
酷瓜云课堂依托腾讯云基础服务架构采用C扩展框架Phalcon开发GPL-2.0开源协议,致力开源网课系统,开源网校系统,开源在线教育系统。
酷瓜云课堂依托腾讯云基础服务架构采用C扩展框架Phalcon开发GPL-2.0开源协议,致力开源网课系统,开源网校系统,开源知识付费系统,开源在线教育系统。
[![Gitee star](https://gitee.com/koogua/course-tencent-cloud/badge/star.svg?theme=gitee)](https://gitee.com/koogua/course-tencent-cloud)
[![Gitee fork](https://gitee.com/koogua/course-tencent-cloud/badge/fork.svg?theme=gitee)](https://gitee.com/koogua/course-tencent-cloud)
[![Github stars](https://img.shields.io/github/stars/mindskip/xzs-mysql?logo=github)](https://github.com/xiaochong0302/course-tencent-cloud)
[![Github forks](https://img.shields.io/github/forks/mindskip/xzs-mysql?logo=github)](https://github.com/xiaochong0302/course-tencent-cloud)
[![Github stars](https://img.shields.io/github/stars/xiaochong0302/course-tencent-cloud?logo=github)](https://github.com/xiaochong0302/course-tencent-cloud)
[![Github forks](https://img.shields.io/github/forks/xiaochong0302/course-tencent-cloud?logo=github)](https://github.com/xiaochong0302/course-tencent-cloud)
![GPL-2.0](https://img.shields.io/static/v1?label=license&message=GPL-2.0&color=blue)
### 系统功能
实现了点播、直播、专栏、面授、问答、会员、群组、积分、秒杀等100%真开源在线教育解决方案
实现了点播、直播、专栏、面授、问答、会员、群组、微聊、积分、秒杀等。
友情提示:
@ -57,7 +57,7 @@ Tips: 请用手机注册一个新账号,用户中心 -> 关注订阅,扫码
### 项目组件
- 后台框架:[phalcon 3.4.5](https://phalcon.io)
- 前端框架:[layui 2.5.6](https://layui.com) [layim 3.9.5](https://www.layui.com/layim)(已授权)
- 前端框架:[layui 2.6.8](https://layui.com) [layim 3.9.8](https://www.layui.com/layim)(已授权)
- 全文检索:[xunsearch 1.4.9](http://www.xunsearch.com)
- 即时通讯:[workerman 3.5.22](https://workerman.net)
- 基础依赖:[php7.3](https://php.net) [mysql5.7](https://mysql.com) [redis5.0](https://redis.io)
@ -70,8 +70,8 @@ Tips: 请用手机注册一个新账号,用户中心 -> 关注订阅,扫码
### 意见反馈
- [在线反馈](https://gitee.com/koogua/course-tencent-cloud/issues)(推荐)
- [官方论坛](https://koogua.com/forum)(推荐)
- [码云平台](https://gitee.com/koogua/course-tencent-cloud/issues)
- [官方社区](https://koogua.com/community)
- QQ交流群: 787363898
### 有阿里云版吗?

View File

@ -25,7 +25,7 @@ class TopAnswererList extends Cache
public function getKey($id = null)
{
return 'question_top_answerer_list';
return 'top_answerer_list';
}
public function getContent($id = null)

View File

@ -9,6 +9,7 @@ namespace App\Console\Tasks;
use App\Http\Admin\Services\Setting as SettingService;
use App\Library\Utils\Password as PasswordUtil;
use App\Models\ChapterVod as ChapterVodModel;
use App\Services\Utils\IndexCourseCache as IndexCourseCacheUtil;
use App\Validators\Account as AccountValidator;
@ -119,4 +120,28 @@ class MaintainTask extends Task
echo '------ enable site success ------' . PHP_EOL;
}
/**
* 清理点播转码缓存
*
* @command: php console.php maintain clear_file_transcode
*/
public function clearFileTranscodeAction()
{
$chapterVodModel = new ChapterVodModel();
$tableName = $chapterVodModel->getSource();
$data = ['file_transcode' => '[]'];
$fields = array_keys($data);
$values = array_values($data);
$where = ['conditions' => 'file_id > 0'];
$this->db->update($tableName, $fields, $values, $where);
echo '------ clear file transcode success ------' . PHP_EOL;
}
}

View File

@ -26,9 +26,11 @@ class IndexController extends Controller
$topMenus = $indexService->getTopMenus();
$leftMenus = $indexService->getLeftMenus();
$appInfo = $indexService->getAppInfo();
$siteInfo = $indexService->getSiteInfo();
$this->view->setRenderLevel(View::LEVEL_ACTION_VIEW);
$this->view->setVar('app_info', $appInfo);
$this->view->setVar('site_info', $siteInfo);
$this->view->setVar('top_menus', $topMenus);
$this->view->setVar('left_menus', $leftMenus);
}

View File

@ -47,6 +47,11 @@ class Index extends Service
return $appInfo;
}
public function getSiteInfo()
{
return $this->getSettings('site');
}
public function getServerInfo()
{
return [

View File

@ -67,7 +67,7 @@ class Tag extends Service
if (isset($post['name'])) {
$data['name'] = $validator->checkName($post['name']);
if ($data['name'] != $tag->name) {
if (strtolower($data['name']) != strtolower($tag->name)) {
$validator->checkIfNameExists($data['name']);
}
}

View File

@ -4,6 +4,21 @@
{{ partial('macros/answer') }}
{% set search_url = url({'for':'admin.answer.search'}) %}
<div class="kg-nav">
<div class="kg-nav-left">
<span class="layui-breadcrumb">
<a><cite>回答管理</cite></a>
</span>
</div>
<div class="kg-nav-right">
<a class="layui-btn layui-btn-sm" href="{{ search_url }}">
<i class="layui-icon layui-icon-search"></i>搜索回答
</a>
</div>
</div>
<table class="layui-table kg-table layui-form">
<colgroup>
<col>

View File

@ -13,7 +13,7 @@
<body class="layui-layout-body">
<div class="layui-layout layui-layout-admin">
<div class="layui-header">
<div class="layui-logo">酷瓜云课堂</div>
<div class="layui-logo">{{ site_info.title }}</div>
<div class="kg-side-menu-bar">
<a href="javascript:"><i class="layui-icon layui-icon-spread-left"></i></a>
</div>

View File

@ -10,7 +10,7 @@
<br>
<div class="kg-center">
<button class="layui-btn layui-bg-gray kg-back">返回上页</button>
<button class="layui-btn layui-btn-primary kg-back">返回上页</button>
</div>
{% if refunds.count() > 0 %}

View File

@ -7,18 +7,16 @@
<div class="kg-login-wrap">
<div class="layui-card">
<div class="layui-card-header">管理登录</div>
<div class="layui-card-header">后台登录</div>
<div class="layui-card-body">
<form class="layui-form kg-login-form" method="POST" action="{{ url({'for':'admin.login'}) }}">
<div class="layui-form-item">
<div class="layui-input-block">
<input class="layui-input" type="text" name="account" autocomplete="off" placeholder="手机 / 邮箱" lay-verify="required">
</div>
<label class="layui-icon layui-icon-username"></label>
<input class="layui-input" type="text" name="account" autocomplete="off" placeholder="手机 / 邮箱" lay-verify="required">
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<input class="layui-input" type="password" name="password" autocomplete="off" placeholder="密码" lay-verify="required">
</div>
<label class="layui-icon layui-icon-password"></label>
<input class="layui-input" type="password" name="password" autocomplete="off" placeholder="密码" lay-verify="required">
</div>
{% if captcha.enabled == 1 %}
<div id="captcha-block" class="layui-form-item">
@ -48,13 +46,41 @@
{% block inline_css %}
<style>
html {
height: 95%;
}
body {
background: #f2f2f2;
background: #16a085;
}
.circles {
display: block;
width: 20px;
height: 20px;
background: #fff;
border-radius: 50%;
position: absolute;
opacity: 0.5;
z-index: -1;
}
</style>
{% endblock %}
{% block include_js %}
{{ js_include('lib/jquery.min.js') }}
{{ js_include('lib/jquery.buoyant.min.js') }}
{% if captcha.enabled == 1 %}
{{ js_include('https://ssl.captcha.qq.com/TCaptcha.js', false) }}
{% endif %}
{% endblock %}
{% block inline_js %}
<script>
@ -63,16 +89,19 @@
}
</script>
<script>
$('body').buoyant({
elementClass: 'circles',
numberOfItems: 20,
minRadius: 5,
maxRadius: 30,
});
</script>
{% if captcha.enabled == 1 %}
{{ js_include('https://ssl.captcha.qq.com/TCaptcha.js', false) }}
<script>
layui.use(['jquery', 'form'], function () {
var $ = layui.jquery;
new TencentCaptcha(
$('#captcha-btn')[0],
$('#captcha-btn').data('app-id'),
@ -85,11 +114,8 @@
}
}
);
});
</script>
{% endif %}
{% endblock %}

View File

@ -67,7 +67,7 @@
</form>
{% else %}
<div class="kg-center">
<button class="layui-btn layui-bg-gray kg-back">返回上页</button>
<button class="layui-btn layui-btn-primary kg-back">返回上页</button>
</div>
{% endif %}

View File

@ -85,11 +85,11 @@
</tr>
<tr>
<td>cover_270</td>
<td>mageMogr2/thumbnail/270x/interlace/0</td>
<td>imageMogr2/thumbnail/270x/interlace/0</td>
</tr>
<tr>
<td>content_800</td>
<td>mageMogr2/thumbnail/800x/interlace/0</td>
<td>imageMogr2/thumbnail/800x/interlace/0</td>
</tr>
<tr>
<td>slide_1100</td>
@ -152,10 +152,4 @@
</div>
</div>
{% endblock %}

View File

@ -13,9 +13,9 @@
<div class="kg-center">
{% if trade.status == 2 %}
<button class="kg-refund layui-btn layui-bg-green" data-url="{{ refund_url }}">申请退款</button>
<button class="kg-refund layui-btn" data-url="{{ refund_url }}">申请退款</button>
{% endif %}
<button class="kg-back layui-btn layui-bg-gray">返回上页</button>
<button class="kg-back layui-btn layui-btn-primary">返回上页</button>
</div>
{% if refunds.count() > 0 %}

View File

@ -56,6 +56,10 @@ class AnswerController extends Controller
$answer = $service->handle($id);
if ($answer['deleted'] == 1) {
return $this->notFound();
}
$questionId = $answer['question']['id'];
if ($answer['me']['owned'] == 0) {

View File

@ -102,6 +102,10 @@ class ArticleController extends Controller
$article = $service->handle($id);
if ($article['deleted'] == 1) {
return $this->notFound();
}
if ($article['me']['owned'] == 0) {
$this->response->redirect(['for' => 'home.error.403']);
}

View File

@ -43,6 +43,10 @@ class ChapterController extends Controller
$chapter = $service->handle($id);
if ($chapter['deleted'] == 1) {
return $this->notFound();
}
$service = new CourseInfoService();
$course = $service->handle($chapter['course']['id']);

View File

@ -37,6 +37,10 @@ class ConsultController extends Controller
$consult = $service->handle($id);
if ($consult['deleted'] == 1) {
return $this->notFound();
}
$this->view->setVar('consult', $consult);
}

View File

@ -77,6 +77,10 @@ class CourseController extends Controller
$course = $service->handle($id);
if ($course['deleted'] == 1) {
return $this->notFound();
}
$service = new CourseChapterListService();
$chapters = $service->handle($id);

View File

@ -40,6 +40,10 @@ class HelpController extends Controller
$help = $service->handle($id);
if ($help['deleted'] == 1) {
return $this->notFound();
}
$featuredCourses = $this->getFeaturedCourses();
$this->seo->prependTitle(['帮助', $help['title']]);

View File

@ -51,6 +51,10 @@ class ImGroupController extends Controller
$group = $service->getGroup($id);
if ($group['deleted'] == 1) {
return $this->notFound();
}
$this->seo->prependTitle([$group['name'], '群组']);
$this->view->pick('im/group/show');

View File

@ -26,6 +26,10 @@ class PackageController extends Controller
$package = $service->handle($id);
if ($package['deleted'] == 1) {
return $this->notFound();
}
$this->seo->prependTitle(['套餐', $package['title']]);
$this->view->setVar('package', $package);

View File

@ -25,6 +25,10 @@ class PageController extends Controller
$page = $service->handle($id);
if ($page['deleted'] == 1) {
return $this->notFound();
}
if ($page['me']['owned'] == 0) {
$this->response->redirect(['for' => 'home.error.403']);
}

View File

@ -68,6 +68,10 @@ class PointGiftController extends Controller
$gift = $service->handle($id);
if ($gift['deleted'] == 1) {
return $this->notFound();
}
$hotGifts = $this->getHotGifts();
$userBalance = $this->getUserBalance();

View File

@ -101,6 +101,10 @@ class QuestionController extends Controller
$question = $service->handle($id);
if ($question['deleted'] == 1) {
return $this->notFound();
}
if ($question['me']['owned'] == 0) {
$this->response->redirect(['for' => 'home.error.403']);
}

View File

@ -31,6 +31,10 @@ class UserController extends Controller
$user = $service->handle($id);
if ($user['deleted'] == 1) {
return $this->notFound();
}
$this->seo->prependTitle([$user['name'], '个人主页']);
$this->view->setVar('user', $user);

View File

@ -53,8 +53,12 @@ class ImGroup extends Service
'name' => $group->name,
'avatar' => $group->avatar,
'about' => $group->about,
'published' => $group->published,
'deleted' => $group->deleted,
'user_count' => $group->user_count,
'msg_count' => $group->msg_count,
'create_time' => $group->create_time,
'update_time' => $group->update_time,
'owner' => $owner,
];
}

View File

@ -10,18 +10,17 @@
<div class="account-wrap wrap">
<form class="layui-form account-form" method="POST" action="{{ url({'for':'home.account.reset_pwd'}) }}">
<div class="layui-form-item">
<div class="layui-input-block">
<input id="cv-account" class="layui-input" type="text" name="account" autocomplete="off" placeholder="手机 / 邮箱" lay-verify="required">
</div>
<label class="layui-icon layui-icon-username"></label>
<input id="cv-account" class="layui-input" type="text" name="account" autocomplete="off" placeholder="手机 / 邮箱" lay-verify="required">
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<input class="layui-input" type="password" name="new_password" autocomplete="off" placeholder="新密码字母数字特殊字符6-16位" lay-verify="required">
</div>
<label class="layui-icon layui-icon-password"></label>
<input class="layui-input" type="password" name="new_password" autocomplete="off" placeholder="新密码字母数字特殊字符6-16位" lay-verify="required">
</div>
<div class="layui-form-item">
<div class="layui-input-inline verify-input-inline">
<input class="layui-input" type="text" name="verify_code" placeholder="验证码" lay-verify="required">
<label class="layui-icon layui-icon-vercode"></label>
<input class="layui-input" type="text" name="verify_code" autocomplete="off" placeholder="验证码" lay-verify="required">
</div>
<div class="layui-input-inline verify-btn-inline">
<button id="cv-verify-emit" class="layui-btn layui-btn-primary layui-btn-disabled" type="button" disabled="disabled">获取验证码</button>

View File

@ -1,13 +1,11 @@
<form class="layui-form account-form" method="POST" action="{{ url({'for':'home.account.pwd_login'}) }}">
<div class="layui-form-item">
<div class="layui-input-block">
<input class="layui-input" type="text" name="account" autocomplete="off" placeholder="手机 / 邮箱" lay-verify="required">
</div>
<label class="layui-icon layui-icon-username"></label>
<input class="layui-input" type="text" name="account" autocomplete="off" placeholder="手机 / 邮箱" lay-verify="required">
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<input class="layui-input" type="password" name="password" autocomplete="off" placeholder="密码" lay-verify="required">
</div>
<label class="layui-icon layui-icon-password"></label>
<input class="layui-input" type="password" name="password" autocomplete="off" placeholder="密码" lay-verify="required">
</div>
<div id="captcha-block" class="layui-form-item">
<div class="layui-input-block">

View File

@ -1,12 +1,12 @@
<form class="layui-form account-form" method="POST" action="{{ url({'for':'home.account.verify_login'}) }}">
<div class="layui-form-item">
<div class="layui-input-block">
<input id="cv-account" class="layui-input" type="text" name="account" autocomplete="off" placeholder="手机 / 邮箱" lay-verify="required">
</div>
<label class="layui-icon layui-icon-username"></label>
<input id="cv-account" class="layui-input" type="text" name="account" autocomplete="off" placeholder="手机 / 邮箱" lay-verify="required">
</div>
<div class="layui-form-item">
<div class="layui-input-inline verify-input-inline">
<input class="layui-input" type="text" name="verify_code" placeholder="验证码" lay-verify="required">
<label class="layui-icon layui-icon-vercode"></label>
<input class="layui-input" type="text" name="verify_code" autocomplete="off" placeholder="验证码" lay-verify="required">
</div>
<div class="layui-input-inline verify-btn-inline">
<button id="cv-verify-emit" class="layui-btn layui-btn-disabled" type="button" disabled="disabled">获取验证码</button>

View File

@ -10,17 +10,16 @@
<div class="account-wrap wrap">
<form class="layui-form account-form" method="POST" action="{{ url({'for':'home.account.do_register'}) }}">
<div class="layui-form-item">
<div class="layui-input-block">
<input id="cv-account" class="layui-input" type="text" name="account" autocomplete="off" placeholder="手机 / 邮箱" lay-verify="required">
</div>
<label class="layui-icon layui-icon-username"></label>
<input id="cv-account" class="layui-input" type="text" name="account" autocomplete="off" placeholder="手机 / 邮箱" lay-verify="required">
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<input class="layui-input" type="password" name="password" autocomplete="off" placeholder="密码字母数字特殊字符6-16位" lay-verify="required">
</div>
<label class="layui-icon layui-icon-password"></label>
<input class="layui-input" type="password" name="password" autocomplete="off" placeholder="密码字母数字特殊字符6-16位" lay-verify="required">
</div>
<div class="layui-form-item">
<div class="layui-input-inline verify-input-inline">
<label class="layui-icon layui-icon-vercode"></label>
<input class="layui-input" type="text" name="verify_code" placeholder="验证码" lay-verify="required">
</div>
<div class="layui-input-inline verify-btn-inline">

View File

@ -10,7 +10,7 @@
<div class="toolbar"></div>
<div class="action">
<button class="{{ submit_class }}" lay-submit="true" lay-filter="add_comment">发布</button>
<button class="layui-btn layui-btn-sm layui-bg-gray" id="btn-cancel-comment" type="button">取消</button>
<button class="layui-btn layui-btn-sm layui-btn-primary" id="btn-cancel-comment" type="button">取消</button>
</div>
</div>
<input type="hidden" name="item_id" value="{{ article.id }}">

View File

@ -37,7 +37,6 @@
<label class="layui-form-label">分类标签</label>
<div class="layui-input-block">
<div id="xm-tag-ids"></div>
<input type="hidden" name="xm_tags" value='{{ xm_tags|json_encode }}'>
</div>
</div>
<div class="layui-form-item">
@ -83,6 +82,10 @@
</form>
</div>
<div class="layui-hide">
<input type="hidden" name="xm_tags" value='{{ xm_tags|json_encode }}'>
</div>
{% endblock %}
{% block link_css %}

View File

@ -9,7 +9,7 @@
<div class="toolbar"></div>
<div class="action">
<button class="layui-btn layui-btn-sm" lay-submit="true" lay-filter="add_comment">发布</button>
<button class="layui-btn layui-btn-sm layui-bg-gray" id="btn-cancel-comment" type="button">取消</button>
<button class="layui-btn layui-btn-sm layui-btn-primary" id="btn-cancel-comment" type="button">取消</button>
</div>
</div>
<input type="hidden" name="item_id" value="{{ chapter.id }}">

View File

@ -8,7 +8,6 @@
<div class="breadcrumb">
<span class="layui-breadcrumb">
<a href="{{ course_url }}"><i class="layui-icon layui-icon-return"></i> 返回课程</a>
<a><cite>{{ chapter.title }}</cite></a>
</span>
<span class="share">
<a href="javascript:" title="分享到微信"><i class="layui-icon layui-icon-login-wechat icon-wechat"></i></a>
@ -22,9 +21,14 @@
{{ partial('chapter/sticky') }}
</div>
<div class="layout-content">
<div class="read-info wrap" id="preview">{{ chapter.content }}</div>
<div class="article-info wrap">
<div class="title">{{ chapter.title }}</div>
<div class="content markdown-body">
{{ chapter.content }}
</div>
</div>
<div id="comment-anchor"></div>
<div class="read-comment wrap">
<div class="article-comment wrap">
{{ partial('chapter/comment') }}
</div>
</div>
@ -53,14 +57,12 @@
{% block link_css %}
{{ css_link('https://cdn.jsdelivr.net/npm/vditor/dist/index.css', false) }}
{{ css_link('home/css/markdown.css') }}
{% endblock %}
{% block include_js %}
{{ js_include('https://cdn.jsdelivr.net/npm/vditor/dist/method.min.js', false) }}
{{ js_include('home/js/markdown.preview.js') }}
{{ js_include('home/js/course.share.js') }}
{{ js_include('home/js/chapter.read.js') }}
{{ js_include('home/js/chapter.show.js') }}

View File

@ -5,7 +5,6 @@
<table class="kg-table layui-table">
<tr>
<th>名称</th>
<th>类型</th>
<th>大小</th>
<th width="15%">操作</th>
</tr>
@ -13,7 +12,6 @@
{% set download_url = url({'for':'home.download','md5':item.md5}) %}
<tr>
<td>{{ item.name }}</td>
<td>{{ item.mime }}</td>
<td>{{ item.size|human_size }}</td>
<td><a class="layui-btn layui-btn-sm" href="{{ download_url }}" target="_blank">下载</a></td>
</tr>

View File

@ -59,7 +59,7 @@
<div class="toolbar"></div>
<div class="action">
<button class="layui-btn layui-btn-sm" lay-submit="true" lay-filter="reply_comment" data-comment-id="{{ item.id }}" data-parent-id="{{ item.parent_id }}">发布</button>
<button class="layui-btn layui-btn-sm layui-bg-gray btn-cancel-reply" type="button" data-id="{{ item.id }}">取消</button>
<button class="layui-btn layui-btn-sm layui-btn-primary btn-cancel-reply" type="button" data-id="{{ item.id }}">取消</button>
</div>
</div>
</form>

View File

@ -59,7 +59,7 @@
<div class="toolbar"></div>
<div class="action">
<button class="layui-btn layui-btn-sm" lay-submit="true" lay-filter="reply_comment" data-comment-id="{{ item.id }}" data-parent-id="{{ item.parent_id }}">发布</button>
<button class="layui-btn layui-btn-sm layui-bg-gray btn-cancel-reply" type="button" data-id="{{ item.id }}">取消</button>
<button class="layui-btn layui-btn-sm layui-btn-primary btn-cancel-reply" type="button" data-id="{{ item.id }}">取消</button>
</div>
</div>
</form>

View File

@ -36,7 +36,6 @@
<label class="layui-form-label">分类标签</label>
<div class="layui-input-block">
<div id="xm-tag-ids"></div>
<input type="hidden" name="xm_tags" value='{{ xm_tags|json_encode }}'>
</div>
</div>
<div class="layui-form-item last-form-item">
@ -49,6 +48,10 @@
</form>
</div>
<div class="layui-hide">
<input type="hidden" name="xm_tags" value='{{ xm_tags|json_encode }}'>
</div>
{% endblock %}
{% block link_css %}

View File

@ -12,7 +12,7 @@
<div class="my-content">
<div class="wrap">
<div class="my-nav">
<span class="title">用户咨询</span>
<span class="title">课程咨询</span>
{% for key,value in status_types %}
{% set class = (status == key) ? 'layui-btn layui-btn-xs' : 'none' %}
{% set url = url({'for':'home.tc.consults'},{'status':key}) %}

View File

@ -429,9 +429,7 @@ function kg_cos_img_style_trim($path)
*/
function kg_parse_markdown($content)
{
$content = preg_replace_callback('/\/img\/content\/(.*?)\)/', function ($matches) {
return sprintf('/img/content/%s!content_800)', trim($matches[1]));
}, $content);
$content = str_replace('!content_800', '', $content);
$parser = new League\CommonMark\GithubFlavoredMarkdownConverter([
'html_input' => 'strip',

View File

@ -22,6 +22,7 @@ class Upload extends Model
const TYPE_RESOURCE = 4; // 课件资源
const TYPE_IM_IMG = 5; // IM图片
const TYPE_IM_FILE = 6; // IM文件
const TYPE_ICON_IMG = 7; // 图标
const TYPE_DEFAULT_IMG = 99; // 默认图片
/**

View File

@ -33,7 +33,6 @@ class Cache extends Provider
'host' => $config->path('redis.host'),
'port' => $config->path('redis.port'),
'auth' => $config->path('redis.auth'),
'index' => $config->path('cache.db'),
]);
});
}

View File

@ -39,6 +39,7 @@ class AnswerInfo extends LogicService
'anonymous' => $answer->anonymous,
'accepted' => $answer->accepted,
'published' => $answer->published,
'deleted' => $answer->deleted,
'like_count' => $answer->like_count,
'create_time' => $answer->create_time,
'update_time' => $answer->update_time,

View File

@ -55,6 +55,7 @@ class ArticleInfo extends LogicService
'private' => $article->private,
'closed' => $article->closed,
'published' => $article->published,
'deleted' => $article->deleted,
'source_type' => $article->source_type,
'source_url' => $article->source_url,
'word_count' => $article->word_count,

View File

@ -75,12 +75,16 @@ class BasicInfo extends LogicService
'title' => $chapter->title,
'summary' => $chapter->summary,
'model' => $chapter->model,
'published' => $chapter->published,
'deleted' => $chapter->deleted,
'play_urls' => $playUrls,
'resource_count' => $chapter->resource_count,
'comment_count' => $chapter->comment_count,
'consult_count' => $chapter->consult_count,
'user_count' => $chapter->user_count,
'like_count' => $chapter->like_count,
'create_time' => $chapter->create_time,
'update_time' => $chapter->update_time,
];
}
@ -101,6 +105,8 @@ class BasicInfo extends LogicService
'title' => $chapter->title,
'summary' => $chapter->summary,
'model' => $chapter->model,
'published' => $chapter->published,
'deleted' => $chapter->deleted,
'play_urls' => $playUrls,
'start_time' => $live->start_time,
'end_time' => $live->end_time,
@ -110,6 +116,8 @@ class BasicInfo extends LogicService
'consult_count' => $chapter->consult_count,
'user_count' => $chapter->user_count,
'like_count' => $chapter->like_count,
'create_time' => $chapter->create_time,
'update_time' => $chapter->update_time,
];
}
@ -127,11 +135,15 @@ class BasicInfo extends LogicService
'summary' => $chapter->summary,
'model' => $chapter->model,
'content' => $read->content,
'published' => $chapter->published,
'deleted' => $chapter->deleted,
'resource_count' => $chapter->resource_count,
'comment_count' => $chapter->comment_count,
'consult_count' => $chapter->consult_count,
'user_count' => $chapter->user_count,
'like_count' => $chapter->like_count,
'create_time' => $chapter->create_time,
'update_time' => $chapter->update_time,
];
}

View File

@ -32,10 +32,13 @@ class CommentInfo extends LogicService
return [
'id' => $comment->id,
'content' => $comment->content,
'published' => $comment->published,
'deleted' => $comment->deleted,
'parent_id' => $comment->parent_id,
'like_count' => $comment->like_count,
'reply_count' => $comment->reply_count,
'create_time' => $comment->create_time,
'update_time' => $comment->update_time,
'owner' => $owner,
'to_user' => $toUser,
];

View File

@ -34,6 +34,8 @@ class ConsultInfo extends LogicService
'answer' => $consult->answer,
'rating' => $consult->rating,
'private' => $consult->private,
'published' => $consult->published,
'deleted' => $consult->deleted,
'like_count' => $consult->like_count,
'create_time' => $consult->create_time,
'update_time' => $consult->update_time,

View File

@ -49,6 +49,8 @@ class BasicInfo extends LogicService
'model' => $course->model,
'level' => $course->level,
'attrs' => $course->attrs,
'published' => $course->published,
'deleted' => $course->deleted,
'user_count' => $course->user_count,
'lesson_count' => $course->lesson_count,
'resource_count' => $course->resource_count,
@ -56,6 +58,8 @@ class BasicInfo extends LogicService
'review_count' => $course->review_count,
'consult_count' => $course->consult_count,
'favorite_count' => $course->favorite_count,
'create_time' => $course->create_time,
'update_time' => $course->update_time,
];
}

View File

@ -31,6 +31,8 @@ class HelpInfo extends LogicService
'id' => $help->id,
'title' => $help->title,
'content' => $help->content,
'published' => $help->published,
'deleted' => $help->deleted,
'create_time' => $help->create_time,
'update_time' => $help->update_time,
];

View File

@ -29,9 +29,13 @@ class PackageInfo extends LogicService
'id' => $package->id,
'title' => $package->title,
'summary' => $package->summary,
'published' => $package->published,
'deleted' => $package->deleted,
'market_price' => $package->market_price,
'vip_price' => $package->vip_price,
'course_count' => $package->course_count,
'create_time' => $package->create_time,
'update_time' => $package->update_time,
];
}

View File

@ -36,6 +36,8 @@ class PageInfo extends LogicService
'id' => $page->id,
'title' => $page->title,
'content' => $page->content,
'published' => $page->published,
'deleted' => $page->deleted,
'create_time' => $page->create_time,
'update_time' => $page->update_time,
'me' => $me,

View File

@ -37,8 +37,12 @@ class GiftInfo extends LogicService
'type' => $gift->type,
'stock' => $gift->stock,
'point' => $gift->point,
'published' => $gift->published,
'deleted' => $gift->deleted,
'redeem_limit' => $gift->redeem_limit,
'redeem_count' => $gift->redeem_count,
'create_time' => $gift->create_time,
'update_time' => $gift->update_time,
];
}

View File

@ -58,6 +58,7 @@ class QuestionInfo extends LogicService
'solved' => $question->solved,
'closed' => $question->closed,
'published' => $question->published,
'deleted' => $question->deleted,
'view_count' => $question->view_count,
'like_count' => $question->like_count,
'answer_count' => $question->answer_count,

View File

@ -35,6 +35,8 @@ class ReviewInfo extends LogicService
'rating1' => $review->rating1,
'rating2' => $review->rating2,
'rating3' => $review->rating3,
'published' => $review->published,
'deleted' => $review->deleted,
'like_count' => $review->like_count,
'create_time' => $review->create_time,
'update_time' => $review->update_time,

View File

@ -29,6 +29,10 @@ class TopicInfo extends LogicService
'id' => $topic->id,
'title' => $topic->title,
'summary' => $topic->summary,
'published' => $topic->published,
'deleted' => $topic->deleted,
'create_time' => $topic->create_time,
'update_time' => $topic->update_time,
];
}

View File

@ -40,6 +40,7 @@ class UserInfo extends LogicService
'gender' => $user->gender,
'vip' => $user->vip,
'locked' => $user->locked,
'deleted' => $user->deleted,
'course_count' => $user->course_count,
'article_count' => $user->article_count,
'question_count' => $user->question_count,

View File

@ -156,9 +156,7 @@ class MyStorage extends Storage
*/
public function uploadContentImage()
{
$dir = date('Y') . '/' . date('m') . '/';
return $this->upload("/img/content/{$dir}", self::MIME_IMAGE, UploadModel::TYPE_CONTENT_IMG);
return $this->upload('/img/content/', self::MIME_IMAGE, UploadModel::TYPE_CONTENT_IMG);
}
/**
@ -168,9 +166,7 @@ class MyStorage extends Storage
*/
public function uploadAvatarImage()
{
$dir = date('Y') . '/' . date('m') . '/';
return $this->upload("/img/avatar/{$dir}", self::MIME_IMAGE, UploadModel::TYPE_AVATAR_IMG);
return $this->upload('/img/avatar/', self::MIME_IMAGE, UploadModel::TYPE_AVATAR_IMG);
}
/**
@ -180,7 +176,7 @@ class MyStorage extends Storage
*/
public function uploadIconImage()
{
return $this->upload('/img/icon/', self::MIME_IMAGE, UploadModel::TYPE_AVATAR_IMG);
return $this->upload('/img/icon/', self::MIME_IMAGE, UploadModel::TYPE_ICON_IMG);
}
/**
@ -200,9 +196,7 @@ class MyStorage extends Storage
*/
public function uploadImImage()
{
$dir = date('Y') . '/' . date('m') . '/';
return $this->upload("/im/img/{$dir}", self::MIME_IMAGE, UploadModel::TYPE_IM_IMG);
return $this->upload('/im/img/', self::MIME_IMAGE, UploadModel::TYPE_IM_IMG);
}
/**
@ -210,9 +204,7 @@ class MyStorage extends Storage
*/
public function uploadImFile()
{
$dir = date('Y') . '/' . date('m') . '/';
return $this->upload("/im/file/{$dir}", self::MIME_FILE, UploadModel::TYPE_IM_FILE);
return $this->upload('/im/file/', self::MIME_FILE, UploadModel::TYPE_IM_FILE);
}
/**

View File

@ -11,10 +11,27 @@ use Phalcon\Config;
use Phalcon\Di;
use Phalcon\Http\Request as HttpRequest;
use Phalcon\Http\Response as HttpResponse;
use Phalcon\Mvc\Dispatcher;
trait Response
{
public function notFound()
{
/**
* @var Dispatcher $dispatcher
*/
$dispatcher = Di::getDefault()->getShared('dispatcher');
$dispatcher->forward([
'module' => 'home',
'controller' => 'error',
'action' => 'show404',
]);
return false;
}
public function setCors()
{
/**

View File

@ -100,33 +100,55 @@
.kg-login-wrap {
width: 500px;
margin: 100px auto;
margin: 150px auto 100px;
}
.kg-login-wrap .layui-card {
border-radius: 5px;
}
.kg-login-wrap .layui-card-header {
height: 50px;
line-height: 50px;
line-height: 60px;
text-align: center;
font-size: 16px;
}
.kg-login-form {
padding: 15px 10px 5px 10px;
.kg-login-wrap .layui-card-body {
padding: 30px 50px;
}
.kg-login-form .layui-input-block {
margin-left: 0;
}
.kg-login-form .layui-form-item {
position: relative;
}
.kg-login-form .layui-form-item label {
position: absolute;
left: 1px;
top: 1px;
width: 38px;
line-height: 36px;
text-align: center;
color: #d2d2d2;
}
.kg-login-form .layui-form-item input {
padding-left: 36px;
}
.kg-login-copyright {
margin-top: -80px;
color: #666;
color: #fff;
font-size: 12px;
text-align: center;
}
.kg-login-copyright a {
color: #666;
color: #fff;
}
.kg-input-inline {

View File

@ -106,8 +106,6 @@ layui.use(['jquery', 'element', 'layer'], function () {
function getKeyName(filename) {
var ext = getFileExtension(filename);
var date = new Date();
var year = date.getFullYear();
var month = ('0' + (date.getMonth() + 1)).slice(-2);
var name = [
date.getDate(),
date.getHours(),
@ -115,7 +113,7 @@ layui.use(['jquery', 'element', 'layer'], function () {
date.getSeconds(),
Math.round(10000 * Math.random())
].join('');
return '/resource/' + year + '/' + month + '/' + name + '.' + ext;
return '/resource/' + name + '.' + ext;
}
function getFileExtension(filename) {

View File

@ -1,106 +0,0 @@
/**
* 挑选课程组件
* @param data array 默认数据
* @param url string 请求地址
*/
function xmCourse(data, url) {
layui.use(['jquery', 'table'], function () {
var $ = layui.jquery;
var table = layui.table;
var xmCourse = xmSelect.render({
el: '#xm-course-ids',
name: 'xm_course_ids',
height: 'auto',
autoRow: true,
prop: {
name: 'title',
value: 'id',
},
data: data,
content: `
<div class="kg-search-box">
<div class="layui-inline">
<input class="layui-input" type="text" placeholder="请输入课程标题..." id="search-keyword">
</div>
<div class="layui-inline">
<button type="button" class="layui-btn" id="search-btn">搜索</button>
</div>
</div>
<table class="layui-hide" id="course-table" lay-filter="course"></table>`
});
table.render({
id: 'course-table',
elem: '#course-table',
width: 900,
url: url,
page: true,
cols: [[
{field: 'id', title: '编号', width: 50},
{field: 'title', title: '标题', width: 390},
{
field: 'model', title: '类型', width: 50, templet: function (d) {
if (d.model === 1) {
return '点播';
} else if (d.model === 2) {
return '直播';
} else if (d.model === 3) {
return '图文';
}
}
},
{
field: 'level', title: '难度', width: 50, templet: function (d) {
if (d.level === 1) {
return '入门';
} else if (d.level === 2) {
return '初级';
} else if (d.level === 3) {
return '中级';
} else if (d.level === 4) {
return '高级';
}
}
},
{
field: 'user_count', title: '用户', width: 50, templet: function (d) {
return d.user_count;
}
},
{
field: 'market_price', title: '优惠价', width: 50, templet: function (d) {
return '¥' + d.market_price;
}
},
{
field: 'vip_price', title: '会员价', width: 50, templet: function (d) {
return '¥' + d.vip_price;
}
}
]]
});
table.on('rowDouble(course)', function (obj) {
var item = obj.data;
var values = xmCourse.getValue();
var has = values.find(function (i) {
return i.id === item.id;
});
if (!has) {
xmCourse.append([item]);
}
});
$('#search-btn').on('click', function () {
table.reload('course-table', {
where: {title: $('#search-keyword').val()},
page: {curr: 1}
});
});
});
}

View File

@ -399,7 +399,6 @@
margin-bottom: 10px;
line-height: 1.5em;
max-height: 4.5em;
font-size: 12px;
color: #666;
overflow: hidden;
overflow-wrap: break-word;
@ -462,36 +461,6 @@
color: #666;
}
.article-sort,
.question-sort {
padding-bottom: 15px;
margin-bottom: 20px;
border-bottom: 1px solid #e6e6e6;
}
.article-sort a,
.question-sort a {
margin-right: 20px;
}
.article-cate-list li {
padding: 5px 0;
border-radius: 3px;
text-align: center;
}
.article-cate-list .active {
background-color: #009688;
}
.article-cate-list a {
display: block;
}
.article-cate-list .active a {
color: #fff;
}
.article-list {
margin-bottom: 20px;
}
@ -509,12 +478,14 @@
}
.article-card .info {
width: 550px;
flex: 1 1 auto;
}
.article-card .cover {
flex: 0 0 auto;
width: 150px;
height: 84px;
margin-left: 10px;
}
.article-card .cover img {
@ -533,7 +504,6 @@
.article-card .summary {
color: #666;
font-size: 12px;
line-height: 1.5em;
max-height: 4.5em;
margin-bottom: 10px;
@ -1327,11 +1297,6 @@
color: gray;
}
.read-info {
min-height: 428px;
margin-bottom: 20px;
}
.share .layui-icon {
margin-right: 5px;
cursor: pointer;
@ -1625,6 +1590,24 @@
margin: 0 auto;
}
.account-form .layui-form-item {
position: relative;
}
.account-form .layui-form-item label {
position: absolute;
left: 1px;
top: 1px;
width: 38px;
line-height: 36px;
text-align: center;
color: #d2d2d2;
}
.account-form .layui-form-item input {
padding-left: 36px;
}
.account-form .layui-input-block {
margin-left: 0;
}

View File

@ -95,6 +95,7 @@
.markdown-body img {
border-style: none;
cursor: pointer;
}
.markdown-body code,

View File

@ -127,6 +127,23 @@ layui.use(['jquery', 'form', 'element', 'layer', 'helper'], function () {
window.history.back();
});
$('.markdown-body').on('click', 'img', function () {
var width = $(window).width() * 0.8 + 'px';
var height = $(window).height() * 0.8 + 'px';
var src = $(this).attr('src');
var style = 'max-width:' + width + ';max-height:' + height;
var content = '<img alt="preview" src="' + src + '" style="' + style + '">';
layer.open({
type: 1,
title: false,
closeBtn: 0,
area: ['auto'],
skin: 'layui-layer-nobg',
shadeClose: true,
content: content,
});
});
$('.nav-search').on('click', function () {
var content = '<form action="' + $(this).data('url') + '">';
content += '<input type="text" name="query" autocomplete="off" placeholder="搜索内容,回车跳转">';

View File

@ -1,20 +0,0 @@
layui.use(['jquery'], function () {
var $ = layui.jquery;
var element = document.getElementById('preview');
var markdown = element.innerHTML;
var options = {
lazyLoadImage: true,
markdown: {
autoSpace: true,
chinesePunct: true
}
};
Vditor.preview(element, markdown, options);
setTimeout(function () {
$(element).removeClass('layui-hide');
}, 500);
});

View File

@ -0,0 +1,2 @@
!function(e){e.fn.buoyant=function(t){var l=e.extend({containerClass:"buoyant-container",parentClass:"buoyant-parent",elementClass:"",imgSrc:"",width:50,height:-1,backgroundColor:"black",fps:60,numberOfItems:4,minRadius:10,maxRadius:40,minSpeed:20,maxSpeed:70,collisionEfficiency:1,gravity:0,trails:!1,colliding:!1},t),h=this,i=h.width(),n=h.parent().innerHeight(),f=[],v=[],x=[];h.parent().addClass(l.parentClass),this.each(function(){e(this).addClass("buoyant-container"),e(this).addClass(l.containerClass)});function s(t,i,n,s,a){var e;this.x=t,this.y=i,this.r=n,this.w=2*n,this.h=2*n,this.vx=s,this.vy=a,e=l.imgSrc?document.createElement("img"):document.createElement("span"),l.imgSrc&&(e.src=l.imgSrc),l.elementClass&&e.classList.add(l.elementClass),e.style.height=this.h+"px",e.style.width=this.w+"px",e.style.marginLeft="-"+this.r+"px",e.style.marginTop="-"+this.r+"px",e.style.left=this.x+"px",e.style.top=this.y+"px",x.push(e),h.append(e),this.step=function(t){this.x+=this.vx/l.fps*t,this.y+=this.vy/l.fps*t},this.getMomentum=function(){return console.log(1),1},this.halt=function(){this.vx=0,this.vy=0},this.update=m(this),f.push(this)}function m(t){t.x+=t.vx/l.fps,t.y+=t.vy/l.fps,t.vy+=l.gravity,t.x+t.vx/l.fps+t.r>i?(t.vx=-1*Math.abs(t.vx),t.vx=t.vx*l.collisionEfficiency):t.x+t.vx/l.fps-t.r<0&&(t.vx=Math.abs(t.vx),t.vx=t.vx*l.collisionEfficiency),t.y+t.vy/l.fps+t.r>n?(t.vy=-1*Math.abs(t.vy),t.vy=t.vy*l.collisionEfficiency):t.y+t.vy/l.fps-t.r<0&&(t.vy=Math.abs(t.vy),t.vy=t.vy*l.collisionEfficiency)}function p(t,i){return Math.sqrt((t.x-i.x)*(t.x-i.x)+(t.y-i.y)*(t.y-i.y))}function d(t,i){if(Math.abs(t.x-i.x)<=t.r+i.r&&Math.abs(t.y-i.y)<=t.r+i.r&&p(t,i)<=t.r+i.r)return!0}for(var u=0;u<l.numberOfItems;u++)new s(Math.random()*i,Math.random()*n,l.minRadius+Math.random()*(l.maxRadius-l.minRadius),(l.minSpeed+Math.random()*(l.maxSpeed-l.minSpeed))*[1,-1][Math.floor(Math.random()+.5)],(l.minSpeed+Math.random()*(l.maxSpeed-l.minSpeed))*[1,-1][Math.floor(Math.random()+.5)]);for(u=0;u<f.length-1;u++)for(var a=u+1;a<f.length;a++)v.push([f[u],f[a]]);for(u in v){d(v[u][0],v[u][1])}return window.onresize=function(){i=h.width(),n=h.parent().innerHeight()},setInterval(function(){if(l.trails,l.colliding)for(u in v){var t=v[u][0],i=v[u][1];if(d(t,i)){var n=Math.atan((i.y-t.y)/(i.x-t.x)),s=(t.r,i.r,p(t,i),Math.cos(n),Math.sin(n),Math.cos(n)*t.vx+Math.sin(n)*t.vy),a=Math.cos(n)*t.vy-Math.sin(n)*t.vx,e=Math.cos(n)*i.vx+Math.sin(n)*i.vy,h=Math.cos(n)*i.vy-Math.sin(n)*i.vx,o=((t.m-i.m)*s+2*i.m*e)/(t.m+i.m),r=a,c=(2*t.m*s-(t.m-i.m)*e)/(t.m+i.m),y=h;t.vx=Math.cos(n)*o-Math.sin(n)*r,t.vy=Math.cos(n)*r+Math.sin(n)*o,i.vx=Math.cos(n)*c-Math.sin(n)*y,i.vy=Math.cos(n)*y+Math.sin(n)*c,t.vx=t.vx*l.collisionEfficiency,t.vy=t.vy*l.collisionEfficiency}}for(u in f)x[u].style.left=f[u].x+"px",x[u].style.top=f[u].y+"px",m(f[u])},1e3/l.fps),this.each(function(){e(this).css("height",n+"px"),setTimeout(function(){i=h.width(),n=h.parent().innerHeight()},100)})}}(jQuery);
//# sourceMappingURL=jquery.buoyant.min.js.map