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

Merge branch 'koogua/v1.4.2'

This commit is contained in:
koogua 2021-08-12 20:14:03 +08:00
commit 33be4028b6
69 changed files with 523 additions and 279 deletions

View File

@ -1,3 +1,19 @@
### [v1.4.2](https://gitee.com/koogua/course-tencent-cloud/releases/v1.4.2)(2021-08-13)
- 后台增加转码码率配置选项
- 后台增加微聊配置开关
- 优化外链播放地址逻辑
- 访问课程文章等未发布资源404处理
- 优化课件上传不返回md5值的处理
- 优化用户中心内容数据展示
- 前台暂时屏蔽文章仅我可见和关闭评论功能
- 直播增加极速码率选项
- 调整码率标签对应
- 修复后台数据统计中心Hash缓存问题
- 修复未发布的课程仍然可购买问题
- 修复购买课程后学员人数未增加问题
- 增加同步课程数据统计脚本
### [v1.4.1](https://gitee.com/koogua/course-tencent-cloud/releases/v1.4.1)(2021-08-08)
- AnswerInfo结构补充遗漏的comment_count字段

View File

@ -14,6 +14,7 @@ use App\Models\Order as OrderModel;
use App\Models\Refund as RefundModel;
use App\Models\Task as TaskModel;
use App\Models\Trade as TradeModel;
use App\Repos\Course as CourseRepo;
use App\Repos\ImGroup as ImGroupRepo;
use App\Repos\ImGroupUser as ImGroupUserRepo;
use App\Repos\Order as OrderRepo;
@ -137,9 +138,17 @@ class DeliverTask extends Task
throw new \RuntimeException('Create Course User Failed');
}
$courseRepo = new CourseRepo();
$course = $courseRepo->findById($course['id']);
$course->user_count += 1;
$course->update();
$groupRepo = new ImGroupRepo();
$group = $groupRepo->findByCourseId($order->item_id);
$group = $groupRepo->findByCourseId($course->id);
$groupUserRepo = new ImGroupUserRepo();
@ -176,9 +185,17 @@ class DeliverTask extends Task
throw new \RuntimeException('Create Course User Failed');
}
$courseRepo = new CourseRepo();
$course = $courseRepo->findById($course['id']);
$course->user_count += 1;
$course->update();
$groupRepo = new ImGroupRepo();
$group = $groupRepo->findByCourseId($course['id']);
$group = $groupRepo->findByCourseId($course->id);
$groupUserRepo = new ImGroupUserRepo();

View File

@ -0,0 +1,51 @@
<?php
/**
* @copyright Copyright (c) 2021 深圳市酷瓜软件有限公司
* @license https://opensource.org/licenses/GPL-2.0
* @link https://www.koogua.com
*/
namespace App\Console\Tasks;
use App\Models\Course as CourseModel;
use App\Repos\Course as CourseRepo;
class SyncCourseStatTask extends Task
{
public function mainAction()
{
$courses = $this->findCourses();
echo sprintf('pending courses: %s', $courses->count()) . PHP_EOL;
if ($courses->count() == 0) return;
echo '------ start sync course stat task ------' . PHP_EOL;
foreach ($courses as $course) {
$this->recountUsers($course);
}
echo '------ end sync course stat task ------' . PHP_EOL;
}
protected function recountUsers(CourseModel $course)
{
$courseRepo = new CourseRepo();
$userCount = $courseRepo->countUsers($course->id);
$course->user_count = $userCount;
$course->update();
}
protected function findCourses()
{
return CourseModel::query()
->where('published = 1')
->execute();
}
}

View File

@ -10,7 +10,7 @@ namespace App\Console\Tasks;
use App\Models\Tag as TagModel;
use App\Repos\Tag as TagRepo;
class SyncTagCountTask extends Task
class SyncTagStatTask extends Task
{
public function mainAction()
@ -21,13 +21,13 @@ class SyncTagCountTask extends Task
if ($tags->count() == 0) return;
echo '------ start recount task ------' . PHP_EOL;
echo '------ start sync tag stat task ------' . PHP_EOL;
foreach ($tags as $tag) {
$this->recountTaggedItems($tag);
}
echo '------ end recount task ------' . PHP_EOL;
echo '------ end sync tag stat task ------' . PHP_EOL;
}
protected function recountTaggedItems(TagModel $tag)

View File

@ -39,9 +39,7 @@ class VodEventTask extends Task
$count++;
if ($count >= 12) {
break;
}
if ($count >= 12) break;
}
$this->confirmEvents($handles);

View File

@ -1199,7 +1199,7 @@ class AuthNode extends Service
],
[
'id' => '5-1-11',
'title' => '微聊设置',
'title' => '即时通讯',
'type' => 'menu',
'route' => 'admin.setting.im',
],

View File

@ -175,24 +175,16 @@ class ChapterContent extends Service
$validator->checkDuration($duration);
$odUrl = $post['file_remote']['od']['url'] ?? '';
$hdUrl = $post['file_remote']['hd']['url'] ?? '';
$sdUrl = $post['file_remote']['sd']['url'] ?? '';
$fdUrl = $post['file_remote']['fd']['url'] ?? '';
$fileRemote = [
'od' => ['url' => ''],
'hd' => ['url' => ''],
'sd' => ['url' => ''],
'fd' => ['url' => ''],
];
$attrs = $chapter->attrs;
if (!empty($odUrl)) {
$fileRemote['od']['url'] = $validator->checkFileUrl($odUrl);
$attrs['file']['status'] = ChapterModel::FS_UPLOADED;
$attrs['duration'] = $duration;
}
if (!empty($hdUrl)) {
$fileRemote['hd']['url'] = $validator->checkFileUrl($hdUrl);
}
@ -201,13 +193,27 @@ class ChapterContent extends Service
$fileRemote['sd']['url'] = $validator->checkFileUrl($sdUrl);
}
if (!empty($fdUrl)) {
$fileRemote['fd']['url'] = $validator->checkFileUrl($fdUrl);
}
$validator->checkRemoteFile($hdUrl, $sdUrl, $fdUrl);
$chapterRepo = new ChapterRepo();
$vod = $chapterRepo->findChapterVod($chapter->id);
$vod->file_remote = $fileRemote;
$vod->update();
$attrs = $chapter->attrs;
$attrs['file']['status'] = ChapterModel::FS_UPLOADED;
$attrs['duration'] = $duration;
$chapter->attrs = $attrs;
$chapter->update();
$this->updateCourseVodAttrs($vod->course_id);

View File

@ -35,7 +35,10 @@ class Resource extends Service
$upload = $uploadRepo->findByMd5($post['upload']['md5']);
if (!$upload) {
/**
* 腾讯COS存储可能不会返回文件md5值
*/
if (!$upload || empty($post['upload']['md5'])) {
$upload = new UploadModel();

View File

@ -161,6 +161,10 @@ class Setting extends Service
public function updateVodSettings($section, $settings)
{
if (isset($settings['video_quality'])) {
$settings['video_quality'] = kg_json_encode($settings['video_quality']);
}
$this->updateSettings($section, $settings);
}

View File

@ -157,6 +157,11 @@ class Stat extends Service
return date('Y-m') == "{$year}-{$month}";
}
protected function getLifetime()
{
return strtotime('tomorrow') - time();
}
protected function getPrevMonth($year, $month)
{
$currentMonthTime = strtotime("{$year}-{$month}");
@ -226,9 +231,9 @@ class Stat extends Service
$currMonth = date('Y-m');
if ($queryMonth < $currMonth) {
$cache->save($keyName, $items, 7 * 86400);
$cache->save($keyName, $items, 86400);
} else {
$cache->save($keyName, $items, 2 * 3600);
$cache->save($keyName, $items, 3600);
}
}
@ -254,21 +259,12 @@ class Stat extends Service
$key = substr($date, -2);
if ($date < $currDate) {
$list[$key] = $statRepo->sumDailySales($date);
} elseif ($date == $currDate) {
$list[$key] = -999;
} else {
$list[$key] = 0;
}
}
$redis->hMSet($keyName, $list);
$redis->expire($keyName, 7 * 86400);
}
foreach ($list as $key => $value) {
if ($value < 0) {
$list[$key] = $statRepo->sumDailySales("{$year}-{$month}-{$key}");
$redis->hSet($keyName, $key, $list[$key]);
}
$redis->expire($keyName, $this->getLifetime());
}
if ($this->isCurrMonth($year, $month)) {
@ -297,21 +293,12 @@ class Stat extends Service
$key = substr($date, -2);
if ($date < $currDate) {
$list[$key] = $statRepo->sumDailyRefunds($date);
} elseif ($date == $currDate) {
$list[$key] = -999;
} else {
$list[$key] = 0;
}
}
$redis->hMSet($keyName, $list);
$redis->expire($keyName, 7 * 86400);
}
foreach ($list as $key => $value) {
if ($value < 0) {
$list[$key] = $statRepo->sumDailyRefunds("{$year}-{$month}-{$key}");
$redis->hSet($keyName, $key, $list[$key]);
}
$redis->expire($keyName, $this->getLifetime());
}
if ($this->isCurrMonth($year, $month)) {
@ -340,21 +327,12 @@ class Stat extends Service
$key = substr($date, -2);
if ($date < $currDate) {
$list[$key] = $statRepo->countDailyRegisteredUsers($date);
} elseif ($date == $currDate) {
$list[$key] = -999;
} else {
$list[$key] = 0;
}
}
$redis->hMSet($keyName, $list);
$redis->expire($keyName, 7 * 86400);
}
foreach ($list as $key => $value) {
if ($value < 0) {
$list[$key] = $statRepo->countDailyRegisteredUsers("{$year}-{$month}-{$key}");
$redis->hSet($keyName, $key, $list[$key]);
}
$redis->expire($keyName, $this->getLifetime());
}
if ($this->isCurrMonth($year, $month)) {
@ -383,21 +361,12 @@ class Stat extends Service
$key = substr($date, -2);
if ($date < $currDate) {
$list[$key] = $statRepo->countDailyOnlineUsers($date);
} elseif ($date == $currDate) {
$list[$key] = -999;
} else {
$list[$key] = 0;
}
}
$redis->hMSet($keyName, $list);
$redis->expire($keyName, 7 * 86400);
}
foreach ($list as $key => $value) {
if ($value < 0) {
$list[$key] = $statRepo->countDailyOnlineUsers("{$year}-{$month}-{$key}");
$redis->hSet($keyName, $key, $list[$key]);
}
$redis->expire($keyName, $this->getLifetime());
}
if ($this->isCurrMonth($year, $month)) {

View File

@ -44,7 +44,7 @@
{% set edit_url = url({'for':'admin.answer.edit','id':item.id}) %}
{% set delete_url = url({'for':'admin.answer.delete','id':item.id}) %}
{% set restore_url = url({'for':'admin.answer.restore','id':item.id}) %}
{% set review_url = url({'for':'admin.answer.moderate','id':item.id}) %}
{% set moderate_url = url({'for':'admin.answer.moderate','id':item.id}) %}
<tr>
<td>
<P>问题:<a href="{{ question_url }}" target="_blank">{{ item.question.title }}</a></P>
@ -58,9 +58,10 @@
<div class="kg-dropdown">
<button class="layui-btn layui-btn-sm">操作 <i class="layui-icon layui-icon-triangle-d"></i></button>
<ul>
<li><a href="{{ answer_url }}" target="_blank">预览回答</a></li>
{% if item.published == 1 %}
<li><a href="{{ review_url }}">审核回答</a></li>
<li><a href="{{ moderate_url }}">审核回答</a></li>
{% elseif item.published == 2 %}
<li><a href="{{ answer_url }}" target="_blank">浏览回答</a></li>
{% endif %}
<li><a href="{{ edit_url }}">编辑回答</a></li>
{% if item.deleted == 0 %}

View File

@ -50,13 +50,13 @@
</thead>
<tbody>
{% for item in pager.items %}
{% set preview_url = url({'for':'home.article.show','id':item.id}) %}
{% set article_url = url({'for':'home.article.show','id':item.id}) %}
{% set owner_url = url({'for':'home.user.show','id':item.owner.id}) %}
{% set edit_url = url({'for':'admin.article.edit','id':item.id}) %}
{% set update_url = url({'for':'admin.article.update','id':item.id}) %}
{% set delete_url = url({'for':'admin.article.delete','id':item.id}) %}
{% set restore_url = url({'for':'admin.article.restore','id':item.id}) %}
{% set review_url = url({'for':'admin.article.moderate','id':item.id}) %}
{% set moderate_url = url({'for':'admin.article.moderate','id':item.id}) %}
{% set comment_url = url({'for':'admin.comment.list'},{'item_id':item.id,'item_type':2}) %}
<tr>
<td>
@ -87,9 +87,9 @@
<button class="layui-btn layui-btn-sm">操作 <i class="layui-icon layui-icon-triangle-d"></i></button>
<ul>
{% if item.published == 1 %}
<li><a href="{{ review_url }}">审核文章</a></li>
<li><a href="{{ moderate_url }}">审核文章</a></li>
{% elseif item.published == 2 %}
<li><a href="{{ preview_url }}" target="_blank">预览文章</a></li>
<li><a href="{{ article_url }}" target="_blank">浏览文章</a></li>
{% endif %}
<li><a href="{{ edit_url }}">编辑文章</a></li>
{% if item.deleted == 0 %}

View File

@ -110,26 +110,6 @@
</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">原画地址</label>
{% if remote_play_urls.od.url %}
<div class="layui-inline" style="width:55%;">
<input id="tc-od-url" class="layui-input" type="text" name="file_remote[od][url]" value="{{ remote_play_urls.od.url }}" lay-verify="required">
</div>
<div class="layui-inline">
<span class="layui-btn kg-preview" data-chapter-id="{{ chapter.id }}" data-play-url="{{ remote_play_urls.hd.url }}">预览</span>
<span class="layui-btn layui-btn-primary kg-copy" data-clipboard-target="#tc-od-url">复制</span>
</div>
{% else %}
<div class="layui-inline" style="width:55%;">
<input id="tc-od-url" class="layui-input" type="text" name="file_remote[od][url]" value="" lay-verify="required">
</div>
<div class="layui-inline">
<span class="layui-btn layui-btn-disabled">预览</span>
<span class="layui-btn layui-btn-disabled">复制</span>
</div>
{% endif %}
</div>
<div class="layui-form-item">
<label class="layui-form-label">高清地址</label>
{% if remote_play_urls.hd.url %}
@ -162,7 +142,27 @@
</div>
{% else %}
<div class="layui-inline" style="width:55%;">
<input id="tc-sd-url" class="layui-input" type="text" name="file_remote[sd][url]" value="{{ remote_play_urls.sd.url }}">
<input id="tc-sd-url" class="layui-input" type="text" name="file_remote[sd][url]" value="">
</div>
<div class="layui-inline">
<span class="layui-btn layui-btn-disabled">预览</span>
<span class="layui-btn layui-btn-disabled">复制</span>
</div>
{% endif %}
</div>
<div class="layui-form-item">
<label class="layui-form-label">极速地址</label>
{% if remote_play_urls.fd.url %}
<div class="layui-inline" style="width:55%;">
<input id="tc-fd-url" class="layui-input" type="text" name="file_remote[fd][url]" value="{{ remote_play_urls.fd.url }}">
</div>
<div class="layui-inline">
<span class="layui-btn kg-preview" data-chapter-id="{{ chapter.id }}" data-play-url="{{ remote_play_urls.hd.url }}">预览</span>
<span class="layui-btn layui-btn-primary kg-copy" data-clipboard-target="#tc-fd-url">复制</span>
</div>
{% else %}
<div class="layui-inline" style="width:55%;">
<input id="tc-fd-url" class="layui-input" type="text" name="file_remote[fd][url]" value="">
</div>
<div class="layui-inline">
<span class="layui-btn layui-btn-disabled">预览</span>

View File

@ -36,9 +36,9 @@
<th>编号</th>
<th>名称</th>
<th>课件</th>
<th>学员</th>
<th>点赞</th>
<th>评论</th>
<th>直播时间</th>
<th>时间</th>
<th>推流</th>
<th>排序</th>
<th>免费</th>
@ -48,7 +48,7 @@
</thead>
<tbody>
{% for item in lessons %}
{% set preview_url = url({'for':'home.chapter.show','id':item.id}) %}
{% set chapter_url = url({'for':'home.chapter.show','id':item.id}) %}
{% set edit_url = url({'for':'admin.chapter.edit','id':item.id}) %}
{% set update_url = url({'for':'admin.chapter.update','id':item.id}) %}
{% set delete_url = url({'for':'admin.chapter.delete','id':item.id}) %}
@ -60,8 +60,8 @@
<span class="layui-badge layui-bg-green">课</span>
</td>
<td>{{ item.resource_count }}</td>
<td>{{ item.user_count }}</td>
<td>{{ item.like_count }}</td>
<td>{{ item.comment_count }}</td>
<td>{{ live_time_info(item.attrs) }}</td>
<td>{{ live_status_info(item.attrs['stream']['status']) }}</td>
<td><input class="layui-input kg-priority" type="text" name="priority" title="数值越小排序越靠前" value="{{ item.priority }}" data-url="{{ update_url }}"></td>
@ -71,7 +71,9 @@
<div class="kg-dropdown">
<button class="layui-btn layui-btn-sm">操作 <i class="layui-icon layui-icon-triangle-d"></i></button>
<ul>
<li><a href="{{ preview_url }}" target="_blank">预览</a></li>
{% if item.published == 1 %}
<li><a href="{{ chapter_url }}" target="_blank">浏览</a></li>
{% endif %}
<li><a href="{{ edit_url }}">编辑</a></li>
{% if item.deleted == 0 %}
<li><a href="javascript:" class="kg-delete" data-url="{{ delete_url }}">删除</a></li>

View File

@ -8,6 +8,7 @@
<col>
<col>
<col>
<col>
<col width="10%">
</colgroup>
<thead>
@ -15,6 +16,7 @@
<th>编号</th>
<th>名称</th>
<th>课件</th>
<th>学员</th>
<th>点赞</th>
<th>评论</th>
<th>排序</th>
@ -25,7 +27,7 @@
</thead>
<tbody>
{% for item in lessons %}
{% set preview_url = url({'for':'home.chapter.show','id':item.id}) %}
{% set chapter_url = url({'for':'home.chapter.show','id':item.id}) %}
{% set edit_url = url({'for':'admin.chapter.edit','id':item.id}) %}
{% set update_url = url({'for':'admin.chapter.update','id':item.id}) %}
{% set delete_url = url({'for':'admin.chapter.delete','id':item.id}) %}
@ -40,6 +42,7 @@
</p>
</td>
<td>{{ item.resource_count }}</td>
<td>{{ item.user_count }}</td>
<td>{{ item.like_count }}</td>
<td>{{ item.comment_count }}</td>
<td><input class="layui-input kg-priority" type="text" name="priority" title="数值越小排序越靠前" value="{{ item.priority }}" data-url="{{ update_url }}"></td>
@ -49,7 +52,9 @@
<div class="kg-dropdown">
<button class="layui-btn layui-btn-sm">操作 <i class="layui-icon layui-icon-triangle-d"></i></button>
<ul>
<li><a href="{{ preview_url }}" target="_blank">预览</a></li>
{% if item.published == 1 %}
<li><a href="{{ chapter_url }}" target="_blank">浏览</a></li>
{% endif %}
<li><a href="{{ edit_url }}">编辑</a></li>
{% if item.deleted == 0 %}
<li><a href="javascript:" class="kg-delete" data-url="{{ delete_url }}">删除</a></li>

View File

@ -42,7 +42,7 @@
</thead>
<tbody>
{% for item in lessons %}
{% set preview_url = url({'for':'home.chapter.show','id':item.id}) %}
{% set chapter_url = url({'for':'home.chapter.show','id':item.id}) %}
{% set edit_url = url({'for':'admin.chapter.edit','id':item.id}) %}
{% set update_url = url({'for':'admin.chapter.update','id':item.id}) %}
{% set delete_url = url({'for':'admin.chapter.delete','id':item.id}) %}
@ -71,7 +71,9 @@
<div class="kg-dropdown">
<button class="layui-btn layui-btn-sm">操作 <i class="layui-icon layui-icon-triangle-d"></i></button>
<ul>
<li><a href="{{ preview_url }}" target="_blank">预览</a></li>
{% if item.published == 1 %}
<li><a href="{{ chapter_url }}" target="_blank">浏览</a></li>
{% endif %}
<li><a href="{{ edit_url }}">编辑</a></li>
{% if item.deleted == 0 %}
<li><a href="javascript:" class="kg-delete" data-url="{{ delete_url }}">删除</a></li>

View File

@ -54,7 +54,7 @@
</thead>
<tbody>
{% for item in pager.items %}
{% set preview_url = url({'for':'home.course.show','id':item.id}) %}
{% set course_url = url({'for':'home.course.show','id':item.id}) %}
{% set edit_url = url({'for':'admin.course.edit','id':item.id}) %}
{% set update_url = url({'for':'admin.course.update','id':item.id}) %}
{% set delete_url = url({'for':'admin.course.delete','id':item.id}) %}
@ -98,7 +98,9 @@
<div class="kg-dropdown">
<button class="layui-btn layui-btn-sm">操作 <i class="layui-icon layui-icon-triangle-d"></i></button>
<ul>
<li><a href="{{ preview_url }}" target="_blank">预览课程</a></li>
{% if item.published == 1 %}
<li><a href="{{ course_url }}" target="_blank">浏览课程</a></li>
{% endif %}
<li><a href="{{ edit_url }}">编辑课程</a></li>
{% if item.deleted == 0 %}
<li><a href="javascript:" class="kg-delete" data-url="{{ delete_url }}">删除课程</a></li>

View File

@ -39,7 +39,7 @@
<tbody>
{% for item in helps %}
{% set list_url = url({'for':'admin.help.list'},{'category_id':item.category.id}) %}
{% set preview_url = url({'for':'home.help.show','id':item.id}) %}
{% set help_url = url({'for':'home.help.show','id':item.id}) %}
{% set edit_url = url({'for':'admin.help.edit','id':item.id}) %}
{% set update_url = url({'for':'admin.help.update','id':item.id}) %}
{% set delete_url = url({'for':'admin.help.delete','id':item.id}) %}
@ -54,7 +54,9 @@
<div class="kg-dropdown">
<button class="layui-btn layui-btn-sm">操作 <i class="layui-icon layui-icon-triangle-d"></i></button>
<ul>
<li><a href="{{ preview_url }}" target="_blank">预览</a></li>
{% if item.published == 1 %}
<li><a href="{{ help_url }}" target="_blank">浏览</a></li>
{% endif %}
<li><a href="{{ edit_url }}">编辑</a></li>
{% if item.deleted == 0 %}
<li><a href="javascript:" class="kg-delete" data-url="{{ delete_url }}">删除</a></li>

View File

@ -44,7 +44,7 @@
</thead>
<tbody>
{% for item in pager.items %}
{% set preview_url = url({'for':'home.im_group.show','id':item.id}) %}
{% set group_url = url({'for':'home.im_group.show','id':item.id}) %}
{% set edit_url = url({'for':'admin.im_group.edit','id':item.id}) %}
{% set update_url = url({'for':'admin.im_group.update','id':item.id}) %}
{% set delete_url = url({'for':'admin.im_group.delete','id':item.id}) %}
@ -56,7 +56,7 @@
</td>
<td>
<p>
名称:<a href="{{ preview_url }}" title="{{ item.about }}" target="_blank">{{ item.name }}</a>{{ item.id }}
名称:<a href="{{ edit_url }}">{{ item.name }}</a>{{ item.id }}
</p>
<p class="meta">
<span>类型:{{ type_info(item.type) }}</span>
@ -77,7 +77,9 @@
<div class="kg-dropdown">
<button class="layui-btn layui-btn-sm">操作 <i class="layui-icon layui-icon-triangle-d"></i></button>
<ul>
<li><a href="{{ preview_url }}" target="_blank">预览</a></li>
{% if item.published == 1 %}
<li><a href="{{ group_url }}" target="_blank">浏览</a></li>
{% endif %}
<li><a href="{{ users_url }}">成员</a></li>
<li><a href="{{ edit_url }}">编辑</a></li>
{% if item.deleted == 0 %}

View File

@ -48,7 +48,7 @@
</thead>
<tbody>
{% for item in pager.items %}
{% set preview_url = url({'for':'home.page.show','id':item.id}) %}
{% set page_url = url({'for':'home.page.show','id':item.id}) %}
{% set edit_url = url({'for':'admin.page.edit','id':item.id}) %}
{% set update_url = url({'for':'admin.page.update','id':item.id}) %}
{% set delete_url = url({'for':'admin.page.delete','id':item.id}) %}
@ -65,7 +65,9 @@
<div class="kg-dropdown">
<button class="layui-btn layui-btn-sm">操作 <i class="layui-icon layui-icon-triangle-d"></i></button>
<ul>
<li><a href="{{ preview_url }}" target="_blank">预览</a></li>
{% if item.published == 1 %}
<li><a href="{{ page_url }}" target="_blank">浏览</a></li>
{% endif %}
<li><a href="{{ edit_url }}">编辑</a></li>
{% if item.deleted == 0 %}
<li><a href="javascript:" class="kg-delete" data-url="{{ delete_url }}">删除</a></li>

View File

@ -51,7 +51,7 @@
<tbody>
{% for item in pager.items %}
{% set redeem_url = url({'for':'admin.point_redeem.list'},{'gift_id':item.id}) %}
{% set preview_url = url({'for':'home.point_gift.show','id':item.id}) %}
{% set gift_url = url({'for':'home.point_gift.show','id':item.id}) %}
{% set edit_url = url({'for':'admin.point_gift.edit','id':item.id}) %}
{% set update_url = url({'for':'admin.point_gift.update','id':item.id}) %}
{% set delete_url = url({'for':'admin.point_gift.delete','id':item.id}) %}
@ -69,14 +69,16 @@
<div class="kg-dropdown">
<button class="layui-btn layui-btn-sm">操作 <i class="layui-icon layui-icon-triangle-d"></i></button>
<ul>
<li><a href="{{ preview_url }}" target="_blank">前台预览</a></li>
<li><a href="{{ redeem_url }}">兑换记录</a></li>
{% if item.published == 1 %}
<li><a href="{{ gift_url }}" target="_blank">浏览</a></li>
{% endif %}
<li><a href="{{ edit_url }}">编辑</a></li>
{% if item.deleted == 0 %}
<li><a href="javascript:" class="kg-delete" data-url="{{ delete_url }}">删除</a></li>
{% else %}
<li><a href="javascript:" class="kg-restore" data-url="{{ restore_url }}">还原</a></li>
{% endif %}
<li><a href="{{ redeem_url }}">兑换记录</a></li>
</ul>
</div>
</td>

View File

@ -54,7 +54,7 @@
</td>
<td>{{ item.gift_point }}</td>
<td>{{ redeem_status_info(item.status) }}</td>
<td>{{ date('Y-m-d H:i',item.create_time) }}</td>
<td>{{ date('Y-m-d H:i:s',item.create_time) }}</td>
<td class="center">
{% if item.gift_type == 2 %}
<button class="layui-btn layui-btn-sm kg-deliver" data-url="{{ deliver_url }}">发货</button>

View File

@ -48,6 +48,7 @@
{name: 'od', label: '原画'},
{name: 'hd', label: '高清'},
{name: 'sd', label: '标清'},
{name: 'fd', label: '极速'},
];
var quality = [];

View File

@ -48,13 +48,13 @@
</thead>
<tbody>
{% for item in pager.items %}
{% set preview_url = url({'for':'home.question.show','id':item.id}) %}
{% set question_url = url({'for':'home.question.show','id':item.id}) %}
{% set owner_url = url({'for':'home.user.show','id':item.owner.id}) %}
{% set edit_url = url({'for':'admin.question.edit','id':item.id}) %}
{% set update_url = url({'for':'admin.question.update','id':item.id}) %}
{% set delete_url = url({'for':'admin.question.delete','id':item.id}) %}
{% set restore_url = url({'for':'admin.question.restore','id':item.id}) %}
{% set review_url = url({'for':'admin.question.moderate','id':item.id}) %}
{% set moderate_url = url({'for':'admin.question.moderate','id':item.id}) %}
{% set answer_add_url = url({'for':'admin.answer.add'},{'question_id':item.id}) %}
{% set answer_list_url = url({'for':'admin.answer.list'},{'question_id':item.id}) %}
<tr>
@ -84,9 +84,9 @@
<button class="layui-btn layui-btn-sm">操作 <i class="layui-icon layui-icon-triangle-d"></i></button>
<ul>
{% if item.published == 1 %}
<li><a href="{{ review_url }}">审核问题</a></li>
<li><a href="{{ moderate_url }}">审核问题</a></li>
{% elseif item.published == 2 %}
<li><a href="{{ preview_url }}" target="_blank">预览问题</a></li>
<li><a href="{{ question_url }}" target="_blank">浏览问题</a></li>
<li><a href="{{ answer_add_url }}">回答问题</a></li>
{% endif %}
<li><a href="{{ edit_url }}">编辑问题</a></li>

View File

@ -4,7 +4,7 @@
<div class="layui-tab layui-tab-brief">
<ul class="layui-tab-title kg-tab-title">
<li class="layui-this">基本设置</li>
<li class="layui-this">微聊设置</li>
<li>在线客服</li>
</ul>
<div class="layui-tab-content">

View File

@ -2,8 +2,8 @@
<div class="layui-form-item">
<label class="layui-form-label">开启服务</label>
<div class="layui-input-block">
<input type="radio" name="enabled" value="1" title="是" lay-filter="status" {% if cs.enabled == 1 %}checked="checked"{% endif %}>
<input type="radio" name="enabled" value="0" title="否" lay-filter="status" {% if cs.enabled == 0 %}checked="checked"{% endif %}>
<input type="radio" name="enabled" value="1" title="是" {% if cs.enabled == 1 %}checked="checked"{% endif %}>
<input type="radio" name="enabled" value="0" title="否" {% if cs.enabled == 0 %}checked="checked"{% endif %}>
</div>
</div>
<div class="layui-form-item">

View File

@ -1,4 +1,11 @@
<form class="layui-form kg-form" method="POST" action="{{ url({'for':'admin.setting.im'}) }}">
<div class="layui-form-item">
<label class="layui-form-label">开启服务</label>
<div class="layui-input-block">
<input type="radio" name="enabled" value="1" title="是" {% if main.enabled == 1 %}checked="checked"{% endif %}>
<input type="radio" name="enabled" value="0" title="否" {% if main.enabled == 0 %}checked="checked"{% endif %}>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">应用名称</label>
<div class="layui-input-block">

View File

@ -5,6 +5,7 @@
{% set storage_region_display = vod.storage_type == 'fixed' ? 'display:block' : 'display:none' %}
{% set wmk_tpl_display = vod.wmk_enabled == 1 ? 'display:block' : 'display:none' %}
{% set key_anti_display = vod.key_anti_enabled == 1 ? 'display:block': 'display:none' %}
{% set video_quality = vod.video_quality|json_decode %}
<form class="layui-form kg-form" method="POST" action="{{ url({'for':'admin.setting.vod'}) }}">
<fieldset class="layui-elem-field layui-field-title">
@ -42,6 +43,14 @@
<input type="radio" name="audio_format" value="m4a" title="M4A" disabled="disabled" lay-filter="audio_format" {% if vod.audio_format == "m4a" %}checked="checked"{% endif %}>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">视频码率</label>
<div class="layui-input-block">
<input type="checkbox" name="video_quality[]" value="hd" title="高清" {% if 'hd' in video_quality %}checked="checked"{% endif %}>
<input type="checkbox" name="video_quality[]" value="sd" title="标清" {% if 'sd' in video_quality %}checked="checked"{% endif %}>
<input type="checkbox" name="video_quality[]" value="fd" title="极速" {% if 'fd' in video_quality %}checked="checked"{% endif %}>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">开启水印</label>
<div class="layui-input-block">

View File

@ -44,7 +44,7 @@
</thead>
<tbody>
{% for item in pager.items %}
{% set preview_url = url({'for':'home.topic.show','id':item.id}) %}
{% set topic_url = url({'for':'home.topic.show','id':item.id}) %}
{% set edit_url = url({'for':'admin.topic.edit','id':item.id}) %}
{% set update_url = url({'for':'admin.topic.update','id':item.id}) %}
{% set delete_url = url({'for':'admin.topic.delete','id':item.id}) %}
@ -60,7 +60,9 @@
<div class="kg-dropdown">
<button class="layui-btn layui-btn-sm">操作 <i class="layui-icon layui-icon-triangle-d"></i></button>
<ul>
<li><a href="{{ preview_url }}" target="_blank">预览</a></li>
{% if item.published == 1 %}
<li><a href="{{ topic_url }}" target="_blank">浏览</a></li>
{% endif %}
<li><a href="{{ edit_url }}">编辑</a></li>
{% if item.deleted == 0 %}
<li><a href="javascript:" class="kg-delete" data-url="{{ delete_url }}">删除</a></li>

View File

@ -52,7 +52,7 @@
</thead>
<tbody>
{% for item in pager.items %}
{% set preview_url = url({'for':'home.user.show','id':item.id}) %}
{% set user_url = url({'for':'home.user.show','id':item.id}) %}
{% set online_url = url({'for':'admin.user.online','id':item.id}) %}
{% set edit_url = url({'for':'admin.user.edit','id':item.id}) %}
<tr>
@ -61,7 +61,7 @@
</td>
<td>
<p>
<a href="{{ preview_url }}" title="{{ item.about }}" target="_blank">{{ item.name }}</a>{{ item.id }}{{ status_info(item) }}
<a href="{{ edit_url }}">{{ item.name }}</a>{{ item.id }}{{ status_info(item) }}
</p>
<p class="meta">
<span>性别:{{ gender_info(item.gender) }}</span>
@ -82,7 +82,7 @@
<div class="kg-dropdown">
<button class="layui-btn layui-btn-sm">操作 <i class="layui-icon layui-icon-triangle-d"></i></button>
<ul>
<li><a href="{{ preview_url }}" target="_blank">用户主页</a></li>
<li><a href="{{ user_url }}" target="_blank">用户主页</a></li>
<li><a href="javascript:" class="kg-online" data-url="{{ online_url }}">在线记录</a></li>
<li><a href="{{ edit_url }}">编辑用户</a></li>
</ul>

View File

@ -9,6 +9,7 @@ namespace App\Http\Home\Controllers;
use App\Http\Home\Services\Answer as AnswerService;
use App\Http\Home\Services\Question as QuestionService;
use App\Models\Answer as AnswerModel;
use App\Services\Logic\Answer\AnswerAccept as AnswerAcceptService;
use App\Services\Logic\Answer\AnswerCreate as AnswerCreateService;
use App\Services\Logic\Answer\AnswerDelete as AnswerDeleteService;
@ -56,14 +57,10 @@ class AnswerController extends Controller
$answer = $service->handle($id);
if ($answer['deleted'] == 1) {
if ($answer['published'] != AnswerModel::PUBLISH_APPROVED) {
return $this->notFound();
}
if ($answer['me']['owned'] == 0) {
return $this->forbidden();
}
$questionId = $answer['question']['id'];
$location = $this->url->get(
@ -116,14 +113,17 @@ class AnswerController extends Controller
$answer = $service->handle();
$location = $this->url->get([
'for' => 'home.answer.show',
'id' => $answer->id,
]);
if ($answer->published == AnswerModel::PUBLISH_APPROVED) {
$location = $this->url->get(['for' => 'home.question.show', 'id' => $answer->question_id]);
$msg = '发布回答成功';
} else {
$location = $this->url->get(['for' => 'home.uc.answers']);
$msg = '创建回答成功,管理员审核后对外可见';
}
$content = [
'location' => $location,
'msg' => '创建回答成功',
'msg' => $msg,
];
return $this->jsonSuccess($content);
@ -138,14 +138,17 @@ class AnswerController extends Controller
$answer = $service->handle($id);
$location = $this->url->get([
'for' => 'home.answer.show',
'id' => $answer->id,
]);
if ($answer->published == AnswerModel::PUBLISH_APPROVED) {
$location = $this->url->get(['for' => 'home.question.show', 'id' => $answer->question_id]);
$msg = '更新回答成功';
} else {
$location = $this->url->get(['for' => 'home.uc.answers']);
$msg = '更新回答成功,管理员审核后对外可见';
}
$content = [
'location' => $location,
'msg' => '更新回答成功',
'msg' => $msg,
];
return $this->jsonSuccess($content);

View File

@ -9,6 +9,7 @@ namespace App\Http\Home\Controllers;
use App\Http\Home\Services\Article as ArticleService;
use App\Http\Home\Services\ArticleQuery as ArticleQueryService;
use App\Models\Article as ArticleModel;
use App\Services\Logic\Article\ArticleCreate as ArticleCreateService;
use App\Services\Logic\Article\ArticleDelete as ArticleDeleteService;
use App\Services\Logic\Article\ArticleFavorite as ArticleFavoriteService;
@ -67,7 +68,7 @@ class ArticleController extends Controller
$article = $service->getArticleModel();
$xmTags = $service->getXmTags(0);
$this->seo->prependTitle('写文章');
$this->seo->prependTitle('写文章');
$this->view->pick('article/edit');
$this->view->setVar('source_types', $sourceTypes);
@ -102,14 +103,10 @@ class ArticleController extends Controller
$article = $service->handle($id);
if ($article['deleted'] == 1) {
if ($article['published'] != ArticleModel::PUBLISH_APPROVED) {
return $this->notFound();
}
if ($article['me']['owned'] == 0) {
return $this->forbidden();
}
$this->seo->prependTitle(['专栏', $article['title']]);
$this->seo->setDescription($article['summary']);
@ -138,14 +135,17 @@ class ArticleController extends Controller
$article = $service->handle();
$location = $this->url->get([
'for' => 'home.article.show',
'id' => $article->id,
]);
if ($article->published == ArticleModel::PUBLISH_APPROVED) {
$location = $this->url->get(['for' => 'home.article.show', 'id' => $article->id]);
$msg = '发布文章成功';
} else {
$location = $this->url->get(['for' => 'home.uc.articles']);
$msg = '创建文章成功,管理员审核后对外可见';
}
$content = [
'location' => $location,
'msg' => '创建文章成功',
'msg' => $msg,
];
return $this->jsonSuccess($content);
@ -160,14 +160,17 @@ class ArticleController extends Controller
$article = $service->handle($id);
$location = $this->url->get([
'for' => 'home.article.show',
'id' => $article->id,
]);
if ($article->published == ArticleModel::PUBLISH_APPROVED) {
$location = $this->url->get(['for' => 'home.article.show', 'id' => $article->id]);
$msg = '更新文章成功';
} else {
$location = $this->url->get(['for' => 'home.uc.articles']);
$msg = '更新文章成功,管理员审核后对外可见';
}
$content = [
'location' => $location,
'msg' => '更新文章成功',
'msg' => $msg,
];
return $this->jsonSuccess($content);

View File

@ -43,10 +43,14 @@ class ChapterController extends Controller
$chapter = $service->handle($id);
if ($chapter['deleted'] == 1) {
if ($chapter['published'] == 0) {
return $this->notFound();
}
if ($this->authUser->id == 0) {
return $this->response->redirect(['for' => 'home.account.login']);
}
if ($chapter['me']['owned'] == 0) {
return $this->forbidden();
}

View File

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

View File

@ -77,7 +77,7 @@ class CourseController extends Controller
$course = $service->handle($id);
if ($course['deleted'] == 1) {
if ($course['published'] == 0) {
return $this->notFound();
}

View File

@ -40,7 +40,7 @@ class HelpController extends Controller
$help = $service->handle($id);
if ($help['deleted'] == 1) {
if ($help['published'] == 0) {
return $this->notFound();
}

View File

@ -51,7 +51,7 @@ class ImGroupController extends Controller
$group = $service->getGroup($id);
if ($group['deleted'] == 1) {
if ($group['published'] == 0) {
return $this->notFound();
}

View File

@ -26,7 +26,7 @@ class PackageController extends Controller
$package = $service->handle($id);
if ($package['deleted'] == 1) {
if ($package['published'] == 0) {
return $this->notFound();
}

View File

@ -25,7 +25,7 @@ class PageController extends Controller
$page = $service->handle($id);
if ($page['deleted'] == 1) {
if ($page['published'] == 0) {
return $this->notFound();
}

View File

@ -68,7 +68,7 @@ class PointGiftController extends Controller
$gift = $service->handle($id);
if ($gift['deleted'] == 1) {
if ($gift['published'] == 0) {
return $this->notFound();
}

View File

@ -9,6 +9,7 @@ namespace App\Http\Home\Controllers;
use App\Http\Home\Services\Question as QuestionService;
use App\Http\Home\Services\QuestionQuery as QuestionQueryService;
use App\Models\Question as QuestionModel;
use App\Services\Logic\Question\AnswerList as AnswerListService;
use App\Services\Logic\Question\QuestionCreate as QuestionCreateService;
use App\Services\Logic\Question\QuestionDelete as QuestionDeleteService;
@ -68,7 +69,7 @@ class QuestionController extends Controller
$xmTags = $service->getXmTags(0);
$this->seo->prependTitle('提问');
$this->seo->prependTitle('提问');
$this->view->pick('question/edit');
$this->view->setVar('question', $question);
@ -101,14 +102,10 @@ class QuestionController extends Controller
$question = $service->handle($id);
if ($question['deleted'] == 1) {
if ($question['published'] != QuestionModel::PUBLISH_APPROVED) {
return $this->notFound();
}
if ($question['me']['owned'] == 0) {
return $this->forbidden();
}
$this->seo->prependTitle(['问答', $question['title']]);
$this->seo->setDescription($question['summary']);
@ -157,14 +154,17 @@ class QuestionController extends Controller
$question = $service->handle();
$location = $this->url->get([
'for' => 'home.question.show',
'id' => $question->id,
]);
if ($question->published == QuestionModel::PUBLISH_APPROVED) {
$location = $this->url->get(['for' => 'home.question.show', 'id' => $question->id]);
$msg = '发布问题成功';
} else {
$location = $this->url->get(['for' => 'home.uc.questions']);
$msg = '创建问题成功,管理员审核后对外可见';
}
$content = [
'location' => $location,
'msg' => '创建问题成功',
'msg' => $msg,
];
return $this->jsonSuccess($content);
@ -179,14 +179,17 @@ class QuestionController extends Controller
$question = $service->handle($id);
$location = $this->url->get([
'for' => 'home.question.show',
'id' => $question->id,
]);
if ($question->published == QuestionModel::PUBLISH_APPROVED) {
$location = $this->url->get(['for' => 'home.question.show', 'id' => $question->id]);
$msg = '更新问题成功';
} else {
$location = $this->url->get(['for' => 'home.uc.questions']);
$msg = '更新问题成功,管理员审核后对外可见';
}
$content = [
'location' => $location,
'msg' => '更新问题成功',
'msg' => $msg,
];
return $this->jsonSuccess($content);

View File

@ -26,7 +26,7 @@ class TopicController extends Controller
$topic = $service->handle($id);
if ($topic['deleted'] == 1) {
if ($topic['published'] == 0) {
return $this->notFound();
}

View File

@ -2,7 +2,7 @@
{% block content %}
{% set title = article.id > 0 ? '编辑文章' : '写文章' %}
{% set title = article.id > 0 ? '编辑文章' : '写文章' %}
{% set action_url = article.id > 0 ? url({'for':'home.article.update','id':article.id}) : url({'for':'home.article.create'}) %}
{% set source_url_display = article.source_type == 1 ? 'display:none;' : 'display:block;' %}
@ -58,20 +58,6 @@
</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">关闭评论</label>
<div class="layui-input-block">
<input type="radio" name="closed" value="1" title="是" {% if article.closed == 1 %}checked="checked"{% endif %}>
<input type="radio" name="closed" value="0" title="否" {% if article.closed == 0 %}checked="checked"{% endif %}>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">仅我可见</label>
<div class="layui-input-block">
<input type="radio" name="private" value="1" title="是" {% if article.private == 1 %}checked="checked"{% endif %}>
<input type="radio" name="private" value="0" title="否" {% if article.private == 0 %}checked="checked"{% endif %}>
</div>
</div>
<div class="layui-form-item last-form-item">
<div class="layui-input-block">
<button class="layui-btn layui-btn-fluid kg-submit" lay-submit="true" lay-filter="go">确认发布</button>

View File

@ -21,7 +21,7 @@
<i class="layui-icon layui-icon-video"></i>
<span class="title">{{ lesson.title }}</span>
{% if lesson.free == 1 %}
<span class="layui-badge free-badge">免费</span>
<span class="layui-badge free-badge">试听</span>
{% endif %}
{% if lesson.me.duration > 0 %}
<span class="study-time" title="学习时长:{{ lesson.me.duration|duration }}"><i class="layui-icon layui-icon-time"></i></span>
@ -37,7 +37,7 @@
<i class="layui-icon layui-icon-read"></i>
<span class="title">{{ lesson.title }}</span>
{% if lesson.free == 1 %}
<span class="layui-badge free-badge">免费</span>
<span class="layui-badge free-badge">试读</span>
{% endif %}
{% if lesson.me.duration > 0 %}
<span class="study-time" title="学习时长:{{ lesson.me.duration|duration }}"><i class="layui-icon layui-icon-time"></i></span>
@ -50,7 +50,7 @@
<i class="layui-icon layui-icon-user"></i>
<span class="title">{{ lesson.title }}</span>
{% if lesson.free == 1 %}
<span class="layui-badge free-badge">免费</span>
<span class="layui-badge free-badge">试听</span>
{% endif %}
<span class="live" title="{{ date('Y-m-d H:i',lesson.attrs.start_time) }}">{{ offline_status_info(lesson) }}</span>
</a>

View File

@ -1,15 +1,11 @@
{% if course.me.owned == 0 and course.market_price > 0 %}
{% if course.me.allow_order == 1 %}
{% set order_url = url({'for':'home.order.confirm'},{'item_id':course.id,'item_type':1}) %}
{% set live_model_ok = course.model == 2 and course.attrs.end_date < date('Y-m-d') %}
{% set other_model_ok = course.model != 2 %}
{% if live_model_ok or other_model_ok %}
<div class="sidebar wrap">
<button class="layui-btn layui-btn-fluid layui-bg-red btn-buy" data-url="{{ order_url }}">立即购买</button>
</div>
{% endif %}
<div class="sidebar wrap">
<button class="layui-btn layui-btn-fluid layui-bg-red btn-buy" data-url="{{ order_url }}">立即购买</button>
</div>
{% endif %}
{% if course.market_price == 0 %}
{% if course.me.allow_reward == 1 %}
<div class="sidebar">
<div class="layui-card">
<div class="layui-card-header">赞赏支持</div>

View File

@ -35,7 +35,7 @@
<li class="layui-nav-item">
<a href="{{ url({'for':'home.vip.index'}) }}" class="nav-vip"><i class="layui-icon layui-icon-diamond"></i> 会员</a>
</li>
{% if im_info.cs.enabled == 1 %}
{% if im_info.main.enabled == 1 %}
<li class="layui-nav-item">
<a href="{{ url({'for':'home.im.index'}) }}" class="nav-im" target="im"><i class="layui-icon layui-icon-chat"></i> 微聊</a>
</li>

View File

@ -68,7 +68,6 @@
<div class="connect-list">
<table class="layui-table">
<tr>
<td>序号</td>
<td>提供方</td>
<td>用户信息</td>
<td>创建日期</td>
@ -77,11 +76,10 @@
{% for connect in connects %}
{% set url = url({'for':'home.uc.unconnect','id':connect.id}) %}
<tr>
<td>{{ loop.index }}</td>
<td>{{ connect_provider(connect) }}</td>
<td>{{ connect_user(connect) }}</td>
<td>{{ date('Y-m-d H:i',connect.create_time) }}</td>
<td><a class="layui-btn layui-btn-danger layui-btn-sm kg-delete" href="javascript:" data-url="{{ url }}" data-tips="确定要解除绑定吗?">解</a></td>
<td><a class="layui-btn layui-btn-danger layui-btn-sm kg-delete" href="javascript:" data-url="{{ url }}" data-tips="确定要解除绑定吗?">解绑</a></td>
</tr>
{% endfor %}
</table>

View File

@ -22,6 +22,7 @@
{% if pager.total_pages > 0 %}
<table class="layui-table review-table">
<colgroup>
<col>
<col>
<col>
<col width="15%">
@ -30,24 +31,26 @@
<tr>
<th>内容</th>
<th>点赞</th>
<th>评论</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for item in pager.items %}
{% set show_url = url({'for':'home.answer.show','id':item.id}) %}
{% set question_url = url({'for':'home.question.show','id':item.question.id}) %}
{% set edit_url = url({'for':'home.answer.edit','id':item.id}) %}
{% set delete_url = url({'for':'home.answer.delete','id':item.id}) %}
<tr>
<td>
<p>提问:<a href="{{ show_url }}" target="_blank">{{ item.question.title }}</a></p>
<p>提问:<a href="{{ question_url }}" target="_blank">{{ item.question.title }}</a></p>
<p>回答:{{ substr(item.summary,0,32) }}</p>
<p class="meta">
创建<span class="layui-badge layui-bg-gray">{{ item.create_time|time_ago }}</span>
时间<span class="layui-badge layui-bg-gray">{{ item.create_time|time_ago }}</span>
状态:<span class="layui-badge layui-bg-gray">{{ publish_status(item.published) }}</span>
</p>
</td>
<td>{{ item.like_count }}</td>
<td>{{ item.comment_count }}</td>
<td>
<a href="{{ edit_url }}" class="layui-btn layui-btn-xs layui-bg-blue">修改</a>
<a href="javascript:" class="layui-btn layui-btn-xs layui-bg-red kg-delete" data-url="{{ delete_url }}">删除</a>

View File

@ -25,13 +25,15 @@
<col>
<col>
<col>
<col>
<col width="15%">
</colgroup>
<thead>
<tr>
<th>文章</th>
<th>评论</th>
<th>浏览</th>
<th>点赞</th>
<th>评论</th>
<th>操作</th>
</tr>
</thead>
@ -42,17 +44,20 @@
{% set delete_url = url({'for':'home.article.delete','id':item.id}) %}
<tr>
<td>
<p>
标题:<a href="{{ show_url }}" target="_blank">{{ item.title }}</a>
</p>
{% if item.published == 2 %}
<p>标题:<a href="{{ show_url }}" target="_blank">{{ item.title }}</a></p>
{% else %}
<p>标题:<a href="{{ edit_url }}" target="_blank">{{ item.title }}</a></p>
{% endif %}
<p class="meta">
来源:<span class="layui-badge layui-bg-gray">{{ source_type(item.source_type) }}</span>
时间:<span class="layui-badge layui-bg-gray">{{ item.create_time|time_ago }}</span>
状态:<span class="layui-badge layui-bg-gray">{{ publish_status(item.published) }}</span>
</p>
</td>
<td>{{ item.comment_count }}</td>
<td>{{ item.view_count }}</td>
<td>{{ item.like_count }}</td>
<td>{{ item.comment_count }}</td>
<td class="center">
<a href="{{ edit_url }}" class="layui-btn layui-btn-xs layui-bg-blue">编辑</a>
<a href="javascript:" class="layui-btn layui-btn-xs layui-bg-red kg-delete" data-url="{{ delete_url }}">删除</a>

View File

@ -14,14 +14,12 @@
{% if pager.total_pages > 0 %}
<table class="layui-table consult-table">
<colgroup>
<col>
<col>
<col width="20%">
</colgroup>
<thead>
<tr>
<th>内容</th>
<th>时间</th>
<th>操作</th>
</tr>
</thead>
@ -35,8 +33,8 @@
<td>
<p class="content layui-elip" title="{{ item.question }}">咨询:{{ item.question }}</p>
<p class="content layui-elip" title="{{ item.answer }}">回复:{{ item.answer }}</p>
<p class="time">时间:{{ item.create_time|time_ago }}</p>
</td>
<td>{{ date('Y-m-d',item.create_time) }}</td>
<td>
<button class="layui-btn layui-btn-xs layui-bg-green btn-show-consult" data-url="{{ show_url }}">详情</button>
<button class="layui-btn layui-btn-xs layui-bg-blue btn-edit-consult" data-url="{{ edit_url }}">修改</button>

View File

@ -26,12 +26,14 @@
<col>
<col>
<col>
<col>
</colgroup>
<thead>
<tr>
<th>问题</th>
<th>回答</th>
<th>浏览</th>
<th>点赞</th>
<th>回答</th>
<th>操作</th>
</tr>
</thead>
@ -42,14 +44,19 @@
{% set delete_url = url({'for':'home.question.delete','id':item.id}) %}
<tr>
<td>
<p>标题:<a href="{{ show_url }}" target="_blank">{{ item.title }}</a></p>
{% if item.published == 2 %}
<p>标题:<a href="{{ show_url }}" target="_blank">{{ item.title }}</a></p>
{% else %}
<p>标题:<a href="{{ edit_url }}" target="_blank">{{ item.title }}</a></p>
{% endif %}
<p class="meta">
创建:<span class="layui-badge layui-bg-gray">{{ item.create_time|time_ago }}</span>
时间<span class="layui-badge layui-bg-gray">{{ item.create_time|time_ago }}</span>
状态:<span class="layui-badge layui-bg-gray">{{ publish_status(item.published) }}</span>
</p>
</td>
<td>{{ item.answer_count }}</td>
<td>{{ item.view_count }}</td>
<td>{{ item.like_count }}</td>
<td>{{ item.answer_count }}</td>
<td class="center">
<a href="{{ edit_url }}" class="layui-btn layui-btn-xs layui-bg-blue">编辑</a>
<a href="javascript:" class="layui-btn layui-btn-xs layui-bg-red kg-delete" data-url="{{ delete_url }}">删除</a>

View File

@ -34,6 +34,7 @@
<td>
<p class="title layui-elip">课程:<a href="{{ course_url }}" target="_blank">{{ item.course.title }}</a></p>
<p class="content layui-elip" title="{{ item.content }}">评价:{{ item.content }}</p>
<p class="time">时间:{{ item.create_time|time_ago }}</p>
</td>
<td>
<p class="rating">内容实用:{{ "%0.1f"|format(item.rating1) }}</p>

View File

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

View File

@ -361,8 +361,8 @@ class Course extends Repository
public function countUsers($courseId)
{
return (int)CourseUserModel::count([
'conditions' => 'course_id = :course_id: AND deleted = 0',
'bind' => ['course_id' => $courseId],
'conditions' => 'course_id = ?1 AND role_type = ?2 AND deleted = 0',
'bind' => [1 => $courseId, 2 => CourseUserModel::ROLE_STUDENT],
]);
}

View File

@ -122,7 +122,7 @@ class Tag extends Repository
{
return (int)CourseTagModel::count([
'conditions' => 'tag_id = :tag_id:',
'bind' => ['tag' => $tagId],
'bind' => ['tag_id' => $tagId],
]);
}

View File

@ -59,9 +59,9 @@ class ChapterVod extends Service
$vod = $chapterRepo->findChapterVod($chapterId);
$result = [
'od' => ['url' => ''],
'hd' => ['url' => ''],
'sd' => ['url' => ''],
'fd' => ['url' => ''],
];
if (!empty($vod->file_remote)) {
@ -73,7 +73,7 @@ class ChapterVod extends Service
protected function getDefinitionType($height)
{
$default = 'od';
$default = 'sd';
$vodTemplates = $this->getVodTemplates();
@ -86,15 +86,12 @@ class ChapterVod extends Service
return $default;
}
/**
* 腾讯云播放器只支持[od|hd|sd],实际转码速率[hd|sd|fd],重新映射清晰度
*/
protected function getVodTemplates()
{
return [
'od' => ['height' => 720, 'rate' => 1800],
'hd' => ['height' => 540, 'rate' => 1000],
'sd' => ['height' => 360, 'rate' => 400],
'hd' => ['height' => 720, 'rate' => 1800],
'sd' => ['height' => 540, 'rate' => 1000],
'fd' => ['height' => 360, 'rate' => 400],
];
}

View File

@ -10,6 +10,7 @@ namespace App\Services\Logic\Article;
use App\Models\Article as ArticleModel;
use App\Services\Logic\ArticleTrait;
use App\Services\Logic\Service as LogicService;
use App\Validators\Article as ArticleValidator;
class ArticleUpdate extends LogicService
{
@ -23,26 +24,16 @@ class ArticleUpdate extends LogicService
$article = $this->checkArticle($id);
$validator = new ArticleValidator();
$validator->checkIfAllowEdit($article);
$data = $this->handlePostData($post);
if ($article->published == ArticleModel::PUBLISH_REJECTED) {
$data['published'] = ArticleModel::PUBLISH_PENDING;
}
/**
* 当通过审核后,禁止修改部分文章属性
*/
if ($article->published == ArticleModel::PUBLISH_APPROVED) {
unset(
$data['title'],
$data['content'],
$data['source_type'],
$data['source_url'],
$data['category_id'],
$post['xm_tag_ids'],
);
}
$article->update($data);
if (isset($post['xm_tag_ids'])) {

View File

@ -37,6 +37,8 @@ class CourseInfo extends LogicService
$me = [
'plan_id' => 0,
'allow_order' => 0,
'allow_reward' => 0,
'joined' => 0,
'owned' => 0,
'reviewed' => 0,
@ -47,6 +49,21 @@ class CourseInfo extends LogicService
$me['joined'] = $this->joinedCourse ? 1 : 0;
$me['owned'] = $this->ownedCourse ? 1 : 0;
$caseOwned = $this->ownedCourse == false;
$casePrice = $course->market_price > 0;
/**
* 过期直播不允许购买
*/
if ($course->model == CourseModel::MODEL_LIVE) {
$caseModel = $course->attrs['end_date'] < date('Y-m-d');
} else {
$caseModel = true;
}
$me['allow_order'] = $caseOwned && $casePrice && $caseModel ? 1 : 0;
$me['allow_reward'] = $course->market_price == 0 ? 1 : 0;
if ($user->id > 0) {
$favoriteRepo = new CourseFavoriteRepo();

View File

@ -632,21 +632,33 @@ class Vod extends Service
*/
public function getVideoTransTemplates()
{
$hls = [
100210 => ['height' => 360, 'bit_rate' => 400, 'frame_rate' => 25],
100220 => ['height' => 540, 'bit_rate' => 1000, 'frame_rate' => 25],
100230 => ['height' => 720, 'bit_rate' => 1800, 'frame_rate' => 25],
$hlsTemplates = [
100210 => ['quality' => 'fd', 'height' => 360, 'bit_rate' => 400, 'frame_rate' => 25],
100220 => ['quality' => 'sd', 'height' => 540, 'bit_rate' => 1000, 'frame_rate' => 25],
100230 => ['quality' => 'hd', 'height' => 720, 'bit_rate' => 1800, 'frame_rate' => 25],
];
$mp4 = [
100010 => ['height' => 360, 'bit_rate' => 400, 'frame_rate' => 25],
100020 => ['height' => 540, 'bit_rate' => 1000, 'frame_rate' => 25],
100030 => ['height' => 720, 'bit_rate' => 1800, 'frame_rate' => 25],
$mp4Templates = [
100010 => ['quality' => 'fd', 'height' => 360, 'bit_rate' => 400, 'frame_rate' => 25],
100020 => ['quality' => 'sd', 'height' => 540, 'bit_rate' => 1000, 'frame_rate' => 25],
100030 => ['quality' => 'hd', 'height' => 720, 'bit_rate' => 1800, 'frame_rate' => 25],
];
$format = $this->settings['video_format'];
$format = $this->settings['video_format'] ?: 'hls';
return $format == 'hls' ? $hls : $mp4;
$quality = !empty($this->settings['video_quality']) ? json_decode($this->settings['video_quality'], true) : ['sd'];
$templates = $format == 'hls' ? $hlsTemplates : $mp4Templates;
$result = [];
foreach ($templates as $key => $item) {
if (in_array($item['quality'], $quality)) {
$result[$key] = $item;
}
}
return $result;
}
/**
@ -656,16 +668,29 @@ class Vod extends Service
*/
public function getAudioTransTemplates()
{
$m4a = [
1110 => ['bit_rate' => 48, 'sample_rate' => 44100],
1120 => ['bit_rate' => 96, 'sample_rate' => 44100],
$mp3Templates = [
1010 => ['quality' => 'sd', 'bit_rate' => 128, 'sample_rate' => 44100],
];
$mp3 = [
1010 => ['bit_rate' => 128, 'sample_rate' => 44100],
$m4aTemplates = [
1120 => ['quality' => 'sd', 'bit_rate' => 96, 'sample_rate' => 44100],
];
return $this->settings['audio_format'] == 'm4a' ? $m4a : $mp3;
$format = $this->settings['audio_format'] ?: 'mp3';
$quality = !empty($this->settings['audio_quality']) ? json_decode($this->settings['audio_quality'], true) : ['sd'];
$templates = $format == 'mp3' ? $mp3Templates : $m4aTemplates;
$result = [];
foreach ($templates as $key => $item) {
if (in_array($item['quality'], $quality)) {
$result[$key] = $item;
}
}
return $result;
}
/**

View File

@ -170,4 +170,13 @@ class Article extends Validator
}
}
public function checkIfAllowEdit(ArticleModel $article)
{
$approved = $article->published == ArticleModel::PUBLISH_APPROVED;
if ($approved) {
throw new BadRequestException('article.edit_not_allowed');
}
}
}

View File

@ -57,4 +57,11 @@ class ChapterVod extends Validator
return $value;
}
public function checkRemoteFile($hd, $sd, $fd)
{
if (empty($hd) && empty($sd) && empty($fd)) {
throw new BadRequestException('chapter_vod.remote_file_required');
}
}
}

View File

@ -68,7 +68,7 @@ class Order extends Validator
$course = $courseRepo->findById($itemId);
if (!$course) {
if (!$course || $course->published == 0) {
throw new BadRequestException('order.item_not_found');
}
@ -81,7 +81,7 @@ class Order extends Validator
$package = $packageRepo->findById($itemId);
if (!$package) {
if (!$package || $package->published == 0) {
throw new BadRequestException('order.item_not_found');
}
@ -94,7 +94,7 @@ class Order extends Validator
$vip = $vipRepo->findById($itemId);
if (!$vip) {
if (!$vip || $vip->deleted == 1) {
throw new BadRequestException('order.item_not_found');
}

View File

@ -128,6 +128,8 @@ $error['article.invalid_publish_status'] = '无效的发布状态';
$error['article.invalid_private_status'] = '无效的私有状态';
$error['article.invalid_close_status'] = '无效的关闭状态';
$error['article.invalid_reject_reason'] = '无效的拒绝理由';
$error['article.edit_not_allowed'] = '当前不允许编辑文章';
$error['article.delete_not_allowed'] = '当前不允许删除文章';
/**
* 问答相关
@ -267,6 +269,7 @@ $error['chapter_vod.invalid_duration'] = '无效的视频时长';
$error['chapter_vod.invalid_file_id'] = '无效的文件编号';
$error['chapter_vod.invalid_file_url'] = '无效的文件地址';
$error['chapter_vod.invalid_file_ext'] = '无效的文件格式目前只支持mp4m3u8';
$error['chapter_vod.remote_file_required'] = '请填写远程播放地址';
/**
* 直播相关

View File

@ -684,7 +684,7 @@ final class V20210403184518 extends AbstractMigration
[
'section' => 'site',
'item_key' => 'copyright',
'item_value' => '2016-2020 深圳市酷瓜软件有限公司',
'item_value' => '深圳市酷瓜软件有限公司',
],
[
'section' => 'site',

View File

@ -0,0 +1,85 @@
<?php
/**
* @copyright Copyright (c) 2021 深圳市酷瓜软件有限公司
* @license https://opensource.org/licenses/GPL-2.0
* @link https://www.koogua.com
*/
use Phinx\Migration\AbstractMigration;
final class V20210809153030 extends AbstractMigration
{
public function up()
{
$this->handleVodSetting();
$this->handleImSetting();
$this->handleRemotePlayUrl();
}
protected function handleVodSetting()
{
$rows = [
[
'section' => 'vod',
'item_key' => 'video_quality',
'item_value' => json_encode(['hd', 'sd', 'fd']),
],
[
'section' => 'vod',
'item_key' => 'audio_quality',
'item_value' => json_encode(['sd']),
],
];
$this->table('kg_setting')->insert($rows)->save();
}
protected function handleImSetting()
{
$row = [
'section' => 'im.main',
'item_key' => 'enabled',
'item_value' => '1',
];
$this->table('kg_setting')->insert($row)->saveData();
}
protected function handleRemotePlayUrl()
{
$rows = $this->getQueryBuilder()
->select('*')
->from('kg_chapter_vod')
->where(['file_remote !=' => '[]'])
->execute();
if ($rows->count() == 0) return;
foreach ($rows as $row) {
$value = json_decode($row['file_remote'], true);
if (isset($value['od']['url'])) {
$newValue = json_encode([
'hd' => ['url' => $value['od']['url']],
'sd' => ['url' => $value['hd']['url']],
'fd' => ['url' => $value['sd']['url']],
]);
$this->updateFileRemote($row['id'], $newValue);
}
}
}
protected function updateFileRemote($id, $fileRemote)
{
$this->getQueryBuilder()
->update('kg_chapter_vod')
->where(['id' => $id])
->set('file_remote', $fileRemote)
->execute();
}
}

View File

@ -69,7 +69,7 @@ layui.use(['jquery', 'element', 'layer'], function () {
mime: file.type,
size: file.size,
path: keyName,
md5: data.ETag.replace(/"/g, '')
md5: data.ETag ? data.ETag.replace(/"/g, '') : ''
},
chapter_id: chapterId,
}, function () {

View File

@ -17,6 +17,7 @@ layui.use(['jquery', 'helper'], function () {
{name: 'od', label: '原画'},
{name: 'hd', label: '高清'},
{name: 'sd', label: '标清'},
{name: 'fd', label: '极速'},
];
var quality = [];

View File

@ -13,9 +13,9 @@ layui.use(['jquery', 'helper'], function () {
var playUrls = JSON.parse($('input[name="chapter.play_urls"]').val());
var rates = [
{name: 'od', label: '原画'},
{name: 'hd', label: '高清'},
{name: 'sd', label: '标清'},
{name: 'fd', label: '极速'},
];
var quality = [];

View File

@ -84,12 +84,15 @@ $scheduler->php($script, $bin, ['--task' => 'revoke_vip', '--action' => 'main'])
$scheduler->php($script, $bin, ['--task' => 'sync_app_info', '--action' => 'main'])
->daily(3, 13);
$scheduler->php($script, $bin, ['--task' => 'sync_tag_count', '--action' => 'main'])
$scheduler->php($script, $bin, ['--task' => 'sync_tag_stat', '--action' => 'main'])
->daily(3, 17);
$scheduler->php($script, $bin, ['--task' => 'close_question', '--action' => 'main'])
$scheduler->php($script, $bin, ['--task' => 'sync_course_stat', '--action' => 'main'])
->daily(3, 19);
$scheduler->php($script, $bin, ['--task' => 'close_question', '--action' => 'main'])
->daily(3, 23);
$scheduler->php($script, $bin, ['--task' => 'sitemap', '--action' => 'main'])
->daily(4, 3);