diff --git a/CHANGELOG.md b/CHANGELOG.md index 5bfc3bb1..00dd33e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,17 @@ +### [v1.3.2](https://gitee.com/koogua/course-tencent-cloud/releases/v1.3.2)(2021-04-20) + +### 更新 + +- 前台增文章和章节评论功能 +- 后台增加评论相关管理功能 +- 优化课程,章节,文章等前台界面 +- 优化分享链接的生成和跳转方式 +- 优化课程,章节,文章相关js +- 优化后台数据展示 +- 修正后台分类二级分类错位问题 +- 修正文章命名空间问题 +- 修正后台轮播没有保存问题 + ### [v1.3.1](https://gitee.com/koogua/course-tencent-cloud/releases/v1.3.1)(2021-04-09) ### 更新 diff --git a/app/Http/Admin/Views/article/list.volt b/app/Http/Admin/Views/article/list.volt index 4dde3172..3e7f8cfd 100644 --- a/app/Http/Admin/Views/article/list.volt +++ b/app/Http/Admin/Views/article/list.volt @@ -32,14 +32,16 @@ + 文章 - 来源 - 作者 - 统计 + 浏览 + 评论 + 点赞 + 收藏 推荐 评论 发布 @@ -48,6 +50,7 @@ {% for item in pager.items %} + {% set owner_url = url({'for':'home.user.show','id':item.owner.id}) %} {% set preview_url = url({'for':'home.article.show','id':item.id}) %} {% set edit_url = url({'for':'admin.article.edit','id':item.id}) %} {% set update_url = url({'for':'admin.article.update','id':item.id}) %} @@ -65,17 +68,16 @@ 标签:{{ tags_info(item.tags) }} {% endif %}

-

创建:{{ date('Y-m-d H:i',item.create_time) }},更新:{{ date('Y-m-d H:i',item.update_time) }}

- - {{ source_info(item.source_type,item.source_url) }} - -

昵称:{{ item.owner.name }}

-

编号:{{ item.owner.id }}

- - -

浏览:{{ item.view_count }},评论:{{ item.comment_count }}

-

点赞:{{ item.like_count }},收藏:{{ item.favorite_count }}

+

+ 来源:{{ source_info(item.source_type,item.source_url) }} + 作者:{{ item.owner.name }} + 创建:{{ date('Y-m-d',item.create_time) }} +

+ {{ item.view_count }} + {{ item.comment_count }} + {{ item.like_count }} + {{ item.favorite_count }} diff --git a/app/Http/Admin/Views/chapter/edit_lesson.volt b/app/Http/Admin/Views/chapter/edit_lesson.volt index 9f4e98ab..8d9bd066 100644 --- a/app/Http/Admin/Views/chapter/edit_lesson.volt +++ b/app/Http/Admin/Views/chapter/edit_lesson.volt @@ -22,7 +22,7 @@
diff --git a/app/Http/Admin/Views/chapter/edit_resource.volt b/app/Http/Admin/Views/chapter/edit_resource.volt index 2aefec6f..e2c860c9 100644 --- a/app/Http/Admin/Views/chapter/edit_resource.volt +++ b/app/Http/Admin/Views/chapter/edit_resource.volt @@ -12,7 +12,6 @@
-
选择文件 diff --git a/app/Http/Admin/Views/chapter/lessons.volt b/app/Http/Admin/Views/chapter/lessons.volt index f4d22162..861ca1a3 100644 --- a/app/Http/Admin/Views/chapter/lessons.volt +++ b/app/Http/Admin/Views/chapter/lessons.volt @@ -63,6 +63,16 @@ }); }); + $('.kg-comment').on('click', function () { + var url = $(this).data('url'); + layer.open({ + type: 2, + title: '评论管理', + area: ['1000px', '600px'], + content: url + }); + }); + }); diff --git a/app/Http/Admin/Views/chapter/lessons_live.volt b/app/Http/Admin/Views/chapter/lessons_live.volt index 8ecd0f97..88d3749a 100644 --- a/app/Http/Admin/Views/chapter/lessons_live.volt +++ b/app/Http/Admin/Views/chapter/lessons_live.volt @@ -26,14 +26,20 @@ - + + + + 编号 名称 + 课件 + 点赞 + 评论 直播时间 - 推流状态 + 推流 排序 免费 发布 @@ -50,9 +56,12 @@ {{ item.id }} - {{ item.title }} + {{ item.title }} + {{ item.resource_count }} + {{ item.like_count }} + {{ item.comment_count }} {{ live_time_info(item.attrs) }} {{ live_status_info(item.attrs['stream']['status']) }} diff --git a/app/Http/Admin/Views/chapter/lessons_read.volt b/app/Http/Admin/Views/chapter/lessons_read.volt index e5fdacb0..bef1af3c 100644 --- a/app/Http/Admin/Views/chapter/lessons_read.volt +++ b/app/Http/Admin/Views/chapter/lessons_read.volt @@ -6,13 +6,17 @@ - + + + 编号 名称 - 字数 + 课件 + 点赞 + 评论 排序 免费 发布 @@ -26,13 +30,18 @@ {% set update_url = url({'for':'admin.chapter.update','id':item.id}) %} {% set delete_url = url({'for':'admin.chapter.delete','id':item.id}) %} {% set restore_url = url({'for':'admin.chapter.restore','id':item.id}) %} + {% set comment_url = url({'for':'admin.comment.list'},{'item_id':item.id,'item_type':1}) %} {{ item.id }} - {{ item.title }} - +

+ {{ item.title }} + +

- {{ item.attrs['word_count'] }} + {{ item.resource_count }} + {{ item.like_count }} + {{ item.comment_count }} @@ -47,6 +56,8 @@ {% else %}
  • 还原
  • {% endif %} +
    +
  • 评论管理
  • diff --git a/app/Http/Admin/Views/chapter/lessons_vod.volt b/app/Http/Admin/Views/chapter/lessons_vod.volt index 838017da..6fa43f3d 100644 --- a/app/Http/Admin/Views/chapter/lessons_vod.volt +++ b/app/Http/Admin/Views/chapter/lessons_vod.volt @@ -1,14 +1,14 @@ {%- macro file_status(value) %} {% if value == 'pending' %} - 待上传 + 待上传 {% elseif value == 'uploaded' %} - 已上传 + 已上传 {% elseif value == 'translating' %} - 转码中 + 转码中 {% elseif value == 'translated' %} - 已转码 + 已转码 {% elseif value == 'failed' %} - 已失败 + 已失败 {% endif %} {%- endmacro %} @@ -21,14 +21,19 @@ + + + 编号 名称 - 状态 - 时长 + 课件 + 学员 + 点赞 + 评论 排序 免费 发布 @@ -42,14 +47,23 @@ {% set update_url = url({'for':'admin.chapter.update','id':item.id}) %} {% set delete_url = url({'for':'admin.chapter.delete','id':item.id}) %} {% set restore_url = url({'for':'admin.chapter.restore','id':item.id}) %} + {% set comment_url = url({'for':'admin.comment.list'},{'item_id':item.id,'item_type':1}) %} {{ item.id }} - {{ item.title }} - +

    + {{ item.title }} + +

    +

    + 状态:{{ file_status(item.attrs['file']['status']) }} + 时长:{{ item.attrs['duration']|duration }} +

    - {{ file_status(item.attrs['file']['status']) }} - {{ item.attrs['duration']|duration }} + {{ item.resource_count }} + {{ item.user_count }} + {{ item.like_count }} + {{ item.comment_count }} @@ -64,6 +78,8 @@ {% else %}
  • 还原
  • {% endif %} +
    +
  • 评论管理
  • diff --git a/app/Http/Admin/Views/course/chapters.volt b/app/Http/Admin/Views/course/chapters.volt index 080d2269..32b117fc 100644 --- a/app/Http/Admin/Views/course/chapters.volt +++ b/app/Http/Admin/Views/course/chapters.volt @@ -26,13 +26,21 @@ - + + + + + 编号 名称 - 课时数 + 课时 + 课件 + 学员 + 点赞 + 评论 排序 操作 @@ -50,11 +58,11 @@ {{ item.title }} - - - {{ item.lesson_count }} - - + {{ item.lesson_count }} + {{ item.resource_count }} + {{ item.user_count }} + {{ item.like_count }} + {{ item.comment_count }}
    diff --git a/app/Http/Admin/Views/course/list.volt b/app/Http/Admin/Views/course/list.volt index 7a7982bc..03faed20 100644 --- a/app/Http/Admin/Views/course/list.volt +++ b/app/Http/Admin/Views/course/list.volt @@ -32,14 +32,20 @@ + + + 课程 - 类型 - 课时数 - 用户数 + 课时 + 课件 + 学员 + 收藏 + 咨询 + 评价 价格 推荐 发布 @@ -69,22 +75,22 @@ {% endif %} 难度:{{ level_info(item.level) }}

    +

    + 类型:{{ model_info(item.model) }} + 评分:{{ item.rating }} + 创建:{{ date('Y-m-d',item.create_time) }} +

    - {{ model_info(item.model) }} + {{ item.lesson_count }} + {{ item.resource_count }} + {{ item.user_count }} + {{ item.favorite_count }} + {{ item.consult_count }} + {{ item.review_count }} - - {{ item.lesson_count }} - - - - - {{ item.user_count }} - - - -

    原始价:{{ '¥%0.2f'|format(item.origin_price) }}

    -

    市场价:{{ '¥%0.2f'|format(item.market_price) }}

    -

    会员价:{{ '¥%0.2f'|format(item.vip_price) }}

    +

    原始:{{ '¥%0.2f'|format(item.origin_price) }}

    +

    市场:{{ '¥%0.2f'|format(item.market_price) }}

    +

    会员:{{ '¥%0.2f'|format(item.vip_price) }}

    diff --git a/app/Http/Admin/Views/im/group/list.volt b/app/Http/Admin/Views/im/group/list.volt index 02d07b93..c74a0780 100644 --- a/app/Http/Admin/Views/im/group/list.volt +++ b/app/Http/Admin/Views/im/group/list.volt @@ -25,7 +25,6 @@ - @@ -38,7 +37,6 @@ - @@ -56,15 +54,23 @@ - + -
    头像 名称 群主类型 成员 发布 操作 {{ item.name }} {{ item.name }}({{ item.id }}) +

    + 名称:{{ item.name }}({{ item.id }}) +

    +

    + 类型:{{ type_info(item.type) }} + 创建:{{ date('Y-m-d',item.create_time) }} +

    +
    {% if item.owner.id is defined %} - {{ item.owner.name }}({{ item.owner.id }}) +

    昵称:{{ item.owner.name }}

    +

    编号:{{ item.owner.id }}

    {% else %} N/A {% endif %}
    {{ type_info(item.type) }} {{ item.user_count }} diff --git a/app/Http/Admin/Views/macros/article.volt b/app/Http/Admin/Views/macros/article.volt index 0c025121..fad0df84 100644 --- a/app/Http/Admin/Views/macros/article.volt +++ b/app/Http/Admin/Views/macros/article.volt @@ -1,12 +1,12 @@ {%- macro source_info(type,url) %} {% if type == 1 %} - 原创 + 原创 {% elseif type == 2 %} 转载 {% elseif type == 3 %} - 翻译 + 翻译 {% else %} - N/A + N/A {% endif %} {%- endmacro %} diff --git a/app/Http/Admin/Views/user/list.volt b/app/Http/Admin/Views/user/list.volt index 551163d9..a9ff78cd 100644 --- a/app/Http/Admin/Views/user/list.volt +++ b/app/Http/Admin/Views/user/list.volt @@ -25,7 +25,8 @@ - + + @@ -38,9 +39,10 @@ - - + + + @@ -54,15 +56,24 @@ - - - + - - + + + + +
    用户头像 用户昵称所在地区用户性别 用户角色课程文章收藏 活跃时间 注册时间 操作 {{ item.name }} {{ item.name }}({{ item.id }}){{ status_info(item) }}{{ item.area }}{{ gender_info(item.gender) }} +

    + {{ item.name }}({{ item.id }}){{ status_info(item) }} +

    +

    + 性别:{{ gender_info(item.gender) }} + 地区:{{ item.area|default('N/A') }} +

    +

    教学:{{ edu_role_info(item.edu_role) }}

    后台:{{ admin_role_info(item.admin_role) }}

    {{ date('Y-m-d H:i:s',item.active_time) }}{{ date('Y-m-d H:i:s',item.create_time) }}{{ item.course_count }}{{ item.article_count }}{{ item.favorite_count }}{{ date('Y-m-d',item.active_time) }}{{ date('Y-m-d',item.create_time) }}
    diff --git a/app/Http/Home/Controllers/CommentController.php b/app/Http/Home/Controllers/CommentController.php new file mode 100644 index 00000000..4d11ee38 --- /dev/null +++ b/app/Http/Home/Controllers/CommentController.php @@ -0,0 +1,144 @@ +handle(); + + $pager->target = 'comment-list'; + + $this->view->setRenderLevel(View::LEVEL_ACTION_VIEW); + + $this->view->setVar('pager', $pager); + } + + /** + * @Get("/{id:[0-9]+}/replies", name="home.comment.replies") + */ + public function repliesAction($id) + { + $service = new ReplyListService(); + + $pager = $service->handle($id); + + $pager->target = "reply-list-{$id}"; + + $this->view->setRenderLevel(View::LEVEL_ACTION_VIEW); + + $this->view->setVar('pager', $pager); + } + + /** + * @Get("/{id:[0-9]+}/info", name="home.comment.info") + */ + public function infoAction($id) + { + $service = new CommentInfoService(); + + $comment = $service->handle($id); + + $this->view->setRenderLevel(View::LEVEL_ACTION_VIEW); + + $this->view->setVar('comment', $comment); + } + + /** + * @Get("/add", name="home.comment.add") + */ + public function addAction() + { + + } + + /** + * @Get("/{id:[0-9]+}/reply", name="home.comment.reply") + */ + public function replyAction($id) + { + $service = new CommentInfoService(); + + $comment = $service->handle($id); + + $this->view->setVar('comment', $comment); + } + + /** + * @Post("/create", name="home.comment.create") + */ + public function createAction() + { + $service = new CommentCreateService(); + + $comment = $service->handle(); + + $service = new CommentInfoService(); + + $comment = $service->handle($comment->id); + + return $this->jsonSuccess(['comment' => $comment]); + } + + /** + * @Post("/{id:[0-9]+}/reply", name="home.comment.create_reply") + */ + public function createReplyAction($id) + { + $service = new CommentReplyService(); + + $comment = $service->handle($id); + + $service = new CommentInfoService(); + + $comment = $service->handle($comment->id); + + return $this->jsonSuccess(['comment' => $comment]); + } + + /** + * @Post("/{id:[0-9]+}/like", name="home.comment.like") + */ + public function likeAction($id) + { + $service = new CommentLikeService(); + + $data = $service->handle($id); + + $msg = $data['action'] == 'do' ? '点赞成功' : '取消点赞成功'; + + return $this->jsonSuccess(['data' => $data, 'msg' => $msg]); + } + + /** + * @Post("/{id:[0-9]+}/delete", name="home.comment.delete") + */ + public function deleteAction($id) + { + $service = new CommentDeleteService(); + + $service->handle($id); + + return $this->jsonSuccess(['msg' => '删除评论成功']); + } + +} diff --git a/app/Http/Home/Controllers/PackageController.php b/app/Http/Home/Controllers/PackageController.php index 12a7f513..a879cde6 100644 --- a/app/Http/Home/Controllers/PackageController.php +++ b/app/Http/Home/Controllers/PackageController.php @@ -12,6 +12,20 @@ use Phalcon\Mvc\View; class PackageController extends Controller { + /** + * @Get("/{id:[0-9]+}", name="home.package.show") + */ + public function showAction($id) + { + $service = new PackageInfoService(); + + $package = $service->handle($id); + + $this->seo->prependTitle(['套餐', $package['title']]); + + $this->view->setVar('package', $package); + } + /** * @Get("/{id:[0-9]+}/info", name="home.package.info") */ diff --git a/app/Http/Home/Controllers/PublicController.php b/app/Http/Home/Controllers/PublicController.php index c37faf2f..e1363c8e 100644 --- a/app/Http/Home/Controllers/PublicController.php +++ b/app/Http/Home/Controllers/PublicController.php @@ -2,6 +2,7 @@ namespace App\Http\Home\Controllers; +use App\Http\Home\Services\ShareUrl as ShareUrlService; use App\Library\CsrfToken as CsrfTokenService; use App\Repos\Upload as UploadRepo; use App\Services\LiveNotify as LiveNotifyService; @@ -43,6 +44,22 @@ class PublicController extends \Phalcon\Mvc\Controller } } + /** + * @Get("/share", name="home.share") + */ + public function shareAction() + { + $id = $this->request->getQuery('id', 'int', 0); + $type = $this->request->getQuery('type', 'string', 'course'); + $referer = $this->request->getQuery('referer', 'int', 0); + + $service = new ShareUrlService(); + + $location = $service->handle($id, $type, $referer); + + return $this->response->redirect($location, true); + } + /** * @Get("/qrcode", name="home.qrcode") */ diff --git a/app/Http/Home/Services/ShareUrl.php b/app/Http/Home/Services/ShareUrl.php new file mode 100644 index 00000000..134f0989 --- /dev/null +++ b/app/Http/Home/Services/ShareUrl.php @@ -0,0 +1,159 @@ +webBaseUrl = $this->getWebBaseUrl(); + $this->h5BaseUrl = $this->getH5BaseUrl(); + } + + public function handle($id, $type, $referer = 0) + { + if ($type == 'article') { + $result = $this->getArticleUrl($id, $referer); + } elseif ($type == 'course') { + $result = $this->getCourseUrl($id, $referer); + } elseif ($type == 'chapter') { + $result = $this->getChapterUrl($id, $referer); + } elseif ($type == 'package') { + $result = $this->getPackageUrl($id, $referer); + } elseif ($type == 'vip') { + $result = $this->getVipUrl($id, $referer); + } elseif ($type == 'user') { + $result = $this->getUserUrl($id, $referer); + } else { + $result = $this->getHomeUrl($referer); + } + + return $this->h5Enabled() ? $result['h5'] : $result['web']; + } + + public function getHomeUrl($referer = 0) + { + $webUrl = sprintf('%s?referer=%s', $this->webBaseUrl, $referer); + + $h5Url = sprintf('%s?referer=%s', $this->h5BaseUrl, $referer); + + return ['web' => $webUrl, 'h5' => $h5Url]; + } + + public function getArticleUrl($id, $referer = 0) + { + $route = $this->url->get( + ['for' => 'home.article.show', 'id' => $id], + ['referer' => $referer] + ); + + $webUrl = $this->webBaseUrl . $route; + + $h5Url = sprintf('%s/article/info?id=%s&referer=%s', $this->h5BaseUrl, $id, $referer); + + return ['web' => $webUrl, 'h5' => $h5Url]; + } + + public function getCourseUrl($id, $referer = 0) + { + $route = $this->url->get( + ['for' => 'home.course.show', 'id' => $id], + ['referer' => $referer] + ); + + $webUrl = $this->webBaseUrl . $route; + + $h5Url = sprintf('%s/course/info?id=%s&referer=%s', $this->h5BaseUrl, $id, $referer); + + return ['web' => $webUrl, 'h5' => $h5Url]; + } + + public function getChapterUrl($id, $referer = 0) + { + $route = $this->url->get( + ['for' => 'home.chapter.show', 'id' => $id], + ['referer' => $referer] + ); + + $webUrl = $this->webBaseUrl . $route; + + $h5Url = sprintf('%s/chapter/info?id=%s&referer=%s', $this->h5BaseUrl, $id, $referer); + + return ['web' => $webUrl, 'h5' => $h5Url]; + } + + public function getPackageUrl($id, $referer = 0) + { + $route = $this->url->get( + ['for' => 'home.package.show', 'id' => $id], + ['referer' => $referer] + ); + + $webUrl = $this->webBaseUrl . $route; + + $h5Url = sprintf('%s/package/info?id=%s&referer=%s', $this->h5BaseUrl, $id, $referer); + + return ['web' => $webUrl, 'h5' => $h5Url]; + } + + public function getUserUrl($id, $referer = 0) + { + $route = $this->url->get( + ['for' => 'home.user.show', 'id' => $id], + ['referer' => $referer] + ); + + $webUrl = $this->webBaseUrl . $route; + + $h5Url = sprintf('%s/user/index?id=%s&referer=%s', $this->h5BaseUrl, $id, $referer); + + return ['web' => $webUrl, 'h5' => $h5Url]; + } + + public function getVipUrl($id, $referer = 0) + { + $route = $this->url->get( + ['for' => 'home.vip.index'], + ['id' => $id, 'referer' => $referer] + ); + + $webUrl = $this->webBaseUrl . $route; + + $h5Url = sprintf('%s/vip/index?id=%s&referer=%s', $this->h5BaseUrl, $id, $referer); + + return ['web' => $webUrl, 'h5' => $h5Url]; + } + + protected function h5Enabled() + { + $file = public_path('h5/index.html'); + + return file_exists($file); + } + + protected function getWebBaseUrl() + { + return kg_site_url(); + } + + protected function getH5BaseUrl() + { + return sprintf('%s/h5/#/pages', kg_site_url()); + } + +} diff --git a/app/Http/Home/Views/article/comment.volt b/app/Http/Home/Views/article/comment.volt new file mode 100644 index 00000000..91731085 --- /dev/null +++ b/app/Http/Home/Views/article/comment.volt @@ -0,0 +1,21 @@ +{% set item_type = 2 %} +{% set comment_list_url = url({'for':'home.comment.list'},{'item_id':article.id,'item_type':item_type}) %} +{% set comment_create_url = url({'for':'home.comment.create'}) %} +{% set submit_class = auth_user.id > 0 ? 'layui-btn layui-btn-sm' : 'layui-btn layui-btn-sm layui-btn-disabled' %} + +
    + + + + + + +
    + +
    \ No newline at end of file diff --git a/app/Http/Home/Views/article/show.volt b/app/Http/Home/Views/article/show.volt index 90027ca8..97de06a6 100644 --- a/app/Http/Home/Views/article/show.volt +++ b/app/Http/Home/Views/article/show.volt @@ -4,52 +4,27 @@ {{ partial('macros/article') }} - {% set list_url = url({'for':'home.article.list'}) %} - {% set category_url = url({'for':'home.article.list'},{'category_id':article.category.id}) %} + {% set article_list_url = url({'for':'home.article.list'}) %} + {% set related_article_url = url({'for':'home.article.related','id':article.id}) %} {% set owner_url = url({'for':'home.user.show','id':article.owner.id}) %} - {% set favorite_url = url({'for':'home.article.favorite','id':article.id}) %} - {% set like_url = url({'for':'home.article.like','id':article.id}) %} - {% set favorited_class = article.me.favorited ? 'layui-icon-star-fill' : 'layui-icon-star' %} - {% set liked_class = article.me.liked ? 'active' : '' %} - {% set article.owner.title = article.owner.title ? article.owner.title : '默默无名' %}
    - -
    -
    -
    - -
    -
    {{ article.like_count }}
    -
    -
    -
    - -
    -
    {{ article.comment_count }}
    -
    -
    -
    - -
    -
    {{ article.favorite_count }}
    -
    +
    + {{ partial('article/sticky') }}
    -
    {{ article.content }}
    {% if article.tags %} @@ -79,18 +54,15 @@
    {% endif %}
    -
    -
    - +
    + {% if article.allow_comment == 1 %} +
    + {{ partial('article/comment') }}
    -
    - -
    -
    + {% else %} +
    评论已关闭
    + {% endif %}
    - - {% set related_article_url = url({'for':'home.article.related','id':article.id}) %} -
    @@ -112,10 +84,9 @@
    - - {% set share_url = full_url({'for':'home.article.show','id':article.id}) %} + {% set share_url = full_url({'for':'home.share'},{'id':article.id,'type':'article','referer':auth_user.id}) %} {% set qrcode_url = url({'for':'home.qrcode'},{'text':share_url}) %}
    @@ -137,5 +108,6 @@ {{ js_include('home/js/article.show.js') }} {{ js_include('home/js/article.share.js') }} + {{ js_include('home/js/comment.js') }} {% endblock %} \ No newline at end of file diff --git a/app/Http/Home/Views/article/sticky.volt b/app/Http/Home/Views/article/sticky.volt new file mode 100644 index 00000000..50be63ab --- /dev/null +++ b/app/Http/Home/Views/article/sticky.volt @@ -0,0 +1,27 @@ +{% set favorite_url = url({'for':'home.article.favorite','id':article.id}) %} +{% set like_url = url({'for':'home.article.like','id':article.id}) %} +{% set favorite_title = article.me.favorited == 1 ? '取消收藏' : '收藏文章' %} +{% set like_title = article.me.liked == 1 ? '取消点赞' : '点赞支持' %} +{% set favorite_class = article.me.favorited == 1 ? 'layui-icon-star-fill' : 'layui-icon-star' %} +{% set like_class = article.me.liked == 1 ? 'active' : '' %} + +
    +
    +
    + +
    +
    {{ article.like_count }}
    +
    +
    +
    + +
    +
    {{ article.comment_count }}
    +
    +
    +
    + +
    +
    {{ article.favorite_count }}
    +
    +
    \ No newline at end of file diff --git a/app/Http/Home/Views/chapter/comment.volt b/app/Http/Home/Views/chapter/comment.volt new file mode 100644 index 00000000..35a0f786 --- /dev/null +++ b/app/Http/Home/Views/chapter/comment.volt @@ -0,0 +1,20 @@ +{% set item_type = 1 %} +{% set comment_list_url = url({'for':'home.comment.list'},{'item_id':chapter.id,'item_type':item_type}) %} +{% set comment_create_url = url({'for':'home.comment.create'}) %} + +
    +
    + + + + +
    +
    + +
    \ No newline at end of file diff --git a/app/Http/Home/Views/chapter/live/active.volt b/app/Http/Home/Views/chapter/live/active.volt index 26a8f398..da9fb90a 100644 --- a/app/Http/Home/Views/chapter/live/active.volt +++ b/app/Http/Home/Views/chapter/live/active.volt @@ -2,16 +2,12 @@ {% block content %} - {% set full_chapter_url = full_url({'for':'home.chapter.show','id':chapter.id}) %} {% set course_url = url({'for':'home.course.show','id':chapter.course.id}) %} - {% set resources_url = url({'for':'home.chapter.resources','id':chapter.id}) %} {% set learning_url = url({'for':'home.chapter.learning','id':chapter.id}) %} {% set live_chats_url = url({'for':'home.live.chats','id':chapter.id}) %} {% set live_stats_url = url({'for':'home.live.stats','id':chapter.id}) %} {% set send_msg_url = url({'for':'home.live.send_msg','id':chapter.id}) %} {% set bind_user_url = url({'for':'home.live.bind_user','id':chapter.id}) %} - {% set like_url = url({'for':'home.chapter.like','id':chapter.id}) %} - {% set qrcode_url = url({'for':'home.qrcode'},{'text':full_chapter_url}) %}
    +
    + {{ partial('chapter/live/sticky') }} +
    @@ -63,10 +57,13 @@
    + {% set share_url = full_url({'for':'home.share'},{'id':chapter.id,'type':'chapter','referer':auth_user.id}) %} + {% set qrcode_url = url({'for':'home.qrcode'},{'text':share_url}) %} +
    - +
    @@ -77,7 +74,7 @@ {{ js_include('https://imgcache.qq.com/open/qcloud/video/vcplayer/TcPlayer-2.3.3.js', false) }} {{ js_include('home/js/chapter.live.player.js') }} {{ js_include('home/js/chapter.live.chat.js') }} - {{ js_include('home/js/chapter.action.js') }} + {{ js_include('home/js/chapter.show.js') }} {{ js_include('home/js/course.share.js') }} {% endblock %} \ No newline at end of file diff --git a/app/Http/Home/Views/chapter/live/sticky.volt b/app/Http/Home/Views/chapter/live/sticky.volt new file mode 100644 index 00000000..52479690 --- /dev/null +++ b/app/Http/Home/Views/chapter/live/sticky.volt @@ -0,0 +1,27 @@ +{% set download_url = url({'for':'home.chapter.resources','id':chapter.id}) %} +{% set like_url = url({'for':'home.chapter.like','id':chapter.id}) %} +{% set like_title = chapter.me.liked == 1 ? '取消点赞' : '点赞支持' %} +{% set like_class = chapter.me.liked == 1 ? 'active' : '' %} + +
    +
    +
    + +
    +
    {{ chapter.like_count }}
    +
    +
    +
    + +
    +
    0
    +
    + {% if chapter.resource_count > 0 %} +
    +
    + +
    +
    资料
    +
    + {% endif %} +
    \ No newline at end of file diff --git a/app/Http/Home/Views/chapter/read.volt b/app/Http/Home/Views/chapter/read.volt index ee858df5..81d10d44 100644 --- a/app/Http/Home/Views/chapter/read.volt +++ b/app/Http/Home/Views/chapter/read.volt @@ -2,13 +2,8 @@ {% block content %} - {% set full_chapter_url = full_url({'for':'home.chapter.show','id':chapter.id}) %} {% set course_url = url({'for':'home.course.show','id':chapter.course.id}) %} - {% set resources_url = url({'for':'home.chapter.resources','id':chapter.id}) %} {% set learning_url = url({'for':'home.chapter.learning','id':chapter.id}) %} - {% set like_url = url({'for':'home.chapter.like','id':chapter.id}) %} - {% set consult_url = url({'for':'home.consult.add'},{'chapter_id':chapter.id}) %} - {% set qrcode_url = url({'for':'home.qrcode'},{'text':full_chapter_url}) %}
    +
    + {{ partial('chapter/sticky') }} +
    {{ chapter.content }}
    +
    +
    + {{ partial('chapter/comment') }} +
    {{ partial('chapter/catalog') }} @@ -45,10 +39,13 @@
    + {% set share_url = full_url({'for':'home.share'},{'id':chapter.id,'type':'chapter','referer':auth_user.id}) %} + {% set qrcode_url = url({'for':'home.qrcode'},{'text':share_url}) %} +
    - +
    @@ -66,6 +63,7 @@ {{ 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.action.js') }} + {{ js_include('home/js/chapter.show.js') }} + {{ js_include('home/js/comment.js') }} {% endblock %} \ No newline at end of file diff --git a/app/Http/Home/Views/chapter/sticky.volt b/app/Http/Home/Views/chapter/sticky.volt new file mode 100644 index 00000000..cc4c20b3 --- /dev/null +++ b/app/Http/Home/Views/chapter/sticky.volt @@ -0,0 +1,42 @@ +{% set download_url = url({'for':'home.chapter.resources','id':chapter.id}) %} +{% set consult_url = url({'for':'home.consult.add'},{'chapter_id':chapter.id}) %} +{% set like_url = url({'for':'home.chapter.like','id':chapter.id}) %} +{% set like_title = chapter.me.liked == 1 ? '取消点赞' : '点赞支持' %} +{% set like_class = chapter.me.liked == 1 ? 'active' : '' %} + +
    +
    +
    + +
    +
    {{ chapter.like_count }}
    +
    +
    +
    + +
    +
    {{ chapter.user_count }}
    +
    +
    +
    + +
    +
    {{ chapter.comment_count }}
    +
    + {% if chapter.resource_count > 0 %} +
    +
    + +
    +
    资料
    +
    + {% endif %} + {% if course.market_price > 0 %} +
    +
    + +
    +
    咨询
    +
    + {% endif %} +
    \ No newline at end of file diff --git a/app/Http/Home/Views/chapter/vod.volt b/app/Http/Home/Views/chapter/vod.volt index 4e10cb46..10e69f46 100644 --- a/app/Http/Home/Views/chapter/vod.volt +++ b/app/Http/Home/Views/chapter/vod.volt @@ -2,14 +2,8 @@ {% block content %} - {% set full_chapter_url = full_url({'for':'home.chapter.show','id':chapter.id}) %} {% set course_url = url({'for':'home.course.show','id':chapter.course.id}) %} - {% set resources_url = url({'for':'home.chapter.resources','id':chapter.id}) %} {% set learning_url = url({'for':'home.chapter.learning','id':chapter.id}) %} - {% set like_url = url({'for':'home.chapter.like','id':chapter.id}) %} - {% set qrcode_url = url({'for':'home.qrcode'},{'text':full_chapter_url}) %} - {% set consult_url = url({'for':'home.consult.add'},{'chapter_id':chapter.id}) %} - {% set liked_class = chapter.me.liked ? 'active' : '' %}
    +
    + {{ partial('chapter/sticky') }} +
    +
    +
    + {{ partial('chapter/comment') }} +
    {{ partial('chapter/catalog') }} @@ -50,10 +43,13 @@
    + {% set share_url = full_url({'for':'home.share'},{'id':chapter.id,'type':'chapter','referer':auth_user.id}) %} + {% set qrcode_url = url({'for':'home.qrcode'},{'text':share_url}) %} +
    - +
    @@ -63,7 +59,8 @@ {{ js_include('https://imgcache.qq.com/open/qcloud/video/vcplayer/TcPlayer-2.3.3.js', false) }} {{ js_include('home/js/course.share.js') }} - {{ js_include('home/js/chapter.action.js') }} + {{ js_include('home/js/chapter.show.js') }} {{ js_include('home/js/chapter.vod.player.js') }} + {{ js_include('home/js/comment.js') }} {% endblock %} \ No newline at end of file diff --git a/app/Http/Home/Views/comment/info.volt b/app/Http/Home/Views/comment/info.volt new file mode 100644 index 00000000..f64a65fd --- /dev/null +++ b/app/Http/Home/Views/comment/info.volt @@ -0,0 +1,63 @@ +{% set owner_url = url({'for':'home.user.show','id':comment.owner.id}) %} +{% set delete_url = url({'for':'home.comment.delete','id':comment.id}) %} + +{% if comment.parent_id == 0 %} +
    +
    +
    + + {{ comment.owner.name }} + +
    +
    + +
    {{ comment.content }}
    + +
    +
    +
    +{% endif %} + +{% if comment.parent_id > 0 %} +
    +
    + + {{ comment.owner.name }} + +
    +
    +
    + {{ comment.owner.name }} + {% if comment.to_user.id is defined %} + {% set to_user_url = url({'for':'home.user.show','id':comment.to_user.id}) %} + 回复 + {{ comment.to_user.name }} + {% endif %} +
    +
    {{ comment.content }}
    + +
    +
    +{% endif %} diff --git a/app/Http/Home/Views/comment/list.volt b/app/Http/Home/Views/comment/list.volt new file mode 100644 index 00000000..15f853bb --- /dev/null +++ b/app/Http/Home/Views/comment/list.volt @@ -0,0 +1,70 @@ +{% if pager.total_pages > 0 %} + {% for item in pager.items %} + {% set owner_url = url({'for':'home.user.show','id':item.owner.id}) %} + {% set like_url = url({'for':'home.comment.like','id':item.id}) %} + {% set delete_url = url({'for':'home.comment.delete','id':item.id}) %} + {% set reply_create_url = url({'for':'home.comment.create_reply','id':item.id}) %} + {% set reply_list_url = url({'for':'home.comment.replies','id':item.id},{'limit':5}) %} +
    +
    +
    + + {{ item.owner.name }} + +
    +
    + +
    {{ item.content }}
    + +
    +
    + + +
    + {% endfor %} + {{ partial('partials/pager_ajax') }} +{% endif %} \ No newline at end of file diff --git a/app/Http/Home/Views/comment/replies.volt b/app/Http/Home/Views/comment/replies.volt new file mode 100644 index 00000000..4b05ab1b --- /dev/null +++ b/app/Http/Home/Views/comment/replies.volt @@ -0,0 +1,69 @@ +{% if pager.total_pages > 0 %} + {% for item in pager.items %} + {% set owner_url = url({'for':'home.user.show','id':item.owner.id}) %} + {% set like_url = url({'for':'home.comment.like','id':item.id}) %} + {% set delete_url = url({'for':'home.comment.delete','id':item.id}) %} + {% set reply_create_url = url({'for':'home.comment.create_reply','id':item.id}) %} +
    +
    +
    + + {{ item.owner.name }} + +
    +
    +
    + {{ item.owner.name }} + {% if item.to_user.id is defined %} + {% set to_user_url = url({'for':'home.user.show','id':item.to_user.id}) %} + 回复 + {{ item.to_user.name }} + {% endif %} +
    +
    {{ item.content }}
    + +
    +
    + +
    + {% endfor %} + {{ partial('partials/pager_ajax') }} +{% endif %} \ No newline at end of file diff --git a/app/Http/Home/Views/comment/reply.volt b/app/Http/Home/Views/comment/reply.volt new file mode 100644 index 00000000..6143f829 --- /dev/null +++ b/app/Http/Home/Views/comment/reply.volt @@ -0,0 +1,19 @@ +{% extends 'templates/layer.volt' %} + +{% block content %} +
    +
    + +
    +
    + + +
    +
    +{% endblock %} + +{% block include_js %} + + {{ js_include('home/js/comment.js') }} + +{% endblock %} \ No newline at end of file diff --git a/app/Http/Home/Views/course/consults.volt b/app/Http/Home/Views/course/consults.volt index e1806cb4..9043c915 100644 --- a/app/Http/Home/Views/course/consults.volt +++ b/app/Http/Home/Views/course/consults.volt @@ -5,7 +5,7 @@ {% set owner_url = url({'for':'home.user.show','id':item.owner.id}) %} {% set consult_url = url({'for':'home.consult.show','id':item.id}) %} {% set like_url = url({'for':'home.consult.like','id':item.id}) %} -
    +
    {{ item.owner.name }} @@ -20,11 +20,19 @@
    {{ item.question }}
    {{ item.answer }}
    diff --git a/app/Http/Home/Views/course/reviews.volt b/app/Http/Home/Views/course/reviews.volt index 31b24ebb..52235a7f 100644 --- a/app/Http/Home/Views/course/reviews.volt +++ b/app/Http/Home/Views/course/reviews.volt @@ -5,7 +5,7 @@ {% for item in pager.items %} {% set owner_url = url({'for':'home.user.show','id':item.owner.id}) %} {% set like_url = url({'for':'home.review.like','id':item.id}) %} -
    +
    {{ item.content }}
    diff --git a/app/Http/Home/Views/course/show.volt b/app/Http/Home/Views/course/show.volt index e10584ed..0c65df54 100644 --- a/app/Http/Home/Views/course/show.volt +++ b/app/Http/Home/Views/course/show.volt @@ -4,13 +4,6 @@ {{ partial('macros/course') }} - {% set favorite_title = course.me.favorited ? '取消收藏' : '收藏课程' %} - {% set favorite_star = course.me.favorited ? 'layui-icon-star-fill' : 'layui-icon-star' %} - {% set full_course_url = full_url({'for':'home.course.show','id':course.id}) %} - {% set favorite_url = url({'for':'home.course.favorite','id':course.id}) %} - {% set consult_url = url({'for':'home.consult.add'},{'course_id':course.id}) %} - {% set qrcode_url = url({'for':'home.qrcode'},{'text':full_course_url}) %} -
    {{ item.user.name }} @@ -38,7 +37,7 @@ {{ gender_info(item.user.gender) }} {{ date('Y-m-d H:i:s',item.create_time) }} - {% if is_owner == 0 %} + {% if item.user.id == group.owner.id %} {% else %} diff --git a/app/Http/Home/Views/im/group/pager.volt b/app/Http/Home/Views/im/group/pager.volt index d6027450..aa1f6209 100644 --- a/app/Http/Home/Views/im/group/pager.volt +++ b/app/Http/Home/Views/im/group/pager.volt @@ -5,7 +5,6 @@
    {% for item in pager.items %} {% set group_url = url({'for':'home.im_group.show','id':item.id}) %} - {% set item.about = item.about ? item.about : '这家伙真懒,什么都没留下!' %}
    {{ type_info(item.type) }} diff --git a/app/Http/Home/Views/im/group/show.volt b/app/Http/Home/Views/im/group/show.volt index dd3dcde0..845db2c2 100644 --- a/app/Http/Home/Views/im/group/show.volt +++ b/app/Http/Home/Views/im/group/show.volt @@ -2,7 +2,6 @@ {% block content %} - {% set group.about = group.about ? group.about : '这个家伙真懒,什么都没有留下~' %} {% set users_url = url({'for':'home.im_group.users','id':group.id}) %} {% set active_users_url = url({'for':'home.im_group.active_users','id':group.id}) %} @@ -18,7 +17,7 @@
    小组介绍
    -
    {{ group.about }}
    +
    {{ group.about|default('这个家伙真懒,什么都没有留下') }}
    小组成员
    diff --git a/app/Http/Home/Views/im/group/show_owner.volt b/app/Http/Home/Views/im/group/show_owner.volt index 937cf80b..743bb5a5 100644 --- a/app/Http/Home/Views/im/group/show_owner.volt +++ b/app/Http/Home/Views/im/group/show_owner.volt @@ -1,5 +1,4 @@ {% set owner_url = url({'for':'home.user.show','id':group.owner.id}) %} -{% set group.owner.title = group.owner.title ? group.owner.title : '暂无头衔' %}
    小组组长
    @@ -12,7 +11,7 @@ -
    {{ group.owner.title }}
    +
    {{ group.owner.title|default('暂露头角') }}
    diff --git a/app/Http/Home/Views/im/group/users.volt b/app/Http/Home/Views/im/group/users.volt index 02c3c0ed..7bbb42c1 100644 --- a/app/Http/Home/Views/im/group/users.volt +++ b/app/Http/Home/Views/im/group/users.volt @@ -2,7 +2,6 @@
    {% for item in pager.items %} {% set user_url = url({'for':'home.user.show','id':item.id}) %} - {% set item.user.title = item.user.title ? item.user.title : '暂露头角' %} {% set avatar_class = item.user.vip == 1 ? 'avatar vip' : 'avatar' %}
    @@ -14,7 +13,7 @@ -
    {{ item.user.title }}
    +
    {{ item.user.title|default('暂露头角') }}
    添加好友
    diff --git a/app/Http/Home/Views/im/index_groups.volt b/app/Http/Home/Views/im/index_groups.volt index 1ffe1b6e..e3eb3bc8 100644 --- a/app/Http/Home/Views/im/index_groups.volt +++ b/app/Http/Home/Views/im/index_groups.volt @@ -2,7 +2,6 @@
    {% for group in groups %} {% set group_url = url({'for':'home.im_group.show','id':group.id}) %} - {% set group.about = group.about ? group.about : '这家伙真懒,什么都没留下!' %}
    {{ type_info(group.type) }} diff --git a/app/Http/Home/Views/im/index_users.volt b/app/Http/Home/Views/im/index_users.volt index 9d97281c..0734435a 100644 --- a/app/Http/Home/Views/im/index_users.volt +++ b/app/Http/Home/Views/im/index_users.volt @@ -1,8 +1,6 @@
    {% for user in users %} - {% set user.title = user.title ? user.title : '暂露头角' %} - {% set user.about = user.about ? user.about : '这个人很懒,什么都没留下' %} {% set user_url = url({'for':'home.user.show','id':user.id}) %} {% set avatar_class = user.vip == 1 ? 'avatar vip' : 'avatar' %}
    @@ -15,7 +13,7 @@ -
    {{ user.title }}
    +
    {{ user.title|default('暂露头角') }}
    添加好友
    diff --git a/app/Http/Home/Views/search/article.volt b/app/Http/Home/Views/search/article.volt index 5776259a..a363d625 100644 --- a/app/Http/Home/Views/search/article.volt +++ b/app/Http/Home/Views/search/article.volt @@ -11,7 +11,7 @@
    {{ item.summary }}
    diff --git a/app/Http/Home/Views/teacher/pager.volt b/app/Http/Home/Views/teacher/pager.volt index 1ca92bf5..d2275f38 100644 --- a/app/Http/Home/Views/teacher/pager.volt +++ b/app/Http/Home/Views/teacher/pager.volt @@ -2,8 +2,6 @@
    {% for item in pager.items %} - {% set item.title = item.title ? item.title : '小小教书匠' %} - {% set item.about = item.about ? item.about : '这个人很懒,什么都没留下' %} {% set user_url = url({'for':'home.teacher.show','id':item.id}) %}
    @@ -15,7 +13,7 @@ -
    {{ item.title }}
    +
    {{ item.title|default('小小教书匠') }}
    添加好友
    diff --git a/app/Http/Home/Views/user/friends.volt b/app/Http/Home/Views/user/friends.volt index d5e646cf..19ba658d 100644 --- a/app/Http/Home/Views/user/friends.volt +++ b/app/Http/Home/Views/user/friends.volt @@ -4,8 +4,6 @@
    {% for item in pager.items %} - {% set item.title = item.title ? item.title : '暂露头角' %} - {% set item.about = item.about ? item.about : '这个人很懒,什么都没留下' %} {% set user_url = url({'for':'home.user.show','id':item.id}) %} {% set avatar_class = item.vip == 1 ? 'avatar vip' : 'avatar' %}
    @@ -18,7 +16,7 @@ -
    {{ item.title }}
    +
    {{ item.title|default('暂露头角') }}
    添加好友
    diff --git a/app/Http/Home/Views/user/groups.volt b/app/Http/Home/Views/user/groups.volt index 86a390d1..afd4caa5 100644 --- a/app/Http/Home/Views/user/groups.volt +++ b/app/Http/Home/Views/user/groups.volt @@ -5,7 +5,6 @@
    {% for item in pager.items %} {% set group_url = url({'for':'home.im_group.show','id':item.id}) %} - {% set item.about = item.about ? item.about : '这家伙真懒,什么都没留下!' %}
    {{ type_info(item.type) }} diff --git a/app/Http/Home/Views/user/show.volt b/app/Http/Home/Views/user/show.volt index fa71f8f5..82a50354 100644 --- a/app/Http/Home/Views/user/show.volt +++ b/app/Http/Home/Views/user/show.volt @@ -2,13 +2,8 @@ {% block content %} - {{ partial('macros/course') }} {{ partial('macros/user') }} - {% set full_user_url = full_url({'for':'home.user.show','id':user.id}) %} - {% set qrcode_url = url({'for':'home.qrcode'},{'text':full_user_url}) %} - {% set user.area = user.area ? user.area : '火星' %} - {% set user.about = user.about ? user.about : '这个家伙很懒,什么都没留下!' %} {% set avatar_class = user.vip == 1 ? 'avatar vip' : 'avatar' %}
    -

    {{ user.name }}{{ gender_icon(user.gender) }}

    -

    {{ user.area }}

    -

    {{ date('Y-m-d H:i',user.active_time) }}

    +

    + {{ user.name }} + {{ gender_icon(user.gender) }} +

    +

    + + {{ user.area|default('火星') }} +

    +

    + + {{ user.active_time|time_ago }} +

    -
    {{ user.about }}
    +
    {{ user.about|default('这个家伙很懒,什么都没留下') }}
    {% set show_tab_courses = user.course_count > 0 %} @@ -76,10 +80,13 @@
    + {% set share_url = full_url({'for':'home.share'},{'id':user.id,'type':'user','referer':auth_user.id}) %} + {% set qrcode_url = url({'for':'home.qrcode'},{'text':share_url}) %} +
    - +
    diff --git a/app/Http/Home/Views/vip/users.volt b/app/Http/Home/Views/vip/users.volt index f00d84ab..3096ad03 100644 --- a/app/Http/Home/Views/vip/users.volt +++ b/app/Http/Home/Views/vip/users.volt @@ -3,8 +3,6 @@
    {% for item in pager.items %} {% set user_url = url({'for':'home.user.show','id':item.id}) %} - {% set item.title = item.title ? item.title : '暂露头角' %} - {% set item.about = item.about ? item.about : '这个人很懒,什么都没留下' %}
    @@ -15,7 +13,7 @@ -
    {{ item.title }}
    +
    {{ item.title|default('暂露头角') }}
    {% endfor %} diff --git a/app/Library/AppInfo.php b/app/Library/AppInfo.php index 3e782a98..3639ff96 100644 --- a/app/Library/AppInfo.php +++ b/app/Library/AppInfo.php @@ -11,7 +11,7 @@ class AppInfo protected $link = 'https://koogua.com'; - protected $version = '1.3.1'; + protected $version = '1.3.2'; public function __get($name) { diff --git a/app/Models/Comment.php b/app/Models/Comment.php index 970f02bc..2b9c1393 100644 --- a/app/Models/Comment.php +++ b/app/Models/Comment.php @@ -144,6 +144,10 @@ class Comment extends Model public function beforeUpdate() { + if ($this->deleted == 1) { + $this->published = 0; + } + $this->update_time = time(); } diff --git a/app/Models/Course.php b/app/Models/Course.php index 4d04ed3e..d8c50fed 100644 --- a/app/Models/Course.php +++ b/app/Models/Course.php @@ -164,7 +164,7 @@ class Course extends Model * * @var float */ - public $rating = 0.00; + public $rating = 5.00; /** * 综合得分 diff --git a/app/Repos/Comment.php b/app/Repos/Comment.php index c0e855bd..89cecccd 100644 --- a/app/Repos/Comment.php +++ b/app/Repos/Comment.php @@ -23,10 +23,6 @@ class Comment extends Repository $builder->andWhere('id = :id:', ['id' => $where['id']]); } - if (!empty($where['parent_id'])) { - $builder->andWhere('parent_id = :parent_id:', ['parent_id' => $where['parent_id']]); - } - if (!empty($where['owner_id'])) { $builder->andWhere('owner_id = :owner_id:', ['owner_id' => $where['owner_id']]); } @@ -39,6 +35,10 @@ class Comment extends Repository $builder->andWhere('item_type = :item_type:', ['item_type' => $where['item_type']]); } + if (isset($where['parent_id'])) { + $builder->andWhere('parent_id = :parent_id:', ['parent_id' => $where['parent_id']]); + } + if (isset($where['published'])) { $builder->andWhere('published = :published:', ['published' => $where['published']]); } diff --git a/app/Repos/CommentLike.php b/app/Repos/CommentLike.php index 8e9bd8be..4d348e86 100644 --- a/app/Repos/CommentLike.php +++ b/app/Repos/CommentLike.php @@ -4,6 +4,8 @@ namespace App\Repos; use App\Models\CommentLike as CommentLikeModel; use Phalcon\Mvc\Model; +use Phalcon\Mvc\Model\Resultset; +use Phalcon\Mvc\Model\ResultsetInterface; class CommentLike extends Repository { @@ -21,4 +23,15 @@ class CommentLike extends Repository ]); } + /** + * @param int $userId + * @return ResultsetInterface|Resultset|CommentLikeModel[] + */ + public function findByUserId($userId) + { + return CommentLikeModel::query() + ->where('user_id = :user_id:', ['user_id' => $userId]) + ->execute(); + } + } diff --git a/app/Repos/ConsultLike.php b/app/Repos/ConsultLike.php index 859bdcd2..5c79fa91 100644 --- a/app/Repos/ConsultLike.php +++ b/app/Repos/ConsultLike.php @@ -4,6 +4,8 @@ namespace App\Repos; use App\Models\ConsultLike as ConsultLikeModel; use Phalcon\Mvc\Model; +use Phalcon\Mvc\Model\Resultset; +use Phalcon\Mvc\Model\ResultsetInterface; class ConsultLike extends Repository { @@ -21,4 +23,15 @@ class ConsultLike extends Repository ]); } + /** + * @param int $userId + * @return ResultsetInterface|Resultset|ConsultLikeModel[] + */ + public function findByUserId($userId) + { + return ConsultLikeModel::query() + ->where('user_id = :user_id:', ['user_id' => $userId]) + ->execute(); + } + } diff --git a/app/Repos/ReviewLike.php b/app/Repos/ReviewLike.php index eb3ab98c..5c9fa3a6 100644 --- a/app/Repos/ReviewLike.php +++ b/app/Repos/ReviewLike.php @@ -4,6 +4,8 @@ namespace App\Repos; use App\Models\ReviewLike as ReviewLikeModel; use Phalcon\Mvc\Model; +use Phalcon\Mvc\Model\Resultset; +use Phalcon\Mvc\Model\ResultsetInterface; class ReviewLike extends Repository { @@ -21,4 +23,15 @@ class ReviewLike extends Repository ]); } + /** + * @param int $userId + * @return ResultsetInterface|Resultset|ReviewLikeModel[] + */ + public function findByUserId($userId) + { + return ReviewLikeModel::query() + ->where('user_id = :user_id:', ['user_id' => $userId]) + ->execute(); + } + } diff --git a/app/Services/Logic/Article/ArticleInfo.php b/app/Services/Logic/Article/ArticleInfo.php index de45c484..edc52bde 100644 --- a/app/Services/Logic/Article/ArticleInfo.php +++ b/app/Services/Logic/Article/ArticleInfo.php @@ -48,6 +48,7 @@ class ArticleInfo extends LogicService 'category' => $category, 'owner' => $owner, 'me' => $me, + 'allow_comment' => $article->allow_comment, 'source_type' => $article->source_type, 'source_url' => $article->source_url, 'word_count' => $article->word_count, @@ -56,7 +57,6 @@ class ArticleInfo extends LogicService 'comment_count' => $article->comment_count, 'favorite_count' => $article->favorite_count, 'create_time' => $article->create_time, - 'update_time' => $article->update_time, ]; } @@ -67,8 +67,6 @@ class ArticleInfo extends LogicService 'favorited' => 0, ]; - $me['allow_comment'] = $article->allow_comment ? 1 : 0; - if ($user->id > 0) { $likeRepo = new ArticleLikeRepo(); diff --git a/app/Services/Logic/Article/CommentList.php b/app/Services/Logic/Article/CommentList.php index 8f43e5c9..2f311af2 100644 --- a/app/Services/Logic/Article/CommentList.php +++ b/app/Services/Logic/Article/CommentList.php @@ -6,12 +6,14 @@ use App\Library\Paginator\Query as PagerQuery; use App\Models\Comment as CommentModel; use App\Repos\Comment as CommentRepo; use App\Services\Logic\ArticleTrait; -use App\Services\Logic\Comment\CommentList as CommentListService; +use App\Services\Logic\Comment\CommentListTrait; +use App\Services\Logic\Service as LogicService; -class CommentList extends CommentListService +class CommentList extends LogicService { use ArticleTrait; + use CommentListTrait; public function handle($id) { @@ -33,7 +35,7 @@ class CommentList extends CommentListService $pager = $commentRepo->paginate($params, $sort, $page, $limit); - return $this->handlePager($pager); + return $this->handleComments($pager); } } diff --git a/app/Services/Logic/Chapter/BasicInfo.php b/app/Services/Logic/Chapter/BasicInfo.php index 8a7f4baa..688114d8 100644 --- a/app/Services/Logic/Chapter/BasicInfo.php +++ b/app/Services/Logic/Chapter/BasicInfo.php @@ -72,6 +72,7 @@ class BasicInfo extends LogicService 'model' => $chapter->model, '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, @@ -100,6 +101,7 @@ class BasicInfo extends LogicService 'end_time' => $live->end_time, 'status' => $live->status, '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, @@ -121,6 +123,7 @@ class BasicInfo extends LogicService 'model' => $chapter->model, 'content' => $read->content, '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, diff --git a/app/Services/Logic/Chapter/ChapterInfo.php b/app/Services/Logic/Chapter/ChapterInfo.php index dbf0d66e..938d3d16 100644 --- a/app/Services/Logic/Chapter/ChapterInfo.php +++ b/app/Services/Logic/Chapter/ChapterInfo.php @@ -194,6 +194,13 @@ class ChapterInfo extends LogicService $chapter->user_count += 1; $chapter->update(); + + $parent = $this->checkChapter($chapter->parent_id); + + $parent->user_count += 1; + + $parent->update(); + } protected function incrGroupUserCount(ImGroupModel $group) diff --git a/app/Services/Logic/Chapter/ChapterLike.php b/app/Services/Logic/Chapter/ChapterLike.php index ff6faf72..57424145 100644 --- a/app/Services/Logic/Chapter/ChapterLike.php +++ b/app/Services/Logic/Chapter/ChapterLike.php @@ -64,6 +64,12 @@ class ChapterLike extends LogicService $chapter->like_count += 1; $chapter->update(); + + $parent = $this->checkChapter($chapter->parent_id); + + $parent->like_count += 1; + + $parent->update(); } protected function decrChapterLikeCount(ChapterModel $chapter) @@ -72,6 +78,13 @@ class ChapterLike extends LogicService $chapter->like_count -= 1; $chapter->update(); } + + $parent = $this->checkChapter($chapter->parent_id); + + if ($parent->like_count > 0) { + $parent->like_count -= 1; + $parent->update(); + } } protected function incrUserDailyChapterLikeCount(UserModel $user) diff --git a/app/Services/Logic/Chapter/CommentList.php b/app/Services/Logic/Chapter/CommentList.php new file mode 100644 index 00000000..beca7675 --- /dev/null +++ b/app/Services/Logic/Chapter/CommentList.php @@ -0,0 +1,41 @@ +checkChapter($id); + + $pagerQuery = new PagerQuery(); + + $params = $pagerQuery->getParams(); + + $params['item_type'] = CommentModel::ITEM_CHAPTER; + $params['item_id'] = $chapter->id; + $params['published'] = 1; + + $sort = $pagerQuery->getSort(); + $page = $pagerQuery->getPage(); + $limit = $pagerQuery->getLimit(); + + $commentRepo = new CommentRepo(); + + $pager = $commentRepo->paginate($params, $sort, $page, $limit); + + return $this->handleComments($pager); + } + +} diff --git a/app/Services/Logic/Chapter/ConsultList.php b/app/Services/Logic/Chapter/ConsultList.php index 7f81aba0..2f3a33ee 100644 --- a/app/Services/Logic/Chapter/ConsultList.php +++ b/app/Services/Logic/Chapter/ConsultList.php @@ -3,14 +3,16 @@ namespace App\Services\Logic\Chapter; use App\Library\Paginator\Query as PagerQuery; +use App\Repos\Consult as ConsultRepo; use App\Services\Logic\ChapterTrait; -use App\Services\Logic\Consult\ConsultList as ConsultListHandler; +use App\Services\Logic\Course\ConsultListTrait; use App\Services\Logic\Service as LogicService; class ConsultList extends LogicService { use ChapterTrait; + use ConsultListTrait; public function handle($id) { @@ -28,9 +30,11 @@ class ConsultList extends LogicService 'published' => 1, ]; - $service = new ConsultListHandler(); + $consultRepo = new ConsultRepo(); - return $service->paginate($params, $sort, $page, $limit); + $pager = $consultRepo->paginate($params, $sort, $page, $limit); + + return $this->handleConsults($pager); } } diff --git a/app/Services/Logic/Comment/CommentCountTrait.php b/app/Services/Logic/Comment/CommentCountTrait.php new file mode 100644 index 00000000..1bdfc499 --- /dev/null +++ b/app/Services/Logic/Comment/CommentCountTrait.php @@ -0,0 +1,83 @@ +reply_count += 1; + + $comment->update(); + } + + protected function incrChapterCommentCount(ChapterModel $chapter) + { + $chapter->comment_count += 1; + + $chapter->update(); + + $parent = $this->checkChapter($chapter->parent_id); + + $parent->comment_count += 1; + + $parent->update(); + } + + protected function incrArticleCommentCount(ArticleModel $article) + { + $article->comment_count += 1; + + $article->update(); + } + + protected function decrCommentReplyCount(CommentModel $comment) + { + if ($comment->reply_count > 0) { + $comment->reply_count -= 1; + $comment->update(); + } + } + + protected function decrChapterCommentCount(ChapterModel $chapter) + { + if ($chapter->comment_count > 0) { + $chapter->comment_count -= 1; + $chapter->update(); + } + + $parent = $this->checkChapter($chapter->parent_id); + + if ($parent->comment_count > 0) { + $parent->comment_count -= 1; + $parent->update(); + } + } + + protected function decrArticleCommentCount(ArticleModel $article) + { + if ($article->comment_count > 0) { + $article->comment_count -= 1; + $article->update(); + } + } + + protected function incrUserDailyCommentCount(UserModel $user) + { + /** + * @var EventsManager $eventsManager + */ + $eventsManager = Di::getDefault()->get('eventsManager'); + + $eventsManager->fire('UserDailyCounter:incrCommentCount', $this, $user); + } + +} diff --git a/app/Services/Logic/Comment/CommentCreate.php b/app/Services/Logic/Comment/CommentCreate.php index 9fc5f5dc..4c7c54e4 100644 --- a/app/Services/Logic/Comment/CommentCreate.php +++ b/app/Services/Logic/Comment/CommentCreate.php @@ -2,11 +2,11 @@ namespace App\Services\Logic\Comment; -use App\Models\Article as ArticleModel; use App\Models\Comment as CommentModel; -use App\Models\User as UserModel; use App\Services\Logic\ArticleTrait; +use App\Services\Logic\ChapterTrait; use App\Services\Logic\Service as LogicService; +use App\Traits\Client as ClientTrait; use App\Validators\Comment as CommentValidator; use App\Validators\UserLimit as UserLimitValidator; @@ -14,6 +14,9 @@ class CommentCreate extends LogicService { use ArticleTrait; + use ChapterTrait; + use ClientTrait; + use CommentCountTrait; public function handle() { @@ -32,19 +35,26 @@ class CommentCreate extends LogicService $comment = new CommentModel(); $data = [ + 'item_id' => $post['item_id'], + 'item_type' => $post['item_type'], 'owner_id' => $user->id, 'published' => 1, ]; $data['content'] = $validator->checkContent($post['content']); + $data['client_type'] = $this->getClientType(); + $data['client_ip'] = $this->getClientIp(); - if (isset($post['to_user_id'])) { - $toUser = $validator->checkToUser($post['to_user_id']); - $data['to_user_id'] = $toUser->id; - } + if ($post['item_type'] == CommentModel::ITEM_CHAPTER) { + + $chapter = $this->checkChapter($post['item_id']); + + $this->incrChapterCommentCount($chapter); + + } elseif ($post['item_type'] == CommentModel::ITEM_ARTICLE) { - if ($post['item_type'] == CommentModel::ITEM_ARTICLE) { $article = $this->checkArticle($post['item_id']); + $this->incrArticleCommentCount($article); } @@ -55,16 +65,4 @@ class CommentCreate extends LogicService return $comment; } - protected function incrArticleCommentCount(ArticleModel $article) - { - $article->comment_count += 1; - - $article->update(); - } - - protected function incrUserDailyCommentCount(UserModel $user) - { - $this->eventsManager->fire('UserDailyCounter:incrCommentCount', $this, $user); - } - } diff --git a/app/Services/Logic/Comment/CommentDelete.php b/app/Services/Logic/Comment/CommentDelete.php index 0c4f60e7..dcd8847e 100644 --- a/app/Services/Logic/Comment/CommentDelete.php +++ b/app/Services/Logic/Comment/CommentDelete.php @@ -2,9 +2,9 @@ namespace App\Services\Logic\Comment; -use App\Models\Article as ArticleModel; use App\Models\Comment as CommentModel; use App\Services\Logic\ArticleTrait; +use App\Services\Logic\ChapterTrait; use App\Services\Logic\CommentTrait; use App\Services\Logic\Service as LogicService; use App\Validators\Comment as CommentValidator; @@ -13,7 +13,9 @@ class CommentDelete extends LogicService { use ArticleTrait; + use ChapterTrait; use CommentTrait; + use CommentCountTrait; public function handle($id) { @@ -29,18 +31,25 @@ class CommentDelete extends LogicService $comment->update(); - if ($comment->item_type == CommentModel::ITEM_ARTICLE) { + if ($comment->parent_id > 0) { + + $parent = $this->checkComment($comment->parent_id); + + $this->decrCommentReplyCount($parent); + } + + if ($comment->item_type == CommentModel::ITEM_CHAPTER) { + + $chapter = $this->checkChapter($comment->item_id); + + $this->decrChapterCommentCount($chapter); + + } elseif ($comment->item_type == CommentModel::ITEM_ARTICLE) { + $article = $this->checkArticle($comment->item_id); + $this->decrArticleCommentCount($article); } } - protected function decrArticleCommentCount(ArticleModel $article) - { - if ($article->comment_count > 0) { - $article->comment_count -= 1; - $article->update(); - } - } - } diff --git a/app/Services/Logic/Comment/CommentInfo.php b/app/Services/Logic/Comment/CommentInfo.php index f8580d55..e60a9fb4 100644 --- a/app/Services/Logic/Comment/CommentInfo.php +++ b/app/Services/Logic/Comment/CommentInfo.php @@ -21,13 +21,18 @@ class CommentInfo extends LogicService protected function handleComment(CommentModel $comment) { - $owner = $this->handleOwnerInfo($comment); + $owner = $comment->owner_id > 0 ? $this->handleOwnerInfo($comment) : new \stdClass(); + $toUser = $comment->to_user_id > 0 ? $this->handleToUserInfo($comment) : new \stdClass(); return [ 'id' => $comment->id, - 'owner' => $owner, 'content' => $comment->content, + 'parent_id' => $comment->parent_id, + 'like_count' => $comment->like_count, + 'reply_count' => $comment->reply_count, 'create_time' => $comment->create_time, + 'owner' => $owner, + 'to_user' => $toUser, ]; } @@ -35,12 +40,25 @@ class CommentInfo extends LogicService { $userRepo = new UserRepo(); - $owner = $userRepo->findById($comment->owner_id); + $user = $userRepo->findById($comment->owner_id); return [ - 'id' => $owner->id, - 'name' => $owner->name, - 'avatar' => $owner->avatar, + 'id' => $user->id, + 'name' => $user->name, + 'avatar' => $user->avatar, + ]; + } + + protected function handleToUserInfo(CommentModel $comment) + { + $userRepo = new UserRepo(); + + $user = $userRepo->findById($comment->to_user_id); + + return [ + 'id' => $user->id, + 'name' => $user->name, + 'avatar' => $user->avatar, ]; } diff --git a/app/Services/Logic/Comment/CommentList.php b/app/Services/Logic/Comment/CommentList.php index 3de347be..b6e9f931 100644 --- a/app/Services/Logic/Comment/CommentList.php +++ b/app/Services/Logic/Comment/CommentList.php @@ -2,45 +2,33 @@ namespace App\Services\Logic\Comment; -use App\Builders\CommentList as CommentListBuilder; +use App\Library\Paginator\Query as PagerQuery; +use App\Repos\Comment as CommentRepo; use App\Services\Logic\Service as LogicService; class CommentList extends LogicService { - protected function handlePager($pager) + use CommentListTrait; + + public function handle() { - if ($pager->total_items == 0) { - return $pager; - } + $pagerQuery = new PagerQuery(); - $comments = $pager->items->toArray(); + $params = $pagerQuery->getParams(); - $builder = new CommentListBuilder(); + $params['parent_id'] = 0; + $params['published'] = 1; - $users = $builder->getUsers($comments); + $sort = $pagerQuery->getSort(); + $page = $pagerQuery->getPage(); + $limit = $pagerQuery->getLimit(); - $items = []; + $commentRepo = new CommentRepo(); - foreach ($comments as $comment) { + $pager = $commentRepo->paginate($params, $sort, $page, $limit); - $owner = $users[$comment['owner_id']] ?? new \stdClass(); - $toUser = $users[$comment['to_user_id']] ?? new \stdClass(); - - $items[] = [ - 'id' => $comment['id'], - 'content' => $comment['content'], - 'owner' => $owner, - 'to_user' => $toUser, - 'like_count' => $comment['like_count'], - 'reply_count' => $comment['reply_count'], - 'create_time' => $comment['create_time'], - ]; - } - - $pager->items = $items; - - return $pager; + return $this->handleComments($pager); } } diff --git a/app/Services/Logic/Comment/CommentListTrait.php b/app/Services/Logic/Comment/CommentListTrait.php new file mode 100644 index 00000000..bef84037 --- /dev/null +++ b/app/Services/Logic/Comment/CommentListTrait.php @@ -0,0 +1,75 @@ +total_items == 0) { + return $pager; + } + + $comments = $pager->items->toArray(); + + $builder = new CommentListBuilder(); + + $users = $builder->getUsers($comments); + + $meMappings = $this->getMeMappings($comments); + + $items = []; + + foreach ($comments as $comment) { + + $owner = $users[$comment['owner_id']] ?? new \stdClass(); + $toUser = $users[$comment['to_user_id']] ?? new \stdClass(); + $me = $meMappings[$comment['id']]; + + $items[] = [ + 'id' => $comment['id'], + 'content' => $comment['content'], + 'parent_id' => $comment['parent_id'], + 'like_count' => $comment['like_count'], + 'reply_count' => $comment['reply_count'], + 'create_time' => $comment['create_time'], + 'to_user' => $toUser, + 'owner' => $owner, + 'me' => $me, + ]; + } + + $pager->items = $items; + + return $pager; + } + + protected function getMeMappings($comments) + { + $user = $this->getCurrentUser(true); + + $likeRepo = new CommentLikeRepo(); + + $likedIds = []; + + if ($user->id > 0) { + $likes = $likeRepo->findByUserId($user->id); + $likedIds = array_column($likes->toArray(), 'comment_id'); + } + + $result = []; + + foreach ($comments as $comment) { + $result[$comment['id']] = [ + 'liked' => in_array($comment['id'], $likedIds) ? 1 : 0, + ]; + } + + return $result; + } + +} diff --git a/app/Services/Logic/Comment/CommentReply.php b/app/Services/Logic/Comment/CommentReply.php new file mode 100644 index 00000000..fc31d0fe --- /dev/null +++ b/app/Services/Logic/Comment/CommentReply.php @@ -0,0 +1,81 @@ +request->getPost(); + + $user = $this->getLoginUser(); + + $comment = $this->checkComment($id); + + $validator = new UserLimitValidator(); + + $validator->checkDailyCommentLimit($user); + + $parent = $comment; + + $validator = new CommentValidator(); + + $data = [ + 'parent_id' => $parent->id, + 'item_id' => $comment->item_id, + 'item_type' => $comment->item_type, + 'owner_id' => $user->id, + 'published' => 1, + ]; + + if ($comment->parent_id > 0) { + $parent = $validator->checkParent($comment->parent_id); + $data['parent_id'] = $parent->id; + $data['to_user_id'] = $comment->owner_id; + } + + $data['content'] = $validator->checkContent($post['content']); + $data['client_type'] = $this->getClientType(); + $data['client_ip'] = $this->getClientIp(); + + $comment = new CommentModel(); + + $comment->create($data); + + $this->incrCommentReplyCount($parent); + + if ($comment->item_type == CommentModel::ITEM_CHAPTER) { + + $chapter = $this->checkChapter($comment->item_id); + + $this->incrChapterCommentCount($chapter); + + } elseif ($comment->item_type == CommentModel::ITEM_ARTICLE) { + + $article = $this->checkArticle($comment->item_id); + + $this->incrArticleCommentCount($article); + } + + $this->incrUserDailyCommentCount($user); + + return $comment; + } + +} diff --git a/app/Services/Logic/Comment/ReplyList.php b/app/Services/Logic/Comment/ReplyList.php new file mode 100644 index 00000000..8834bd95 --- /dev/null +++ b/app/Services/Logic/Comment/ReplyList.php @@ -0,0 +1,36 @@ +getParams(); + + $params['parent_id'] = $id; + $params['published'] = 1; + + $sort = $pagerQuery->getSort(); + $page = $pagerQuery->getPage(); + $limit = $pagerQuery->getLimit(); + + $commentRepo = new CommentRepo(); + + $pager = $commentRepo->paginate($params, $sort, $page, $limit); + + return $this->handlePager($pager); + } + +} diff --git a/app/Services/Logic/Course/ConsultList.php b/app/Services/Logic/Course/ConsultList.php index bf1dcdc1..280f52f1 100644 --- a/app/Services/Logic/Course/ConsultList.php +++ b/app/Services/Logic/Course/ConsultList.php @@ -2,7 +2,6 @@ namespace App\Services\Logic\Course; -use App\Builders\ConsultList as ConsultListBuilder; use App\Library\Paginator\Query as PagerQuery; use App\Repos\Consult as ConsultRepo; use App\Services\Logic\CourseTrait; @@ -12,6 +11,7 @@ class ConsultList extends LogicService { use CourseTrait; + use ConsultListTrait; public function handle($id) { @@ -36,39 +36,4 @@ class ConsultList extends LogicService return $this->handleConsults($pager); } - protected function handleConsults($pager) - { - if ($pager->total_items == 0) { - return $pager; - } - - $consults = $pager->items->toArray(); - - $builder = new ConsultListBuilder(); - - $users = $builder->getUsers($consults); - - $items = []; - - foreach ($consults as $consult) { - - $owner = $users[$consult['owner_id']] ?? new \stdClass(); - - $items[] = [ - 'id' => $consult['id'], - 'question' => $consult['question'], - 'answer' => $consult['answer'], - 'like_count' => $consult['like_count'], - 'reply_time' => $consult['reply_time'], - 'create_time' => $consult['create_time'], - 'update_time' => $consult['update_time'], - 'owner' => $owner, - ]; - } - - $pager->items = $items; - - return $pager; - } - } diff --git a/app/Services/Logic/Consult/ConsultList.php b/app/Services/Logic/Course/ConsultListTrait.php similarity index 54% rename from app/Services/Logic/Consult/ConsultList.php rename to app/Services/Logic/Course/ConsultListTrait.php index 7ea8d178..2ea63229 100644 --- a/app/Services/Logic/Consult/ConsultList.php +++ b/app/Services/Logic/Course/ConsultListTrait.php @@ -1,23 +1,13 @@ paginate($params, $sort, $page, $limit); - - return $this->handleConsults($pager); - } - protected function handleConsults($pager) { if ($pager->total_items == 0) { @@ -30,11 +20,14 @@ class ConsultList extends LogicService $users = $builder->getUsers($consults); + $meMappings = $this->getMeMappings($consults); + $items = []; foreach ($consults as $consult) { $owner = $users[$consult['owner_id']] ?? new \stdClass(); + $me = $meMappings[$consult['id']]; $items[] = [ 'id' => $consult['id'], @@ -43,8 +36,8 @@ class ConsultList extends LogicService 'like_count' => $consult['like_count'], 'reply_time' => $consult['reply_time'], 'create_time' => $consult['create_time'], - 'update_time' => $consult['update_time'], 'owner' => $owner, + 'me' => $me, ]; } @@ -53,4 +46,28 @@ class ConsultList extends LogicService return $pager; } + protected function getMeMappings($consults) + { + $user = $this->getCurrentUser(true); + + $likeRepo = new ConsultLikeRepo(); + + $likedIds = []; + + if ($user->id > 0) { + $likes = $likeRepo->findByUserId($user->id); + $likedIds = array_column($likes->toArray(), 'consult_id'); + } + + $result = []; + + foreach ($consults as $consult) { + $result[$consult['id']] = [ + 'liked' => in_array($consult['id'], $likedIds) ? 1 : 0, + ]; + } + + return $result; + } + } diff --git a/app/Services/Logic/Course/ReviewList.php b/app/Services/Logic/Course/ReviewList.php index 7f6a0266..5c198a19 100644 --- a/app/Services/Logic/Course/ReviewList.php +++ b/app/Services/Logic/Course/ReviewList.php @@ -5,6 +5,7 @@ namespace App\Services\Logic\Course; use App\Builders\ReviewList as ReviewListBuilder; use App\Library\Paginator\Query as PagerQuery; use App\Repos\Review as ReviewRepo; +use App\Repos\ReviewLike as ReviewLikeRepo; use App\Services\Logic\CourseTrait; use App\Services\Logic\Service as LogicService; @@ -47,11 +48,14 @@ class ReviewList extends LogicService $users = $builder->getUsers($reviews); + $meMappings = $this->getMeMappings($reviews); + $items = []; foreach ($reviews as $review) { $owner = $users[$review['owner_id']] ?? new \stdClass(); + $me = $meMappings[$review['id']]; $items[] = [ 'id' => $review['id'], @@ -60,6 +64,7 @@ class ReviewList extends LogicService 'like_count' => $review['like_count'], 'create_time' => $review['create_time'], 'owner' => $owner, + 'me' => $me, ]; } @@ -68,4 +73,28 @@ class ReviewList extends LogicService return $pager; } + protected function getMeMappings($consults) + { + $user = $this->getCurrentUser(true); + + $likeRepo = new ReviewLikeRepo(); + + $likedIds = []; + + if ($user->id > 0) { + $likes = $likeRepo->findByUserId($user->id); + $likedIds = array_column($likes->toArray(), 'review_id'); + } + + $result = []; + + foreach ($consults as $consult) { + $result[$consult['id']] = [ + 'liked' => in_array($consult['id'], $likedIds) ? 1 : 0, + ]; + } + + return $result; + } + } diff --git a/app/Services/Logic/Teacher/Console/ConsultList.php b/app/Services/Logic/Teacher/Console/ConsultList.php index b0ced828..040836a8 100644 --- a/app/Services/Logic/Teacher/Console/ConsultList.php +++ b/app/Services/Logic/Teacher/Console/ConsultList.php @@ -76,7 +76,6 @@ class ConsultList extends LogicService 'like_count' => $consult['like_count'], 'reply_time' => $consult['reply_time'], 'create_time' => $consult['create_time'], - 'update_time' => $consult['update_time'], 'course' => $course, 'chapter' => $chapter, 'owner' => $owner, diff --git a/app/Services/Logic/User/Console/ConsultList.php b/app/Services/Logic/User/Console/ConsultList.php index 2016425e..6a758df9 100644 --- a/app/Services/Logic/User/Console/ConsultList.php +++ b/app/Services/Logic/User/Console/ConsultList.php @@ -60,7 +60,6 @@ class ConsultList extends LogicService 'like_count' => $consult['like_count'], 'reply_time' => $consult['reply_time'], 'create_time' => $consult['create_time'], - 'update_time' => $consult['update_time'], 'course' => $course, 'chapter' => $chapter, ]; diff --git a/public/static/home/css/common.css b/public/static/home/css/common.css index db1acaa4..53a8439d 100644 --- a/public/static/home/css/common.css +++ b/public/static/home/css/common.css @@ -71,13 +71,11 @@ .qrcode img { width: 160px; height: 160px; - border: 3px dashed #ccc; } .qrcode-sm img { width: 100px; height: 100px; - border: 3px dashed #ccc; } .breadcrumb { @@ -532,18 +530,138 @@ color: #666; } -.action-sticky { +#comment-form { + margin-bottom: 30px; +} + +.comment-form { + margin-top: 20px; + margin-bottom: 20px; +} + +.comment-form .footer { + display: flex; + justify-content: space-between; + align-items: center; + margin-top: 15px; +} + +.comment-form .layui-textarea { + min-height: 40px; +} + +.comment-card { + position: relative; + padding-bottom: 10px; + margin-bottom: 10px; + border-bottom: 1px solid #f6f6f6; +} + +.comment-card:last-child { + border-bottom: none; +} + +.comment-card .avatar { + float: left; + width: 48px; + height: 48px; + margin-right: 15px; +} + +.comment-card .avatar img { + width: 100%; + height: 100%; + border-radius: 60px; +} + +.comment-card .info { + float: left; + width: 690px; +} + +.comment-card .title { + margin-bottom: 10px; + color: #333; +} + +.comment-card .user { + margin-bottom: 10px; + color: #666; +} + +.comment-card .user .separator { + margin: 0 10px; +} + +.comment-card .content { + margin-bottom: 10px; + line-height: 1.5em; + max-height: 6em; + overflow-wrap: break-word; + white-space: pre-wrap; + overflow: hidden; + color: #666; +} + +.comment-card .footer { + display: flex; + justify-content: space-between; + line-height: 1.2em; + color: #999; +} + +.comment-card .footer .left, +.comment-card .footer .right { + display: flex; +} + +.comment-card .footer .column { + margin-right: 10px; +} + +.comment-card .footer .column:last-child { + margin-right: 0; +} + +.comment-card .footer .action:hover { + background-color: #393D49; + cursor: pointer; + color: white; +} + +.comment-card .action-reply, +.comment-card .action-report, +.comment-card .action-delete { + display: none; +} + +.comment-card .info:hover .action-reply, +.comment-card .info:hover .action-report, +.comment-card .info:hover .action-delete { + display: inline; +} + +.reply-list { + margin-left: 48px; +} + +.reply-list .comment-card .info { + float: left; + width: 640px; +} + +.toolbar-sticky { position: fixed; top: 150px; margin-left: -65px; } -.action-sticky .item { +.toolbar-sticky .item { margin-bottom: 15px; text-align: center; } -.action-sticky .item .icon { +.toolbar-sticky .item .icon { width: 36px; height: 36px; line-height: 36px; @@ -553,18 +671,17 @@ background-color: #fff; } -.action-sticky .layui-icon { +.toolbar-sticky .layui-icon { color: #999; cursor: pointer; } -.action-sticky .item .text { +.toolbar-sticky .item .text { color: #999; } -.action-sticky .active, -.action-sticky .layui-icon-star-fill, -.action-sticky .layui-icon:hover { +.toolbar-sticky .active, +.toolbar-sticky .layui-icon-star-fill { color: orange; } @@ -904,31 +1021,6 @@ .review-card { position: relative; - padding-bottom: 10px; - margin-bottom: 10px; - border-bottom: 1px dashed #ccc; -} - -.review-card:last-child { - border-bottom: none; -} - -.review-card .avatar { - float: left; - width: 60px; - height: 60px; - margin-right: 15px; -} - -.review-card .avatar img { - width: 100%; - height: 100%; - border-radius: 60px; -} - -.review-card .info { - float: left; - width: 650px; } .review-card .rating, .review-card .more { @@ -948,47 +1040,6 @@ cursor: pointer; } -.review-card .title { - margin-bottom: 10px; -} - -.review-card .user { - margin-bottom: 15px; - color: #666; -} - -.review-card .content { - margin-bottom: 15px; - line-height: 1.5em; - max-height: 6em; - overflow-wrap: break-word; - white-space: pre-wrap; - overflow: hidden; - color: #666; -} - -.review-card .footer { - line-height: 1.2em; - color: #666; -} - -.review-card .footer span { - margin-right: 10px; -} - -.like .icon-praise { - margin-right: 5px; - cursor: pointer; -} - -.like .active, .like .icon-praise:hover { - color: orange; -} - -.like .like-count { - font-style: normal; -} - .sidebar-card .layui-card-header { text-align: center; } @@ -1105,7 +1156,7 @@ .read-info { min-height: 428px; - margin-bottom: 0; + margin-bottom: 20px; } .share .layui-icon { @@ -1113,14 +1164,11 @@ cursor: pointer; } +.share .active, .share .layui-icon-star-fill { color: orange; } -.share .active, .share .layui-icon:hover { - color: orange; -} - .share a { margin-right: 5px; } @@ -1167,7 +1215,7 @@ position: relative; width: 760px; height: 428px; - margin-bottom: 0; + margin-bottom: 20px; } .chat-wrap .layui-card-header { @@ -1387,7 +1435,6 @@ #pay-layer .qrcode img { width: 160px; height: 160px; - border: 3px dashed #ccc; } #pay-layer .success-tips { diff --git a/public/static/home/js/article.show.js b/public/static/home/js/article.show.js index 0d9fc60f..77577a4f 100644 --- a/public/static/home/js/article.show.js +++ b/public/static/home/js/article.show.js @@ -3,15 +3,22 @@ layui.use(['jquery', 'helper'], function () { var $ = layui.jquery; var helper = layui.helper; - var $related = $('#related-article-list'); + var $relatedList = $('#related-article-list'); + var $commentList = $('#comment-list'); - helper.ajaxLoadHtml($related.data('url'), $related.attr('id')); + if ($relatedList.length > 0) { + helper.ajaxLoadHtml($relatedList.data('url'), $relatedList.attr('id')); + } + + if ($commentList.length > 0) { + helper.ajaxLoadHtml($commentList.data('url'), $commentList.attr('id')); + } $('.icon-star').on('click', function () { var $this = $(this); var $parent = $this.parent(); var $favoriteCount = $parent.next(); - var favoriteCount = parseInt($favoriteCount.text()) + var favoriteCount = $favoriteCount.data('count'); helper.checkLogin(function () { $.ajax({ type: 'POST', @@ -20,16 +27,15 @@ layui.use(['jquery', 'helper'], function () { if ($this.hasClass('layui-icon-star-fill')) { $this.removeClass('layui-icon-star-fill'); $this.addClass('layui-icon-star'); - $parent.attr('title', '收藏'); - $favoriteCount.text(favoriteCount - 1); - favoriteCount -= 1; + $parent.attr('title', '收藏文章'); + favoriteCount--; } else { $this.removeClass('layui-icon-star'); $this.addClass('layui-icon-star-fill'); $parent.attr('title', '取消收藏'); - $favoriteCount.text(favoriteCount + 1); - favoriteCount += 1; + favoriteCount++; } + $favoriteCount.data('count', favoriteCount).text(favoriteCount); } }); }); @@ -61,12 +67,4 @@ layui.use(['jquery', 'helper'], function () { }); }); - $('.icon-reply').on('click', function () { - console.log('scroll'); - console.log($('#comment-wrap').offset().top); - $('html').animate({ - scrollTop: $('#comment-wrap').offset().top - }, 500); - }); - }); \ No newline at end of file diff --git a/public/static/home/js/chapter.live.chat.js b/public/static/home/js/chapter.live.chat.js index 06951130..edb92926 100644 --- a/public/static/home/js/chapter.live.chat.js +++ b/public/static/home/js/chapter.live.chat.js @@ -94,7 +94,7 @@ layui.use(['jquery', 'form', 'helper'], function () { } function refreshLiveStats() { - var $count = $('.layui-icon-user').next(); + var $count = $('#toolbar-online > .text'); $.get(liveStatsUrl, function (res) { $count.text(res.client_count); }); diff --git a/public/static/home/js/chapter.action.js b/public/static/home/js/chapter.show.js similarity index 72% rename from public/static/home/js/chapter.action.js rename to public/static/home/js/chapter.show.js index f5a2ee60..8c778e47 100644 --- a/public/static/home/js/chapter.action.js +++ b/public/static/home/js/chapter.show.js @@ -3,14 +3,17 @@ layui.use(['jquery', 'helper'], function () { var $ = layui.jquery; var helper = layui.helper; - /** - * 点赞 - */ + var $commentList = $('#comment-list'); + + if ($commentList.length > 0) { + helper.ajaxLoadHtml($commentList.data('url'), $commentList.attr('id')); + } + $('.icon-praise').on('click', function () { var $this = $(this); var $parent = $this.parent(); - var $likeCount = $this.next(); - var likeCount = parseInt($likeCount.text()); + var $likeCount = $parent.next(); + var likeCount = $likeCount.data('count'); helper.checkLogin(function () { $.ajax({ type: 'POST', @@ -18,23 +21,19 @@ layui.use(['jquery', 'helper'], function () { success: function () { if ($this.hasClass('active')) { $this.removeClass('active'); - $parent.attr('title', '点赞'); - $likeCount.text(likeCount - 1); - likeCount -= 1; + $parent.attr('title', '点赞支持'); + likeCount--; } else { $this.addClass('active'); $parent.attr('title', '取消点赞'); - $likeCount.text(likeCount + 1); - likeCount += 1; + likeCount++; } + $likeCount.data('count', likeCount).text(likeCount); } }); }); }); - /** - * 咨询 - */ $('.icon-help').on('click', function () { var url = $(this).parent().data('url'); helper.checkLogin(function () { @@ -47,10 +46,7 @@ layui.use(['jquery', 'helper'], function () { }); }); - /** - * 资料 - */ - $('.icon-resource').on('click', function () { + $('.icon-download').on('click', function () { var url = $(this).parent().data('url'); helper.checkLogin(function () { layer.open({ diff --git a/public/static/home/js/comment.js b/public/static/home/js/comment.js new file mode 100644 index 00000000..72b89a19 --- /dev/null +++ b/public/static/home/js/comment.js @@ -0,0 +1,187 @@ +layui.use(['jquery', 'form', 'layer', 'helper'], function () { + + var $ = layui.jquery; + var form = layui.form; + var layer = layui.layer; + var helper = layui.helper; + + form.on('submit(addComment)', function (data) { + var submit = $(this); + var $commentList = $('#comment-list'); + var $textarea = $(data.form).find('.layui-textarea'); + var $tbCommentCount = $('#toolbar-comment > .text'); + var tbCommentCount = $tbCommentCount.data('count'); + submit.attr('disabled', 'disabled').addClass('layui-btn-disabled'); + $.ajax({ + type: 'POST', + url: data.form.action, + data: data.field, + success: function (res) { + $.ajax({ + type: 'GET', + url: '/comment/' + res.comment.id + '/info', + success: function (html) { + tbCommentCount++; + $tbCommentCount.data('count', tbCommentCount).text(tbCommentCount); + $commentList.prepend(html); + } + }); + $textarea.val(''); + layer.msg('发表评论成功'); + submit.removeAttr('disabled').removeClass('layui-btn-disabled'); + }, + error: function (xhr) { + var res = JSON.parse(xhr.responseText); + layer.msg(res.msg); + submit.removeAttr('disabled').removeClass('layui-btn-disabled'); + } + }); + return false; + }); + + form.on('submit(replyComment)', function (data) { + var submit = $(this); + var commentId = submit.data('comment-id'); + var parentId = submit.data('parent-id'); + var blockId = parentId > 0 ? parentId : commentId; + var $commentForm = $('#comment-form-' + commentId); + var $replyList = $('#reply-list-' + blockId); + var $textarea = $(data.form).find('.layui-textarea'); + var $replyCount = $('#comment-' + blockId).find('.reply-count'); + var replyCount = $replyCount.data('count'); + var $tbCommentCount = $('#toolbar-comment > .text'); + var tbCommentCount = $tbCommentCount.data('count'); + submit.attr('disabled', 'disabled').addClass('layui-btn-disabled'); + $.ajax({ + type: 'POST', + url: data.form.action, + data: data.field, + success: function (res) { + $.ajax({ + type: 'GET', + url: '/comment/' + res.comment.id + '/info', + success: function (html) { + $replyList.prepend(html); + } + }); + replyCount++; + tbCommentCount++; + $commentForm.hide(); + $replyList.show(); + $textarea.val(''); + $replyCount.data('count', replyCount).text(replyCount); + $tbCommentCount.data('count', tbCommentCount).text(tbCommentCount); + layer.msg('发表回复成功'); + submit.removeAttr('disabled').removeClass('layui-btn-disabled'); + }, + error: function (xhr) { + var res = JSON.parse(xhr.responseText); + layer.msg(res.msg); + submit.removeAttr('disabled').removeClass('layui-btn-disabled'); + } + }); + return false; + }); + + $('.icon-comment').on('click', function () { + $('html').animate({ + scrollTop: $('#comment-anchor').offset().top + }, 500); + }); + + $('#btn-cancel-comment').on('click', function () { + $('#comment-footer').hide(); + }); + + $('#comment-content').on('click', function () { + $('#comment-footer').show(); + }); + + $('body').on('click', '.btn-cancel-reply', function () { + var id = $(this).data('id'); + $('#comment-form-' + id).hide(); + }); + + $('body').on('click', '.action-toggle', function () { + var $this = $(this); + var id = $this.data('id'); + var url = $this.data('url'); + var $replyList = $('#comment-' + id + '>.reply-list'); + if ($replyList.hasClass('loaded')) { + if ($this.hasClass('expanded')) { + $this.attr('title', '展开回应').removeClass('expanded'); + } else { + $this.attr('title', '收起回应').addClass('expanded'); + } + $replyList.toggle(); + } else { + $.ajax({ + type: 'GET', + url: url, + success: function (html) { + $this.attr('title', '收起回应').addClass('expanded'); + $replyList.addClass('loaded').show(); + $replyList.html(html); + } + }); + } + }); + + $('body').on('click', '.action-reply', function () { + var id = $(this).data('id'); + var $block = $('#comment-form-' + id); + var $textarea = $block.find('textarea'); + $block.toggle(); + $textarea.focus(); + }); + + $('body').on('click', '.action-like', function () { + var $this = $(this); + var $likeCount = $this.prev(); + var likeCount = $likeCount.data('count'); + helper.checkLogin(function () { + $.ajax({ + type: 'POST', + url: $this.data('url'), + success: function () { + if ($this.hasClass('liked')) { + $this.attr('title', '点赞支持').text('点赞').removeClass('liked'); + likeCount--; + } else { + $this.attr('title', '取消点赞').text('已赞').addClass('liked'); + likeCount++; + } + $likeCount.data('count', likeCount).text(likeCount); + } + }); + }); + }); + + $('body').on('click', '.action-delete', function () { + var $this = $(this); + var id = $this.data('id'); + var parentId = $this.data('parent-id'); + var $comment = $('#comment-' + id); + var $tbCommentCount = $('#toolbar-comment > .text'); + var tbCommentCount = $tbCommentCount.data('count'); + layer.confirm('确定要删除吗?', function () { + $.ajax({ + type: 'POST', + url: $this.data('url'), + success: function () { + if (parentId > 0) { + var $replyCount = $('#comment-' + parentId).find('.reply-count'); + var replyCount = $replyCount.data('count'); + replyCount--; + $replyCount.data('count', replyCount).text(replyCount); + } + tbCommentCount--; + $tbCommentCount.data('count', tbCommentCount).text(tbCommentCount); + $comment.remove(); + layer.msg('删除评论成功'); + } + }); + }); + }); + +}); \ No newline at end of file diff --git a/public/static/home/js/course.show.js b/public/static/home/js/course.show.js index 9a022292..0abfb5a0 100644 --- a/public/static/home/js/course.show.js +++ b/public/static/home/js/course.show.js @@ -10,6 +10,8 @@ layui.use(['jquery', 'layer', 'helper'], function () { $('.icon-star').on('click', function () { var $this = $(this); var $parent = $this.parent(); + var $favoriteCount = $parent.next(); + var favoriteCount = $favoriteCount.data('count'); helper.checkLogin(function () { $.ajax({ type: 'POST', @@ -18,12 +20,15 @@ layui.use(['jquery', 'layer', 'helper'], function () { if ($this.hasClass('layui-icon-star-fill')) { $this.removeClass('layui-icon-star-fill'); $this.addClass('layui-icon-star'); - $parent.attr('title', '收藏'); + $parent.attr('title', '收藏课程'); + favoriteCount--; } else { $this.removeClass('layui-icon-star'); $this.addClass('layui-icon-star-fill'); $parent.attr('title', '取消收藏'); + favoriteCount++; } + $favoriteCount.data('count', favoriteCount).text(favoriteCount); } }); }); @@ -93,27 +98,23 @@ layui.use(['jquery', 'layer', 'helper'], function () { /** * 点赞(咨询|评价) */ - $('body').on('click', '.icon-praise', function () { + $('body').on('click', '.action-like', function () { var $this = $(this); - var $parent = $this.parent(); - var $likeCount = $this.next(); - var likeCount = parseInt($likeCount.text()); + var $likeCount = $this.prev(); + var likeCount = $likeCount.data('count'); helper.checkLogin(function () { $.ajax({ type: 'POST', - url: $parent.data('url'), + url: $this.data('url'), success: function () { - if ($this.hasClass('active')) { - $this.removeClass('active'); - $parent.attr('title', '点赞'); - $likeCount.text(likeCount - 1); - likeCount -= 1; + if ($this.hasClass('liked')) { + $this.attr('title', '点赞支持').text('点赞').removeClass('liked'); + likeCount--; } else { - $this.addClass('active'); - $parent.attr('title', '取消点赞'); - $likeCount.text(likeCount + 1); - likeCount += 1; + $this.attr('title', '取消点赞').text('已赞').addClass('liked'); + likeCount++; } + $likeCount.data('count', likeCount).text(likeCount); } }); });