1.更改模块继承基类
2.升级layui到2.6.8 3.升级腾讯云播放器 4.点播增加外链支持
@ -2,9 +2,9 @@
|
||||
|
||||
namespace App\Builders;
|
||||
|
||||
use Phalcon\Mvc\User\Component;
|
||||
use Phalcon\Di\Injectable;
|
||||
|
||||
class Builder extends Component
|
||||
class Builder extends Injectable
|
||||
{
|
||||
|
||||
public function objects(array $items)
|
||||
|
@ -3,9 +3,9 @@
|
||||
namespace App\Caches;
|
||||
|
||||
use Phalcon\Cache\Backend\Redis as RedisCache;
|
||||
use Phalcon\Mvc\User\Component;
|
||||
use Phalcon\Di\Injectable;
|
||||
|
||||
abstract class Cache extends Component
|
||||
abstract class Cache extends Injectable
|
||||
{
|
||||
|
||||
/**
|
||||
|
@ -3,9 +3,9 @@
|
||||
namespace App\Caches;
|
||||
|
||||
use App\Library\Cache\Backend\Redis as RedisCache;
|
||||
use Phalcon\Mvc\User\Component;
|
||||
use Phalcon\Di\Injectable;
|
||||
|
||||
abstract class Counter extends Component
|
||||
abstract class Counter extends Injectable
|
||||
{
|
||||
|
||||
/**
|
||||
|
@ -63,7 +63,6 @@ class VodEventTask extends Task
|
||||
* 获取不到时长视为失败
|
||||
*/
|
||||
if ($duration == 0) {
|
||||
$attrs['file']['id'] = $fileId;
|
||||
$attrs['file']['status'] = ChapterModel::FS_FAILED;
|
||||
$chapter->update(['attrs' => $attrs]);
|
||||
return;
|
||||
@ -77,7 +76,6 @@ class VodEventTask extends Task
|
||||
$vodService->createTransVideoTask($fileId);
|
||||
}
|
||||
|
||||
$attrs['file']['id'] = $fileId;
|
||||
$attrs['file']['status'] = ChapterModel::FS_TRANSLATING;
|
||||
$attrs['duration'] = (int)$duration;
|
||||
|
||||
@ -106,7 +104,6 @@ class VodEventTask extends Task
|
||||
* 获取不到处理结果视为失败
|
||||
*/
|
||||
if (empty($processResult)) {
|
||||
$attrs['file']['id'] = $fileId;
|
||||
$attrs['file']['status'] = ChapterModel::FS_FAILED;
|
||||
$chapter->update(['attrs' => $attrs]);
|
||||
return;
|
||||
|
@ -124,9 +124,13 @@ class ChapterController extends Controller
|
||||
switch ($course->model) {
|
||||
case CourseModel::MODEL_VOD:
|
||||
$vod = $contentService->getChapterVod($chapter->id);
|
||||
$playUrls = $contentService->getPlayUrls($chapter->id);
|
||||
$cosPlayUrls = $contentService->getCosPlayUrls($chapter->id);
|
||||
$remotePlayUrls = $contentService->getRemotePlayUrls($chapter->id);
|
||||
$remoteDuration = $contentService->getRemoteDuration($chapter->id);
|
||||
$this->view->setVar('vod', $vod);
|
||||
$this->view->setVar('play_urls', $playUrls);
|
||||
$this->view->setVar('cos_play_urls', $cosPlayUrls);
|
||||
$this->view->setVar('remote_play_urls', $remotePlayUrls);
|
||||
$this->view->setVar('remote_duration', $remoteDuration);
|
||||
break;
|
||||
case CourseModel::MODEL_LIVE:
|
||||
$live = $contentService->getChapterLive($chapter->id);
|
||||
|
@ -10,14 +10,14 @@ use Phalcon\Mvc\ModuleDefinitionInterface;
|
||||
class Module implements ModuleDefinitionInterface
|
||||
{
|
||||
|
||||
public function registerAutoLoaders(DiInterface $di = null)
|
||||
public function registerAutoLoaders(DiInterface $dependencyInjector = null)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function registerServices(DiInterface $di)
|
||||
public function registerServices(DiInterface $dependencyInjector)
|
||||
{
|
||||
$di->setShared('view', function () {
|
||||
$dependencyInjector->setShared('view', function () {
|
||||
$view = new MyView();
|
||||
$view->setViewsDir(__DIR__ . '/Views');
|
||||
$view->registerEngines([
|
||||
@ -26,7 +26,7 @@ class Module implements ModuleDefinitionInterface
|
||||
return $view;
|
||||
});
|
||||
|
||||
$di->setShared('auth', function () {
|
||||
$dependencyInjector->setShared('auth', function () {
|
||||
return new AdminAuth();
|
||||
});
|
||||
}
|
||||
|
@ -3,9 +3,9 @@
|
||||
namespace App\Http\Admin\Services;
|
||||
|
||||
use App\Services\Auth\Admin as AdminAuth;
|
||||
use Phalcon\Mvc\User\Component;
|
||||
use Phalcon\Di\Injectable;
|
||||
|
||||
class AuthMenu extends Component
|
||||
class AuthMenu extends Injectable
|
||||
{
|
||||
|
||||
protected $authInfo;
|
||||
|
@ -47,11 +47,37 @@ class ChapterContent extends Service
|
||||
return $chapterRepo->findChapterOffline($chapterId);
|
||||
}
|
||||
|
||||
public function getPlayUrls($chapterId)
|
||||
public function getCosPlayUrls($chapterId)
|
||||
{
|
||||
$service = new ChapterVodService();
|
||||
|
||||
return $service->getPlayUrls($chapterId);
|
||||
return $service->getCosPlayUrls($chapterId);
|
||||
}
|
||||
|
||||
public function getRemotePlayUrls($chapterId)
|
||||
{
|
||||
$service = new ChapterVodService();
|
||||
|
||||
return $service->getRemotePlayUrls($chapterId);
|
||||
}
|
||||
|
||||
public function getRemoteDuration($chapterId)
|
||||
{
|
||||
$chapterRepo = new ChapterRepo();
|
||||
|
||||
$chapter = $chapterRepo->findById($chapterId);
|
||||
|
||||
$duration = $chapter->attrs['duration'] ?? 0;
|
||||
|
||||
$result = ['hours' => 0, 'minutes' => 0, 'seconds' => 0];
|
||||
|
||||
if ($duration == 0) return $result;
|
||||
|
||||
$result['hours'] = floor($duration / 3600);
|
||||
$result['minutes'] = floor(($duration - $result['hours'] * 3600) / 60);
|
||||
$result['seconds'] = $duration % 60;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function updateChapterContent($chapterId)
|
||||
@ -84,6 +110,17 @@ class ChapterContent extends Service
|
||||
{
|
||||
$post = $this->request->getPost();
|
||||
|
||||
if (isset($post['file_id'])) {
|
||||
$this->updateCosChapterVod($chapter);
|
||||
} elseif (isset($post['file_remote'])) {
|
||||
$this->updateRemoteChapterVod($chapter);
|
||||
}
|
||||
}
|
||||
|
||||
protected function updateCosChapterVod(ChapterModel $chapter)
|
||||
{
|
||||
$post = $this->request->getPost();
|
||||
|
||||
$validator = new ChapterVodValidator();
|
||||
|
||||
$fileId = $validator->checkFileId($post['file_id']);
|
||||
@ -119,6 +156,54 @@ class ChapterContent extends Service
|
||||
$this->updateCourseVodAttrs($vod->course_id);
|
||||
}
|
||||
|
||||
protected function updateRemoteChapterVod(ChapterModel $chapter)
|
||||
{
|
||||
$post = $this->request->getPost();
|
||||
|
||||
$validator = new ChapterVodValidator();
|
||||
|
||||
$hours = $post['file_remote']['duration']['hours'] ?? 0;
|
||||
$minutes = $post['file_remote']['duration']['minutes'] ?? 0;
|
||||
$seconds = $post['file_remote']['duration']['seconds'] ?? 0;
|
||||
|
||||
$duration = 3600 * $hours + 60 * $minutes + $seconds;
|
||||
|
||||
$validator->checkDuration($duration);
|
||||
|
||||
$odUrl = $post['file_remote']['od']['url'] ?? '';
|
||||
$hdUrl = $post['file_remote']['hd']['url'] ?? '';
|
||||
$sdUrl = $post['file_remote']['sd']['url'] ?? '';
|
||||
|
||||
$fileRemote = [];
|
||||
|
||||
$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);
|
||||
}
|
||||
|
||||
if (!empty($sdUrl)) {
|
||||
$fileRemote['sd']['url'] = $validator->checkFileUrl($sdUrl);
|
||||
}
|
||||
|
||||
$chapterRepo = new ChapterRepo();
|
||||
|
||||
$vod = $chapterRepo->findChapterVod($chapter->id);
|
||||
$vod->file_remote = $fileRemote;
|
||||
$vod->update();
|
||||
|
||||
$chapter->attrs = $attrs;
|
||||
$chapter->update();
|
||||
|
||||
$this->updateCourseVodAttrs($vod->course_id);
|
||||
}
|
||||
|
||||
protected function updateChapterLive(ChapterModel $chapter)
|
||||
{
|
||||
$post = $this->request->getPost();
|
||||
|
@ -40,7 +40,7 @@
|
||||
<td>{{ item.like_count }}</td>
|
||||
<td>{{ publish_status(item.published) }}</td>
|
||||
<td class="center">
|
||||
<div class="layui-dropdown">
|
||||
<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>
|
||||
|
@ -83,7 +83,7 @@
|
||||
<td><input type="checkbox" name="featured" value="1" lay-skin="switch" lay-text="是|否" lay-filter="featured" data-url="{{ update_url }}" {% if item.featured == 1 %}checked="checked"{% endif %}></td>
|
||||
<td><input type="checkbox" name="comment" value="1" lay-skin="switch" lay-text="是|否" lay-filter="closed" data-url="{{ update_url }}" {% if item.closed == 1 %}checked="checked"{% endif %}></td>
|
||||
<td class="center">
|
||||
<div class="layui-dropdown">
|
||||
<div class="kg-dropdown">
|
||||
<button class="layui-btn layui-btn-sm">操作 <i class="layui-icon layui-icon-triangle-d"></i></button>
|
||||
<ul>
|
||||
{% if item.published == 1 %}
|
||||
|
@ -67,7 +67,7 @@
|
||||
<td><input class="layui-input kg-priority" type="text" name="priority" title="数值越小排序越靠前" value="{{ item.priority }}" data-url="{{ update_url }}"></td>
|
||||
<td><input type="checkbox" name="published" value="1" lay-skin="switch" lay-text="是|否" lay-filter="published" data-url="{{ update_url }}" {% if item.published == 1 %}checked="checked"{% endif %}></td>
|
||||
<td class="center">
|
||||
<div class="layui-dropdown">
|
||||
<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="{{ edit_url }}">编辑</a></li>
|
||||
|
@ -1,66 +1,159 @@
|
||||
{% set file_id = vod ? vod.file_id : '' %}
|
||||
{% set action_url = url({'for':'admin.chapter.content','id':chapter.id}) %}
|
||||
|
||||
{% if play_urls %}
|
||||
<fieldset class="layui-elem-field layui-field-title">
|
||||
<legend>视频信息</legend>
|
||||
</fieldset>
|
||||
<table class="kg-table layui-table">
|
||||
<tr>
|
||||
<th>格式</th>
|
||||
<th>时长</th>
|
||||
<th>分辨率</th>
|
||||
<th>码率</th>
|
||||
<th>大小</th>
|
||||
<th width="16%">操作</th>
|
||||
</tr>
|
||||
{% for item in play_urls %}
|
||||
<tr>
|
||||
<td>{{ item.format }}</td>
|
||||
<td>{{ item.duration|duration }}</td>
|
||||
<td>{{ item.width }} x {{ item.height }}</td>
|
||||
<td>{{ item.rate }}kbps</td>
|
||||
<td>{{ item.size }}M</td>
|
||||
<td>
|
||||
<span class="layui-btn layui-btn-sm kg-preview" data-chapter-id="{{ chapter.id }}" data-play-url="{{ item.url|url_encode }}">预览</span>
|
||||
<span class="layui-btn layui-btn-sm kg-copy" data-clipboard-text="{{ item.url }}">复制</span>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
<br>
|
||||
{% if vod.file_id is defined %}
|
||||
{% set file_id = vod.file_id %}
|
||||
{% else %}
|
||||
{% set file_id = '' %}
|
||||
{% endif %}
|
||||
|
||||
<fieldset class="layui-elem-field layui-field-title">
|
||||
<legend>上传视频</legend>
|
||||
</fieldset>
|
||||
|
||||
<form class="layui-form kg-form" id="vod-form" method="POST" action="{{ url({'for':'admin.chapter.content','id':chapter.id}) }}">
|
||||
<div class="layui-form-item" id="upload-block">
|
||||
<label class="layui-form-label">视频文件</label>
|
||||
<div class="layui-input-block">
|
||||
<span class="layui-btn" id="upload-btn">选择视频</span>
|
||||
<input class="layui-hide" type="file" name="file" accept="video/*,audio/*">
|
||||
<div class="layui-tab layui-tab-brief">
|
||||
<ul class="layui-tab-title kg-tab-title">
|
||||
<li class="layui-this">腾讯云点播</li>
|
||||
<li>外链云点播</li>
|
||||
</ul>
|
||||
<div class="layui-tab-content">
|
||||
<div class="layui-tab-item layui-show">
|
||||
{% if cos_play_urls %}
|
||||
<fieldset class="layui-elem-field layui-field-title">
|
||||
<legend>视频信息</legend>
|
||||
</fieldset>
|
||||
<table class="kg-table layui-table">
|
||||
<tr>
|
||||
<th>格式</th>
|
||||
<th>时长</th>
|
||||
<th>分辨率</th>
|
||||
<th>码率</th>
|
||||
<th>大小</th>
|
||||
<th width="16%">操作</th>
|
||||
</tr>
|
||||
{% for item in cos_play_urls %}
|
||||
<tr>
|
||||
<td>{{ item.format }}</td>
|
||||
<td>{{ item.duration|duration }}</td>
|
||||
<td>{{ item.width }} x {{ item.height }}</td>
|
||||
<td>{{ item.rate }}kbps</td>
|
||||
<td>{{ item.size }}M</td>
|
||||
<td>
|
||||
<span class="layui-btn kg-preview" data-chapter-id="{{ chapter.id }}" data-play-url="{{ item.url|url_encode }}">预览</span>
|
||||
<span class="layui-btn layui-btn-primary kg-copy" data-clipboard-text="{{ item.url }}">复制</span>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
<br>
|
||||
{% endif %}
|
||||
<form class="layui-form kg-form" id="vod-form" method="POST" action="{{ action_url }}">
|
||||
<fieldset class="layui-elem-field layui-field-title">
|
||||
<legend>上传视频</legend>
|
||||
</fieldset>
|
||||
<div class="layui-form-item" id="upload-block">
|
||||
<label class="layui-form-label">视频文件</label>
|
||||
<div class="layui-input-block">
|
||||
<span class="layui-btn" id="upload-btn">选择视频</span>
|
||||
<input class="layui-hide" type="file" name="file" accept="video/*,audio/*">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-hide" id="upload-progress-block">
|
||||
<label class="layui-form-label">上传进度</label>
|
||||
<div class="layui-input-block">
|
||||
<div class="layui-progress layui-progress-big" lay-showpercent="yes" lay-filter="upload-progress" style="top:10px;">
|
||||
<div class="layui-progress-bar" lay-percent="0%"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">文件编号</label>
|
||||
<div class="layui-input-block">
|
||||
<input class="layui-input" type="text" name="file_id" value="{{ file_id }}" readonly="readonly" lay-verify="required">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label"></label>
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit="true" lay-filter="go">提交</button>
|
||||
<button type="button" class="kg-back layui-btn layui-btn-primary">返回</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<form class="layui-form kg-form" method="POST" action="{{ action_url }}">
|
||||
<fieldset class="layui-elem-field layui-field-title">
|
||||
<legend>外链视频</legend>
|
||||
</fieldset>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">视频时长</label>
|
||||
<div class="layui-input-block">
|
||||
<div class="layui-inline">
|
||||
<select name="file_remote[duration][hours]">
|
||||
{% for value in 0..10 %}
|
||||
{% set selected = value == remote_duration.hours ? 'selected="selected"' : '' %}
|
||||
<option value="{{ value }}" {{ selected }}>{{ value }}小时</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<select name="file_remote[duration][minutes]">
|
||||
{% for value in 0..59 %}
|
||||
{% set selected = value == remote_duration.minutes ? 'selected="selected"' : '' %}
|
||||
<option value="{{ value }}" {{ selected }}>{{ value }}分钟</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<select name="file_remote[duration][seconds]">
|
||||
{% for value in 0..59 %}
|
||||
{% set selected = value == remote_duration.seconds ? 'selected="selected"' : '' %}
|
||||
<option value="{{ value }}" {{ selected }}>{{ value }}秒</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">原画地址</label>
|
||||
<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>
|
||||
{% if remote_play_urls.od.url %}
|
||||
<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>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">高清地址</label>
|
||||
<div class="layui-inline" style="width:55%;">
|
||||
<input id="tc-hd-url" class="layui-input" type="text" name="file_remote[hd][url]" value="{{ remote_play_urls.hd.url }}">
|
||||
</div>
|
||||
{% if remote_play_urls.hd.url %}
|
||||
<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-hd-url">复制</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">标清地址</label>
|
||||
<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 }}">
|
||||
</div>
|
||||
{% if remote_play_urls.hd.url %}
|
||||
<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-sd-url">复制</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label"></label>
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit="true" lay-filter="go">提交</button>
|
||||
<button type="button" class="kg-back layui-btn layui-btn-primary">返回</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-hide" id="upload-progress-block">
|
||||
<label class="layui-form-label">上传进度</label>
|
||||
<div class="layui-input-block">
|
||||
<div class="layui-progress layui-progress-big" lay-showpercent="yes" lay-filter="upload-progress" style="top:10px;">
|
||||
<div class="layui-progress-bar" lay-percent="0%"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">文件编号</label>
|
||||
<div class="layui-input-block">
|
||||
<input class="layui-input" type="text" name="file_id" value="{{ file_id }}" readonly="readonly" lay-verify="required">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label"></label>
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" lay-submit="true" lay-filter="go">提交</button>
|
||||
<button type="button" class="kg-back layui-btn layui-btn-primary">返回</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
@ -68,7 +68,7 @@
|
||||
<td><input type="checkbox" name="free" value="1" lay-skin="switch" lay-text="是|否" lay-filter="free" data-url="{{ update_url }}" {% if item.free == 1 %}checked="checked"{% endif %}></td>
|
||||
<td><input type="checkbox" name="published" value="1" lay-skin="switch" lay-text="是|否" lay-filter="published" data-url="{{ update_url }}" {% if item.published == 1 %}checked="checked"{% endif %}></td>
|
||||
<td class="center">
|
||||
<div class="layui-dropdown">
|
||||
<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>
|
||||
|
@ -46,7 +46,7 @@
|
||||
<td><input type="checkbox" name="free" value="1" lay-skin="switch" lay-text="是|否" lay-filter="free" data-url="{{ update_url }}" {% if item.free == 1 %}checked="checked"{% endif %}></td>
|
||||
<td><input type="checkbox" name="published" value="1" lay-skin="switch" lay-text="是|否" lay-filter="published" data-url="{{ update_url }}" {% if item.published == 1 %}checked="checked"{% endif %}></td>
|
||||
<td class="center">
|
||||
<div class="layui-dropdown">
|
||||
<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="{{ edit_url }}">编辑</a></li>
|
||||
|
@ -46,7 +46,7 @@
|
||||
<td><input type="checkbox" name="free" value="1" lay-skin="switch" lay-text="是|否" lay-filter="free" data-url="{{ update_url }}" {% if item.free == 1 %}checked="checked"{% endif %}></td>
|
||||
<td><input type="checkbox" name="published" value="1" lay-skin="switch" lay-text="是|否" lay-filter="published" data-url="{{ update_url }}" {% if item.published == 1 %}checked="checked"{% endif %}></td>
|
||||
<td class="center">
|
||||
<div class="layui-dropdown">
|
||||
<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>
|
||||
|
@ -68,7 +68,7 @@
|
||||
<td><input type="checkbox" name="free" value="1" lay-skin="switch" lay-text="是|否" lay-filter="free" data-url="{{ update_url }}" {% if item.free == 1 %}checked="checked"{% endif %}></td>
|
||||
<td><input type="checkbox" name="published" value="1" lay-skin="switch" lay-text="是|否" lay-filter="published" data-url="{{ update_url }}" {% if item.published == 1 %}checked="checked"{% endif %}></td>
|
||||
<td class="center">
|
||||
<div class="layui-dropdown">
|
||||
<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>
|
||||
|
@ -73,7 +73,7 @@
|
||||
</td>
|
||||
<td><input type="checkbox" name="published" value="1" lay-skin="switch" lay-text="是|否" lay-filter="published" data-url="{{ update_url }}" {% if item.published == 1 %}checked="checked"{% endif %}></td>
|
||||
<td class="center">
|
||||
<div class="layui-dropdown">
|
||||
<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="{{ edit_url }}">编辑</a></li>
|
||||
|
@ -65,7 +65,7 @@
|
||||
<td>{{ item.comment_count }}</td>
|
||||
<td><input class="layui-input kg-priority" type="text" name="priority" value="{{ item.priority }}" data-url="{{ update_url }}"></td>
|
||||
<td class="center">
|
||||
<div class="layui-dropdown">
|
||||
<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="{{ edit_url }}">编辑</a></li>
|
||||
|
@ -95,7 +95,7 @@
|
||||
<td><input type="checkbox" name="featured" value="1" lay-skin="switch" lay-text="是|否" lay-filter="featured" data-url="{{ update_url }}" {% if item.featured == 1 %}checked="checked"{% endif %}></td>
|
||||
<td><input type="checkbox" name="published" value="1" lay-skin="switch" lay-text="是|否" lay-filter="published" data-url="{{ update_url }}" {% if item.published == 1 %}checked="checked"{% endif %}></td>
|
||||
<td class="center">
|
||||
<div class="layui-dropdown">
|
||||
<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>
|
||||
|
@ -61,7 +61,7 @@
|
||||
<td>{{ schedules_info(item.schedules) }}</td>
|
||||
<td><input type="checkbox" name="published" value="1" lay-filter="published" lay-skin="switch" lay-text="是|否" data-url="{{ update_url }}" {% if item.published == 1 %}checked="checked"{% endif %}></td>
|
||||
<td class="center">
|
||||
<div class="layui-dropdown">
|
||||
<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="{{ edit_url }}">编辑</a></li>
|
||||
|
@ -51,7 +51,7 @@
|
||||
<td class="center"><input class="layui-input kg-priority" type="text" name="priority" title="数值越小排序越靠前" value="{{ item.priority }}" data-url="{{ update_url }}"></td>
|
||||
<td class="center"><input type="checkbox" name="published" value="1" lay-skin="switch" lay-text="是|否" lay-filter="published" data-url="{{ update_url }}" {% if item.published == 1 %}checked="checked"{% endif %}></td>
|
||||
<td class="center">
|
||||
<div class="layui-dropdown">
|
||||
<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>
|
||||
|
@ -74,7 +74,7 @@
|
||||
<td><a href="{{ users_url }}" class="layui-badge layui-bg-green">{{ item.user_count }}</a></td>
|
||||
<td><input type="checkbox" name="published" value="1" lay-filter="published" lay-skin="switch" lay-text="是|否" data-url="{{ update_url }}" {% if item.published == 1 %}checked="checked"{% endif %}></td>
|
||||
<td class="center">
|
||||
<div class="layui-dropdown">
|
||||
<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>
|
||||
|
@ -84,7 +84,7 @@
|
||||
<td><input class="layui-input kg-priority" type="text" name="priority" title="数值越小排序越靠前" value="{{ item.priority }}" data-url="{{ update_url }}"></td>
|
||||
<td><input type="checkbox" name="published" value="1" lay-skin="switch" lay-text="是|否" lay-filter="published" data-url="{{ update_url }}" {% if item.published == 1 %}checked="checked"{% endif %}></td>
|
||||
<td class="center">
|
||||
<div class="layui-dropdown">
|
||||
<div class="kg-dropdown">
|
||||
<button class="layui-btn layui-btn-sm">操作 <span class="layui-icon layui-icon-triangle-d"></span></button>
|
||||
<ul>
|
||||
<li><a href="{{ edit_url }}">编辑</a></li>
|
||||
|
@ -56,7 +56,7 @@
|
||||
<td>{{ '¥%0.2f'|format(item.vip_price) }}</td>
|
||||
<td><input type="checkbox" name="published" value="1" lay-skin="switch" lay-text="是|否" lay-filter="published" data-url="{{ update_url }}" {% if item.published == 1 %}checked="checked"{% endif %}></td>
|
||||
<td class="center">
|
||||
<div class="layui-dropdown">
|
||||
<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="{{ edit_url }}">编辑</a></li>
|
||||
|
@ -50,7 +50,7 @@
|
||||
<td><input type="checkbox" name="published" value="1" lay-skin="switch" lay-text="是|否" lay-filter="published" data-url="{{ update_url }}" {% if item.published == 1 %}checked="checked"{% endif %}>
|
||||
</td>
|
||||
<td class="center">
|
||||
<div class="layui-dropdown">
|
||||
<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>
|
||||
|
@ -66,7 +66,7 @@
|
||||
<td><a class="layui-badge layui-bg-green" href="{{ redeem_url }}">{{ item.redeem_count }}</a></td>
|
||||
<td><input type="checkbox" name="published" value="1" lay-filter="published" lay-skin="switch" lay-text="是|否" data-url="{{ update_url }}" {% if item.published == 1 %}checked="checked"{% endif %}></td>
|
||||
<td class="center">
|
||||
<div class="layui-dropdown">
|
||||
<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>
|
||||
|
@ -16,9 +16,13 @@
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block inline_js %}
|
||||
{% block include_js %}
|
||||
|
||||
<script src="https://imgcache.qq.com/open/qcloud/video/vcplayer/TcPlayer-2.3.3.js"></script>
|
||||
{{ js_include('lib/tc-player-2.4.0.js') }}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block inline_js %}
|
||||
|
||||
<script>
|
||||
|
||||
|
@ -4,6 +4,10 @@
|
||||
|
||||
<div id="player"></div>
|
||||
|
||||
<div class="layui-hide">
|
||||
<input type="hidden" name="play_url" value="{{ play_url }}">
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block inline_css %}
|
||||
@ -16,16 +20,24 @@
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block inline_js %}
|
||||
{% block include_js %}
|
||||
|
||||
<script src="https://imgcache.qq.com/open/qcloud/video/vcplayer/TcPlayer-2.3.3.js"></script>
|
||||
{{ js_include('lib/tc-player-2.4.0.js') }}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block inline_js %}
|
||||
|
||||
<script>
|
||||
|
||||
layui.use(['jquery'], function () {
|
||||
|
||||
var $ = layui.jquery;
|
||||
|
||||
var playUrl = $('input[name=play_url]').val();
|
||||
|
||||
new TcPlayer('player', {
|
||||
m3u8: '{{ play_url }}',
|
||||
m3u8: playUrl,
|
||||
autoplay: false,
|
||||
width: 720,
|
||||
height: 405
|
||||
|
@ -80,7 +80,7 @@
|
||||
<td>{{ publish_status(item.published) }}</td>
|
||||
<td><input type="checkbox" name="closed" value="1" lay-skin="switch" lay-text="是|否" lay-filter="closed" data-url="{{ update_url }}" {% if item.closed == 1 %}checked="checked"{% endif %}></td>
|
||||
<td class="center">
|
||||
<div class="layui-dropdown">
|
||||
<div class="kg-dropdown">
|
||||
<button class="layui-btn layui-btn-sm">操作 <i class="layui-icon layui-icon-triangle-d"></i></button>
|
||||
<ul>
|
||||
{% if item.published == 1 %}
|
||||
|
@ -63,7 +63,7 @@
|
||||
</td>
|
||||
<td><input type="checkbox" name="published" value="1" lay-skin="switch" lay-text="是|否" lay-filter="published" data-url="{{ update_url }}" {% if item.published == 1 %}checked="checked"{% endif %}></td>
|
||||
<td class="center">
|
||||
<div class="layui-dropdown">
|
||||
<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="{{ edit_url }}">编辑</a></li>
|
||||
|
@ -62,7 +62,7 @@
|
||||
</a>
|
||||
</td>
|
||||
<td class="center">
|
||||
<div class="layui-dropdown">
|
||||
<div class="kg-dropdown">
|
||||
<button class="layui-btn layui-btn-sm">操作 <i class="layui-icon layui-icon-triangle-d"></i></button>
|
||||
<ul>
|
||||
{% if item.id == 1 %}
|
||||
|
@ -32,29 +32,21 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">Logo</label>
|
||||
<div class="kg-input-inline">
|
||||
<input class="layui-input" type="text" name="logo" placeholder="请确保存储已正确配置" value="{{ site.logo }}">
|
||||
</div>
|
||||
<label class="layui-form-label">Logo</label>
|
||||
<div class="layui-inline" style="width:40%;">
|
||||
<input class="layui-input" type="text" name="logo" placeholder="请确保存储已正确配置" value="{{ site.logo }}">
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<div class="kg-input-inline">
|
||||
<button class="layui-btn" type="button" id="upload-logo">上传文件</button>
|
||||
</div>
|
||||
<button class="layui-btn" type="button" id="upload-logo">上传文件</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">Favicon</label>
|
||||
<div class="kg-input-inline">
|
||||
<input class="layui-input" type="text" name="favicon" placeholder="请确保存储已正确配置" value="{{ site.favicon }}">
|
||||
</div>
|
||||
<label class="layui-form-label">Favicon</label>
|
||||
<div class="layui-inline" style="width:40%;">
|
||||
<input class="layui-input" type="text" name="favicon" placeholder="请确保存储已正确配置" value="{{ site.favicon }}">
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<div class="kg-input-inline">
|
||||
<button class="layui-btn" type="button" id="upload-favicon">上传文件</button>
|
||||
</div>
|
||||
<button class="layui-btn" type="button" id="upload-favicon">上传文件</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
@ -96,7 +88,7 @@
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">备案链接</label>
|
||||
<div class="kg-input-inline">
|
||||
<div class="kg-input-inline" style="width:500px;">
|
||||
<input class="layui-input" type="text" name="icp_link" value="{{ site.icp_link }}">
|
||||
</div>
|
||||
</div>
|
||||
@ -110,7 +102,7 @@
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<label class="layui-form-label">备案链接</label>
|
||||
<div class="kg-input-inline">
|
||||
<div class="kg-input-inline" style="width:500px;">
|
||||
<input class="layui-input" type="text" name="police_link" value="{{ site.police_link }}">
|
||||
</div>
|
||||
</div>
|
||||
|
@ -58,7 +58,7 @@
|
||||
<td><input class="layui-input kg-priority" type="text" name="priority" title="数值越小排序越靠前" value="{{ item.priority }}" data-url="{{ update_url }}"></td>
|
||||
<td><input type="checkbox" name="published" value="1" lay-filter="published" lay-skin="switch" lay-text="是|否" data-url="{{ update_url }}" {% if item.published == 1 %}checked="checked"{% endif %}></td>
|
||||
<td class="center">
|
||||
<div class="layui-dropdown">
|
||||
<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="{{ edit_url }}">编辑</a></li>
|
||||
|
@ -83,7 +83,7 @@
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="center">
|
||||
<div class="layui-dropdown">
|
||||
<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="{{ edit_url }}">编辑学员</a></li>
|
||||
|
@ -59,7 +59,7 @@
|
||||
<td><input type="checkbox" name="published" value="1" lay-skin="switch" lay-text="是|否" lay-filter="published" data-url="{{ update_url }}" {% if item.published == 1 %}checked="checked"{% endif %}>
|
||||
</td>
|
||||
<td class="center">
|
||||
<div class="layui-dropdown">
|
||||
<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="{{ edit_url }}">编辑</a></li>
|
||||
|
@ -8,7 +8,7 @@
|
||||
<title>管理后台</title>
|
||||
{{ icon_link('favicon.ico') }}
|
||||
{{ css_link('lib/layui/css/layui.css') }}
|
||||
{{ css_link('lib/layui/extends/dropdown.css') }}
|
||||
{{ css_link('lib/layui/extends/kg-dropdown.css') }}
|
||||
{{ css_link('admin/css/common.css') }}
|
||||
{% block link_css %}{% endblock %}
|
||||
{% block inline_css %}{% endblock %}
|
||||
|
@ -57,7 +57,7 @@
|
||||
<td>{{ date('Y-m-d H:i',item.update_time) }}</td>
|
||||
<td><input type="checkbox" name="published" value="1" lay-skin="switch" lay-text="是|否" lay-filter="published" data-url="{{ update_url }}" {% if item.published == 1 %}checked="checked"{% endif %}></td>
|
||||
<td class="center">
|
||||
<div class="layui-dropdown">
|
||||
<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>
|
||||
|
@ -79,7 +79,7 @@
|
||||
<td>{{ date('Y-m-d',item.active_time) }}</td>
|
||||
<td>{{ date('Y-m-d',item.create_time) }}</td>
|
||||
<td class="center">
|
||||
<div class="layui-dropdown">
|
||||
<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>
|
||||
|
@ -10,20 +10,20 @@ use Phalcon\Mvc\View;
|
||||
class Module implements ModuleDefinitionInterface
|
||||
{
|
||||
|
||||
public function registerAutoLoaders(DiInterface $di = null)
|
||||
public function registerAutoLoaders(DiInterface $dependencyInjector = null)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function registerServices(DiInterface $di)
|
||||
public function registerServices(DiInterface $dependencyInjector)
|
||||
{
|
||||
$di->setShared('view', function () {
|
||||
$dependencyInjector->setShared('view', function () {
|
||||
$view = new View();
|
||||
$view->disable();
|
||||
return $view;
|
||||
});
|
||||
|
||||
$di->setShared('auth', function () {
|
||||
$dependencyInjector->setShared('auth', function () {
|
||||
return new AppAuth();
|
||||
});
|
||||
}
|
||||
|
@ -10,14 +10,14 @@ use Phalcon\Mvc\ModuleDefinitionInterface;
|
||||
class Module implements ModuleDefinitionInterface
|
||||
{
|
||||
|
||||
public function registerAutoLoaders(DiInterface $di = null)
|
||||
public function registerAutoLoaders(DiInterface $dependencyInjector = null)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function registerServices(DiInterface $di)
|
||||
public function registerServices(DiInterface $dependencyInjector)
|
||||
{
|
||||
$di->setShared('view', function () {
|
||||
$dependencyInjector->setShared('view', function () {
|
||||
$view = new MyView();
|
||||
$view->setViewsDir(__DIR__ . '/Views');
|
||||
$view->registerEngines([
|
||||
@ -26,7 +26,7 @@ class Module implements ModuleDefinitionInterface
|
||||
return $view;
|
||||
});
|
||||
|
||||
$di->setShared('auth', function () {
|
||||
$dependencyInjector->setShared('auth', function () {
|
||||
return new HomeAuth();
|
||||
});
|
||||
}
|
||||
|
@ -71,7 +71,7 @@
|
||||
|
||||
{% block include_js %}
|
||||
|
||||
{{ js_include('https://imgcache.qq.com/open/qcloud/video/vcplayer/TcPlayer-2.3.3.js', false) }}
|
||||
{{ js_include('lib/tc-player-2.4.0.js') }}
|
||||
{{ js_include('home/js/chapter.live.player.js') }}
|
||||
{{ js_include('home/js/chapter.live.chat.js') }}
|
||||
{{ js_include('home/js/chapter.show.js') }}
|
||||
|
@ -57,7 +57,7 @@
|
||||
|
||||
{% block include_js %}
|
||||
|
||||
{{ js_include('https://imgcache.qq.com/open/qcloud/video/vcplayer/TcPlayer-2.3.3.js', false) }}
|
||||
{{ js_include('lib/tc-player-2.4.0.js') }}
|
||||
{{ js_include('home/js/course.share.js') }}
|
||||
{{ js_include('home/js/chapter.show.js') }}
|
||||
{{ js_include('home/js/chapter.vod.player.js') }}
|
||||
|
@ -4,7 +4,8 @@
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<title>聊天记录</title>
|
||||
<link rel="stylesheet" href="/static/lib/layui/css/layui.css">
|
||||
{{ css_link('lib/layui/css/layui.css') }}
|
||||
{{ css_link('lib/layui/extends/layim/assets/layim.css') }}
|
||||
<style>
|
||||
body .layim-chat-main {
|
||||
height: auto;
|
||||
@ -34,15 +35,15 @@
|
||||
}); %>
|
||||
</textarea>
|
||||
|
||||
<script src="/static/lib/layui/layui.js"></script>
|
||||
{{ js_include('lib/layui/layui.js') }}
|
||||
|
||||
<script>
|
||||
layui.use(['jquery', 'layim', 'laytpl', 'laypage'], function () {
|
||||
|
||||
layui.use(['jquery', 'laypage'], function () {
|
||||
|
||||
var $ = layui.jquery;
|
||||
var layim = layui.layim;
|
||||
var laytpl = layui.laytpl;
|
||||
var laypage = layui.laypage;
|
||||
var laytpl = parent.layui.laytpl;
|
||||
|
||||
laytpl.config({
|
||||
open: '<%',
|
||||
@ -97,6 +98,7 @@
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
@ -24,7 +24,7 @@
|
||||
<colgroup>
|
||||
<col>
|
||||
<col>
|
||||
<col width="20%">
|
||||
<col width="15%">
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
|
@ -54,7 +54,7 @@
|
||||
<td>{{ item.comment_count }}</td>
|
||||
<td>{{ item.view_count }}</td>
|
||||
<td class="center">
|
||||
<a href="{{ edit_url }}" class="layui-btn layui-btn-xs">编辑</a>
|
||||
<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>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -51,7 +51,7 @@
|
||||
<td>{{ item.answer_count }}</td>
|
||||
<td>{{ item.view_count }}</td>
|
||||
<td class="center">
|
||||
<a href="{{ edit_url }}" class="layui-btn layui-btn-xs">编辑</a>
|
||||
<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>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -41,7 +41,7 @@
|
||||
<p class="rating">逻辑清晰:{{ "%0.1f"|format(item.rating3) }}</p>
|
||||
</td>
|
||||
<td>
|
||||
<button class="layui-btn layui-btn-xs btn-edit-review" data-url="{{ edit_url }}">修改</button>
|
||||
<button class="layui-btn layui-btn-xs layui-bg-blue btn-edit-review" data-url="{{ edit_url }}">修改</button>
|
||||
<button class="layui-btn layui-btn-xs layui-bg-red kg-delete" data-url="{{ delete_url }}">删除</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -31,7 +31,7 @@ class Chapter extends Model
|
||||
*/
|
||||
protected $_vod_attrs = [
|
||||
'duration' => 0,
|
||||
'file' => ['id' => '', 'status' => self::FS_PENDING],
|
||||
'file' => ['status' => self::FS_PENDING],
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -42,6 +42,13 @@ class ChapterVod extends Model
|
||||
*/
|
||||
public $file_transcode = [];
|
||||
|
||||
/**
|
||||
* 远程资源
|
||||
*
|
||||
* @var array|string
|
||||
*/
|
||||
public $file_remote = [];
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*
|
||||
@ -67,6 +74,10 @@ class ChapterVod extends Model
|
||||
$this->file_transcode = kg_json_encode($this->file_transcode);
|
||||
}
|
||||
|
||||
if (is_array($this->file_remote) || is_object($this->file_remote)) {
|
||||
$this->file_remote = kg_json_encode($this->file_remote);
|
||||
}
|
||||
|
||||
$this->create_time = time();
|
||||
}
|
||||
|
||||
@ -76,6 +87,10 @@ class ChapterVod extends Model
|
||||
$this->file_transcode = kg_json_encode($this->file_transcode);
|
||||
}
|
||||
|
||||
if (is_array($this->file_remote) || is_object($this->file_remote)) {
|
||||
$this->file_remote = kg_json_encode($this->file_remote);
|
||||
}
|
||||
|
||||
$this->update_time = time();
|
||||
}
|
||||
|
||||
@ -85,6 +100,10 @@ class ChapterVod extends Model
|
||||
$this->file_transcode = json_decode($this->file_transcode, true);
|
||||
}
|
||||
|
||||
if (is_string($this->file_remote)) {
|
||||
$this->file_remote = json_decode($this->file_remote, true);
|
||||
}
|
||||
|
||||
if (!empty($this->file_id) && empty($this->file_transcode)) {
|
||||
$this->file_transcode = $this->getFileTranscode($this->file_id);
|
||||
}
|
||||
|
@ -29,161 +29,161 @@ class User extends Model
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $id;
|
||||
public $id = 0;
|
||||
|
||||
/**
|
||||
* 名称
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $name;
|
||||
public $name = '';
|
||||
|
||||
/**
|
||||
* 头像
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $avatar;
|
||||
public $avatar = '';
|
||||
|
||||
/**
|
||||
* 头衔
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $title;
|
||||
public $title = '';
|
||||
|
||||
/**
|
||||
* 介绍
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $about;
|
||||
public $about = '';
|
||||
|
||||
/**
|
||||
* 地区
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $area;
|
||||
public $area = '';
|
||||
|
||||
/**
|
||||
* 性别
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $gender;
|
||||
public $gender = self::GENDER_NONE;
|
||||
|
||||
/**
|
||||
* 会员标识
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $vip;
|
||||
public $vip = 0;
|
||||
|
||||
/**
|
||||
* 锁定标识
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $locked;
|
||||
public $locked = 0;
|
||||
|
||||
/**
|
||||
* 删除标识
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $deleted;
|
||||
public $deleted = 0;
|
||||
|
||||
/**
|
||||
* 教学角色
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $edu_role;
|
||||
public $edu_role = self::EDU_ROLE_STUDENT;
|
||||
|
||||
/**
|
||||
* 后台角色
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $admin_role;
|
||||
public $admin_role = 0;
|
||||
|
||||
/**
|
||||
* 课程数
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $course_count;
|
||||
public $course_count = 0;
|
||||
|
||||
/**
|
||||
* 文章数
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $article_count;
|
||||
public $article_count = 0;
|
||||
|
||||
/**
|
||||
* 提问数
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $question_count;
|
||||
public $question_count = 0;
|
||||
|
||||
/**
|
||||
* 回答数
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $answer_count;
|
||||
public $answer_count = 0;
|
||||
|
||||
/**
|
||||
* 评论数
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $comment_count;
|
||||
public $comment_count = 0;
|
||||
|
||||
/**
|
||||
* 收藏数
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $favorite_count;
|
||||
public $favorite_count = 0;
|
||||
|
||||
/**
|
||||
* 会员期限
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $vip_expiry_time;
|
||||
public $vip_expiry_time = 0;
|
||||
|
||||
/**
|
||||
* 锁定期限
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $lock_expiry_time;
|
||||
public $lock_expiry_time = 0;
|
||||
|
||||
/**
|
||||
* 活跃时间
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $active_time;
|
||||
public $active_time = 0;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $create_time;
|
||||
public $create_time = 0;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $update_time;
|
||||
public $update_time = 0;
|
||||
|
||||
public function getSource(): string
|
||||
{
|
||||
|
@ -2,10 +2,10 @@
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use Phalcon\Di\Injectable;
|
||||
use Phalcon\DiInterface;
|
||||
use Phalcon\Mvc\User\Component;
|
||||
|
||||
abstract class Provider extends Component implements ProviderInterface
|
||||
abstract class Provider extends Injectable implements ProviderInterface
|
||||
{
|
||||
|
||||
/**
|
||||
|
@ -2,9 +2,9 @@
|
||||
|
||||
namespace App\Repos;
|
||||
|
||||
use Phalcon\Mvc\User\Component;
|
||||
use Phalcon\Di\Injectable;
|
||||
|
||||
class Repository extends Component
|
||||
class Repository extends Injectable
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -14,6 +14,24 @@ class ChapterVod extends Service
|
||||
|
||||
$vod = $chapterRepo->findChapterVod($chapterId);
|
||||
|
||||
/**
|
||||
* 腾讯云点播优先
|
||||
*/
|
||||
if ($vod->file_id) {
|
||||
$result = $this->getCosPlayUrls($chapterId);
|
||||
} else {
|
||||
$result = $this->getRemotePlayUrls($chapterId);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getCosPlayUrls($chapterId)
|
||||
{
|
||||
$chapterRepo = new ChapterRepo();
|
||||
|
||||
$vod = $chapterRepo->findChapterVod($chapterId);
|
||||
|
||||
if (empty($vod->file_transcode)) return [];
|
||||
|
||||
$vodService = new VodService();
|
||||
@ -21,9 +39,28 @@ class ChapterVod extends Service
|
||||
$result = [];
|
||||
|
||||
foreach ($vod->file_transcode as $key => $file) {
|
||||
$file['url'] = $vodService->getPlayUrl($file['url']);
|
||||
$url = $vodService->getPlayUrl($file['url']);
|
||||
$type = $this->getDefinitionType($file['height']);
|
||||
$result[$type] = $file;
|
||||
$result[$type] = ['url' => $url];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getRemotePlayUrls($chapterId)
|
||||
{
|
||||
$chapterRepo = new ChapterRepo();
|
||||
|
||||
$vod = $chapterRepo->findChapterVod($chapterId);
|
||||
|
||||
$result = [
|
||||
'od' => ['url' => ''],
|
||||
'hd' => ['url' => ''],
|
||||
'sd' => ['url' => ''],
|
||||
];
|
||||
|
||||
if (!empty($vod->file_remote)) {
|
||||
$result = $vod->file_remote;
|
||||
}
|
||||
|
||||
return $result;
|
||||
|
@ -5,9 +5,9 @@ namespace App\Services\Search;
|
||||
use App\Models\Article as ArticleModel;
|
||||
use App\Repos\Category as CategoryRepo;
|
||||
use App\Repos\User as UserRepo;
|
||||
use Phalcon\Mvc\User\Component;
|
||||
use Phalcon\Di\Injectable;
|
||||
|
||||
class ArticleDocument extends Component
|
||||
class ArticleDocument extends Injectable
|
||||
{
|
||||
|
||||
/**
|
||||
|
@ -5,9 +5,9 @@ namespace App\Services\Search;
|
||||
use App\Models\Category as CategoryModel;
|
||||
use App\Models\Course as CourseModel;
|
||||
use App\Models\User as UserModel;
|
||||
use Phalcon\Mvc\User\Component;
|
||||
use Phalcon\Di\Injectable;
|
||||
|
||||
class CourseDocument extends Component
|
||||
class CourseDocument extends Injectable
|
||||
{
|
||||
|
||||
/**
|
||||
|
@ -4,9 +4,9 @@ namespace App\Services\Search;
|
||||
|
||||
use App\Models\ImGroup as GroupModel;
|
||||
use App\Models\User as UserModel;
|
||||
use Phalcon\Mvc\User\Component;
|
||||
use Phalcon\Di\Injectable;
|
||||
|
||||
class GroupDocument extends Component
|
||||
class GroupDocument extends Injectable
|
||||
{
|
||||
|
||||
/**
|
||||
|
@ -6,9 +6,9 @@ use App\Models\Question as QuestionModel;
|
||||
use App\Repos\Answer as AnswerRepo;
|
||||
use App\Repos\Category as CategoryRepo;
|
||||
use App\Repos\User as UserRepo;
|
||||
use Phalcon\Mvc\User\Component;
|
||||
use Phalcon\Di\Injectable;
|
||||
|
||||
class QuestionDocument extends Component
|
||||
class QuestionDocument extends Injectable
|
||||
{
|
||||
|
||||
/**
|
||||
|
@ -2,9 +2,9 @@
|
||||
|
||||
namespace App\Services\Search;
|
||||
|
||||
use Phalcon\Mvc\User\Component;
|
||||
use Phalcon\Di\Injectable;
|
||||
|
||||
abstract class Searcher extends Component
|
||||
abstract class Searcher extends Injectable
|
||||
{
|
||||
|
||||
/**
|
||||
|
@ -3,9 +3,9 @@
|
||||
namespace App\Services\Search;
|
||||
|
||||
use App\Models\User as UserModel;
|
||||
use Phalcon\Mvc\User\Component;
|
||||
use Phalcon\Di\Injectable;
|
||||
|
||||
class UserDocument extends Component
|
||||
class UserDocument extends Injectable
|
||||
{
|
||||
|
||||
/**
|
||||
|
@ -19,4 +19,35 @@ class ChapterVod extends Validator
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function checkDuration($duration)
|
||||
{
|
||||
$value = $value = $this->filter->sanitize($duration, ['trim', 'int']);
|
||||
|
||||
if ($value < 10 || $value > 10 * 3600) {
|
||||
throw new BadRequestException('chapter_vod.invalid_duration');
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function checkFileUrl($url)
|
||||
{
|
||||
$value = $this->filter->sanitize($url, ['trim', 'string']);
|
||||
|
||||
if (!CommonValidator::url($value)) {
|
||||
throw new BadRequestException('chapter_vod.invalid_file_url');
|
||||
}
|
||||
|
||||
$ext = strtolower(pathinfo($url, PATHINFO_EXTENSION));
|
||||
|
||||
/**
|
||||
* 点播只支持mp4,m3u8格式
|
||||
*/
|
||||
if (!in_array($ext, ['mp4', 'm3u8'])) {
|
||||
throw new BadRequestException('chapter_vod.invalid_file_ext');
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -4,9 +4,9 @@ namespace App\Validators;
|
||||
|
||||
use App\Exceptions\Forbidden as ForbiddenException;
|
||||
use App\Exceptions\Unauthorized as UnauthorizedException;
|
||||
use Phalcon\Mvc\User\Component;
|
||||
use Phalcon\Di\Injectable;
|
||||
|
||||
class Validator extends Component
|
||||
class Validator extends Injectable
|
||||
{
|
||||
|
||||
public function checkAuthUser($userId)
|
||||
|
@ -4,10 +4,10 @@ namespace Bootstrap;
|
||||
|
||||
use App\Library\Logger as AppLogger;
|
||||
use Phalcon\Config as PhConfig;
|
||||
use Phalcon\Di\Injectable;
|
||||
use Phalcon\Logger\Adapter\File as PhLogger;
|
||||
use Phalcon\Mvc\User\Component;
|
||||
|
||||
class ConsoleErrorHandler extends Component
|
||||
class ConsoleErrorHandler extends Injectable
|
||||
{
|
||||
|
||||
public function __construct()
|
||||
|
@ -9,9 +9,9 @@ use App\Exceptions\ServiceUnavailable as ServiceUnavailableException;
|
||||
use App\Exceptions\Unauthorized as UnauthorizedException;
|
||||
use App\Library\Logger as AppLogger;
|
||||
use Phalcon\Config;
|
||||
use Phalcon\Mvc\User\Component;
|
||||
use Phalcon\Di\Injectable;
|
||||
|
||||
class HttpErrorHandler extends Component
|
||||
class HttpErrorHandler extends Injectable
|
||||
{
|
||||
|
||||
public function __construct()
|
||||
|
76
composer.lock
generated
@ -15,16 +15,16 @@
|
||||
"reference": "3e9d791b67d0a2912922b7b7c7312f4b37af41e4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Bacon/BaconQrCode/zipball/3e9d791b67d0a2912922b7b7c7312f4b37af41e4",
|
||||
"reference": "3e9d791b67d0a2912922b7b7c7312f4b37af41e4",
|
||||
"shasum": "",
|
||||
"mirrors": [
|
||||
{
|
||||
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
|
||||
"preferred": true
|
||||
}
|
||||
]
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Bacon/BaconQrCode/zipball/3e9d791b67d0a2912922b7b7c7312f4b37af41e4",
|
||||
"reference": "3e9d791b67d0a2912922b7b7c7312f4b37af41e4",
|
||||
"shasum": "",
|
||||
"mirrors": [
|
||||
{
|
||||
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
|
||||
"preferred": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"require": {
|
||||
"dasprid/enum": "^1.0.3",
|
||||
@ -1199,16 +1199,16 @@
|
||||
"name": "Ashot Khanamiryan",
|
||||
"email": "a.khanamiryan@gmail.com",
|
||||
"homepage": "https://github.com/khanamiryan",
|
||||
"role": "Developer"
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "QR code decoder / reader",
|
||||
"homepage": "https://github.com/khanamiryan/php-qrcode-detector-decoder/",
|
||||
"keywords": [
|
||||
"barcode",
|
||||
"qr",
|
||||
"zxing"
|
||||
],
|
||||
"description": "QR code decoder / reader",
|
||||
"homepage": "https://github.com/khanamiryan/php-qrcode-detector-decoder/",
|
||||
"keywords": [
|
||||
"barcode",
|
||||
"qr",
|
||||
"zxing"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/khanamiryan/php-qrcode-detector-decoder/issues",
|
||||
"source": "https://github.com/khanamiryan/php-qrcode-detector-decoder/tree/1.0.4"
|
||||
@ -1333,16 +1333,16 @@
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/1cb1cde8e8dd0f70cc0fe51354a59acad9302084",
|
||||
"reference": "1cb1cde8e8dd0f70cc0fe51354a59acad9302084",
|
||||
"shasum": "",
|
||||
"mirrors": [
|
||||
{
|
||||
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
|
||||
"preferred": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"require": {
|
||||
"reference": "1cb1cde8e8dd0f70cc0fe51354a59acad9302084",
|
||||
"shasum": "",
|
||||
"mirrors": [
|
||||
{
|
||||
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
|
||||
"preferred": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.2",
|
||||
"psr/log": "^1.0.1"
|
||||
},
|
||||
@ -5348,15 +5348,15 @@
|
||||
"homepage": "http://riimu.net"
|
||||
}
|
||||
],
|
||||
"description": "Highly customizable alternative to var_export for PHP code generation",
|
||||
"homepage": "http://kit.riimu.net",
|
||||
"keywords": [
|
||||
"code",
|
||||
"encoder",
|
||||
"export",
|
||||
"generator",
|
||||
"variable"
|
||||
],
|
||||
"description": "Highly customizable alternative to var_export for PHP code generation",
|
||||
"homepage": "http://kit.riimu.net",
|
||||
"keywords": [
|
||||
"code",
|
||||
"encoder",
|
||||
"export",
|
||||
"generator",
|
||||
"variable"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/Riimu/Kit-PHPEncoder/issues",
|
||||
"source": "https://github.com/Riimu/Kit-PHPEncoder/tree/v2.4.1"
|
||||
@ -5377,5 +5377,5 @@
|
||||
"ext-fileinfo": "*"
|
||||
},
|
||||
"platform-dev": [],
|
||||
"plugin-api-version": "2.0.0"
|
||||
"plugin-api-version": "2.0.0"
|
||||
}
|
||||
|
@ -110,7 +110,7 @@ $error['nav.has_child_node'] = '不允许相关操作(存在子节点)';
|
||||
/**
|
||||
* 文章相关
|
||||
*/
|
||||
$error['article.not_found'] = '课程不存在';
|
||||
$error['article.not_found'] = '文章不存在';
|
||||
$error['article.title_too_short'] = '标题太短(少于5个字符)';
|
||||
$error['article.title_too_long'] = '标题太长(多于50个字符)';
|
||||
$error['article.content_too_short'] = '内容太短(少于10个字符)';
|
||||
@ -254,6 +254,8 @@ $error['chapter.child_existed'] = '不允许相关操作(存在子章节)';
|
||||
*/
|
||||
$error['chapter_vod.not_found'] = '点播资源不存在';
|
||||
$error['chapter_vod.invalid_file_id'] = '无效的文件编号';
|
||||
$error['chapter_vod.invalid_file_url'] = '无效的文件地址';
|
||||
$error['chapter_vod.invalid_file_ext'] = '无效的文件格式(目前只支持mp4,m3u8)';
|
||||
|
||||
/**
|
||||
* 直播相关
|
||||
|
44
db/migrations/20210610034658.php
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
use Phinx\Migration\AbstractMigration;
|
||||
|
||||
final class V20210610034658 extends AbstractMigration
|
||||
{
|
||||
|
||||
public function up()
|
||||
{
|
||||
$this->modifyChapterVodTable();
|
||||
$this->handleVodFileRemote();
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
$this->table('kg_chapter_vod')
|
||||
->removeColumn('file_remote')
|
||||
->save();
|
||||
}
|
||||
|
||||
protected function modifyChapterVodTable()
|
||||
{
|
||||
$this->table('kg_chapter_vod')
|
||||
->addColumn('file_remote', 'string', [
|
||||
'null' => false,
|
||||
'default' => '',
|
||||
'limit' => 1500,
|
||||
'collation' => 'utf8mb4_general_ci',
|
||||
'encoding' => 'utf8mb4',
|
||||
'comment' => '远程文件',
|
||||
'after' => 'file_transcode',
|
||||
])->save();
|
||||
}
|
||||
|
||||
protected function handleVodFileRemote()
|
||||
{
|
||||
$this->getQueryBuilder()
|
||||
->update('kg_chapter_vod')
|
||||
->set('file_remote', '[]')
|
||||
->where(['file_remote' => ''])
|
||||
->execute();
|
||||
}
|
||||
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
layui.config({
|
||||
base: '/static/lib/layui/extends/'
|
||||
}).extend({
|
||||
dropdown: 'dropdown'
|
||||
kgDropdown: 'kg-dropdown'
|
||||
});
|
||||
|
||||
layui.use(['jquery', 'form', 'element', 'layer', 'dropdown'], function () {
|
||||
layui.use(['jquery', 'form', 'element', 'layer', 'kgDropdown'], function () {
|
||||
|
||||
var $ = layui.jquery;
|
||||
var form = layui.form;
|
||||
|
@ -1,7 +1,9 @@
|
||||
layui.config({
|
||||
base: '/static/lib/layui/extends/'
|
||||
base: '/static/lib/layui/extends/',
|
||||
layimAssetsPath: '/static/lib/layui/extends/layim/assets/',
|
||||
}).extend({
|
||||
helper: 'helper'
|
||||
layim: 'layim/layim',
|
||||
helper: 'helper',
|
||||
});
|
||||
|
||||
layui.use(['jquery', 'form', 'element', 'layer', 'helper'], function () {
|
||||
|
BIN
public/static/lib/layui.zip
Normal file
@ -1,2 +1 @@
|
||||
/** layui-v2.5.6 MIT License By https://www.layui.com */
|
||||
html #layuicss-skincodecss{display:none;position:absolute;width:1989px}.layui-code-h3,.layui-code-view{position:relative;font-size:12px}.layui-code-view{display:block;margin:10px 0;padding:0;border:1px solid #e2e2e2;border-left-width:6px;background-color:#F2F2F2;color:#333;font-family:Courier New}.layui-code-h3{padding:0 10px;height:32px;line-height:32px;border-bottom:1px solid #e2e2e2}.layui-code-h3 a{position:absolute;right:10px;top:0;color:#999}.layui-code-view .layui-code-ol{position:relative;overflow:auto}.layui-code-view .layui-code-ol li{position:relative;margin-left:45px;line-height:20px;padding:0 5px;border-left:1px solid #e2e2e2;list-style-type:decimal-leading-zero;*list-style-type:decimal;background-color:#fff}.layui-code-view pre{margin:0}.layui-code-notepad{border:1px solid #0C0C0C;border-left-color:#3F3F3F;background-color:#0C0C0C;color:#C2BE9E}.layui-code-notepad .layui-code-h3{border-bottom:none}.layui-code-notepad .layui-code-ol li{background-color:#3F3F3F;border-left:none}
|
||||
html #layuicss-skincodecss{display:none;position:absolute;width:1989px}.layui-code-h3,.layui-code-view{position:relative;font-size:12px}.layui-code-view{display:block;margin:10px 0;padding:0;border:1px solid #eee;border-left-width:6px;background-color:#FAFAFA;color:#333;font-family:Courier New}.layui-code-h3{padding:0 10px;height:40px;line-height:40px;border-bottom:1px solid #eee}.layui-code-h3 a{position:absolute;right:10px;top:0;color:#999}.layui-code-view .layui-code-ol{position:relative;overflow:auto}.layui-code-view .layui-code-ol li{position:relative;margin-left:45px;line-height:20px;padding:0 10px;border-left:1px solid #e2e2e2;list-style-type:decimal-leading-zero;*list-style-type:decimal;background-color:#fff}.layui-code-view .layui-code-ol li:first-child{padding-top:10px}.layui-code-view .layui-code-ol li:last-child{padding-bottom:10px}.layui-code-view pre{margin:0}.layui-code-notepad{border:1px solid #0C0C0C;border-left-color:#3F3F3F;background-color:#0C0C0C;color:#C2BE9E}.layui-code-notepad .layui-code-h3{border-bottom:none}.layui-code-notepad .layui-code-ol li{background-color:#3F3F3F;border-left:none}.layui-code-demo .layui-code{visibility:visible!important;margin:-15px;border-top:none;border-right:none;border-bottom:none}.layui-code-demo .layui-tab-content{padding:15px;border-top:none}
|
Before Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 3.2 KiB |
@ -1,11 +0,0 @@
|
||||
/*dropdown*/
|
||||
.layui-dropdown {display: inline-block;position: relative;font-size: 14px;}
|
||||
.layui-dropdown>ul {position: absolute;display: none;top:100%;left:0px;padding: 5px 0;margin:5px 0;white-space: nowrap;line-height: 36px;box-shadow: 0 2px 4px rgba(0,0,0,.12);border: 1px solid #d2d2d2;background-color: #fff;border-radius: 2px;z-index: 900;}
|
||||
.layui-dropdown>ul>h4 {color: #999;display: block;padding: 0 20px;font-size: 12px;}
|
||||
.layui-dropdown>ul>li {position: relative;}
|
||||
.layui-dropdown>ul>li>a {color: #333;display: block;padding: 0 20px;transition: all .3s;-webkit-transition: all .3s;}
|
||||
.layui-dropdown>ul>li>a>i {font-size: 14px;margin-right:5px;}
|
||||
.layui-dropdown>ul>li>a:hover {background-color: #f2f2f2;color: #000;}
|
||||
.layui-dropdown.dropdown-right>ul {left:auto;right:0px;}
|
||||
.layui-dropdown>ul>li.dropdown-item-disabled>a{color: #999;cursor:not-allowed;}
|
||||
.layui-dropdown>ul>li.dropdown-item-disabled>a:hover{color: #999;background-color:transparent;}
|
66
public/static/lib/layui/extends/kg-dropdown.css
Normal file
@ -0,0 +1,66 @@
|
||||
/*dropdown*/
|
||||
.kg-dropdown {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.kg-dropdown > ul {
|
||||
position: absolute;
|
||||
display: none;
|
||||
top: 100%;
|
||||
left: 0px;
|
||||
padding: 5px 0;
|
||||
margin: 5px 0;
|
||||
white-space: nowrap;
|
||||
line-height: 36px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, .12);
|
||||
border: 1px solid #d2d2d2;
|
||||
background-color: #fff;
|
||||
border-radius: 2px;
|
||||
z-index: 900;
|
||||
}
|
||||
|
||||
.kg-dropdown > ul > h4 {
|
||||
color: #999;
|
||||
display: block;
|
||||
padding: 0 20px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.kg-dropdown > ul > li {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.kg-dropdown > ul > li > a {
|
||||
color: #333;
|
||||
display: block;
|
||||
padding: 0 20px;
|
||||
transition: all .3s;
|
||||
-webkit-transition: all .3s;
|
||||
}
|
||||
|
||||
.kg-dropdown > ul > li > a > i {
|
||||
font-size: 14px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.kg-dropdown > ul > li > a:hover {
|
||||
background-color: #f2f2f2;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.kg-dropdown.dropdown-right > ul {
|
||||
left: auto;
|
||||
right: 0px;
|
||||
}
|
||||
|
||||
.kg-dropdown > ul > li.dropdown-item-disabled > a {
|
||||
color: #999;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.kg-dropdown > ul > li.dropdown-item-disabled > a:hover {
|
||||
color: #999;
|
||||
background-color: transparent;
|
||||
}
|
@ -4,8 +4,8 @@
|
||||
|
||||
layui.define(['jquery'], function (exports) {
|
||||
|
||||
var MOD_NAME = 'dropdown',
|
||||
CLASS_NAME = '.layui-dropdown',
|
||||
var MOD_NAME = 'kgDropdown',
|
||||
CLASS_NAME = '.kg-dropdown',
|
||||
$ = layui.jquery;
|
||||
|
||||
var dropdown = {
|
||||
@ -58,4 +58,4 @@ layui.define(['jquery'], function (exports) {
|
||||
|
||||
//输出接口
|
||||
exports(MOD_NAME, dropdown);
|
||||
});
|
||||
});
|
@ -5,7 +5,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<title>聊天记录</title>
|
||||
|
||||
<link rel="stylesheet" href="http://local.res.layui.com/layui/src/css/layui.css">
|
||||
<link rel="stylesheet" href="//unpkg.com/layui/dist/css/layui.css">
|
||||
<style>
|
||||
body .layim-chat-main {
|
||||
height: auto;
|
||||
@ -23,7 +23,7 @@
|
||||
|
||||
<textarea title="消息模版" id="LAY_tpl" style="display:none;">
|
||||
{{# layui.each(d.data, function(index, item){
|
||||
if(item.id == parent.layui.layim.cache().mine.id){ }}
|
||||
if(item.id == layui.layim.cache().mine.id){ }}
|
||||
<li class="layim-chat-mine"><div class="layim-chat-user"><img src="{{ item.avatar }}"><cite><i>{{ layui.data.date(item.timestamp) }}</i>{{ item.username }}</cite></div><div class="layim-chat-text">{{ layui.layim.content(item.content) }}</div></li>
|
||||
{{# } else { }}
|
||||
<li><div class="layim-chat-user"><img src="{{ item.avatar }}"><cite>{{ item.username }}<i>{{ layui.data.date(item.timestamp) }}</i></cite></div><div class="layim-chat-text">{{ layui.layim.content(item.content) }}</div></li>
|
||||
@ -32,22 +32,24 @@
|
||||
</textarea>
|
||||
|
||||
<!--
|
||||
上述模版采用了 laytpl 语法,不了解的同学可以去看下文档:http://www.layui.com/doc/modules/laytpl.html
|
||||
上述模版采用了 laytpl 语法
|
||||
|
||||
-->
|
||||
|
||||
|
||||
<script src="http://local.res.layui.com/layui/src/layui.js"></script>
|
||||
<script src="//unpkg.com/layui/dist/layui.js"></script>
|
||||
<script>
|
||||
layui.use(['layim', 'laypage'], function () {
|
||||
var layim = layui.layim
|
||||
, layer = layui.layer
|
||||
, laytpl = layui.laytpl
|
||||
layui.link('../layim.css', 'skinlayimcss') //加载 css
|
||||
layui.config({
|
||||
layimPath: '../../' //配置 layim.js 所在目录
|
||||
, layimAssetsPath: '../../layim-assets/' //layim 资源文件所在目录
|
||||
}).use(['jquery'], function () {
|
||||
var layim = parent.layui.layim
|
||||
, laytpl = parent.layui.laytpl
|
||||
, $ = layui.jquery
|
||||
, laypage = layui.laypage;
|
||||
|
||||
//聊天记录的分页此处不做演示,你可以采用laypage,不了解的同学见文档:http://www.layui.com/doc/modules/laypage.html
|
||||
, laypage = parent.layui.laypage;
|
||||
|
||||
//聊天记录的分页此处不做演示,你可以采用 laypage
|
||||
|
||||
//开始请求聊天记录
|
||||
var param = location.search //获得URL参数。该窗口url会携带会话id和type,他们是你请求聊天记录的重要凭据
|
||||
@ -59,27 +61,27 @@
|
||||
, data: [{
|
||||
username: '纸飞机'
|
||||
, id: 100000
|
||||
, avatar: 'http://tva3.sinaimg.cn/crop.0.0.512.512.180/8693225ajw8f2rt20ptykj20e80e8weu.jpg'
|
||||
, avatar: '' || layui.cache.layimAssetsPath + 'images/default.png'
|
||||
, timestamp: 1480897882000
|
||||
, content: 'face[抱抱] face[心] 你好啊小美女'
|
||||
, content: '我方模拟记录111'
|
||||
}, {
|
||||
username: 'Z_子晴'
|
||||
username: 'test123'
|
||||
, id: 108101
|
||||
, avatar: 'http://tva3.sinaimg.cn/crop.0.0.512.512.180/8693225ajw8f2rt20ptykj20e80e8weu.jpg'
|
||||
, avatar: '' || layui.cache.layimAssetsPath + 'images/default.png'
|
||||
, timestamp: 1480897892000
|
||||
, content: '你没发错吧?face[微笑]'
|
||||
, content: '对方模拟记录111'
|
||||
}, {
|
||||
username: 'Z_子晴'
|
||||
username: 'test123'
|
||||
, id: 108101
|
||||
, avatar: 'http://tva3.sinaimg.cn/crop.0.0.512.512.180/8693225ajw8f2rt20ptykj20e80e8weu.jpg'
|
||||
, avatar: '' || layui.cache.layimAssetsPath + 'images/default.png'
|
||||
, timestamp: 1480897898000
|
||||
, content: '你是谁呀亲。。我爱的是贤心!我爱的是贤心!我爱的是贤心!重要的事情要说三遍~'
|
||||
, content: '对方模拟记录222'
|
||||
}, {
|
||||
username: 'Z_子晴'
|
||||
username: 'test123'
|
||||
, id: 108101
|
||||
, avatar: 'http://tva3.sinaimg.cn/crop.0.0.512.512.180/8693225ajw8f2rt20ptykj20e80e8weu.jpg'
|
||||
, avatar: '' || layui.cache.layimAssetsPath + 'images/default.png'
|
||||
, timestamp: 1480897908000
|
||||
, content: '注意:这些都是模拟数据,实际使用时,需将其中的模拟接口改为你的项目真实接口。\n该模版文件所在目录(相对于layui.js):\n/css/modules/layim/html/chatlog.html'
|
||||
, content: '注意:这些都是模拟数据,实际使用时,需将其中的模拟接口改为你的项目真实接口。\n该模版文件所在目录(相对于layim.js):\n/layim-assets/html/chatlog.html'
|
||||
}]
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<title>发现</title>
|
||||
|
||||
<link rel="stylesheet" href="http://local.res.layui.com/layui/src/css/layui.css">
|
||||
<link rel="stylesheet" href="//unpkg.com/layui/dist/css/layui.css">
|
||||
<style>
|
||||
|
||||
</style>
|
||||
@ -14,14 +14,19 @@
|
||||
|
||||
<div style="margin: 15px;">
|
||||
<blockquote class="layui-elem-quote">此为自定义的【查找】页面,因需求不一,所以官方暂不提供该模版结构与样式,实际使用时,可移至该文件到你的项目中,对页面自行把控。
|
||||
<br>文件所在目录(相对于layui.js):/css/modules/layim/html/find.html
|
||||
<br>文件所在目录(相对于layui.js):/layim-assets/html/find.html
|
||||
</blockquote>
|
||||
</div>
|
||||
|
||||
|
||||
<script src="http://local.res.layui.com/layui/src/layui.js"></script>
|
||||
<script src="//unpkg.com/layui/dist/layui.js"></script>
|
||||
<script>
|
||||
layui.use(['layim', 'laypage'], function () {
|
||||
layui.config({
|
||||
layimPath: '../../' //配置 layim.js 所在目录
|
||||
, layimAssetsPath: '../../layim-assets/' //layim 资源文件所在目录
|
||||
}).extend({
|
||||
layim: layui.cache.layimPath + 'layim' //配置 layim 组件所在的路径
|
||||
}).use(['layim', 'laypage'], function () {
|
||||
var layim = layui.layim
|
||||
, layer = layui.layer
|
||||
, laytpl = layui.laytpl
|
@ -9,14 +9,14 @@
|
||||
"from": 166488,
|
||||
"from_group": 0,
|
||||
"type": 1,
|
||||
"remark": "有问题要问",
|
||||
"remark": "test1",
|
||||
"href": null,
|
||||
"read": 1,
|
||||
"time": "刚刚",
|
||||
"user": {
|
||||
"id": 166488,
|
||||
"avatar": "http://q.qlogo.cn/qqapp/101235792/B704597964F9BD0DB648292D1B09F7E8/100",
|
||||
"username": "李彦宏",
|
||||
"username": "测试111",
|
||||
"sign": null
|
||||
}
|
||||
},
|
||||
@ -27,20 +27,20 @@
|
||||
"from": 347592,
|
||||
"from_group": 0,
|
||||
"type": 1,
|
||||
"remark": "你好啊!",
|
||||
"remark": "test2",
|
||||
"href": null,
|
||||
"read": 1,
|
||||
"time": "刚刚",
|
||||
"user": {
|
||||
"id": 347592,
|
||||
"avatar": "http://q.qlogo.cn/qqapp/101235792/B78751375E0531675B1272AD994BA875/100",
|
||||
"username": "麻花疼",
|
||||
"username": "测试222",
|
||||
"sign": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 62,
|
||||
"content": "雷军 拒绝了你的好友申请",
|
||||
"content": "测试333 拒绝了你的好友申请",
|
||||
"uid": 168,
|
||||
"from": null,
|
||||
"from_group": null,
|
||||
@ -55,22 +55,7 @@
|
||||
},
|
||||
{
|
||||
"id": 60,
|
||||
"content": "马小云 已经同意你的好友申请",
|
||||
"uid": 168,
|
||||
"from": null,
|
||||
"from_group": null,
|
||||
"type": 1,
|
||||
"remark": null,
|
||||
"href": null,
|
||||
"read": 1,
|
||||
"time": "10天前",
|
||||
"user": {
|
||||
"id": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 61,
|
||||
"content": "贤心 已经同意你的好友申请",
|
||||
"content": "测试666 已经同意你的好友申请",
|
||||
"uid": 168,
|
||||
"from": null,
|
||||
"from_group": null,
|
@ -5,7 +5,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<title>消息盒子</title>
|
||||
|
||||
<link rel="stylesheet" href="../../../layui.css?v=1">
|
||||
<link rel="stylesheet" href="//unpkg.com/layui/dist/css/layui.css">
|
||||
<style>
|
||||
.layim-msgbox {
|
||||
margin: 15px;
|
||||
@ -15,6 +15,7 @@
|
||||
position: relative;
|
||||
margin-bottom: 10px;
|
||||
padding: 0 130px 10px 60px;
|
||||
padding-bottom: 10px;
|
||||
line-height: 22px;
|
||||
border-bottom: 1px dotted #e2e2e2;
|
||||
}
|
||||
@ -76,7 +77,7 @@
|
||||
|
||||
<div style="margin: 0 15px;">
|
||||
<blockquote class="layui-elem-quote">注意:这些都是模拟数据,实际使用时,需将其中的模拟接口改为你的项目真实接口。
|
||||
<br>该模版文件所在目录(相对于layui.js):/css/modules/layim/html/msgbox.html
|
||||
<br>该模版文件所在目录(相对于 layim.js):/html/msgbox.html
|
||||
</blockquote>
|
||||
</div>
|
||||
|
||||
@ -109,13 +110,18 @@
|
||||
</textarea>
|
||||
|
||||
<!--
|
||||
上述模版采用了 laytpl 语法,不了解的同学可以去看下文档:http://www.layui.com/doc/modules/laytpl.html
|
||||
上述模版采用了 laytpl 语法
|
||||
-->
|
||||
|
||||
|
||||
<script src="../../../../layui.js?v=1"></script>
|
||||
<script src="//unpkg.com/layui/dist/layui.js"></script>
|
||||
<script>
|
||||
layui.use(['layim', 'flow'], function () {
|
||||
layui.config({
|
||||
layimPath: '../../' //配置 layim.js 所在目录
|
||||
, layimAssetsPath: '../../layim-assets/' //layim 资源文件所在目录
|
||||
}).extend({
|
||||
layim: layui.cache.layimPath + 'layim' //配置 layim 组件所在的路径
|
||||
}).use(['layim', 'flow'], function () {
|
||||
var layim = layui.layim
|
||||
, layer = layui.layer
|
||||
, laytpl = layui.laytpl
|
||||
@ -233,15 +239,20 @@
|
||||
, uid = li.data('uid');
|
||||
|
||||
layer.confirm('确定拒绝吗?', function (index) {
|
||||
layer.close(index);
|
||||
othis.parent().html('<em>已拒绝</em>');
|
||||
|
||||
/*
|
||||
$.post('/im/refuseFriend', {
|
||||
uid: uid //对方用户ID
|
||||
}, function (res) {
|
||||
if (res.code != 0) {
|
||||
return layer.msg(res.msg);
|
||||
}
|
||||
layer.close(index);
|
||||
othis.parent().html('<em>已拒绝</em>');
|
||||
uid: uid //对方用户ID
|
||||
}, function(res){
|
||||
if(res.code != 0){
|
||||
return layer.msg(res.msg);
|
||||
}
|
||||
layer.close(index);
|
||||
othis.parent().html('<em>已拒绝</em>');
|
||||
});
|
||||
*/
|
||||
});
|
||||
}
|
||||
};
|
BIN
public/static/lib/layui/extends/layim/assets/images/default.png
Normal file
After Width: | Height: | Size: 6.6 KiB |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.0 KiB |
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 7.3 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 6.6 KiB |
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.0 KiB |