diff --git a/CHANGELOG.md b/CHANGELOG.md index 44b3b1c5..5690757b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,19 @@ +### [v1.2.4](https://gitee.com/koogua/course-tencent-cloud/releases/v1.2.4)(2021-01-10) + +#### 增加 + +- 后台增加上传logo和favicon图标 +- 后台增加公众号自定义菜单配置 +- 课程页增加咨询 + +### 优化 + +- oauth中state参数为安全base64加解码 +- findById参数类型不对时抛出异常 +- task表增加索引加快数据查找 +- markdown内容解析改由后端完成 +- 公众号应答处理逻辑 + ### [v1.2.3](https://gitee.com/koogua/course-tencent-cloud/releases/v1.2.3)(2021-01-03) #### 增加 diff --git a/README.md b/README.md index c082a651..3e0f415a 100644 --- a/README.md +++ b/README.md @@ -2,16 +2,16 @@ ![酷瓜云网课GPL协议开源](https://images.gitee.com/uploads/images/2020/1127/092621_3805cf8f_23592.png) -#### 项目介绍 +### 项目介绍 酷瓜云课堂,依托腾讯云基础服务架构,采用C扩展框架Phalcon开发,GPL-2.0开源协议,致力开源网课系统,开源网校系统,开源在线教育系统。 -![](https://img.shields.io/static/v1?label=release&message=1.2.3&color=blue) -![](https://img.shields.io/static/v1?label=stars&message=160&color=blue) -![](https://img.shields.io/static/v1?label=forks&message=60&color=blue) +![](https://img.shields.io/static/v1?label=release&message=1.2.4&color=blue) +![](https://img.shields.io/static/v1?label=stars&message=168&color=blue) +![](https://img.shields.io/static/v1?label=forks&message=63&color=blue) ![](https://img.shields.io/static/v1?label=license&message=GPL-2.0&color=blue) -#### 系统功能 +### 系统功能 实现了点播、直播、专栏、会员、微聊等,是一个完整的产品,具体功能我也不想写一大堆,自己体验吧! @@ -21,17 +21,19 @@ - 课程数据来源于网络(无实质内容),切莫购买 - 管理后台已禁止数据提交,私密配置已过滤 -演示帐号:**13507083515 / 123456** (前后台通用) - 桌面端演示: - [前台演示](https://ctc.koogua.com) - [后台演示](https://ctc.koogua.com/admin) +演示帐号:100015@163.com / 123456 (前后台通用) + 移动端演示: ![移动端二维码](https://images.gitee.com/uploads/images/2020/1127/093203_265221a2_23592.png) +演示帐号:13507083515 / 123456 + 支付流程演示: - [MySQL提升课程全面讲解MySQL架构设计(0.01元)](https://ctc.koogua.com/order/confirm?item_id=1390&item_type=1) @@ -40,7 +42,18 @@ Tips: 测试支付请用手机号注册一个新账户,以便接收订单通知,以及避免课程无法购买 -#### 项目组件 +即时通讯演示: + +请使用以下两个帐号在不同终端或者浏览器登录,打开微聊界面 + +- 帐号A:100015@163.com / 123456 +- 帐号B:100065@163.com / 123456 + +微信推送演示: + +Tips: 请用手机注册一个新账号,用户中心 -> 关注订阅,扫码关注公众号。之后的登录、购买、退款、直播、咨询等会有消息推送。 + +### 项目组件 - 后台框架:[phalcon 3.4.5](https://phalcon.io) - 前端框架:[layui 2.5.6](https://layui.com), [layim 3.9.5](https://www.layui.com/layim)(已授权) @@ -48,45 +61,27 @@ Tips: 测试支付请用手机号注册一个新账户,以便接收订单通 - 即时通讯:[workerman 3.5.22](https://workerman.net) - 基础依赖:[php7.3](https://php.net), [mysql5.7](https://mysql.com), [redis5.0](https://redis.io) -#### 安装指南 +### 安装指南 - [运行环境搭建](https://gitee.com/koogua/course-tencent-cloud-docker) - [系统服务配置](https://gitee.com/koogua/course-tencent-cloud/wikis) +- [客户终端配置](https://gitee.com/koogua/course-tencent-cloud-app) -#### 开发计划 - -- 桌面端:进行中 -- 移动端:进行中 -- 小程序:待启动 - -#### 意见反馈 +### 意见反馈 - [在线反馈](https://gitee.com/koogua/course-tencent-cloud/issues)(推荐) +- [官方论坛](https://koogua.com/forum)(推荐) - QQ交流群: 787363898 -#### 通过这个项目能学到什么? - -- 项目规划,phalcon,缓存,JWT,即时通讯,全文检索 -- docker,supervisor,devops -- git,linux,php,mysql,redis,nginx - -#### 有阿里云版吗? +### 有阿里云版吗? 阿里云版规划中,之前阿里云服务过期未续费,所以腾讯云版本先出。 -#### 代码有加密吗? +### 代码有加密吗? 所有代码都公开(授权代码除外,例如layim),没有所谓的商业版和付费插件。 -#### 有商业服务吗? - -生存才能发展,我们目前提供的服务包括: - -- 系统安装 -- 系统定制 -- 企业授权 - -#### 开源助力 +### 开源助力 毫无保留的真开源不容易,如果对你有帮助,请给我们 **STAR** !!! diff --git a/app/Http/Admin/Services/Setting.php b/app/Http/Admin/Services/Setting.php index 1a28edaa..3ce3f6ac 100644 --- a/app/Http/Admin/Services/Setting.php +++ b/app/Http/Admin/Services/Setting.php @@ -210,29 +210,29 @@ class Setting extends Service if (!empty($settings['menu'])) { foreach ($settings['menu'] as $i => $top) { - $buttons[$i]['name'] = !empty($top['name']) ? $top['name'] : sprintf('菜单%s', $i + 1); - if (!empty($top['url'])) { - $buttons[$i]['url'] = $top['url']; - $buttons[$i]['type'] = 'view'; - } + $buttons[$i]['name'] = $top['name']; + $buttons[$i]['url'] = $top['url']; + $buttons[$i]['type'] = 'view'; foreach ($top['children'] as $j => $sub) { if (!empty($sub['name']) && !empty($sub['url'])) { $buttons[$i]['sub_button'][$j]['name'] = $sub['name']; $buttons[$i]['sub_button'][$j]['url'] = $sub['url']; $buttons[$i]['sub_button'][$j]['type'] = 'view'; + } else { + unset($settings['menu'][$i]['children'][$j]); } } } $settings['menu'] = kg_json_encode($settings['menu']); } - $this->updateSettings($section, $settings); - if (!empty($buttons)) { $service = new WechatService(); $oa = $service->getOfficialAccount(); $oa->menu->create($buttons); } + + $this->updateSettings($section, $settings); } } diff --git a/app/Http/Home/Controllers/HelpController.php b/app/Http/Home/Controllers/HelpController.php index d525a80a..22d7bc29 100644 --- a/app/Http/Home/Controllers/HelpController.php +++ b/app/Http/Home/Controllers/HelpController.php @@ -2,6 +2,7 @@ namespace App\Http\Home\Controllers; +use App\Http\Home\Services\Index as IndexService; use App\Services\Logic\Help\HelpInfo as HelpInfoService; use App\Services\Logic\Help\HelpList as HelpListService; @@ -12,7 +13,7 @@ class HelpController extends Controller { /** - * @Get("/index", name="home.help.index") + * @Get("/", name="home.help.index") */ public function indexAction() { @@ -34,9 +35,19 @@ class HelpController extends Controller $help = $service->handle($id); + $featuredCourses = $this->getFeaturedCourses(); + $this->seo->prependTitle(['帮助', $help['title']]); $this->view->setVar('help', $help); + $this->view->setVar('featured_courses', $featuredCourses); + } + + protected function getFeaturedCourses() + { + $service = new IndexService(); + + return $service->getSimpleFeaturedCourses(); } } diff --git a/app/Http/Home/Controllers/PageController.php b/app/Http/Home/Controllers/PageController.php index 6796d63d..38b31f97 100644 --- a/app/Http/Home/Controllers/PageController.php +++ b/app/Http/Home/Controllers/PageController.php @@ -2,6 +2,7 @@ namespace App\Http\Home\Controllers; +use App\Http\Home\Services\Index as IndexService; use App\Services\Logic\Page\PageInfo as PageInfoService; /** @@ -19,9 +20,19 @@ class PageController extends Controller $page = $service->handle($id); - $this->seo->prependTitle(['单页', $page['title']]); + $featuredCourses = $this->getFeaturedCourses(); + + $this->seo->prependTitle($page['title']); $this->view->setVar('page', $page); + $this->view->setVar('featured_courses', $featuredCourses); + } + + protected function getFeaturedCourses() + { + $service = new IndexService(); + + return $service->getSimpleFeaturedCourses(); } } diff --git a/app/Http/Home/Services/WechatOfficialAccount.php b/app/Http/Home/Services/WechatOfficialAccount.php index ea19fd02..6fd0e48c 100644 --- a/app/Http/Home/Services/WechatOfficialAccount.php +++ b/app/Http/Home/Services/WechatOfficialAccount.php @@ -3,9 +3,9 @@ namespace App\Http\Home\Services; use App\Models\WechatSubscribe as WechatSubscribeModel; +use App\Repos\User as UserRepo; use App\Repos\WechatSubscribe as WechatSubscribeRepo; use App\Services\Wechat as WechatService; -use App\Validators\User as UserValidator; use EasyWeChat\Kernel\Messages\Text as TextMessage; class WechatOfficialAccount extends Service @@ -50,7 +50,7 @@ class WechatOfficialAccount extends Service { $service = new WechatService(); - $service->logger->debug('Received Message ' . json_encode($message)); + $service->logger->info('Received Message ' . json_encode($message)); switch ($message['MsgType']) { case 'event': @@ -74,7 +74,7 @@ class WechatOfficialAccount extends Service return $this->handleLocationEvent($message); break; default: - return $this->emptyReplyMessage(); + return $this->noMatchReply(); break; } break; @@ -100,7 +100,7 @@ class WechatOfficialAccount extends Service return $this->handleLinkReply($message); break; default: - return $this->emptyReplyMessage(); + return $this->noMatchReply(); break; } } @@ -108,16 +108,16 @@ class WechatOfficialAccount extends Service protected function handleSubscribeEvent($message) { $openId = $message['FromUserName'] ?? ''; - $eventKey = $message['EventKey'] ?? ''; - if (!$eventKey) { - return $this->emptyReplyMessage(); + $subscribeRepo = new WechatSubscribeRepo(); + + $subscribe = $subscribeRepo->findByOpenId($openId); + + if ($subscribe && $subscribe->deleted == 1) { + $subscribe->deleted = 0; + $subscribe->update(); } - $userId = str_replace('qrscene_', '', $eventKey); - - $this->handleSubscribeRelation($userId, $openId); - return new TextMessage('开心呀,我们又多了一个小伙伴!'); } @@ -129,7 +129,7 @@ class WechatOfficialAccount extends Service $subscribe = $subscribeRepo->findByOpenId($openId); - if ($subscribe) { + if ($subscribe && $subscribe->deleted == 0) { $subscribe->deleted = 1; $subscribe->update(); } @@ -139,100 +139,95 @@ class WechatOfficialAccount extends Service protected function handleScanEvent($message) { - /** - * 注意:当已关注过用户扫码时,"EventKey"没有带"qrscene_"前缀 - */ $openId = $message['FromUserName'] ?? ''; $eventKey = $message['EventKey'] ?? ''; - $userId = $eventKey; - $this->handleSubscribeRelation($userId, $openId); - } + $userId = str_replace('qrscene_', '', $eventKey); - protected function handleClickEvent($message) - { - $this->defaultReplyMessage(); - } + $userRepo = new UserRepo(); - protected function handleViewEvent($message) - { - $this->defaultReplyMessage(); - } + $user = $userRepo->findById($userId); - protected function handleLocationEvent($message) - { - $this->defaultReplyMessage(); - } - - protected function handleTextReply($message) - { - return $this->defaultReplyMessage(); - } - - protected function handleImageReply($message) - { - return $this->defaultReplyMessage(); - } - - protected function handleVoiceReply($message) - { - return $this->defaultReplyMessage(); - } - - protected function handleVideoReply($message) - { - return $this->defaultReplyMessage(); - } - - protected function handleShortVideoReply($message) - { - return $this->defaultReplyMessage(); - } - - protected function handleLocationReply($message) - { - return $this->defaultReplyMessage(); - } - - protected function handleLinkReply($message) - { - return $this->defaultReplyMessage(); - } - - protected function emptyReplyMessage() - { - return new TextMessage(''); - } - - protected function defaultReplyMessage() - { - return new TextMessage('没有匹配的服务,如有需要请联系客服!'); - } - - protected function handleSubscribeRelation($userId, $openId) - { - $validator = new UserValidator(); - - $validator->checkUser($userId); + if (!$user) return; $subscribeRepo = new WechatSubscribeRepo(); $subscribe = $subscribeRepo->findByOpenId($openId); if ($subscribe) { + if ($subscribe->user_id != $userId) { + $subscribe->user_id = $userId; + } if ($subscribe->deleted == 1) { $subscribe->deleted = 0; - $subscribe->update(); } + $subscribe->update(); } else { - $subscribe = $subscribeRepo->findSubscribe($userId, $openId); - if (!$subscribe) { - $subscribe = new WechatSubscribeModel(); - $subscribe->user_id = $userId; - $subscribe->open_id = $openId; - $subscribe->create(); - } + $subscribe = new WechatSubscribeModel(); + $subscribe->user_id = $userId; + $subscribe->open_id = $openId; + $subscribe->create(); } } + protected function handleClickEvent($message) + { + return $this->emptyReply(); + } + + protected function handleViewEvent($message) + { + return $this->emptyReply(); + } + + protected function handleLocationEvent($message) + { + return $this->emptyReply(); + } + + protected function handleTextReply($message) + { + return $this->emptyReply(); + } + + protected function handleImageReply($message) + { + return $this->emptyReply(); + } + + protected function handleVoiceReply($message) + { + return $this->emptyReply(); + } + + protected function handleVideoReply($message) + { + return $this->emptyReply(); + } + + protected function handleShortVideoReply($message) + { + return $this->emptyReply(); + } + + protected function handleLocationReply($message) + { + return $this->emptyReply(); + } + + protected function handleLinkReply($message) + { + return $this->emptyReply(); + } + + protected function emptyReply() + { + return null; + } + + protected function noMatchReply() + { + return new TextMessage('没有匹配的服务哦!'); + } + } diff --git a/app/Http/Home/Views/course/show.volt b/app/Http/Home/Views/course/show.volt index c229a53b..e10584ed 100644 --- a/app/Http/Home/Views/course/show.volt +++ b/app/Http/Home/Views/course/show.volt @@ -58,7 +58,7 @@ {{ partial('course/show_catalog') }}
-
{{ course.details }}
+
{{ course.details }}
{% if show_tab_packages %} {% set packages_url = url({'for':'home.course.packages','id':course.id}) %} @@ -112,14 +112,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.show.js') }} {{ js_include('home/js/course.share.js') }} diff --git a/app/Http/Home/Views/help/show.volt b/app/Http/Home/Views/help/show.volt index 79acca71..b6682c6e 100644 --- a/app/Http/Home/Views/help/show.volt +++ b/app/Http/Home/Views/help/show.volt @@ -2,6 +2,8 @@ {% block content %} + {{ partial('macros/course') }} + -
-
{{ help.content }}
+
+
+
+
{{ help.content }}
+
+
+
+ {% if featured_courses %} + + {% endif %} +
{% endblock %} {% block link_css %} - {{ css_link('https://cdn.jsdelivr.net/npm/vditor/dist/index.css', false) }} - -{% endblock %} - -{% block include_js %} - - {{ js_include('https://cdn.jsdelivr.net/npm/vditor/dist/method.min.js', false) }} - {{ js_include('home/js/markdown.preview.js') }} + {{ css_link('home/css/markdown.css') }} {% endblock %} \ No newline at end of file diff --git a/app/Http/Home/Views/page/show.volt b/app/Http/Home/Views/page/show.volt index 231f2885..023dfa76 100644 --- a/app/Http/Home/Views/page/show.volt +++ b/app/Http/Home/Views/page/show.volt @@ -2,29 +2,41 @@ {% block content %} + {{ partial('macros/course') }} + -
-
{{ page.content }}
+
+
+
+
{{ page.content }}
+
+
+
+ {% if featured_courses %} + + {% endif %} +
{% endblock %} {% block link_css %} - {{ css_link('https://cdn.jsdelivr.net/npm/vditor/dist/index.css', false) }} - -{% endblock %} - -{% block include_js %} - - {{ js_include('https://cdn.jsdelivr.net/npm/vditor/dist/method.min.js', false) }} - {{ js_include('home/js/markdown.preview.js') }} + {{ css_link('home/css/markdown.css') }} {% endblock %} \ No newline at end of file diff --git a/app/Http/Home/Views/partials/header.volt b/app/Http/Home/Views/partials/header.volt index 8300003c..1222e867 100644 --- a/app/Http/Home/Views/partials/header.volt +++ b/app/Http/Home/Views/partials/header.volt @@ -1,4 +1,4 @@ -