mirror of
https://gitee.com/koogua/course-tencent-cloud.git
synced 2025-06-18 10:08:24 +08:00
Compare commits
No commits in common. "master" and "v1.7.6" have entirely different histories.
25
CHANGELOG.md
25
CHANGELOG.md
@ -1,28 +1,3 @@
|
|||||||
### [v1.7.8](https://gitee.com/koogua/course-tencent-cloud/releases/v1.7.8)(2025-06-20)
|
|
||||||
|
|
||||||
- 移除ThrottleLimit
|
|
||||||
- 增加CloseLiveTask
|
|
||||||
- 增加搜索页图片alt属性striptags过滤
|
|
||||||
- 后台增加返回顶部快捷方式
|
|
||||||
- 前台fixbar增加联系电话
|
|
||||||
- 优化安装脚本
|
|
||||||
- 优化课时列表直播提示
|
|
||||||
- 优化后台返回链接
|
|
||||||
- 优化统计分析代码位置
|
|
||||||
- 直播回调后更新课时缓存
|
|
||||||
- 后台清空头像->上传头像
|
|
||||||
- sitemap.xml直接写入网站根目录
|
|
||||||
|
|
||||||
### [v1.7.7](https://gitee.com/koogua/course-tencent-cloud/releases/v1.7.7)(2025-04-20)
|
|
||||||
|
|
||||||
- 优化索引管理工具
|
|
||||||
- 优化章节等页面UI
|
|
||||||
- 修正workerman中onMessage问题
|
|
||||||
- 修正非免费课程试听问题
|
|
||||||
- 优化layer窗口中的表单跳转
|
|
||||||
- 文件清理以及命名优化
|
|
||||||
- 优化倒计时
|
|
||||||
|
|
||||||
### [v1.7.6](https://gitee.com/koogua/course-tencent-cloud/releases/v1.7.6)(2025-03-22)
|
### [v1.7.6](https://gitee.com/koogua/course-tencent-cloud/releases/v1.7.6)(2025-03-22)
|
||||||
|
|
||||||
- 升级layui-v2.9.25
|
- 升级layui-v2.9.25
|
||||||
|
@ -18,13 +18,6 @@ abstract class Migration
|
|||||||
|
|
||||||
abstract public function run();
|
abstract public function run();
|
||||||
|
|
||||||
protected function saveSettings(array $settings)
|
|
||||||
{
|
|
||||||
foreach ($settings as $setting) {
|
|
||||||
$this->saveSetting($setting);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function saveSetting(array $setting)
|
protected function saveSetting(array $setting)
|
||||||
{
|
{
|
||||||
$settingRepo = new SettingRepo();
|
$settingRepo = new SettingRepo();
|
||||||
@ -39,4 +32,4 @@ abstract class Migration
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -20,6 +20,8 @@ class ArticleIndexTask extends Task
|
|||||||
* 搜索测试
|
* 搜索测试
|
||||||
*
|
*
|
||||||
* @command: php console.php article_index search {query}
|
* @command: php console.php article_index search {query}
|
||||||
|
* @param array $params
|
||||||
|
* @throws \XSException
|
||||||
*/
|
*/
|
||||||
public function searchAction($params)
|
public function searchAction($params)
|
||||||
{
|
{
|
||||||
@ -29,9 +31,7 @@ class ArticleIndexTask extends Task
|
|||||||
exit('please special a query word' . PHP_EOL);
|
exit('please special a query word' . PHP_EOL);
|
||||||
}
|
}
|
||||||
|
|
||||||
$handler = new ArticleSearcher();
|
$result = $this->searchArticles($query);
|
||||||
|
|
||||||
$result = $handler->search($query);
|
|
||||||
|
|
||||||
var_export($result);
|
var_export($result);
|
||||||
}
|
}
|
||||||
@ -42,6 +42,24 @@ class ArticleIndexTask extends Task
|
|||||||
* @command: php console.php article_index clean
|
* @command: php console.php article_index clean
|
||||||
*/
|
*/
|
||||||
public function cleanAction()
|
public function cleanAction()
|
||||||
|
{
|
||||||
|
$this->cleanArticleIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重建索引
|
||||||
|
*
|
||||||
|
* @command: php console.php article_index rebuild
|
||||||
|
*/
|
||||||
|
public function rebuildAction()
|
||||||
|
{
|
||||||
|
$this->rebuildArticleIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清空索引
|
||||||
|
*/
|
||||||
|
protected function cleanArticleIndex()
|
||||||
{
|
{
|
||||||
$handler = new ArticleSearcher();
|
$handler = new ArticleSearcher();
|
||||||
|
|
||||||
@ -56,10 +74,8 @@ class ArticleIndexTask extends Task
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 重建索引
|
* 重建索引
|
||||||
*
|
|
||||||
* @command: php console.php article_index rebuild
|
|
||||||
*/
|
*/
|
||||||
public function rebuildAction()
|
protected function rebuildArticleIndex()
|
||||||
{
|
{
|
||||||
$articles = $this->findArticles();
|
$articles = $this->findArticles();
|
||||||
|
|
||||||
@ -67,7 +83,7 @@ class ArticleIndexTask extends Task
|
|||||||
|
|
||||||
$handler = new ArticleSearcher();
|
$handler = new ArticleSearcher();
|
||||||
|
|
||||||
$doc = new ArticleDocument();
|
$documenter = new ArticleDocument();
|
||||||
|
|
||||||
$index = $handler->getXS()->getIndex();
|
$index = $handler->getXS()->getIndex();
|
||||||
|
|
||||||
@ -76,7 +92,7 @@ class ArticleIndexTask extends Task
|
|||||||
$index->beginRebuild();
|
$index->beginRebuild();
|
||||||
|
|
||||||
foreach ($articles as $article) {
|
foreach ($articles as $article) {
|
||||||
$document = $doc->setDocument($article);
|
$document = $documenter->setDocument($article);
|
||||||
$index->add($document);
|
$index->add($document);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,39 +102,17 @@ class ArticleIndexTask extends Task
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 刷新索引缓存
|
* 搜索文章
|
||||||
*
|
*
|
||||||
* @command: php console.php article_index flush_index
|
* @param string $query
|
||||||
|
* @return array
|
||||||
|
* @throws \XSException
|
||||||
*/
|
*/
|
||||||
public function flushIndexAction()
|
protected function searchArticles($query)
|
||||||
{
|
{
|
||||||
$handler = new ArticleSearcher();
|
$handler = new ArticleSearcher();
|
||||||
|
|
||||||
$index = $handler->getXS()->getIndex();
|
return $handler->search($query);
|
||||||
|
|
||||||
echo '------ start flush article index ------' . PHP_EOL;
|
|
||||||
|
|
||||||
$index->flushIndex();
|
|
||||||
|
|
||||||
echo '------ end flush article index ------' . PHP_EOL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 刷新搜索日志
|
|
||||||
*
|
|
||||||
* @command: php console.php article_index flush_logging
|
|
||||||
*/
|
|
||||||
public function flushLoggingAction()
|
|
||||||
{
|
|
||||||
$handler = new ArticleSearcher();
|
|
||||||
|
|
||||||
$index = $handler->getXS()->getIndex();
|
|
||||||
|
|
||||||
echo '------ start flush article logging ------' . PHP_EOL;
|
|
||||||
|
|
||||||
$index->flushLogging();
|
|
||||||
|
|
||||||
echo '------ end flush article logging ------' . PHP_EOL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,72 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* @copyright Copyright (c) 2024 深圳市酷瓜软件有限公司
|
|
||||||
* @license https://opensource.org/licenses/GPL-2.0
|
|
||||||
* @link https://www.koogua.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace App\Console\Tasks;
|
|
||||||
|
|
||||||
use App\Caches\CourseChapterList as CourseChapterListCache;
|
|
||||||
use App\Models\Chapter as ChapterModel;
|
|
||||||
use App\Models\ChapterLive as ChapterLiveModel;
|
|
||||||
use App\Repos\Chapter as ChapterRepo;
|
|
||||||
use Phalcon\Mvc\Model\Resultset;
|
|
||||||
use Phalcon\Mvc\Model\ResultsetInterface;
|
|
||||||
|
|
||||||
class CloseLiveTask extends Task
|
|
||||||
{
|
|
||||||
|
|
||||||
public function mainAction()
|
|
||||||
{
|
|
||||||
$chapterLives = $this->findChapterLives();
|
|
||||||
|
|
||||||
echo sprintf('pending lives: %s', $chapterLives->count()) . PHP_EOL;
|
|
||||||
|
|
||||||
if ($chapterLives->count() == 0) return;
|
|
||||||
|
|
||||||
echo '------ start close live task ------' . PHP_EOL;
|
|
||||||
|
|
||||||
foreach ($chapterLives as $chapterLive) {
|
|
||||||
|
|
||||||
$chapterLive->status = ChapterLiveModel::STATUS_INACTIVE;
|
|
||||||
|
|
||||||
$chapterLive->update();
|
|
||||||
|
|
||||||
$chapterRepo = new ChapterRepo();
|
|
||||||
|
|
||||||
$chapter = $chapterRepo->findById($chapterLive->chapter_id);
|
|
||||||
|
|
||||||
$attrs = $chapter->attrs;
|
|
||||||
$attrs['stream']['status'] = ChapterModel::SS_INACTIVE;
|
|
||||||
$chapter->attrs = $attrs;
|
|
||||||
|
|
||||||
$chapter->update();
|
|
||||||
|
|
||||||
$cache = new CourseChapterListCache();
|
|
||||||
|
|
||||||
$cache->rebuild($chapterLive->course_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
echo '------ end close live task ------' . PHP_EOL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查找待关闭直播
|
|
||||||
*
|
|
||||||
* @param int $limit
|
|
||||||
* @return ResultsetInterface|Resultset|ChapterLiveModel[]
|
|
||||||
*/
|
|
||||||
protected function findChapterLives(int $limit = 100)
|
|
||||||
{
|
|
||||||
$status = ChapterLiveModel::STATUS_ACTIVE;
|
|
||||||
$endTime = time() - 3600;
|
|
||||||
|
|
||||||
return ChapterLiveModel::query()
|
|
||||||
->where('status = :status:', ['status' => $status])
|
|
||||||
->andWhere('end_time < :end_time:', ['end_time' => $endTime])
|
|
||||||
->limit($limit)
|
|
||||||
->execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -20,6 +20,8 @@ class CourseIndexTask extends Task
|
|||||||
* 搜索测试
|
* 搜索测试
|
||||||
*
|
*
|
||||||
* @command: php console.php course_index search {query}
|
* @command: php console.php course_index search {query}
|
||||||
|
* @param array $params
|
||||||
|
* @throws \XSException
|
||||||
*/
|
*/
|
||||||
public function searchAction($params)
|
public function searchAction($params)
|
||||||
{
|
{
|
||||||
@ -29,9 +31,7 @@ class CourseIndexTask extends Task
|
|||||||
exit('please special a query word' . PHP_EOL);
|
exit('please special a query word' . PHP_EOL);
|
||||||
}
|
}
|
||||||
|
|
||||||
$handler = new CourseSearcher();
|
$result = $this->searchCourses($query);
|
||||||
|
|
||||||
$result = $handler->search($query);
|
|
||||||
|
|
||||||
var_export($result);
|
var_export($result);
|
||||||
}
|
}
|
||||||
@ -42,6 +42,24 @@ class CourseIndexTask extends Task
|
|||||||
* @command: php console.php course_index clean
|
* @command: php console.php course_index clean
|
||||||
*/
|
*/
|
||||||
public function cleanAction()
|
public function cleanAction()
|
||||||
|
{
|
||||||
|
$this->cleanCourseIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重建索引
|
||||||
|
*
|
||||||
|
* @command: php console.php course_index rebuild
|
||||||
|
*/
|
||||||
|
public function rebuildAction()
|
||||||
|
{
|
||||||
|
$this->rebuildCourseIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清空索引
|
||||||
|
*/
|
||||||
|
protected function cleanCourseIndex()
|
||||||
{
|
{
|
||||||
$handler = new CourseSearcher();
|
$handler = new CourseSearcher();
|
||||||
|
|
||||||
@ -56,10 +74,8 @@ class CourseIndexTask extends Task
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 重建索引
|
* 重建索引
|
||||||
*
|
|
||||||
* @command: php console.php course_index rebuild
|
|
||||||
*/
|
*/
|
||||||
public function rebuildAction()
|
protected function rebuildCourseIndex()
|
||||||
{
|
{
|
||||||
$courses = $this->findCourses();
|
$courses = $this->findCourses();
|
||||||
|
|
||||||
@ -67,7 +83,7 @@ class CourseIndexTask extends Task
|
|||||||
|
|
||||||
$handler = new CourseSearcher();
|
$handler = new CourseSearcher();
|
||||||
|
|
||||||
$doc = new CourseDocument();
|
$documenter = new CourseDocument();
|
||||||
|
|
||||||
$index = $handler->getXS()->getIndex();
|
$index = $handler->getXS()->getIndex();
|
||||||
|
|
||||||
@ -76,7 +92,7 @@ class CourseIndexTask extends Task
|
|||||||
$index->beginRebuild();
|
$index->beginRebuild();
|
||||||
|
|
||||||
foreach ($courses as $course) {
|
foreach ($courses as $course) {
|
||||||
$document = $doc->setDocument($course);
|
$document = $documenter->setDocument($course);
|
||||||
$index->add($document);
|
$index->add($document);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,39 +102,17 @@ class CourseIndexTask extends Task
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 刷新索引缓存
|
* 搜索课程
|
||||||
*
|
*
|
||||||
* @command: php console.php course_index flush_index
|
* @param string $query
|
||||||
|
* @return array
|
||||||
|
* @throws \XSException
|
||||||
*/
|
*/
|
||||||
public function flushIndexAction()
|
protected function searchCourses($query)
|
||||||
{
|
{
|
||||||
$handler = new CourseSearcher();
|
$handler = new CourseSearcher();
|
||||||
|
|
||||||
$index = $handler->getXS()->getIndex();
|
return $handler->search($query);
|
||||||
|
|
||||||
echo '------ start flush course index ------' . PHP_EOL;
|
|
||||||
|
|
||||||
$index->flushIndex();
|
|
||||||
|
|
||||||
echo '------ end flush course index ------' . PHP_EOL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 刷新搜索日志
|
|
||||||
*
|
|
||||||
* @command: php console.php course_index flush_logging
|
|
||||||
*/
|
|
||||||
public function flushLoggingAction()
|
|
||||||
{
|
|
||||||
$handler = new CourseSearcher();
|
|
||||||
|
|
||||||
$index = $handler->getXS()->getIndex();
|
|
||||||
|
|
||||||
echo '------ start flush course logging ------' . PHP_EOL;
|
|
||||||
|
|
||||||
$index->flushLogging();
|
|
||||||
|
|
||||||
echo '------ end flush course logging ------' . PHP_EOL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -130,7 +124,7 @@ class CourseIndexTask extends Task
|
|||||||
{
|
{
|
||||||
return CourseModel::query()
|
return CourseModel::query()
|
||||||
->where('published = 1')
|
->where('published = 1')
|
||||||
->andWhere('deleted = 0')
|
->where('deleted = 0')
|
||||||
->execute();
|
->execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,6 +20,8 @@ class QuestionIndexTask extends Task
|
|||||||
* 搜索测试
|
* 搜索测试
|
||||||
*
|
*
|
||||||
* @command: php console.php question_index search {query}
|
* @command: php console.php question_index search {query}
|
||||||
|
* @param array $params
|
||||||
|
* @throws \XSException
|
||||||
*/
|
*/
|
||||||
public function searchAction($params)
|
public function searchAction($params)
|
||||||
{
|
{
|
||||||
@ -29,9 +31,7 @@ class QuestionIndexTask extends Task
|
|||||||
exit('please special a query word' . PHP_EOL);
|
exit('please special a query word' . PHP_EOL);
|
||||||
}
|
}
|
||||||
|
|
||||||
$handler = new QuestionSearcher();
|
$result = $this->searchQuestions($query);
|
||||||
|
|
||||||
$result = $handler->search($query);
|
|
||||||
|
|
||||||
var_export($result);
|
var_export($result);
|
||||||
}
|
}
|
||||||
@ -42,6 +42,24 @@ class QuestionIndexTask extends Task
|
|||||||
* @command: php console.php question_index clean
|
* @command: php console.php question_index clean
|
||||||
*/
|
*/
|
||||||
public function cleanAction()
|
public function cleanAction()
|
||||||
|
{
|
||||||
|
$this->cleanQuestionIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重建索引
|
||||||
|
*
|
||||||
|
* @command: php console.php question_index rebuild
|
||||||
|
*/
|
||||||
|
public function rebuildAction()
|
||||||
|
{
|
||||||
|
$this->rebuildQuestionIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清空索引
|
||||||
|
*/
|
||||||
|
protected function cleanQuestionIndex()
|
||||||
{
|
{
|
||||||
$handler = new QuestionSearcher();
|
$handler = new QuestionSearcher();
|
||||||
|
|
||||||
@ -56,10 +74,8 @@ class QuestionIndexTask extends Task
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 重建索引
|
* 重建索引
|
||||||
*
|
|
||||||
* @command: php console.php question_index rebuild
|
|
||||||
*/
|
*/
|
||||||
public function rebuildAction()
|
protected function rebuildQuestionIndex()
|
||||||
{
|
{
|
||||||
$questions = $this->findQuestions();
|
$questions = $this->findQuestions();
|
||||||
|
|
||||||
@ -67,7 +83,7 @@ class QuestionIndexTask extends Task
|
|||||||
|
|
||||||
$handler = new QuestionSearcher();
|
$handler = new QuestionSearcher();
|
||||||
|
|
||||||
$doc = new QuestionDocument();
|
$documenter = new QuestionDocument();
|
||||||
|
|
||||||
$index = $handler->getXS()->getIndex();
|
$index = $handler->getXS()->getIndex();
|
||||||
|
|
||||||
@ -76,7 +92,7 @@ class QuestionIndexTask extends Task
|
|||||||
$index->beginRebuild();
|
$index->beginRebuild();
|
||||||
|
|
||||||
foreach ($questions as $question) {
|
foreach ($questions as $question) {
|
||||||
$document = $doc->setDocument($question);
|
$document = $documenter->setDocument($question);
|
||||||
$index->add($document);
|
$index->add($document);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,39 +102,17 @@ class QuestionIndexTask extends Task
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 刷新索引缓存
|
* 搜索文章
|
||||||
*
|
*
|
||||||
* @command: php console.php question_index flush_index
|
* @param string $query
|
||||||
|
* @return array
|
||||||
|
* @throws \XSException
|
||||||
*/
|
*/
|
||||||
public function flushIndexAction()
|
protected function searchQuestions($query)
|
||||||
{
|
{
|
||||||
$handler = new QuestionSearcher();
|
$handler = new QuestionSearcher();
|
||||||
|
|
||||||
$index = $handler->getXS()->getIndex();
|
return $handler->search($query);
|
||||||
|
|
||||||
echo '------ start flush question index ------' . PHP_EOL;
|
|
||||||
|
|
||||||
$index->flushIndex();
|
|
||||||
|
|
||||||
echo '------ end flush question index ------' . PHP_EOL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 刷新搜索日志
|
|
||||||
*
|
|
||||||
* @command: php console.php question_index flush_logging
|
|
||||||
*/
|
|
||||||
public function flushLoggingAction()
|
|
||||||
{
|
|
||||||
$handler = new QuestionSearcher();
|
|
||||||
|
|
||||||
$index = $handler->getXS()->getIndex();
|
|
||||||
|
|
||||||
echo '------ start flush question logging ------' . PHP_EOL;
|
|
||||||
|
|
||||||
$index->flushLogging();
|
|
||||||
|
|
||||||
echo '------ end flush question logging ------' . PHP_EOL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -37,7 +37,7 @@ class SitemapTask extends Task
|
|||||||
|
|
||||||
$this->sitemap = new Sitemap();
|
$this->sitemap = new Sitemap();
|
||||||
|
|
||||||
$filename = public_path('sitemap.xml');
|
$filename = tmp_path('sitemap.xml');
|
||||||
|
|
||||||
echo '------ start sitemap task ------' . PHP_EOL;
|
echo '------ start sitemap task ------' . PHP_EOL;
|
||||||
|
|
||||||
|
@ -13,12 +13,12 @@ use GuzzleHttp\Client;
|
|||||||
class SyncAppInfoTask extends Task
|
class SyncAppInfoTask extends Task
|
||||||
{
|
{
|
||||||
|
|
||||||
const API_BASE_URL = 'https://www.koogua.com/api';
|
|
||||||
|
|
||||||
public function mainAction()
|
public function mainAction()
|
||||||
{
|
{
|
||||||
echo '------ start sync app info ------' . PHP_EOL;
|
echo '------ start sync app info ------' . PHP_EOL;
|
||||||
|
|
||||||
|
$url = 'https://www.koogua.com/api/instance/collect';
|
||||||
|
|
||||||
$site = $this->getSettings('site');
|
$site = $this->getSettings('site');
|
||||||
|
|
||||||
$serverHost = parse_url($site['url'], PHP_URL_HOST);
|
$serverHost = parse_url($site['url'], PHP_URL_HOST);
|
||||||
@ -38,8 +38,6 @@ class SyncAppInfoTask extends Task
|
|||||||
|
|
||||||
$client = new Client();
|
$client = new Client();
|
||||||
|
|
||||||
$url = sprintf('%s/instance/collect', self::API_BASE_URL);
|
|
||||||
|
|
||||||
$client->request('POST', $url, ['form_params' => $params]);
|
$client->request('POST', $url, ['form_params' => $params]);
|
||||||
|
|
||||||
echo '------ end sync app info ------' . PHP_EOL;
|
echo '------ end sync app info ------' . PHP_EOL;
|
||||||
|
@ -71,6 +71,28 @@ class UploadController extends Controller
|
|||||||
return $this->jsonSuccess(['data' => $data]);
|
return $this->jsonSuccess(['data' => $data]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Post("/avatar/img", name="admin.upload.avatar_img")
|
||||||
|
*/
|
||||||
|
public function uploadAvatarImageAction()
|
||||||
|
{
|
||||||
|
$service = new StorageService();
|
||||||
|
|
||||||
|
$file = $service->uploadAvatarImage();
|
||||||
|
|
||||||
|
if (!$file) {
|
||||||
|
return $this->jsonError(['msg' => '上传文件失败']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'id' => $file->id,
|
||||||
|
'name' => $file->name,
|
||||||
|
'url' => $service->getImageUrl($file->path),
|
||||||
|
];
|
||||||
|
|
||||||
|
return $this->jsonSuccess(['data' => $data]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Post("/content/img", name="admin.upload.content_img")
|
* @Post("/content/img", name="admin.upload.content_img")
|
||||||
*/
|
*/
|
||||||
|
@ -52,8 +52,8 @@ class Setting extends Service
|
|||||||
{
|
{
|
||||||
$alipay = $this->getSettings('pay.alipay');
|
$alipay = $this->getSettings('pay.alipay');
|
||||||
|
|
||||||
$alipay['return_url'] = $alipay['return_url'] ?: kg_full_url(['for' => 'home.alipay.callback']);
|
$alipay['return_url'] = $alipay['return_url'] ?: kg_full_url(['for' => 'home.alipay_callback']);
|
||||||
$alipay['notify_url'] = $alipay['notify_url'] ?: kg_full_url(['for' => 'home.alipay.notify']);
|
$alipay['notify_url'] = $alipay['notify_url'] ?: kg_full_url(['for' => 'home.alipay_notify']);
|
||||||
|
|
||||||
return $alipay;
|
return $alipay;
|
||||||
}
|
}
|
||||||
@ -62,8 +62,8 @@ class Setting extends Service
|
|||||||
{
|
{
|
||||||
$wxpay = $this->getSettings('pay.wxpay');
|
$wxpay = $this->getSettings('pay.wxpay');
|
||||||
|
|
||||||
$wxpay['return_url'] = $wxpay['return_url'] ?: kg_full_url(['for' => 'home.wxpay.callback']);
|
$wxpay['return_url'] = $wxpay['return_url'] ?: kg_full_url(['for' => 'home.wxpay_callback']);
|
||||||
$wxpay['notify_url'] = $wxpay['notify_url'] ?: kg_full_url(['for' => 'home.wxpay.notify']);
|
$wxpay['notify_url'] = $wxpay['notify_url'] ?: kg_full_url(['for' => 'home.wxpay_notify']);
|
||||||
|
|
||||||
return $wxpay;
|
return $wxpay;
|
||||||
}
|
}
|
||||||
@ -109,11 +109,11 @@ class Setting extends Service
|
|||||||
$result = $this->getSettings($section);
|
$result = $this->getSettings($section);
|
||||||
|
|
||||||
if ($section == 'live.notify') {
|
if ($section == 'live.notify') {
|
||||||
$result['stream_begin_url'] = $result['stream_begin_url'] ?: kg_full_url(['for' => 'home.live.notify'], ['action' => 'streamBegin']);
|
$result['stream_begin_url'] = $result['stream_begin_url'] ?: kg_full_url(['for' => 'home.live_notify'], ['action' => 'streamBegin']);
|
||||||
$result['stream_end_url'] = $result['stream_end_url'] ?: kg_full_url(['for' => 'home.live.notify'], ['action' => 'streamEnd']);
|
$result['stream_end_url'] = $result['stream_end_url'] ?: kg_full_url(['for' => 'home.live_notify'], ['action' => 'streamEnd']);
|
||||||
$result['record_url'] = $result['record_url'] ?: kg_full_url(['for' => 'home.live.notify'], ['action' => 'record']);
|
$result['record_url'] = $result['record_url'] ?: kg_full_url(['for' => 'home.live_notify'], ['action' => 'record']);
|
||||||
$result['snapshot_url'] = $result['snapshot_url'] ?: kg_full_url(['for' => 'home.live.notify'], ['action' => 'snapshot']);
|
$result['snapshot_url'] = $result['snapshot_url'] ?: kg_full_url(['for' => 'home.live_notify'], ['action' => 'snapshot']);
|
||||||
$result['porn_url'] = $result['porn_url'] ?: kg_full_url(['for' => 'home.live.notify'], ['action' => 'porn']);
|
$result['porn_url'] = $result['porn_url'] ?: kg_full_url(['for' => 'home.live_notify'], ['action' => 'porn']);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
<div class="kg-nav-left">
|
<div class="kg-nav-left">
|
||||||
<span class="layui-breadcrumb">
|
<span class="layui-breadcrumb">
|
||||||
{% if parent.id > 0 %}
|
{% if parent.id > 0 %}
|
||||||
<a href="{{ back_url }}"><i class="layui-icon layui-icon-return"></i>返回</a>
|
<a class="kg-back" href="{{ back_url }}"><i class="layui-icon layui-icon-return"></i>返回</a>
|
||||||
<a><cite>{{ parent.name }}</cite></a>
|
<a><cite>{{ parent.name }}</cite></a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a><cite>分类管理</cite></a>
|
<a><cite>分类管理</cite></a>
|
||||||
@ -87,4 +87,4 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -88,7 +88,7 @@
|
|||||||
layer.open({
|
layer.open({
|
||||||
type: 2,
|
type: 2,
|
||||||
title: '推流测试',
|
title: '推流测试',
|
||||||
area: ['720px', '540px'],
|
area: ['720px', '500px'],
|
||||||
content: [url, 'no']
|
content: [url, 'no']
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -97,4 +97,4 @@
|
|||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -43,7 +43,7 @@
|
|||||||
<div class="kg-nav">
|
<div class="kg-nav">
|
||||||
<div class="kg-nav-left">
|
<div class="kg-nav-left">
|
||||||
<span class="layui-breadcrumb">
|
<span class="layui-breadcrumb">
|
||||||
<a href="{{ back_url }}"><i class="layui-icon layui-icon-return"></i>返回</a>
|
<a class="kg-back" href="{{ back_url }}"><i class="layui-icon layui-icon-return"></i>返回</a>
|
||||||
<a><cite>{{ course.title }}</cite></a>
|
<a><cite>{{ course.title }}</cite></a>
|
||||||
<a><cite>{{ chapter.title }}</cite></a>
|
<a><cite>{{ chapter.title }}</cite></a>
|
||||||
<a><cite>课时管理</cite></a>
|
<a><cite>课时管理</cite></a>
|
||||||
@ -126,4 +126,4 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -9,7 +9,7 @@
|
|||||||
<div class="kg-nav">
|
<div class="kg-nav">
|
||||||
<div class="kg-nav-left">
|
<div class="kg-nav-left">
|
||||||
<span class="layui-breadcrumb">
|
<span class="layui-breadcrumb">
|
||||||
<a href="{{ back_url }}"><i class="layui-icon layui-icon-return"></i>返回</a>
|
<a class="kg-back" href="{{ back_url }}"><i class="layui-icon layui-icon-return"></i>返回</a>
|
||||||
<a><cite>{{ course.title }}</cite></a>
|
<a><cite>{{ course.title }}</cite></a>
|
||||||
<a><cite>章节管理</cite></a>
|
<a><cite>章节管理</cite></a>
|
||||||
</span>
|
</span>
|
||||||
@ -79,4 +79,4 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -3,6 +3,7 @@
|
|||||||
<table class="kg-table layui-table">
|
<table class="kg-table layui-table">
|
||||||
<tr>
|
<tr>
|
||||||
<th>名称</th>
|
<th>名称</th>
|
||||||
|
<th>类型</th>
|
||||||
<th>大小</th>
|
<th>大小</th>
|
||||||
<th>日期</th>
|
<th>日期</th>
|
||||||
<th width="15%">操作</th>
|
<th width="15%">操作</th>
|
||||||
@ -12,6 +13,7 @@
|
|||||||
{% set delete_url = url({'for':'admin.resource.delete','id':item.id}) %}
|
{% set delete_url = url({'for':'admin.resource.delete','id':item.id}) %}
|
||||||
<tr>
|
<tr>
|
||||||
<td><input class="layui-input res-name" type="text" value="{{ item.upload.name }}" data-url="{{ update_url }}"></td>
|
<td><input class="layui-input res-name" type="text" value="{{ item.upload.name }}" data-url="{{ update_url }}"></td>
|
||||||
|
<td>{{ item.upload.mime }}</td>
|
||||||
<td>{{ item.upload.size|human_size }}</td>
|
<td>{{ item.upload.size|human_size }}</td>
|
||||||
<td>{{ date('Y-m-d H:i:s',item.create_time) }}</td>
|
<td>{{ date('Y-m-d H:i:s',item.create_time) }}</td>
|
||||||
<td>
|
<td>
|
||||||
@ -25,4 +27,4 @@
|
|||||||
{% else %}
|
{% else %}
|
||||||
<div class="kg-center">没有相关资料</div>
|
<div class="kg-center">没有相关资料</div>
|
||||||
<br>
|
<br>
|
||||||
{% endif %}
|
{% endif %}
|
@ -25,7 +25,9 @@
|
|||||||
<div class="kg-nav-left">
|
<div class="kg-nav-left">
|
||||||
<span class="layui-breadcrumb">
|
<span class="layui-breadcrumb">
|
||||||
{% if parent.id > 0 %}
|
{% if parent.id > 0 %}
|
||||||
<a href="{{ back_url }}"><i class="layui-icon layui-icon-return"></i>返回</a>
|
<a class="kg-back" href="{{ back_url }}">
|
||||||
|
<i class="layui-icon layui-icon-return"></i> 返回
|
||||||
|
</a>
|
||||||
<a><cite>{{ parent.name }}</cite></a>
|
<a><cite>{{ parent.name }}</cite></a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a><cite>导航管理</cite></a>
|
<a><cite>导航管理</cite></a>
|
||||||
|
@ -65,7 +65,7 @@
|
|||||||
layer.open({
|
layer.open({
|
||||||
type: 2,
|
type: 2,
|
||||||
title: '推流测试',
|
title: '推流测试',
|
||||||
area: ['720px', '540px'],
|
area: ['720px', '500px'],
|
||||||
content: [url, 'no']
|
content: [url, 'no']
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -85,4 +85,4 @@
|
|||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -20,10 +20,9 @@
|
|||||||
|
|
||||||
{{ js_include('lib/layui/layui.js') }}
|
{{ js_include('lib/layui/layui.js') }}
|
||||||
{{ js_include('admin/js/common.js') }}
|
{{ js_include('admin/js/common.js') }}
|
||||||
{{ js_include('admin/js/fixbar.js') }}
|
|
||||||
|
|
||||||
{% block include_js %}{% endblock %}
|
{% block include_js %}{% endblock %}
|
||||||
{% block inline_js %}{% endblock %}
|
{% block inline_js %}{% endblock %}
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -21,11 +21,12 @@
|
|||||||
<div class="layui-form-item">
|
<div class="layui-form-item">
|
||||||
<label class="layui-form-label" style="padding-top:30px;">头像</label>
|
<label class="layui-form-label" style="padding-top:30px;">头像</label>
|
||||||
<div class="layui-input-inline" style="width:80px;">
|
<div class="layui-input-inline" style="width:80px;">
|
||||||
<img id="img-avatar" class="kg-avatar" src="{{ user.avatar }}">
|
<img id="avatar" class="kg-avatar" src="{{ user.avatar }}">
|
||||||
<input type="hidden" name="avatar" value="{{ user.avatar }}">
|
<input type="hidden" name="avatar" value="{{ user.avatar }}">
|
||||||
|
<input type="hidden" name="default_avatar" value="{{ default_avatar }}">
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-input-inline" style="padding-top:25px;">
|
<div class="layui-input-inline" style="padding-top:25px;">
|
||||||
<button id="change-avatar" class="layui-btn layui-btn-sm" type="button">更换</button>
|
<button id="clear-avatar" class="layui-btn layui-btn-sm" type="button">清空</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-form-item">
|
<div class="layui-form-item">
|
||||||
@ -152,12 +153,6 @@
|
|||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block include_js %}
|
|
||||||
|
|
||||||
{{ js_include('admin/js/avatar.upload.js') }}
|
|
||||||
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block inline_js %}
|
{% block inline_js %}
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@ -168,6 +163,12 @@
|
|||||||
var form = layui.form;
|
var form = layui.form;
|
||||||
var laydate = layui.laydate;
|
var laydate = layui.laydate;
|
||||||
|
|
||||||
|
$('#clear-avatar').on('click', function () {
|
||||||
|
var defaultAvatar = $('input[name=default_avatar]').val();
|
||||||
|
$('input[name=avatar]').val(defaultAvatar);
|
||||||
|
$('#avatar').attr('src', defaultAvatar);
|
||||||
|
});
|
||||||
|
|
||||||
laydate.render({
|
laydate.render({
|
||||||
elem: 'input[name=vip_expiry_time]',
|
elem: 'input[name=vip_expiry_time]',
|
||||||
type: 'datetime'
|
type: 'datetime'
|
||||||
@ -200,4 +201,4 @@
|
|||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -30,6 +30,8 @@ class Controller extends \Phalcon\Mvc\Controller
|
|||||||
$this->setCors();
|
$this->setCors();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->checkRateLimit();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Api\Controllers;
|
namespace App\Http\Api\Controllers;
|
||||||
|
|
||||||
use App\Services\Logic\Live\LiveChat as LiveChatService;
|
use App\Services\Logic\Live\LiveChapter as LiveChapterService;
|
||||||
use App\Services\Logic\Live\LiveList as LiveListService;
|
use App\Services\Logic\Live\LiveList as LiveListService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -33,7 +33,7 @@ class LiveController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function chatsAction($id)
|
public function chatsAction($id)
|
||||||
{
|
{
|
||||||
$service = new LiveChatService();
|
$service = new LiveChapterService();
|
||||||
|
|
||||||
$chats = $service->getRecentChats($id);
|
$chats = $service->getRecentChats($id);
|
||||||
|
|
||||||
@ -45,7 +45,7 @@ class LiveController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function statsAction($id)
|
public function statsAction($id)
|
||||||
{
|
{
|
||||||
$service = new LiveChatService();
|
$service = new LiveChapterService();
|
||||||
|
|
||||||
$stats = $service->getStats($id);
|
$stats = $service->getStats($id);
|
||||||
|
|
||||||
@ -57,7 +57,7 @@ class LiveController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function statusAction($id)
|
public function statusAction($id)
|
||||||
{
|
{
|
||||||
$service = new LiveChatService();
|
$service = new LiveChapterService();
|
||||||
|
|
||||||
$status = $service->getStatus($id);
|
$status = $service->getStatus($id);
|
||||||
|
|
||||||
@ -69,7 +69,7 @@ class LiveController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function bindUserAction($id)
|
public function bindUserAction($id)
|
||||||
{
|
{
|
||||||
$service = new LiveChatService();
|
$service = new LiveChapterService();
|
||||||
|
|
||||||
$service->bindUser($id);
|
$service->bindUser($id);
|
||||||
|
|
||||||
@ -81,7 +81,7 @@ class LiveController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function sendMessageAction($id)
|
public function sendMessageAction($id)
|
||||||
{
|
{
|
||||||
$service = new LiveChatService();
|
$service = new LiveChapterService();
|
||||||
|
|
||||||
$message = $service->sendMessage($id);
|
$message = $service->sendMessage($id);
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ class AccountController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($this->authUser->id > 0) {
|
if ($this->authUser->id > 0) {
|
||||||
return $this->response->redirect(['for' => 'home.index']);
|
return $this->response->redirect('/');
|
||||||
}
|
}
|
||||||
|
|
||||||
$returnUrl = $this->request->getHTTPReferer();
|
$returnUrl = $this->request->getHTTPReferer();
|
||||||
@ -62,7 +62,7 @@ class AccountController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($this->authUser->id > 0) {
|
if ($this->authUser->id > 0) {
|
||||||
return $this->response->redirect(['for' => 'home.index']);
|
return $this->response->redirect('/');
|
||||||
}
|
}
|
||||||
|
|
||||||
$service = new OAuthProviderService();
|
$service = new OAuthProviderService();
|
||||||
@ -105,7 +105,7 @@ class AccountController extends Controller
|
|||||||
return $this->response->redirect(['for' => 'home.index']);
|
return $this->response->redirect(['for' => 'home.index']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->seo->prependTitle('忘记密码');
|
$this->seo->prependTitle('重置密码');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -119,11 +119,9 @@ class AccountController extends Controller
|
|||||||
|
|
||||||
$returnUrl = $this->request->getPost('return_url', 'string');
|
$returnUrl = $this->request->getPost('return_url', 'string');
|
||||||
|
|
||||||
$location = $returnUrl ?: $this->url->get(['for' => 'home.index']);
|
|
||||||
|
|
||||||
$content = [
|
$content = [
|
||||||
'location' => $location,
|
'location' => $returnUrl ?: '/',
|
||||||
'msg' => '注册账号成功',
|
'msg' => '注册成功',
|
||||||
];
|
];
|
||||||
|
|
||||||
return $this->jsonSuccess($content);
|
return $this->jsonSuccess($content);
|
||||||
@ -142,12 +140,7 @@ class AccountController extends Controller
|
|||||||
|
|
||||||
$location = $returnUrl ?: $this->url->get(['for' => 'home.index']);
|
$location = $returnUrl ?: $this->url->get(['for' => 'home.index']);
|
||||||
|
|
||||||
$content = [
|
return $this->jsonSuccess(['location' => $location]);
|
||||||
'location' => $location,
|
|
||||||
'msg' => '登录账号成功',
|
|
||||||
];
|
|
||||||
|
|
||||||
return $this->jsonSuccess($content);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -163,12 +156,7 @@ class AccountController extends Controller
|
|||||||
|
|
||||||
$location = $returnUrl ?: $this->url->get(['for' => 'home.index']);
|
$location = $returnUrl ?: $this->url->get(['for' => 'home.index']);
|
||||||
|
|
||||||
$content = [
|
return $this->jsonSuccess(['location' => $location]);
|
||||||
'location' => $location,
|
|
||||||
'msg' => '登录账号成功',
|
|
||||||
];
|
|
||||||
|
|
||||||
return $this->jsonSuccess($content);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -120,21 +120,27 @@ class ConnectController extends Controller
|
|||||||
$service = new ConnectService();
|
$service = new ConnectService();
|
||||||
|
|
||||||
$openUser = $service->getOpenUserInfo($code, $state, $provider);
|
$openUser = $service->getOpenUserInfo($code, $state, $provider);
|
||||||
|
|
||||||
$connect = $service->getConnectRelation($openUser['id'], $openUser['provider']);
|
$connect = $service->getConnectRelation($openUser['id'], $openUser['provider']);
|
||||||
|
|
||||||
if ($this->authUser->id > 0 && $openUser) {
|
if ($this->authUser->id > 0) {
|
||||||
$service->bindUser($openUser);
|
if ($openUser) {
|
||||||
return $this->response->redirect(['for' => 'home.uc.account']);
|
$service->bindUser($openUser);
|
||||||
|
return $this->response->redirect(['for' => 'home.uc.account']);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ($connect) {
|
||||||
|
$service->authConnectLogin($connect);
|
||||||
|
return $this->response->redirect(['for' => 'home.index']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->authUser->id == 0 && $connect) {
|
$captcha = $service->getSettings('captcha');
|
||||||
$service->authConnectLogin($connect);
|
|
||||||
return $this->response->redirect(['for' => 'home.index']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->seo->prependTitle('绑定帐号');
|
$this->seo->prependTitle('绑定帐号');
|
||||||
|
|
||||||
$this->view->pick('connect/bind');
|
$this->view->pick('connect/bind');
|
||||||
|
$this->view->setVar('captcha', $captcha);
|
||||||
$this->view->setVar('provider', $provider);
|
$this->view->setVar('provider', $provider);
|
||||||
$this->view->setVar('open_user', $openUser);
|
$this->view->setVar('open_user', $openUser);
|
||||||
}
|
}
|
||||||
|
@ -77,14 +77,8 @@ class ConsultController extends Controller
|
|||||||
|
|
||||||
$consult = $service->handle($consult->id);
|
$consult = $service->handle($consult->id);
|
||||||
|
|
||||||
$location = $this->url->get([
|
|
||||||
'for' => 'home.course.show',
|
|
||||||
'id' => $consult['course']['id'],
|
|
||||||
]);
|
|
||||||
|
|
||||||
$content = [
|
$content = [
|
||||||
'location' => $location,
|
'consult' => $consult,
|
||||||
'target' => 'parent',
|
|
||||||
'msg' => '提交咨询成功',
|
'msg' => '提交咨询成功',
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -98,13 +92,14 @@ class ConsultController extends Controller
|
|||||||
{
|
{
|
||||||
$service = new ConsultUpdateService();
|
$service = new ConsultUpdateService();
|
||||||
|
|
||||||
$service->handle($id);
|
$consult = $service->handle($id);
|
||||||
|
|
||||||
$location = $this->url->get(['for' => 'home.uc.consults']);
|
$service = new ConsultInfoService();
|
||||||
|
|
||||||
|
$consult = $service->handle($consult->id);
|
||||||
|
|
||||||
$content = [
|
$content = [
|
||||||
'location' => $location,
|
'consult' => $consult,
|
||||||
'target' => 'parent',
|
|
||||||
'msg' => '更新咨询成功',
|
'msg' => '更新咨询成功',
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -132,13 +127,14 @@ class ConsultController extends Controller
|
|||||||
|
|
||||||
$service = new ConsultReplyService();
|
$service = new ConsultReplyService();
|
||||||
|
|
||||||
$service->handle($id);
|
$consult = $service->handle($id);
|
||||||
|
|
||||||
$location = $this->url->get(['for' => 'home.tc.consults']);
|
$service = new ConsultInfoService();
|
||||||
|
|
||||||
|
$consult = $service->handle($consult->id);
|
||||||
|
|
||||||
$content = [
|
$content = [
|
||||||
'location' => $location,
|
'consult' => $consult,
|
||||||
'target' => 'parent',
|
|
||||||
'msg' => '回复咨询成功',
|
'msg' => '回复咨询成功',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -77,6 +77,8 @@ class Controller extends \Phalcon\Mvc\Controller
|
|||||||
$this->checkCsrfToken();
|
$this->checkCsrfToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->checkRateLimit();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,6 +37,8 @@ class LayerController extends \Phalcon\Mvc\Controller
|
|||||||
$this->checkCsrfToken();
|
$this->checkCsrfToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->checkRateLimit();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Home\Controllers;
|
namespace App\Http\Home\Controllers;
|
||||||
|
|
||||||
use App\Services\Logic\Live\LiveChat as LiveChatService;
|
use App\Services\Logic\Live\LiveChapter as LiveChapterService;
|
||||||
use Phalcon\Mvc\View;
|
use Phalcon\Mvc\View;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -21,7 +21,7 @@ class LiveController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function chatsAction($id)
|
public function chatsAction($id)
|
||||||
{
|
{
|
||||||
$service = new LiveChatService();
|
$service = new LiveChapterService();
|
||||||
|
|
||||||
$chats = $service->getRecentChats($id);
|
$chats = $service->getRecentChats($id);
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ class LiveController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function statsAction($id)
|
public function statsAction($id)
|
||||||
{
|
{
|
||||||
$service = new LiveChatService();
|
$service = new LiveChapterService();
|
||||||
|
|
||||||
$stats = $service->getStats($id);
|
$stats = $service->getStats($id);
|
||||||
|
|
||||||
@ -47,7 +47,7 @@ class LiveController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function statusAction($id)
|
public function statusAction($id)
|
||||||
{
|
{
|
||||||
$service = new LiveChatService();
|
$service = new LiveChapterService();
|
||||||
|
|
||||||
$status = $service->getStatus($id);
|
$status = $service->getStatus($id);
|
||||||
|
|
||||||
@ -59,7 +59,7 @@ class LiveController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function bindUserAction($id)
|
public function bindUserAction($id)
|
||||||
{
|
{
|
||||||
$service = new LiveChatService();
|
$service = new LiveChapterService();
|
||||||
|
|
||||||
$service->bindUser($id);
|
$service->bindUser($id);
|
||||||
|
|
||||||
@ -71,7 +71,7 @@ class LiveController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function sendMessageAction($id)
|
public function sendMessageAction($id)
|
||||||
{
|
{
|
||||||
$service = new LiveChatService();
|
$service = new LiveChapterService();
|
||||||
|
|
||||||
$response = $service->sendMessage($id);
|
$response = $service->sendMessage($id);
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ class PublicController extends \Phalcon\Mvc\Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Get("/alipay/callback", name="home.alipay.callback")
|
* @Get("/alipay/callback", name="home.alipay_callback")
|
||||||
*/
|
*/
|
||||||
public function alipayCallbackAction()
|
public function alipayCallbackAction()
|
||||||
{
|
{
|
||||||
@ -112,7 +112,7 @@ class PublicController extends \Phalcon\Mvc\Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Get("/wxpay/callback", name="home.wxpay.callback")
|
* @Get("/wxpay/callback", name="home.wxpay_callback")
|
||||||
*/
|
*/
|
||||||
public function wxpayCallbackAction()
|
public function wxpayCallbackAction()
|
||||||
{
|
{
|
||||||
@ -120,7 +120,7 @@ class PublicController extends \Phalcon\Mvc\Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Post("/alipay/notify", name="home.alipay.notify")
|
* @Post("/alipay/notify", name="home.alipay_notify")
|
||||||
*/
|
*/
|
||||||
public function alipayNotifyAction()
|
public function alipayNotifyAction()
|
||||||
{
|
{
|
||||||
@ -136,7 +136,7 @@ class PublicController extends \Phalcon\Mvc\Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Post("/wxpay/notify", name="home.wxpay.notify")
|
* @Post("/wxpay/notify", name="home.wxpay_notify")
|
||||||
*/
|
*/
|
||||||
public function wxpayNotifyAction()
|
public function wxpayNotifyAction()
|
||||||
{
|
{
|
||||||
@ -188,7 +188,7 @@ class PublicController extends \Phalcon\Mvc\Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Post("/live/notify", name="home.live.notify")
|
* @Post("/live/notify", name="home.live_notify")
|
||||||
*/
|
*/
|
||||||
public function liveNotifyAction()
|
public function liveNotifyAction()
|
||||||
{
|
{
|
||||||
@ -198,7 +198,6 @@ class PublicController extends \Phalcon\Mvc\Controller
|
|||||||
return $this->jsonSuccess();
|
return $this->jsonSuccess();
|
||||||
} else {
|
} else {
|
||||||
$this->response->setStatusCode(403);
|
$this->response->setStatusCode(403);
|
||||||
return $this->jsonError();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,15 +49,7 @@ class RefundController extends Controller
|
|||||||
|
|
||||||
$service->handle();
|
$service->handle();
|
||||||
|
|
||||||
$location = $this->url->get(['for' => 'home.uc.refunds']);
|
return $this->jsonSuccess(['msg' => '申请退款成功']);
|
||||||
|
|
||||||
$content = [
|
|
||||||
'location' => $location,
|
|
||||||
'target' => 'parent',
|
|
||||||
'msg' => '提交申请成功',
|
|
||||||
];
|
|
||||||
|
|
||||||
return $this->jsonSuccess($content);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -55,6 +55,13 @@ class ReviewController extends Controller
|
|||||||
$this->notFound();
|
$this->notFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$approved = $review['published'] == ReviewModel::PUBLISH_APPROVED;
|
||||||
|
$owned = $review['me']['owned'] == 1;
|
||||||
|
|
||||||
|
if (!$approved && !$owned) {
|
||||||
|
$this->notFound();
|
||||||
|
}
|
||||||
|
|
||||||
return $this->jsonSuccess(['review' => $review]);
|
return $this->jsonSuccess(['review' => $review]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,13 +72,14 @@ class ReviewController extends Controller
|
|||||||
{
|
{
|
||||||
$service = new ReviewCreateService();
|
$service = new ReviewCreateService();
|
||||||
|
|
||||||
$service->handle();
|
$review = $service->handle();
|
||||||
|
|
||||||
$location = $this->url->get(['for' => 'home.uc.reviews']);
|
$service = new ReviewInfoService();
|
||||||
|
|
||||||
|
$review = $service->handle($review->id);
|
||||||
|
|
||||||
$content = [
|
$content = [
|
||||||
'location' => $location,
|
'review' => $review,
|
||||||
'target' => 'parent',
|
|
||||||
'msg' => '发布评价成功',
|
'msg' => '发布评价成功',
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -87,11 +95,12 @@ class ReviewController extends Controller
|
|||||||
|
|
||||||
$service->handle($id);
|
$service->handle($id);
|
||||||
|
|
||||||
$location = $this->url->get(['for' => 'home.uc.reviews']);
|
$service = new ReviewInfoService();
|
||||||
|
|
||||||
|
$review = $service->handle($id);
|
||||||
|
|
||||||
$content = [
|
$content = [
|
||||||
'location' => $location,
|
'review' => $review,
|
||||||
'target' => 'parent',
|
|
||||||
'msg' => '更新评价成功',
|
'msg' => '更新评价成功',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -24,9 +24,12 @@ class WeChatOfficialAccountController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function bindAction()
|
public function bindAction()
|
||||||
{
|
{
|
||||||
|
$captcha = $this->getSettings('captcha');
|
||||||
|
|
||||||
$this->seo->prependTitle('绑定帐号');
|
$this->seo->prependTitle('绑定帐号');
|
||||||
|
|
||||||
$this->view->pick('wechat/oa/bind');
|
$this->view->pick('wechat/oa/bind');
|
||||||
|
$this->view->setVar('captcha', $captcha);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -14,7 +14,6 @@ use App\Repos\User as UserRepo;
|
|||||||
use App\Services\Auth\Home as AuthService;
|
use App\Services\Auth\Home as AuthService;
|
||||||
use App\Services\Logic\Account\Register as RegisterService;
|
use App\Services\Logic\Account\Register as RegisterService;
|
||||||
use App\Services\Logic\Notice\External\AccountLogin as AccountLoginNotice;
|
use App\Services\Logic\Notice\External\AccountLogin as AccountLoginNotice;
|
||||||
use App\Services\Logic\WeChat\OfficialAccount as WeChatOAService;
|
|
||||||
use App\Validators\Account as AccountValidator;
|
use App\Validators\Account as AccountValidator;
|
||||||
use App\Validators\WeChatOfficialAccount as WeChatOAValidator;
|
use App\Validators\WeChatOfficialAccount as WeChatOAValidator;
|
||||||
|
|
||||||
@ -64,13 +63,10 @@ class WeChatOfficialAccount extends Service
|
|||||||
|
|
||||||
$openId = $validator->checkLoginOpenId($post['ticket']);
|
$openId = $validator->checkLoginOpenId($post['ticket']);
|
||||||
|
|
||||||
$unionId = $this->getUnionId($openId);
|
|
||||||
|
|
||||||
$connect = new ConnectModel();
|
$connect = new ConnectModel();
|
||||||
|
|
||||||
$connect->user_id = $user->id;
|
$connect->user_id = $user->id;
|
||||||
$connect->open_id = $openId;
|
$connect->open_id = $openId;
|
||||||
$connect->union_id = $unionId;
|
|
||||||
$connect->provider = ConnectModel::PROVIDER_WECHAT_OA;
|
$connect->provider = ConnectModel::PROVIDER_WECHAT_OA;
|
||||||
|
|
||||||
$connect->create();
|
$connect->create();
|
||||||
@ -90,8 +86,6 @@ class WeChatOfficialAccount extends Service
|
|||||||
|
|
||||||
$openId = $validator->checkLoginOpenId($post['ticket']);
|
$openId = $validator->checkLoginOpenId($post['ticket']);
|
||||||
|
|
||||||
$unionId = $this->getUnionId($openId);
|
|
||||||
|
|
||||||
$registerService = new RegisterService();
|
$registerService = new RegisterService();
|
||||||
|
|
||||||
$account = $registerService->handle();
|
$account = $registerService->handle();
|
||||||
@ -104,7 +98,6 @@ class WeChatOfficialAccount extends Service
|
|||||||
|
|
||||||
$connect->user_id = $user->id;
|
$connect->user_id = $user->id;
|
||||||
$connect->open_id = $openId;
|
$connect->open_id = $openId;
|
||||||
$connect->union_id = $unionId;
|
|
||||||
$connect->provider = ConnectModel::PROVIDER_WECHAT_OA;
|
$connect->provider = ConnectModel::PROVIDER_WECHAT_OA;
|
||||||
|
|
||||||
$connect->create();
|
$connect->create();
|
||||||
@ -118,17 +111,6 @@ class WeChatOfficialAccount extends Service
|
|||||||
$this->eventsManager->fire('Account:afterRegister', $this, $user);
|
$this->eventsManager->fire('Account:afterRegister', $this, $user);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getUnionId($openId)
|
|
||||||
{
|
|
||||||
$service = new WeChatOAService();
|
|
||||||
|
|
||||||
$app = $service->getOfficialAccount();
|
|
||||||
|
|
||||||
$user = $app->user->get($openId);
|
|
||||||
|
|
||||||
return $user['unionid'] ?: '';
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getAppAuth()
|
protected function getAppAuth()
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -36,6 +36,6 @@
|
|||||||
</form>
|
</form>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="register-close-tips">
|
<div class="register-close-tips">
|
||||||
<i class="layui-icon layui-icon-lock"></i> 邮箱注册已关闭
|
<i class="layui-icon layui-icon-tips"></i> 邮箱注册已关闭
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
@ -36,6 +36,6 @@
|
|||||||
</form>
|
</form>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="register-close-tips">
|
<div class="register-close-tips">
|
||||||
<i class="layui-icon layui-icon-lock"></i> 手机注册已关闭
|
<i class="layui-icon layui-icon-tips"></i> 手机注册已关闭
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
@ -1,44 +1,35 @@
|
|||||||
{%- macro model_icon(model) %}
|
|
||||||
{% if model == 1 %}
|
|
||||||
<i class="iconfont icon-video"></i>
|
|
||||||
{% elseif model == 2 %}
|
|
||||||
<i class="iconfont icon-live"></i>
|
|
||||||
{% elseif model == 3 %}
|
|
||||||
<i class="iconfont icon-article"></i>
|
|
||||||
{% elseif model == 4 %}
|
|
||||||
<i class="layui-icon layui-icon-user"></i>
|
|
||||||
{% endif %}
|
|
||||||
{%- endmacro %}
|
|
||||||
|
|
||||||
{%- macro show_lesson_list(parent,chapter) %}
|
{%- macro show_lesson_list(parent,chapter) %}
|
||||||
<ul class="sidebar-lesson-list">
|
<ul class="sidebar-lesson-list">
|
||||||
{% for lesson in parent.children %}
|
{% for lesson in parent.children %}
|
||||||
{% set url = url({'for':'home.chapter.show','id':lesson.id}) %}
|
{% set url = url({'for':'home.chapter.show','id':lesson.id}) %}
|
||||||
{% set active = chapter.id == lesson.id ? 'active' : 'normal' %}
|
{% set active = (chapter.id == lesson.id) ? 'active' : 'normal' %}
|
||||||
{% set priv = lesson.me.owned == 1 ? 'allow' : 'deny' %}
|
<li class="lesson-title layui-elip">
|
||||||
<li class="sidebar-lesson layui-elip {{ priv }} {{ active }}" data-url="{{ url }}">
|
{% if lesson.me.owned == 1 %}
|
||||||
<span class="model">{{ model_icon(lesson.model) }}</span>
|
<a class="{{ active }}" href="{{ url }}" title="{{ lesson.title }}">{{ lesson.title }}</a>
|
||||||
<span class="title" title="{{ lesson.title }}">{{ lesson.title }}</span>
|
{% else %}
|
||||||
{% if lesson.me.owned == 0 %}
|
<span class="deny" title="{{ lesson.title }}">{{ lesson.title }}</span>
|
||||||
<span class="lock"><i class="iconfont icon-lock"></i></span>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
||||||
<div class="layui-card sidebar-card sidebar-catalog">
|
<div class="layui-card sidebar-card sidebar-chapter">
|
||||||
<div class="layui-card-header">课程目录</div>
|
<div class="layui-card-header">课程目录</div>
|
||||||
<div class="layui-card-body">
|
<div class="layui-card-body">
|
||||||
{% if catalog|length > 1 %}
|
{% if catalog|length > 1 %}
|
||||||
<div class="sidebar-chapter-list">
|
<div class="sidebar-chapter-list">
|
||||||
{% for item in catalog %}
|
{% for item in catalog %}
|
||||||
<div class="sidebar-chapter layui-elip">{{ item.title }}</div>
|
<div class="chapter-title layui-elip">{{ item.title }}</div>
|
||||||
{{ show_lesson_list(item,chapter) }}
|
<div class="sidebar-lesson-list">
|
||||||
|
{{ show_lesson_list(item,chapter) }}
|
||||||
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
{{ show_lesson_list(catalog[0],chapter) }}
|
<div class="sidebar-lesson-list">
|
||||||
|
{{ show_lesson_list(catalog[0],chapter) }}
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
@ -35,7 +35,11 @@
|
|||||||
<div class="layui-card-body">
|
<div class="layui-card-body">
|
||||||
<div class="chat-msg-list" id="chat-msg-list" data-url="{{ live_chats_url }}"></div>
|
<div class="chat-msg-list" id="chat-msg-list" data-url="{{ live_chats_url }}"></div>
|
||||||
<form class="layui-form chat-msg-form" method="post" action="{{ send_msg_url }}">
|
<form class="layui-form chat-msg-form" method="post" action="{{ send_msg_url }}">
|
||||||
<input class="layui-input" type="text" name="content" maxlength="50" placeholder="快来一起互动吧" lay-vertype="tips" lay-verify="required">
|
{% if auth_user.id > 0 %}
|
||||||
|
<input class="layui-input" type="text" name="content" maxlength="50" placeholder="快来一起互动吧" lay-verType="tips" lay-verify="required">
|
||||||
|
{% else %}
|
||||||
|
<input class="layui-input" type="text" placeholder="登录后才可以发言哦" readonly="readonly">
|
||||||
|
{% endif %}
|
||||||
<button class="layui-hide" type="submit" lay-submit="true" lay-filter="chat">发送</button>
|
<button class="layui-hide" type="submit" lay-submit="true" lay-filter="chat">发送</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@ -76,4 +80,4 @@
|
|||||||
{{ js_include('home/js/course.share.js') }}
|
{{ js_include('home/js/course.share.js') }}
|
||||||
{{ js_include('home/js/copy.js') }}
|
{{ js_include('home/js/copy.js') }}
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -1,15 +1,9 @@
|
|||||||
{% for chat in chats %}
|
{% for chat in chats %}
|
||||||
{% if chat.user.vip == 1 %}
|
<div class="chat">
|
||||||
<div class="chat chat-vip">
|
{% if chat.user.vip == 1 %}
|
||||||
<span class="icon"><i class="layui-icon layui-icon-diamond"></i></span>
|
<span class="layui-icon layui-icon-diamond icon-vip"></span>
|
||||||
<span class="user layui-badge layui-bg-orange">{{ chat.user.name }}</span>
|
{% endif %}
|
||||||
<span class="content">{{ chat.content }}</span>
|
<span class="user">{{ chat.user.name }}</span>
|
||||||
</div>
|
<span class="content">{{ chat.content }}</span>
|
||||||
{% else %}
|
</div>
|
||||||
<div class="chat chat-normal">
|
{% endfor %}
|
||||||
<span class="icon"><i class="layui-icon layui-icon-username"></i></span>
|
|
||||||
<span class="user layui-badge layui-bg-blue">{{ chat.user.name }}</span>
|
|
||||||
<span class="content">{{ chat.content }}</span>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
@ -11,9 +11,9 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="live-preview">
|
<div class="preview">
|
||||||
<div class="icon"><i class="layui-icon layui-icon-face-cry"></i></div>
|
<div class="icon"><i class="layui-icon layui-icon-face-cry"></i></div>
|
||||||
<div class="tips">直播已禁止,谢谢关注!</div>
|
<div class="tips">直播已禁止,谢谢关注!</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -13,19 +13,19 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if time() < chapter.start_time %}
|
{% if time() < chapter.start_time %}
|
||||||
<div class="live-preview countdown wrap">
|
<div class="preview countdown">
|
||||||
<div class="icon"><i class="layui-icon layui-icon-time"></i></div>
|
<div class="icon"><i class="layui-icon layui-icon-time"></i></div>
|
||||||
<div class="timer"></div>
|
<div class="timer"></div>
|
||||||
<div class="tips">直播倒计时开始啦,敬请关注!</div>
|
<div class="tips">直播倒计时开始啦,敬请关注!</div>
|
||||||
</div>
|
</div>
|
||||||
{% elseif chapter.start_time < time() and chapter.end_time > time() %}
|
{% elseif chapter.start_time < time() and chapter.end_time > time() %}
|
||||||
<div class="live-preview countdown wrap">
|
<div class="preview countdown">
|
||||||
<div class="icon"><i class="layui-icon layui-icon-face-surprised"></i></div>
|
<div class="icon"><i class="layui-icon layui-icon-face-surprised"></i></div>
|
||||||
<div class="timer"></div>
|
<div class="timer"></div>
|
||||||
<div class="tips">直播时间到了,老师去哪了?</div>
|
<div class="tips">直播时间到了,老师去哪了?</div>
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="live-preview wrap">
|
<div class="preview">
|
||||||
<div class="icon"><i class="layui-icon layui-icon-tree"></i></div>
|
<div class="icon"><i class="layui-icon layui-icon-tree"></i></div>
|
||||||
<div class="tips">直播已结束,谢谢关注!</div>
|
<div class="tips">直播已结束,谢谢关注!</div>
|
||||||
</div>
|
</div>
|
||||||
@ -43,4 +43,4 @@
|
|||||||
|
|
||||||
{{ js_include('home/js/chapter.live.countdown.js') }}
|
{{ js_include('home/js/chapter.live.countdown.js') }}
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -7,7 +7,7 @@
|
|||||||
<div class="icon" title="{{ like_title }}" data-url="{{ like_url }}">
|
<div class="icon" title="{{ like_title }}" data-url="{{ like_url }}">
|
||||||
<i class="layui-icon layui-icon-praise icon-praise {{ like_class }}"></i>
|
<i class="layui-icon layui-icon-praise icon-praise {{ like_class }}"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="text" data-count="{{ chapter.like_count }}">{{ chapter.like_count }}</div>
|
<div class="text">{{ chapter.like_count }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="item" id="toolbar-online">
|
<div class="item" id="toolbar-online">
|
||||||
<div class="icon" title="在线人数">
|
<div class="icon" title="在线人数">
|
||||||
@ -15,4 +15,4 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="text">0</div>
|
<div class="text">0</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
@ -1,118 +1,103 @@
|
|||||||
{%- macro show_lesson_list(chapter) %}
|
{%- macro show_lesson_list(chapter) %}
|
||||||
<ul class="lesson-list">
|
<ul class="lesson-list">
|
||||||
{% for lesson in chapter.children %}
|
{% for lesson in chapter.children %}
|
||||||
{% set url = url({'for':'home.chapter.show','id':lesson.id}) %}
|
|
||||||
{% set priv = lesson.me.owned ? 'allow' : 'deny' %}
|
|
||||||
{% if lesson.model == 1 %}
|
{% if lesson.model == 1 %}
|
||||||
<li class="lesson-item {{ priv }}" data-url="{{ url }}">{{ vod_lesson_info(lesson) }}</li>
|
<li class="lesson-item">{{ vod_lesson_info(lesson) }}</li>
|
||||||
{% elseif lesson.model == 2 %}
|
{% elseif lesson.model == 2 %}
|
||||||
<li class="lesson-item {{ priv }}" data-url="{{ url }}">{{ live_lesson_info(lesson) }}</li>
|
<li class="lesson-item">{{ live_lesson_info(lesson) }}</li>
|
||||||
{% elseif lesson.model == 3 %}
|
{% elseif lesson.model == 3 %}
|
||||||
<li class="lesson-item {{ priv }}" data-url="{{ url }}">{{ read_lesson_info(lesson) }}</li>
|
<li class="lesson-item">{{ read_lesson_info(lesson) }}</li>
|
||||||
{% elseif lesson.model == 4 %}
|
{% elseif lesson.model == 4 %}
|
||||||
<li class="lesson-item deny" data-url="{{ url }}">{{ offline_lesson_info(lesson) }}</li>
|
<li class="lesson-item">{{ offline_lesson_info(lesson) }}</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
||||||
{%- macro vod_lesson_info(lesson) %}
|
{%- macro vod_lesson_info(lesson) %}
|
||||||
<div class="left">
|
{% set url = lesson.me.owned ? url({'for':'home.chapter.show','id':lesson.id}) : '' %}
|
||||||
<span class="model"><i class="iconfont icon-video"></i></span>
|
{% set priv = lesson.me.owned ? 'allow' : 'deny' %}
|
||||||
|
<a class="{{ priv }} view-lesson" href="javascript:" data-url="{{ url }}">
|
||||||
|
<i class="layui-icon layui-icon-play"></i>
|
||||||
<span class="title">{{ lesson.title }}</span>
|
<span class="title">{{ lesson.title }}</span>
|
||||||
|
{% if lesson.free == 1 %}
|
||||||
|
<span class="iconfont icon-trial"></span>
|
||||||
|
{% endif %}
|
||||||
{% if lesson.me.duration > 0 %}
|
{% if lesson.me.duration > 0 %}
|
||||||
<span class="study-time" title="学习时长:{{ lesson.me.duration|duration }}"><i class="layui-icon layui-icon-time"></i></span>
|
<span class="study-time" title="学习时长:{{ lesson.me.duration|duration }}"><i class="layui-icon layui-icon-time"></i></span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if lesson.me.owned == 0 %}
|
{% if priv == 'deny' %}
|
||||||
<span class="lock"><i class="iconfont icon-lock"></i></span>
|
<span class="iconfont icon-lock"></span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if lesson.free == 1 %}
|
|
||||||
<span class="flag flag-free">试听</span>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
<div class="right">
|
|
||||||
<span class="duration">{{ lesson.attrs.duration|duration }}</span>
|
<span class="duration">{{ lesson.attrs.duration|duration }}</span>
|
||||||
</div>
|
</a>
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
||||||
{%- macro live_lesson_info(lesson) %}
|
{%- macro live_lesson_info(lesson) %}
|
||||||
<div class="left">
|
{% set url = lesson.me.owned ? url({'for':'home.chapter.show','id':lesson.id}) : '' %}
|
||||||
<span class="model"><i class="iconfont icon-live"></i></span>
|
{% set priv = lesson.me.owned ? 'allow' : 'deny' %}
|
||||||
|
<a class="{{ priv }} view-lesson" href="javascript:" data-url="{{ url }}">
|
||||||
|
<i class="layui-icon layui-icon-video"></i>
|
||||||
<span class="title">{{ lesson.title }}</span>
|
<span class="title">{{ lesson.title }}</span>
|
||||||
|
{% if lesson.free == 1 %}
|
||||||
|
<span class="iconfont icon-trial"></span>
|
||||||
|
{% endif %}
|
||||||
{% if lesson.me.duration > 0 %}
|
{% if lesson.me.duration > 0 %}
|
||||||
<span class="study-time" title="学习时长:{{ lesson.me.duration|duration }}"><i class="layui-icon layui-icon-time"></i></span>
|
<span class="study-time" title="学习时长:{{ lesson.me.duration|duration }}"><i class="layui-icon layui-icon-time"></i></span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if lesson.me.owned == 0 %}
|
{% if priv == 'deny' %}
|
||||||
<span class="lock"><i class="iconfont icon-lock"></i></span>
|
<span class="iconfont icon-lock"></span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if lesson.attrs.playback.ready == 1 %}
|
<span class="live" title="{{ date('Y-m-d H:i',lesson.attrs.start_time) }}">{{ live_status_info(lesson) }}</span>
|
||||||
<span class="flag flag-playback">回放</span>
|
</a>
|
||||||
{% endif %}
|
|
||||||
{% if lesson.free == 1 %}
|
|
||||||
<span class="flag flag-free">试听</span>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
<div class="right">
|
|
||||||
<span class="live-status">{{ live_status_info(lesson) }}</span>
|
|
||||||
<span class="live-time">{{ date('Y-m-d H:i',lesson.attrs.start_time) }}</span>
|
|
||||||
</div>
|
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
||||||
{%- macro read_lesson_info(lesson) %}
|
{%- macro read_lesson_info(lesson) %}
|
||||||
<div class="left">
|
{% set url = lesson.me.owned ? url({'for':'home.chapter.show','id':lesson.id}) : '' %}
|
||||||
<span class="model"><i class="iconfont icon-article"></i></span>
|
{% set priv = lesson.me.owned ? 'allow' : 'deny' %}
|
||||||
|
<a class="{{ priv }} view-lesson" href="javascript:" data-url="{{ url }}">
|
||||||
|
<i class="layui-icon layui-icon-read"></i>
|
||||||
<span class="title">{{ lesson.title }}</span>
|
<span class="title">{{ lesson.title }}</span>
|
||||||
|
{% if lesson.free == 1 %}
|
||||||
|
<span class="iconfont icon-trial"></span>
|
||||||
|
{% endif %}
|
||||||
{% if lesson.me.duration > 0 %}
|
{% if lesson.me.duration > 0 %}
|
||||||
<span class="study-time" title="学习时长:{{ lesson.me.duration|duration }}"><i class="layui-icon layui-icon-time"></i></span>
|
<span class="study-time" title="学习时长:{{ lesson.me.duration|duration }}"><i class="layui-icon layui-icon-time"></i></span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if lesson.me.owned == 0 %}
|
{% if priv == 'deny' %}
|
||||||
<span class="lock"><i class="iconfont icon-lock"></i></span>
|
<span class="iconfont icon-lock"></span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if lesson.free == 1 %}
|
</a>
|
||||||
<span class="flag flag-free">试读</span>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
<div class="right">
|
|
||||||
<span class="size"></span>
|
|
||||||
</div>
|
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
||||||
{%- macro offline_lesson_info(lesson) %}
|
{%- macro offline_lesson_info(lesson) %}
|
||||||
<div class="left">
|
<a class="deny view-lesson" href="javascript:">
|
||||||
<span class="model"><i class="layui-icon layui-icon-user"></i></span>
|
<i class="layui-icon layui-icon-user"></i>
|
||||||
<span class="title">{{ lesson.title }}</span>
|
<span class="title">{{ lesson.title }}</span>
|
||||||
{% if lesson.me.owned == 0 %}
|
|
||||||
<span class="lock"><i class="iconfont icon-lock"></i></span>
|
|
||||||
{% endif %}
|
|
||||||
{% if lesson.free == 1 %}
|
{% if lesson.free == 1 %}
|
||||||
<span class="flag flag-free">试听</span>
|
<span class="layui-badge free-badge">试听</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
<span class="live" title="{{ date('Y-m-d H:i',lesson.attrs.start_time) }}">{{ offline_status_info(lesson) }}</span>
|
||||||
<div class="right">
|
</a>
|
||||||
<span class="live-status">{{ offline_status_info(lesson) }}</span>
|
|
||||||
<span class="live-time">{{ date('Y-m-d H:i',lesson.attrs.start_time) }}</span>
|
|
||||||
</div>
|
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
||||||
{%- macro live_status_info(lesson) %}
|
{%- macro live_status_info(lesson) %}
|
||||||
{% if lesson.attrs.stream.status == 'active' %}
|
{% if lesson.attrs.stream.status == 'active' %}
|
||||||
<span class="flag flag-active">直播中</span>
|
<span class="active">{{ date('m月d日 H:i',lesson.attrs.start_time) }} 直播中</span>
|
||||||
{% elseif lesson.attrs.start_time > time() %}
|
{% elseif lesson.attrs.start_time > time() %}
|
||||||
<span class="flag flag-scheduled">倒计时</span>
|
<span class="pending">{{ date('m月d日 H:i',lesson.attrs.start_time) }} 倒计时</span>
|
||||||
{% elseif lesson.attrs.end_time < time() %}
|
{% elseif lesson.attrs.end_time < time() %}
|
||||||
<span class="flag flag-ended">已结束</span>
|
<span class="finished">{{ date('m月d日 H:i',lesson.attrs.start_time) }} 已结束</span>
|
||||||
{% elseif lesson.attrs.stream.status == 'inactive' %}
|
|
||||||
<span class="flag flag-inactive">未推流</span>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
||||||
{%- macro offline_status_info(lesson) %}
|
{%- macro offline_status_info(lesson) %}
|
||||||
{% if lesson.attrs.start_time < time() and lesson.attrs.end_time > time() %}
|
{% if lesson.attrs.start_time < time() and lesson.attrs.end_time > time() %}
|
||||||
<span class="flag flag-active">授课中</span>
|
<span class="active">{{ date('m月d日 H:i',lesson.attrs.start_time) }} 授课中</span>
|
||||||
{% elseif lesson.attrs.start_time > time() %}
|
{% elseif lesson.attrs.start_time > time() %}
|
||||||
<span class="flag flag-scheduled">未开始</span>
|
<span class="pending">{{ date('m月d日 H:i',lesson.attrs.start_time) }} 未开始</span>
|
||||||
{% elseif lesson.attrs.end_time < time() %}
|
{% elseif lesson.attrs.end_time < time() %}
|
||||||
<span class="flag flag-ended">已结束</span>
|
<span class="finished">{{ date('m月d日 H:i',lesson.attrs.start_time) }} 已结束</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
||||||
@ -134,4 +119,4 @@
|
|||||||
{% else %}
|
{% else %}
|
||||||
{{ show_lesson_list(chapters[0]) }}
|
{{ show_lesson_list(chapters[0]) }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
@ -105,21 +105,21 @@
|
|||||||
{{ offline_meta_info(course) }}
|
{{ offline_meta_info(course) }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div class="ratings">
|
<div class="rating">
|
||||||
<p class="item">
|
<p class="item">
|
||||||
<span class="name">内容实用</span>
|
<span class="name">内容实用</span>
|
||||||
<span class="star" id="rating1" data-value="{{ course.ratings.rating1 }}"></span>
|
<span class="star">{{ star_info(course.ratings.rating1) }}</span>
|
||||||
<span class="score">{{ "%0.1f"|format(course.ratings.rating1) }} 分</span>
|
<span class="score">{{ "%0.1f"|format(course.ratings.rating1) }} 分</span>
|
||||||
</p>
|
</p>
|
||||||
<p class="item">
|
<p class="item">
|
||||||
<span class="name">简洁易懂</span>
|
<span class="name">简洁易懂</span>
|
||||||
<span class="star" id="rating2" data-value="{{ course.ratings.rating2 }}"></span>
|
<span class="star">{{ star_info(course.ratings.rating2) }}</span>
|
||||||
<span class="score">{{ "%0.1f"|format(course.ratings.rating2) }} 分</span>
|
<span class="score">{{ "%0.1f"|format(course.ratings.rating2) }} 分</span>
|
||||||
</p>
|
</p>
|
||||||
<p class="item">
|
<p class="item">
|
||||||
<span class="name">逻辑清晰</span>
|
<span class="name">逻辑清晰</span>
|
||||||
<span class="star" id="rating3" data-value="{{ course.ratings.rating3 }}"></span>
|
<span class="star">{{ star_info(course.ratings.rating3) }}</span>
|
||||||
<span class="score">{{ "%0.1f"|format(course.ratings.rating3) }} 分</span>
|
<span class="score">{{ "%0.1f"|format(course.ratings.rating3) }} 分</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
@ -26,8 +26,8 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="item" id="toolbar-favorite">
|
<div class="item" id="toolbar-favorite">
|
||||||
<div class="icon" title="{{ favorite_title }}" data-url="{{ favorite_url }}">
|
<div class="icon" title="{{ favorite_title }}" data-url="{{ favorite_url }}">
|
||||||
<i class="layui-icon icon-star {{ favorite_class }}"></i>
|
<i class="layui-icon layui-icon-star icon-star {{ favorite_class }}"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="text" data-count="{{ course.favorite_count }}">{{ course.favorite_count }}</div>
|
<div class="text" data-count="{{ course.favorite_count }}">{{ course.favorite_count }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
@ -31,10 +31,17 @@
|
|||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block include_js %}
|
{% block inline_js %}
|
||||||
|
|
||||||
{{ js_include('lib/clipboard.min.js') }}
|
<script>
|
||||||
{{ js_include('home/js/help.show.js') }}
|
layui.use(['jquery', 'helper'], function () {
|
||||||
{{ js_include('home/js/copy.js') }}
|
var $ = layui.jquery;
|
||||||
|
var helper = layui.helper;
|
||||||
|
var $courseList = $('#course-list');
|
||||||
|
if ($courseList.length > 0) {
|
||||||
|
helper.ajaxLoadHtml($courseList.data('url'), $courseList.attr('id'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -10,7 +10,7 @@
|
|||||||
{% if course.model in [1,2,3] %}
|
{% if course.model in [1,2,3] %}
|
||||||
<p>
|
<p>
|
||||||
<span>学习期限:{{ date('Y-m-d',course.study_expiry_time) }}</span>
|
<span>学习期限:{{ date('Y-m-d',course.study_expiry_time) }}</span>
|
||||||
<span>退款期限:{{ course.refund_expiry > 0 ? date('Y-m-d',course.refund_expiry_time) : '不支持' }}</span>
|
<span>退款期限:{{ date('Y-m-d',course.refund_expiry_time) }}</span>
|
||||||
</p>
|
</p>
|
||||||
{% elseif course.model == 4 %}
|
{% elseif course.model == 4 %}
|
||||||
<p>上课时间:{{ course.attrs.start_date }} ~ {{ course.attrs.end_date }}</p>
|
<p>上课时间:{{ course.attrs.start_date }} ~ {{ course.attrs.end_date }}</p>
|
||||||
@ -23,13 +23,13 @@
|
|||||||
<div class="order-item">
|
<div class="order-item">
|
||||||
<p>课程名称:{{ course.title }}</p>
|
<p>课程名称:{{ course.title }}</p>
|
||||||
<p>
|
<p>
|
||||||
<span>市场价格:<em class="price">{{ '¥%0.2f'|format(course.market_price) }}</em></span>
|
<span>市场价格:{{ '¥%0.2f'|format(course.market_price) }}</span>
|
||||||
<span>会员价格:<em class="price">{{ '¥%0.2f'|format(course.vip_price) }}</em></span>
|
<span>会员价格:<em class="price">{{ '¥%0.2f'|format(course.vip_price) }}</em></span>
|
||||||
</p>
|
</p>
|
||||||
{% if course.model in [1,2,3] %}
|
{% if course.model in [1,2,3] %}
|
||||||
<p>
|
<p>
|
||||||
<span>学习期限:{{ date('Y-m-d',course.study_expiry_time) }}</span>
|
<span>学习期限:{{ date('Y-m-d',course.study_expiry_time) }}</span>
|
||||||
<span>退款期限:{{ course.refund_expiry > 0 ? date('Y-m-d',course.refund_expiry_time) : '不支持' }}</span>
|
<span>退款期限:{{ date('Y-m-d',course.refund_expiry_time) }}</span>
|
||||||
</p>
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
<a class="layui-btn layui-bg-blue" href="{{ order_pay_url }}" target="_top">立即支付</a>
|
<a class="layui-btn layui-bg-blue" href="{{ order_pay_url }}" target="_top">立即支付</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if order.me.allow_cancel == 1 %}
|
{% if order.me.allow_cancel == 1 %}
|
||||||
<button class="layui-btn layui-bg-red btn-order-cancel" data-sn="{{ order.sn }}" data-url="{{ order_cancel_url }}">立即取消</button>
|
<a class="layui-btn layui-bg-red order-cancel" href="javascript:" data-sn="{{ order.sn }}" data-url="{{ order_cancel_url }}">立即取消</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if order.me.allow_refund == 1 %}
|
{% if order.me.allow_refund == 1 %}
|
||||||
<a class="layui-btn layui-bg-blue" href="{{ refund_confirm_url }}">申请退款</a>
|
<a class="layui-btn layui-bg-blue" href="{{ refund_confirm_url }}">申请退款</a>
|
||||||
@ -39,4 +39,4 @@
|
|||||||
|
|
||||||
{{ js_include('home/js/order.info.js') }}
|
{{ js_include('home/js/order.info.js') }}
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -30,10 +30,17 @@
|
|||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block include_js %}
|
{% block inline_js %}
|
||||||
|
|
||||||
{{ js_include('lib/clipboard.min.js') }}
|
<script>
|
||||||
{{ js_include('home/js/page.show.js') }}
|
layui.use(['jquery', 'helper'], function () {
|
||||||
{{ js_include('home/js/copy.js') }}
|
var $ = layui.jquery;
|
||||||
|
var helper = layui.helper;
|
||||||
|
var $courseList = $('#course-list');
|
||||||
|
if ($courseList.length > 0) {
|
||||||
|
helper.ajaxLoadHtml($courseList.data('url'), $courseList.attr('id'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -9,7 +9,7 @@
|
|||||||
<div class="order-item">
|
<div class="order-item">
|
||||||
<p>课程名称:<span>{{ course.title }}</span></p>
|
<p>课程名称:<span>{{ course.title }}</span></p>
|
||||||
<p>退款期限:<span>{{ date('Y-m-d H:i:s',course.refund_expiry_time) }} {{ expiry_flag }}</span></p>
|
<p>退款期限:<span>{{ date('Y-m-d H:i:s',course.refund_expiry_time) }} {{ expiry_flag }}</span></p>
|
||||||
<p>退款金额:<span class="price">{{ '¥%0.2f'|format(course.refund_amount) }}</span>退款比例:<span class="rate">{{ 100 * course.refund_rate }}%</span></p>
|
<p>退款金额:<span class="price">{{ '¥%0.2f'|format(course.refund_amount) }}</span>退款比例:<span class="price">{{ 100 * course.refund_percent }}%</span></p>
|
||||||
</div>
|
</div>
|
||||||
{% elseif confirm.item_type == 2 %}
|
{% elseif confirm.item_type == 2 %}
|
||||||
{% set courses = confirm.item_info.courses %}
|
{% set courses = confirm.item_info.courses %}
|
||||||
@ -18,7 +18,7 @@
|
|||||||
<div class="order-item">
|
<div class="order-item">
|
||||||
<p>课程名称:<span>{{ course.title }}</span></p>
|
<p>课程名称:<span>{{ course.title }}</span></p>
|
||||||
<p>退款期限:<span>{{ date('Y-m-d H:i:s',course.refund_expiry_time) }} {{ expiry_flag }}</span></p>
|
<p>退款期限:<span>{{ date('Y-m-d H:i:s',course.refund_expiry_time) }} {{ expiry_flag }}</span></p>
|
||||||
<p>退款金额:<span class="price">{{ '¥%0.2f'|format(course.refund_amount) }}</span>退款比例:<span class="rate">{{ 100 * course.refund_rate }}%</span></p>
|
<p>退款金额:<span class="price">{{ '¥%0.2f'|format(course.refund_amount) }}</span>退款比例:<span class="price">{{ 100 * course.refund_percent }}%</span></p>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -40,9 +40,12 @@
|
|||||||
</table>
|
</table>
|
||||||
<br>
|
<br>
|
||||||
{% if confirm.refund_amount > 0 %}
|
{% if confirm.refund_amount > 0 %}
|
||||||
<form class="layui-form" method="post" action="{{ url({'for':'home.refund.create'}) }}">
|
<form class="layui-form layui-form-pane" method="post" action="{{ url({'for':'home.refund.create'}) }}">
|
||||||
<div class="layui-form-item">
|
<div class="layui-form-item">
|
||||||
<input class="layui-input" name="apply_note" placeholder="请告知我们退款原因,让我们做的更好..." lay-verify="required">
|
<label class="layui-form-label">退款原因</label>
|
||||||
|
<div class="layui-input-block">
|
||||||
|
<input class="layui-input" name="apply_note" lay-verify="required">
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-form-item center">
|
<div class="layui-form-item center">
|
||||||
<button class="layui-btn" lay-submit="true" lay-filter="go">提交申请</button>
|
<button class="layui-btn" lay-submit="true" lay-filter="go">提交申请</button>
|
||||||
@ -65,4 +68,4 @@
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -9,9 +9,9 @@
|
|||||||
<table class="layui-table order-table" lay-size="lg">
|
<table class="layui-table order-table" lay-size="lg">
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="2">
|
<td colspan="2">
|
||||||
<span>订单金额:<em class="price">{{ '¥%0.2f'|format(refund.order.amount) }}</em></span>
|
订单金额:<span class="price">{{ '¥%0.2f'|format(refund.order.amount) }}</span>
|
||||||
<span>退款金额:<em class="price">{{ '¥%0.2f'|format(refund.amount) }}</em></span>
|
退款金额:<span class="price">{{ '¥%0.2f'|format(refund.amount) }}</span>
|
||||||
<span>退款状态:{{ refund_status(refund.status) }}</span>
|
退款状态:<span class="status">{{ refund_status(refund.status) }}</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@ -22,8 +22,41 @@
|
|||||||
<br>
|
<br>
|
||||||
<div class="center">
|
<div class="center">
|
||||||
{% if refund.me.allow_cancel == 1 %}
|
{% if refund.me.allow_cancel == 1 %}
|
||||||
<button class="layui-btn btn-refund-cancel" data-sn="{{ refund.sn }}" data-url="{{ cancel_url }}">取消退款</button>
|
<button class="kg-refund layui-btn" data-sn="{{ refund.sn }}" data-url="{{ cancel_url }}">取消退款</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block inline_js %}
|
||||||
|
|
||||||
|
<script>
|
||||||
|
layui.use(['jquery', 'layer'], function () {
|
||||||
|
|
||||||
|
var $ = layui.jquery;
|
||||||
|
var layer = layui.layer;
|
||||||
|
var index = parent.layer.getFrameIndex(window.name);
|
||||||
|
|
||||||
|
parent.layer.iframeAuto(index);
|
||||||
|
|
||||||
|
$('.kg-refund').on('click', function () {
|
||||||
|
var url = $(this).data('url');
|
||||||
|
var data = {sn: $(this).data('sn')};
|
||||||
|
layer.confirm('确定要取消退款吗?', function () {
|
||||||
|
$.ajax({
|
||||||
|
type: 'POST',
|
||||||
|
url: url,
|
||||||
|
data: data,
|
||||||
|
success: function (res) {
|
||||||
|
layer.msg(res.msg, {icon: 1});
|
||||||
|
setTimeout(function () {
|
||||||
|
parent.window.location.href = '/uc/refunds';
|
||||||
|
}, 1500);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{% endblock %}
|
@ -24,9 +24,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-form-item">
|
<div class="layui-form-item">
|
||||||
<label class="layui-form-label">评价内容</label>
|
<label class="layui-form-label" for="content">评价内容</label>
|
||||||
<div class="layui-input-block">
|
<div class="layui-input-block">
|
||||||
<textarea name="content" class="layui-textarea" placeholder="请描述你的学习经历,例如学习成果、课程内容、讲师风格、教学服务等。" lay-verify="required"></textarea>
|
<textarea name="content" id="content" class="layui-textarea" placeholder="请描述你的学习经历,例如学习成果、课程内容、讲师风格、教学服务等。"></textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-form-item">
|
<div class="layui-form-item">
|
||||||
@ -54,4 +54,4 @@
|
|||||||
|
|
||||||
{{ js_include('home/js/user.console.review.js') }}
|
{{ js_include('home/js/user.console.review.js') }}
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -26,7 +26,7 @@
|
|||||||
<div class="layui-form-item">
|
<div class="layui-form-item">
|
||||||
<label class="layui-form-label">评价内容</label>
|
<label class="layui-form-label">评价内容</label>
|
||||||
<div class="layui-input-block">
|
<div class="layui-input-block">
|
||||||
<textarea name="content" class="layui-textarea" lay-verify="required">{{ review.content }}</textarea>
|
<textarea name="content" class="layui-textarea">{{ review.content }}</textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-form-item">
|
<div class="layui-form-item">
|
||||||
@ -53,4 +53,4 @@
|
|||||||
|
|
||||||
{{ js_include('home/js/user.console.review.js') }}
|
{{ js_include('home/js/user.console.review.js') }}
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -19,7 +19,7 @@
|
|||||||
{% if item.cover %}
|
{% if item.cover %}
|
||||||
<div class="cover">
|
<div class="cover">
|
||||||
<a href="{{ article_url }}" target="_blank">
|
<a href="{{ article_url }}" target="_blank">
|
||||||
<img src="{{ item.cover }}!cover_270" alt="{{ item.title|striptags }}">
|
<img src="{{ item.cover }}!cover_270" alt="{{ item.title }}">
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<div class="search-course-card">
|
<div class="search-course-card">
|
||||||
<div class="cover">
|
<div class="cover">
|
||||||
<a href="{{ course_url }}" target="_blank">
|
<a href="{{ course_url }}" target="_blank">
|
||||||
<img src="{{ item.cover }}!cover_270" alt="{{ item.title|striptags }}">
|
<img src="{{ item.cover }}!cover_270" alt="{{ item.title }}">
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="info">
|
<div class="info">
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
{% if item.cover %}
|
{% if item.cover %}
|
||||||
<div class="cover">
|
<div class="cover">
|
||||||
<a href="{{ question_url }}" target="_blank">
|
<a href="{{ question_url }}" target="_blank">
|
||||||
<img src="{{ item.cover }}!cover_270" alt="{{ item.title|striptags }}">
|
<img src="{{ item.cover }}!cover_270" alt="{{ item.title }}">
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="zh-CN-Hans">
|
<html lang="zh-CN-Hans">
|
||||||
<head>
|
<head>
|
||||||
{% if site_info.analytics_enabled == 1 %}
|
|
||||||
{{ site_info.analytics_script }}
|
|
||||||
{% endif %}
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||||
@ -41,5 +38,12 @@
|
|||||||
|
|
||||||
{% block include_js %}{% endblock %}
|
{% block include_js %}{% endblock %}
|
||||||
{% block inline_js %}{% endblock %}
|
{% block inline_js %}{% endblock %}
|
||||||
|
|
||||||
|
{% if site_info.analytics_enabled == 1 %}
|
||||||
|
<div class="layui-hide">
|
||||||
|
{{ site_info.analytics_script }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -10,11 +10,10 @@
|
|||||||
{% set point_enabled = setting('point','enabled') %}
|
{% set point_enabled = setting('point','enabled') %}
|
||||||
|
|
||||||
<div class="my-profile-card wrap">
|
<div class="my-profile-card wrap">
|
||||||
<div class="vip">{{ vip_info(auth_user) }}</div>
|
|
||||||
<div class="avatar">
|
<div class="avatar">
|
||||||
<img class="my-avatar" src="{{ auth_user.avatar }}" alt="{{ auth_user.name }}">
|
<img class="my-avatar" src="{{ auth_user.avatar }}" alt="{{ auth_user.name }}">
|
||||||
</div>
|
</div>
|
||||||
<div class="name">{{ auth_user.name }}</div>
|
<div class="name">{{ auth_user.name }} {{ vip_info(auth_user) }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="layui-card">
|
<div class="layui-card">
|
||||||
@ -72,4 +71,4 @@
|
|||||||
<li><a href="{{ url({'for':'home.uc.account'}) }}">帐号安全</a></li>
|
<li><a href="{{ url({'for':'home.uc.account'}) }}">帐号安全</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
@ -79,6 +79,7 @@
|
|||||||
|
|
||||||
{% block include_js %}
|
{% block include_js %}
|
||||||
|
|
||||||
|
{{ js_include('home/js/user.avatar.upload.js') }}
|
||||||
{{ js_include('home/js/user.console.profile.js') }}
|
{{ js_include('home/js/user.console.profile.js') }}
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -4,13 +4,13 @@
|
|||||||
|
|
||||||
<div class="vip-header">会员权益</div>
|
<div class="vip-header">会员权益</div>
|
||||||
|
|
||||||
<div class="vip-priv-list wrap">
|
<div class="vip-reason-list wrap">
|
||||||
<button class="layui-btn layui-bg-blue">好课畅学</button>
|
<span class="layui-badge reason-badge">好课畅学</span>
|
||||||
<button class="layui-btn layui-bg-blue">会员折扣</button>
|
<span class="layui-badge reason-badge">会员折扣</span>
|
||||||
<button class="layui-btn layui-bg-blue">高清视频</button>
|
<span class="layui-badge reason-badge">高清视频</span>
|
||||||
<button class="layui-btn layui-bg-blue">广告免疫</button>
|
<span class="layui-badge reason-badge">广告免疫</span>
|
||||||
<button class="layui-btn layui-bg-blue">会员标识</button>
|
<span class="layui-badge reason-badge">会员标识</span>
|
||||||
<button class="layui-btn layui-bg-blue">优先服务</button>
|
<span class="layui-badge reason-badge">贴心服务</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="vip-header">开通会员</div>
|
<div class="vip-header">开通会员</div>
|
||||||
@ -57,4 +57,4 @@
|
|||||||
|
|
||||||
{{ js_include('home/js/vip.index.js') }}
|
{{ js_include('home/js/vip.index.js') }}
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -3,7 +3,7 @@
|
|||||||
<div class="layui-row layui-col-space20">
|
<div class="layui-row layui-col-space20">
|
||||||
{% for item in pager.items %}
|
{% for item in pager.items %}
|
||||||
{% set user_url = url({'for':'home.user.show','id':item.id}) %}
|
{% set user_url = url({'for':'home.user.show','id':item.id}) %}
|
||||||
<div class="layui-col-md3">
|
<div class="layui-col-md2">
|
||||||
<div class="user-card">
|
<div class="user-card">
|
||||||
<div class="avatar">
|
<div class="avatar">
|
||||||
<a href="{{ user_url }}" title="{{ item.about }}" target="_blank">
|
<a href="{{ user_url }}" title="{{ item.about }}" target="_blank">
|
||||||
|
@ -16,7 +16,7 @@ class AppInfo
|
|||||||
|
|
||||||
protected $link = 'https://www.koogua.com';
|
protected $link = 'https://www.koogua.com';
|
||||||
|
|
||||||
protected $version = '1.7.8';
|
protected $version = '1.7.6';
|
||||||
|
|
||||||
public function __get($name)
|
public function __get($name)
|
||||||
{
|
{
|
||||||
|
@ -1,51 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* @copyright Copyright (c) 2024 深圳市酷瓜软件有限公司
|
|
||||||
* @license https://opensource.org/licenses/GPL-2.0
|
|
||||||
* @link https://www.koogua.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace App\Library\Paginator\Adapter;
|
|
||||||
|
|
||||||
use App\Library\Paginator\Query as PaginatorQuery;
|
|
||||||
use Phalcon\Paginator\Adapter\NativeArray as PhNativeArray;
|
|
||||||
use stdClass;
|
|
||||||
|
|
||||||
class NativeArray extends PhNativeArray
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
protected $baseUrl;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
protected $params = [];
|
|
||||||
|
|
||||||
public function paginate(): stdClass
|
|
||||||
{
|
|
||||||
$pager = parent::paginate();
|
|
||||||
|
|
||||||
$query = new PaginatorQuery();
|
|
||||||
|
|
||||||
$this->baseUrl = $query->getBaseUrl();
|
|
||||||
$this->params = $query->getParams();
|
|
||||||
|
|
||||||
$pager->first = $this->buildPageUrl($pager->first);
|
|
||||||
$pager->previous = $this->buildPageUrl($pager->previous);
|
|
||||||
$pager->next = $this->buildPageUrl($pager->next);
|
|
||||||
$pager->last = $this->buildPageUrl($pager->last);
|
|
||||||
|
|
||||||
return $pager;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function buildPageUrl($page)
|
|
||||||
{
|
|
||||||
$this->params['page'] = $page;
|
|
||||||
|
|
||||||
return $this->baseUrl . '?' . http_build_query($this->params);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -29,16 +29,8 @@ class Connect extends Repository
|
|||||||
$query->andWhere('user_id = :user_id:', ['user_id' => $where['user_id']]);
|
$query->andWhere('user_id = :user_id:', ['user_id' => $where['user_id']]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($where['open_id'])) {
|
|
||||||
$query->andWhere('open_id = :open_id:', ['open_id' => $where['open_id']]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!empty($where['provider'])) {
|
if (!empty($where['provider'])) {
|
||||||
if (is_array($where['provider'])) {
|
$query->andWhere('provider = :provider:', ['provider' => $where['provider']]);
|
||||||
$query->inWhere('provider', $where['provider']);
|
|
||||||
} else {
|
|
||||||
$query->andWhere('provider = :provider:', ['provider' => $where['provider']]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($where['deleted'])) {
|
if (isset($where['deleted'])) {
|
||||||
@ -75,6 +67,19 @@ class Connect extends Repository
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $openId
|
||||||
|
* @param int $provider
|
||||||
|
* @return ConnectModel|Model|bool
|
||||||
|
*/
|
||||||
|
public function findByOpenIdShallow($openId, $provider)
|
||||||
|
{
|
||||||
|
return ConnectModel::findFirst([
|
||||||
|
'conditions' => 'open_id = ?1 AND provider = ?2',
|
||||||
|
'bind' => [1 => $openId, 2 => $provider],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param int $userId
|
* @param int $userId
|
||||||
* @param int $provider
|
* @param int $provider
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
namespace App\Services;
|
namespace App\Services;
|
||||||
|
|
||||||
use App\Caches\CourseChapterList as CourseChapterListCache;
|
use App\Caches\CourseChapterList as CatalogCache;
|
||||||
use App\Models\Chapter as ChapterModel;
|
use App\Models\Chapter as ChapterModel;
|
||||||
use App\Models\ChapterLive as ChapterLiveModel;
|
use App\Models\ChapterLive as ChapterLiveModel;
|
||||||
use App\Repos\Chapter as ChapterRepo;
|
use App\Repos\Chapter as ChapterRepo;
|
||||||
@ -175,7 +175,7 @@ class LiveNotify extends Service
|
|||||||
|
|
||||||
protected function rebuildCatalogCache(ChapterModel $chapter)
|
protected function rebuildCatalogCache(ChapterModel $chapter)
|
||||||
{
|
{
|
||||||
$cache = new CourseChapterListCache();
|
$cache = new CatalogCache();
|
||||||
|
|
||||||
$cache->rebuild($chapter->course_id);
|
$cache->rebuild($chapter->course_id);
|
||||||
}
|
}
|
||||||
@ -216,4 +216,4 @@ class LiveNotify extends Service
|
|||||||
return $sign == $mySign;
|
return $sign == $mySign;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -36,8 +36,6 @@ class Register extends LogicService
|
|||||||
|
|
||||||
$accountValidator = new AccountValidator();
|
$accountValidator = new AccountValidator();
|
||||||
|
|
||||||
$accountValidator->checkRegisterStatus($post['account']);
|
|
||||||
|
|
||||||
$accountValidator->checkLoginName($post['account']);
|
$accountValidator->checkLoginName($post['account']);
|
||||||
|
|
||||||
$data = [];
|
$data = [];
|
||||||
|
@ -39,10 +39,10 @@ class ChapterList extends LogicService
|
|||||||
|
|
||||||
if (count($chapters) == 0) return [];
|
if (count($chapters) == 0) return [];
|
||||||
|
|
||||||
if ($user->id > 0) {
|
if ($user->id > 0 && $this->courseUser) {
|
||||||
$chapters = $this->handleLoginUserChapters($chapters, $course, $user);
|
$chapters = $this->handleLoginUserChapters($chapters, $course, $user);
|
||||||
} else {
|
} else {
|
||||||
$chapters = $this->handleGuestUserChapters($chapters, $course);
|
$chapters = $this->handleGuestUserChapters($chapters);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $chapters;
|
return $chapters;
|
||||||
@ -50,11 +50,7 @@ class ChapterList extends LogicService
|
|||||||
|
|
||||||
protected function handleLoginUserChapters(array $chapters, CourseModel $course, UserModel $user)
|
protected function handleLoginUserChapters(array $chapters, CourseModel $course, UserModel $user)
|
||||||
{
|
{
|
||||||
$mappings = [];
|
$mappings = $this->getLearningMappings($course->id, $user->id, $this->courseUser->plan_id);
|
||||||
|
|
||||||
if ($this->courseUser) {
|
|
||||||
$mappings = $this->getLearningMappings($course->id, $user->id, $this->courseUser->plan_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($chapters as &$chapter) {
|
foreach ($chapters as &$chapter) {
|
||||||
foreach ($chapter['children'] as &$lesson) {
|
foreach ($chapter['children'] as &$lesson) {
|
||||||
@ -65,30 +61,23 @@ class ChapterList extends LogicService
|
|||||||
'owned' => $owned ? 1 : 0,
|
'owned' => $owned ? 1 : 0,
|
||||||
'logged' => 1,
|
'logged' => 1,
|
||||||
];
|
];
|
||||||
// 如果课程是免费的,但又设置了课时试听,清除试听标识
|
|
||||||
if ($course->market_price == 0 && $lesson['free'] == 1) {
|
|
||||||
$lesson['free'] = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $chapters;
|
return $chapters;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function handleGuestUserChapters(array $chapters, CourseModel $course)
|
protected function handleGuestUserChapters(array $chapters)
|
||||||
{
|
{
|
||||||
foreach ($chapters as &$chapter) {
|
foreach ($chapters as &$chapter) {
|
||||||
foreach ($chapter['children'] as &$lesson) {
|
foreach ($chapter['children'] as &$lesson) {
|
||||||
|
$owned = ($this->ownedCourse || $lesson['free'] == 1) && $lesson['published'] == 1;
|
||||||
$lesson['me'] = [
|
$lesson['me'] = [
|
||||||
'progress' => 0,
|
'progress' => 0,
|
||||||
'duration' => 0,
|
'duration' => 0,
|
||||||
'logged' => 0,
|
'logged' => 0,
|
||||||
'owned' => 0,
|
'owned' => $owned ? 1 : 0,
|
||||||
];
|
];
|
||||||
// 如果课程是免费的,但又设置了课时试听,清除试听标识
|
|
||||||
if ($course->market_price == 0 && $lesson['free'] == 1) {
|
|
||||||
$lesson['free'] = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,7 +100,7 @@ class CourseInfo extends LogicService
|
|||||||
|
|
||||||
if ($this->courseUser) {
|
if ($this->courseUser) {
|
||||||
$me['reviewed'] = $this->courseUser->reviewed ? 1 : 0;
|
$me['reviewed'] = $this->courseUser->reviewed ? 1 : 0;
|
||||||
$me['progress'] = $this->courseUser->progress;
|
$me['progress'] = $this->courseUser->progress ? 1 : 0;
|
||||||
$me['plan_id'] = $this->courseUser->plan_id;
|
$me['plan_id'] = $this->courseUser->plan_id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ use App\Services\Logic\Service as LogicService;
|
|||||||
use App\Validators\Live as LiveValidator;
|
use App\Validators\Live as LiveValidator;
|
||||||
use GatewayClient\Gateway;
|
use GatewayClient\Gateway;
|
||||||
|
|
||||||
class LiveChat extends LogicService
|
class LiveChapter extends LogicService
|
||||||
{
|
{
|
||||||
|
|
||||||
use ChapterTrait;
|
use ChapterTrait;
|
@ -121,6 +121,7 @@ class OrderConfirm extends LogicService
|
|||||||
'lesson_count' => $course->lesson_count,
|
'lesson_count' => $course->lesson_count,
|
||||||
'study_expiry' => $course->study_expiry,
|
'study_expiry' => $course->study_expiry,
|
||||||
'refund_expiry' => $course->refund_expiry,
|
'refund_expiry' => $course->refund_expiry,
|
||||||
|
'origin_price' => $course->origin_price,
|
||||||
'market_price' => $course->market_price,
|
'market_price' => $course->market_price,
|
||||||
'vip_price' => $course->vip_price,
|
'vip_price' => $course->vip_price,
|
||||||
];
|
];
|
||||||
|
@ -33,7 +33,7 @@ class Article extends Handler
|
|||||||
'limit' => $limit,
|
'limit' => $limit,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$pager = $paginator->paginate();
|
$pager = $paginator->getPaginate();
|
||||||
|
|
||||||
return $this->handleArticles($pager);
|
return $this->handleArticles($pager);
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ class Course extends Handler
|
|||||||
'limit' => $limit,
|
'limit' => $limit,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$pager = $paginator->paginate();
|
$pager = $paginator->getPaginate();
|
||||||
|
|
||||||
return $this->handleCourses($pager);
|
return $this->handleCourses($pager);
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ class Question extends Handler
|
|||||||
'limit' => $limit,
|
'limit' => $limit,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$pager = $paginator->paginate();
|
$pager = $paginator->getPaginate();
|
||||||
|
|
||||||
return $this->handleQuestions($pager);
|
return $this->handleQuestions($pager);
|
||||||
}
|
}
|
||||||
|
@ -111,9 +111,6 @@ class OfficialAccount extends AppService
|
|||||||
|
|
||||||
$logger->debug('Received Message: ' . json_encode($message));
|
$logger->debug('Received Message: ' . json_encode($message));
|
||||||
|
|
||||||
/**
|
|
||||||
* 事件类型文档:https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Receiving_event_pushes.html
|
|
||||||
*/
|
|
||||||
switch ($message['MsgType']) {
|
switch ($message['MsgType']) {
|
||||||
case 'event':
|
case 'event':
|
||||||
switch ($message['Event']) {
|
switch ($message['Event']) {
|
||||||
@ -164,24 +161,44 @@ class OfficialAccount extends AppService
|
|||||||
|
|
||||||
if ($connect) return null;
|
if ($connect) return null;
|
||||||
|
|
||||||
$loginScene = sprintf('qrscene_%s', self::QR_SCENE_LOGIN);
|
/**
|
||||||
|
* 尼玛不知道为什么又多了个"qrscene_"前缀,SCAN事件里面又不带这个前缀
|
||||||
|
*/
|
||||||
$subscribeScene = sprintf('qrscene_%s', self::QR_SCENE_SUBSCRIBE);
|
$subscribeScene = sprintf('qrscene_%s', self::QR_SCENE_SUBSCRIBE);
|
||||||
|
|
||||||
/**
|
$userId = 0;
|
||||||
* 未关注过服务号,在登录页扫登录场景码,关注服务号
|
|
||||||
*/
|
if (Text::startsWith($eventKey, $subscribeScene)) {
|
||||||
if (Text::startsWith($eventKey, $loginScene)) {
|
|
||||||
$ticket = str_replace($loginScene, '', $eventKey);
|
$userId = str_replace($subscribeScene, '', $eventKey);
|
||||||
$this->handleLoginPageSubscribe($ticket, $openId);
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
$connect = $connectRepo->findByOpenIdShallow($openId, ConnectModel::PROVIDER_WECHAT_OA);
|
||||||
|
|
||||||
|
if ($connect) $userId = $connect->user_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
if ($userId > 0) {
|
||||||
* 未关注过服务号,在用户中心扫关注场景码,关注服务号
|
|
||||||
*/
|
$userRepo = new UserRepo();
|
||||||
if (Text::startsWith($eventKey, $subscribeScene)) {
|
|
||||||
$userId = str_replace($subscribeScene, '', $eventKey);
|
$user = $userRepo->findById($userId);
|
||||||
$this->handleAccountPageSubscribe($userId, $openId);
|
|
||||||
|
if (!$user) return null;
|
||||||
|
|
||||||
|
$userInfo = $this->getUserInfo($openId);
|
||||||
|
|
||||||
|
$unionId = $userInfo['unionid'] ?: '';
|
||||||
|
|
||||||
|
$connect = new ConnectModel();
|
||||||
|
|
||||||
|
$connect->user_id = $userId;
|
||||||
|
$connect->open_id = $openId;
|
||||||
|
$connect->union_id = $unionId;
|
||||||
|
$connect->provider = ConnectModel::PROVIDER_WECHAT_OA;
|
||||||
|
|
||||||
|
$connect->create();
|
||||||
}
|
}
|
||||||
|
|
||||||
return new TextMessage('开心呀,我们又多了一个小伙伴!');
|
return new TextMessage('开心呀,我们又多了一个小伙伴!');
|
||||||
@ -211,19 +228,19 @@ class OfficialAccount extends AppService
|
|||||||
$eventKey = $message['EventKey'] ?? '';
|
$eventKey = $message['EventKey'] ?? '';
|
||||||
|
|
||||||
if (Text::startsWith($eventKey, self::QR_SCENE_LOGIN)) {
|
if (Text::startsWith($eventKey, self::QR_SCENE_LOGIN)) {
|
||||||
$ticket = str_replace(self::QR_SCENE_LOGIN, '', $eventKey);
|
return $this->handleLoginScanEvent($eventKey, $openId);
|
||||||
$this->handleLoginPageSubscribe($ticket, $openId);
|
|
||||||
} elseif (Text::startsWith($eventKey, self::QR_SCENE_SUBSCRIBE)) {
|
} elseif (Text::startsWith($eventKey, self::QR_SCENE_SUBSCRIBE)) {
|
||||||
$userId = str_replace(self::QR_SCENE_SUBSCRIBE, '', $eventKey);
|
return $this->handleSubscribeScanEvent($eventKey, $openId);
|
||||||
$this->handleAccountPageSubscribe($userId, $openId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->emptyReply();
|
return $this->emptyReply();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function handleLoginPageSubscribe($ticket, $openId)
|
protected function handleLoginScanEvent($eventKey, $openId)
|
||||||
{
|
{
|
||||||
if (empty($ticket) || empty($openId)) return;
|
$ticket = str_replace(self::QR_SCENE_LOGIN, '', $eventKey);
|
||||||
|
|
||||||
|
if (empty($ticket) || empty($openId)) return null;
|
||||||
|
|
||||||
$connectRepo = new ConnectRepo();
|
$connectRepo = new ConnectRepo();
|
||||||
|
|
||||||
@ -239,27 +256,31 @@ class OfficialAccount extends AppService
|
|||||||
];
|
];
|
||||||
|
|
||||||
$cache->save($keyName, $content, 30 * 60);
|
$cache->save($keyName, $content, 30 * 60);
|
||||||
|
|
||||||
|
return $this->emptyReply();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function handleAccountPageSubscribe($userId, $openId)
|
protected function handleSubscribeScanEvent($eventKey, $openId)
|
||||||
{
|
{
|
||||||
if (empty($userId) || empty($openId)) return;
|
$userId = str_replace(self::QR_SCENE_SUBSCRIBE, '', $eventKey);
|
||||||
|
|
||||||
|
if (empty($userId) || empty($openId)) return null;
|
||||||
|
|
||||||
$userRepo = new UserRepo();
|
$userRepo = new UserRepo();
|
||||||
|
|
||||||
$user = $userRepo->findById($userId);
|
$user = $userRepo->findById($userId);
|
||||||
|
|
||||||
if (!$user) return;
|
if (!$user) return null;
|
||||||
|
|
||||||
|
$userInfo = $this->getUserInfo($openId);
|
||||||
|
|
||||||
|
$unionId = $userInfo['unionid'] ?: '';
|
||||||
|
|
||||||
$connectRepo = new ConnectRepo();
|
$connectRepo = new ConnectRepo();
|
||||||
|
|
||||||
$connect = $connectRepo->findByOpenId($openId, ConnectModel::PROVIDER_WECHAT_OA);
|
$connect = $connectRepo->findByOpenId($openId, ConnectModel::PROVIDER_WECHAT_OA);
|
||||||
|
|
||||||
if ($connect) return;
|
if ($connect) return null;
|
||||||
|
|
||||||
$userInfo = $this->getUserInfo($openId);
|
|
||||||
|
|
||||||
$unionId = $userInfo['unionid'] ?: '';
|
|
||||||
|
|
||||||
$connect = new ConnectModel();
|
$connect = new ConnectModel();
|
||||||
|
|
||||||
@ -269,6 +290,8 @@ class OfficialAccount extends AppService
|
|||||||
$connect->provider = ConnectModel::PROVIDER_WECHAT_OA;
|
$connect->provider = ConnectModel::PROVIDER_WECHAT_OA;
|
||||||
|
|
||||||
$connect->create();
|
$connect->create();
|
||||||
|
|
||||||
|
return $this->emptyReply();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function handleClickEvent($message)
|
protected function handleClickEvent($message)
|
||||||
|
@ -53,15 +53,15 @@ class Refund extends Service
|
|||||||
$serviceFee = $this->getServiceFee($order);
|
$serviceFee = $this->getServiceFee($order);
|
||||||
$serviceRate = $this->getServiceRate($order);
|
$serviceRate = $this->getServiceRate($order);
|
||||||
|
|
||||||
$refundRate = 0.00;
|
$refundPercent = 0.00;
|
||||||
$refundAmount = 0.00;
|
$refundAmount = 0.00;
|
||||||
|
|
||||||
if ($itemInfo['course']['refund_expiry_time'] > time()) {
|
if ($itemInfo['course']['refund_expiry_time'] > time()) {
|
||||||
$refundRate = $this->getCourseRefundRate($order->item_id, $order->owner_id);
|
$refundPercent = $this->getCourseRefundPercent($order->item_id, $order->owner_id);
|
||||||
$refundAmount = round(($order->amount - $serviceFee) * $refundRate, 2);
|
$refundAmount = round(($order->amount - $serviceFee) * $refundPercent, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
$itemInfo['course']['refund_rate'] = $refundRate;
|
$itemInfo['course']['refund_percent'] = $refundPercent;
|
||||||
$itemInfo['course']['refund_amount'] = $refundAmount;
|
$itemInfo['course']['refund_amount'] = $refundAmount;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
@ -95,17 +95,17 @@ class Refund extends Service
|
|||||||
|
|
||||||
$course['cover'] = kg_cos_course_cover_url($course['cover']);
|
$course['cover'] = kg_cos_course_cover_url($course['cover']);
|
||||||
|
|
||||||
$refundRate = 0.00;
|
$refundPercent = 0.00;
|
||||||
$refundAmount = 0.00;
|
$refundAmount = 0.00;
|
||||||
|
|
||||||
if ($course['refund_expiry_time'] > time()) {
|
if ($course['refund_expiry_time'] > time()) {
|
||||||
$priceRate = round($course['market_price'] / $totalMarketPrice, 4);
|
$pricePercent = round($course['market_price'] / $totalMarketPrice, 4);
|
||||||
$refundRate = $this->getCourseRefundRate($course['id'], $order->owner_id);
|
$refundPercent = $this->getCourseRefundPercent($course['id'], $order->owner_id);
|
||||||
$refundAmount = round(($order->amount - $serviceFee) * $priceRate * $refundRate, 2);
|
$refundAmount = round(($order->amount - $serviceFee) * $pricePercent * $refundPercent, 2);
|
||||||
$totalRefundAmount += $refundAmount;
|
$totalRefundAmount += $refundAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
$course['refund_rate'] = $refundRate;
|
$course['refund_percent'] = $refundPercent;
|
||||||
$course['refund_amount'] = $refundAmount;
|
$course['refund_amount'] = $refundAmount;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,7 +176,7 @@ class Refund extends Service
|
|||||||
return $serviceRate;
|
return $serviceRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getCourseRefundRate($courseId, $userId)
|
protected function getCourseRefundPercent($courseId, $userId)
|
||||||
{
|
{
|
||||||
$courseRepo = new CourseRepo();
|
$courseRepo = new CourseRepo();
|
||||||
|
|
||||||
|
@ -10,7 +10,6 @@ namespace App\Services;
|
|||||||
use Phalcon\Logger\Adapter\File as FileLogger;
|
use Phalcon\Logger\Adapter\File as FileLogger;
|
||||||
use Qcloud\Cos\Client as CosClient;
|
use Qcloud\Cos\Client as CosClient;
|
||||||
use TencentCloud\Common\Credential;
|
use TencentCloud\Common\Credential;
|
||||||
use TencentCloud\Common\Exception\TencentCloudSDKException;
|
|
||||||
use TencentCloud\Common\Profile\ClientProfile;
|
use TencentCloud\Common\Profile\ClientProfile;
|
||||||
use TencentCloud\Common\Profile\HttpProfile;
|
use TencentCloud\Common\Profile\HttpProfile;
|
||||||
use TencentCloud\Sts\V20180813\Models\GetFederationTokenRequest;
|
use TencentCloud\Sts\V20180813\Models\GetFederationTokenRequest;
|
||||||
@ -101,12 +100,11 @@ class Storage extends Service
|
|||||||
|
|
||||||
$result = $client->GetFederationToken($request);
|
$result = $client->GetFederationToken($request);
|
||||||
|
|
||||||
} catch (TencentCloudSDKException $e) {
|
} catch (\Exception $e) {
|
||||||
|
|
||||||
$this->logger->error('Get Tmp Token Exception ' . kg_json_encode([
|
$this->logger->error('Get Tmp Token Exception' . kg_json_encode([
|
||||||
'code' => $e->getCode(),
|
'code' => $e->getCode(),
|
||||||
'message' => $e->getMessage(),
|
'message' => $e->getMessage(),
|
||||||
'requestId' => $e->getRequestId(),
|
|
||||||
]));
|
]));
|
||||||
|
|
||||||
$result = false;
|
$result = false;
|
||||||
@ -132,12 +130,11 @@ class Storage extends Service
|
|||||||
|
|
||||||
$result = $response['Location'] ? $key : false;
|
$result = $response['Location'] ? $key : false;
|
||||||
|
|
||||||
} catch (TencentCloudSDKException $e) {
|
} catch (\Exception $e) {
|
||||||
|
|
||||||
$this->logger->error('Put String Exception ' . kg_json_encode([
|
$this->logger->error('Put String Exception ' . kg_json_encode([
|
||||||
'code' => $e->getCode(),
|
'code' => $e->getCode(),
|
||||||
'message' => $e->getMessage(),
|
'message' => $e->getMessage(),
|
||||||
'requestId' => $e->getRequestId(),
|
|
||||||
]));
|
]));
|
||||||
|
|
||||||
$result = false;
|
$result = false;
|
||||||
@ -165,12 +162,11 @@ class Storage extends Service
|
|||||||
|
|
||||||
$result = $response['Location'] ? $key : false;
|
$result = $response['Location'] ? $key : false;
|
||||||
|
|
||||||
} catch (TencentCloudSDKException $e) {
|
} catch (\Exception $e) {
|
||||||
|
|
||||||
$this->logger->error('Put File Exception ' . kg_json_encode([
|
$this->logger->error('Put File Exception ' . kg_json_encode([
|
||||||
'code' => $e->getCode(),
|
'code' => $e->getCode(),
|
||||||
'message' => $e->getMessage(),
|
'message' => $e->getMessage(),
|
||||||
'requestId' => $e->getRequestId(),
|
|
||||||
]));
|
]));
|
||||||
|
|
||||||
$result = false;
|
$result = false;
|
||||||
@ -198,12 +194,11 @@ class Storage extends Service
|
|||||||
|
|
||||||
$result = $response['Location'] ? $key : false;
|
$result = $response['Location'] ? $key : false;
|
||||||
|
|
||||||
} catch (TencentCloudSDKException $e) {
|
} catch (\Exception $e) {
|
||||||
|
|
||||||
$this->logger->error('Delete Object Exception ' . kg_json_encode([
|
$this->logger->error('Delete Object Exception ' . kg_json_encode([
|
||||||
'code' => $e->getCode(),
|
'code' => $e->getCode(),
|
||||||
'message' => $e->getMessage(),
|
'message' => $e->getMessage(),
|
||||||
'requestId' => $e->getRequestId(),
|
|
||||||
]));
|
]));
|
||||||
|
|
||||||
$result = false;
|
$result = false;
|
||||||
|
65
app/Services/Throttle.php
Normal file
65
app/Services/Throttle.php
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @copyright Copyright (c) 2021 深圳市酷瓜软件有限公司
|
||||||
|
* @license https://opensource.org/licenses/GPL-2.0
|
||||||
|
* @link https://www.koogua.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Services;
|
||||||
|
|
||||||
|
class Throttle extends Service
|
||||||
|
{
|
||||||
|
|
||||||
|
public function checkRateLimit()
|
||||||
|
{
|
||||||
|
$config = $this->getConfig();
|
||||||
|
|
||||||
|
if (!$config->path('throttle.enabled')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$cache = $this->getCache();
|
||||||
|
|
||||||
|
$sign = $this->getRequestSignature();
|
||||||
|
|
||||||
|
$cacheKey = $this->getCacheKey($sign);
|
||||||
|
|
||||||
|
if ($cache->ttl($cacheKey) < 1) {
|
||||||
|
$cache->save($cacheKey, 0, $config->path('throttle.lifetime'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$rateLimit = $cache->get($cacheKey);
|
||||||
|
|
||||||
|
if ($rateLimit >= $config->path('throttle.rate_limit')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$cache->increment($cacheKey, 1);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getRequestSignature()
|
||||||
|
{
|
||||||
|
$authUser = $this->getAuthUser();
|
||||||
|
|
||||||
|
if (!empty($authUser['id'])) {
|
||||||
|
return md5($authUser['id']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$httpHost = $this->request->getHttpHost();
|
||||||
|
$clientAddress = $this->request->getClientAddress();
|
||||||
|
|
||||||
|
if ($httpHost && $clientAddress) {
|
||||||
|
return md5($httpHost . '|' . $clientAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \RuntimeException('Unable to generate request signature');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getCacheKey($sign)
|
||||||
|
{
|
||||||
|
return "throttle:{$sign}";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -28,6 +28,13 @@ trait Security
|
|||||||
$validator->checkHttpReferer();
|
$validator->checkHttpReferer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function checkRateLimit()
|
||||||
|
{
|
||||||
|
$validator = new SecurityValidator();
|
||||||
|
|
||||||
|
$validator->checkRateLimit();
|
||||||
|
}
|
||||||
|
|
||||||
public function isNotSafeRequest()
|
public function isNotSafeRequest()
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -129,29 +129,6 @@ class Account extends Validator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function checkRegisterStatus($account)
|
|
||||||
{
|
|
||||||
$local = $this->getSettings('oauth.local');
|
|
||||||
|
|
||||||
$allowPhone = $local['register_with_phone'] ?? false;
|
|
||||||
$allowEmail = $local['register_with_email'] ?? false;
|
|
||||||
|
|
||||||
$isEmail = CommonValidator::email($account);
|
|
||||||
$isPhone = CommonValidator::Phone($account);
|
|
||||||
|
|
||||||
if (!$allowPhone && !$allowEmail) {
|
|
||||||
throw new BadRequestException('account.register_disabled');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($isPhone && !$allowPhone) {
|
|
||||||
throw new BadRequestException('account.register_with_phone_disabled');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($isEmail && !$allowEmail) {
|
|
||||||
throw new BadRequestException('account.register_with_email_disabled');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function checkVerifyLogin($name, $code)
|
public function checkVerifyLogin($name, $code)
|
||||||
{
|
{
|
||||||
$this->checkLoginName($name);
|
$this->checkLoginName($name);
|
||||||
|
@ -11,7 +11,10 @@ use App\Exceptions\BadRequest as BadRequestException;
|
|||||||
use App\Models\Order as OrderModel;
|
use App\Models\Order as OrderModel;
|
||||||
use App\Models\Refund as RefundModel;
|
use App\Models\Refund as RefundModel;
|
||||||
use App\Models\Trade as TradeModel;
|
use App\Models\Trade as TradeModel;
|
||||||
|
use App\Repos\Course as CourseRepo;
|
||||||
use App\Repos\Order as OrderRepo;
|
use App\Repos\Order as OrderRepo;
|
||||||
|
use App\Repos\Package as PackageRepo;
|
||||||
|
use App\Repos\Vip as VipRepo;
|
||||||
|
|
||||||
class Order extends Validator
|
class Order extends Validator
|
||||||
{
|
{
|
||||||
@ -47,36 +50,54 @@ class Order extends Validator
|
|||||||
return $order;
|
return $order;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function checkItemType($type)
|
public function checkItemType($itemType)
|
||||||
{
|
{
|
||||||
$types = OrderModel::itemTypes();
|
$list = OrderModel::itemTypes();
|
||||||
|
|
||||||
if (!array_key_exists($type, $types)) {
|
if (!array_key_exists($itemType, $list)) {
|
||||||
throw new BadRequestException('order.invalid_item_type');
|
throw new BadRequestException('order.invalid_item_type');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $type;
|
return $itemType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function checkCourse($id)
|
public function checkCourse($itemId)
|
||||||
{
|
{
|
||||||
$validator = new Course();
|
$courseRepo = new CourseRepo();
|
||||||
|
|
||||||
return $validator->checkCourse($id);
|
$course = $courseRepo->findById($itemId);
|
||||||
|
|
||||||
|
if (!$course || $course->published == 0) {
|
||||||
|
throw new BadRequestException('order.item_not_found');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $course;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function checkPackage($id)
|
public function checkPackage($itemId)
|
||||||
{
|
{
|
||||||
$validator = new Package();
|
$packageRepo = new PackageRepo();
|
||||||
|
|
||||||
return $validator->checkPackage($id);
|
$package = $packageRepo->findById($itemId);
|
||||||
|
|
||||||
|
if (!$package || $package->published == 0) {
|
||||||
|
throw new BadRequestException('order.item_not_found');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $package;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function checkVip($id)
|
public function checkVip($itemId)
|
||||||
{
|
{
|
||||||
$validator = new Vip();
|
$vipRepo = new VipRepo();
|
||||||
|
|
||||||
return $validator->checkVip($id);
|
$vip = $vipRepo->findById($itemId);
|
||||||
|
|
||||||
|
if (!$vip || $vip->deleted == 1) {
|
||||||
|
throw new BadRequestException('order.item_not_found');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $vip;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function checkAmount($amount)
|
public function checkAmount($amount)
|
||||||
@ -84,7 +105,7 @@ class Order extends Validator
|
|||||||
$value = $this->filter->sanitize($amount, ['trim', 'float']);
|
$value = $this->filter->sanitize($amount, ['trim', 'float']);
|
||||||
|
|
||||||
if ($value < 0.01 || $value > 100000) {
|
if ($value < 0.01 || $value > 100000) {
|
||||||
throw new BadRequestException('order.invalid_amount');
|
throw new BadRequestException('order.invalid_pay_amount');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $value;
|
return $value;
|
||||||
@ -127,7 +148,7 @@ class Order extends Validator
|
|||||||
];
|
];
|
||||||
|
|
||||||
if (!in_array($order->item_type, $types)) {
|
if (!in_array($order->item_type, $types)) {
|
||||||
throw new BadRequestException('order.refund_not_supported');
|
throw new BadRequestException('order.refund_item_unsupported');
|
||||||
}
|
}
|
||||||
|
|
||||||
$orderRepo = new OrderRepo();
|
$orderRepo = new OrderRepo();
|
||||||
@ -146,7 +167,7 @@ class Order extends Validator
|
|||||||
];
|
];
|
||||||
|
|
||||||
if ($refund && in_array($refund->status, $scopes)) {
|
if ($refund && in_array($refund->status, $scopes)) {
|
||||||
throw new BadRequestException('order.refund_request_existed');
|
throw new BadRequestException('order.refund_apply_existed');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,9 @@
|
|||||||
namespace App\Validators;
|
namespace App\Validators;
|
||||||
|
|
||||||
use App\Exceptions\BadRequest as BadRequestException;
|
use App\Exceptions\BadRequest as BadRequestException;
|
||||||
|
use App\Exceptions\ServiceUnavailable as ServiceUnavailableException;
|
||||||
use App\Library\CsrfToken as CsrfTokenService;
|
use App\Library\CsrfToken as CsrfTokenService;
|
||||||
|
use App\Services\Throttle as ThrottleService;
|
||||||
|
|
||||||
class Security extends Validator
|
class Security extends Validator
|
||||||
{
|
{
|
||||||
@ -51,6 +53,17 @@ class Security extends Validator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function checkRateLimit()
|
||||||
|
{
|
||||||
|
$service = new ThrottleService();
|
||||||
|
|
||||||
|
$result = $service->checkRateLimit();
|
||||||
|
|
||||||
|
if (!$result) {
|
||||||
|
throw new ServiceUnavailableException('security.too_many_requests');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected function getCsrfWhitelist()
|
protected function getCsrfWhitelist()
|
||||||
{
|
{
|
||||||
return [];
|
return [];
|
||||||
|
@ -91,7 +91,7 @@ class Trade extends Validator
|
|||||||
];
|
];
|
||||||
|
|
||||||
if ($refund && in_array($refund->status, $scopes)) {
|
if ($refund && in_array($refund->status, $scopes)) {
|
||||||
throw new BadRequestException('trade.refund_request_existed');
|
throw new BadRequestException('trade.refund_apply_existed');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,6 +147,21 @@ $config['cors']['allow_headers'] = '*';
|
|||||||
*/
|
*/
|
||||||
$config['cors']['allow_methods'] = ['GET', 'POST', 'OPTIONS'];
|
$config['cors']['allow_methods'] = ['GET', 'POST', 'OPTIONS'];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 限流开启
|
||||||
|
*/
|
||||||
|
$config['throttle']['enabled'] = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 有效期(秒)
|
||||||
|
*/
|
||||||
|
$config['throttle']['lifetime'] = 60;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 限流频率
|
||||||
|
*/
|
||||||
|
$config['throttle']['rate_limit'] = 60;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 客户端ping服务端间隔(秒)
|
* 客户端ping服务端间隔(秒)
|
||||||
*/
|
*/
|
||||||
|
@ -22,6 +22,7 @@ $error['sys.unknown_error'] = '未知错误';
|
|||||||
/**
|
/**
|
||||||
* 安全相关
|
* 安全相关
|
||||||
*/
|
*/
|
||||||
|
$error['security.too_many_requests'] = '请求过于频繁';
|
||||||
$error['security.invalid_csrf_token'] = '无效的CSRF令牌';
|
$error['security.invalid_csrf_token'] = '无效的CSRF令牌';
|
||||||
$error['security.invalid_http_referer'] = '无效请求来源';
|
$error['security.invalid_http_referer'] = '无效请求来源';
|
||||||
|
|
||||||
@ -56,9 +57,6 @@ $error['account.phone_taken'] = '手机号被占用';
|
|||||||
$error['account.pwd_not_match'] = '密码不匹配';
|
$error['account.pwd_not_match'] = '密码不匹配';
|
||||||
$error['account.origin_pwd_incorrect'] = '原有密码不正确';
|
$error['account.origin_pwd_incorrect'] = '原有密码不正确';
|
||||||
$error['account.login_pwd_incorrect'] = '登录密码不正确';
|
$error['account.login_pwd_incorrect'] = '登录密码不正确';
|
||||||
$error['account.register_disabled'] = '注册已关闭';
|
|
||||||
$error['account.register_with_phone_disabled'] = '手机注册已关闭';
|
|
||||||
$error['account.register_with_email_disabled'] = '邮箱注册已关闭';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用户相关
|
* 用户相关
|
||||||
@ -363,15 +361,17 @@ $error['slide.invalid_publish_status'] = '无效的发布状态';
|
|||||||
* 订单相关
|
* 订单相关
|
||||||
*/
|
*/
|
||||||
$error['order.not_found'] = '订单不存在';
|
$error['order.not_found'] = '订单不存在';
|
||||||
$error['order.invalid_amount'] = '无效的支付金额';
|
|
||||||
$error['order.invalid_status'] = '无效的状态类型';
|
$error['order.invalid_status'] = '无效的状态类型';
|
||||||
|
$error['order.item_not_found'] = '商品不存在';
|
||||||
|
$error['order.trade_expired'] = '交易已过期';
|
||||||
$error['order.is_delivering'] = '已经下过单了,正在准备发货中';
|
$error['order.is_delivering'] = '已经下过单了,正在准备发货中';
|
||||||
$error['order.has_bought_course'] = '已经购买过该课程';
|
$error['order.has_bought_course'] = '已经购买过该课程';
|
||||||
$error['order.has_bought_package'] = '已经购买过该套餐';
|
$error['order.has_bought_package'] = '已经购买过该套餐';
|
||||||
$error['order.cancel_not_allowed'] = '当前不允许取消订单';
|
$error['order.cancel_not_allowed'] = '当前不允许取消订单';
|
||||||
|
$error['order.close_not_allowed'] = '当前不允许关闭订单';
|
||||||
$error['order.refund_not_allowed'] = '当前不允许申请退款';
|
$error['order.refund_not_allowed'] = '当前不允许申请退款';
|
||||||
$error['order.refund_not_supported'] = '该品类不支持退款';
|
$error['order.refund_item_unsupported'] = '该品类不支持退款';
|
||||||
$error['order.refund_request_existed'] = '退款申请已经存在';
|
$error['order.refund_apply_existed'] = '退款申请已经存在';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 交易相关
|
* 交易相关
|
||||||
@ -382,7 +382,7 @@ $error['trade.invalid_channel'] = '无效的平台类型';
|
|||||||
$error['trade.invalid_status'] = '无效的状态类型';
|
$error['trade.invalid_status'] = '无效的状态类型';
|
||||||
$error['trade.close_not_allowed'] = '当前不允许关闭交易';
|
$error['trade.close_not_allowed'] = '当前不允许关闭交易';
|
||||||
$error['trade.refund_not_allowed'] = '当前不允许交易退款';
|
$error['trade.refund_not_allowed'] = '当前不允许交易退款';
|
||||||
$error['trade.refund_request_existed'] = '退款申请已经存在,请等待处理结果';
|
$error['trade.refund_apply_existed'] = '退款申请已经存在,请等待处理结果';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 退款相关
|
* 退款相关
|
||||||
|
@ -294,6 +294,21 @@ final class V20210403184518 extends AbstractMigration
|
|||||||
protected function initSettingData()
|
protected function initSettingData()
|
||||||
{
|
{
|
||||||
$rows = [
|
$rows = [
|
||||||
|
[
|
||||||
|
'section' => 'captcha',
|
||||||
|
'item_key' => 'enabled',
|
||||||
|
'item_value' => '0',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'section' => 'captcha',
|
||||||
|
'item_key' => 'app_id',
|
||||||
|
'item_value' => '',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'section' => 'captcha',
|
||||||
|
'item_key' => 'secret_key',
|
||||||
|
'item_value' => '',
|
||||||
|
],
|
||||||
[
|
[
|
||||||
'section' => 'live.push',
|
'section' => 'live.push',
|
||||||
'item_key' => 'domain',
|
'item_key' => 'domain',
|
||||||
@ -377,7 +392,7 @@ final class V20210403184518 extends AbstractMigration
|
|||||||
[
|
[
|
||||||
'section' => 'mail',
|
'section' => 'mail',
|
||||||
'item_key' => 'smtp_host',
|
'item_key' => 'smtp_host',
|
||||||
'item_value' => '',
|
'item_value' => 'smtp.163.com',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'section' => 'mail',
|
'section' => 'mail',
|
||||||
@ -397,22 +412,22 @@ final class V20210403184518 extends AbstractMigration
|
|||||||
[
|
[
|
||||||
'section' => 'mail',
|
'section' => 'mail',
|
||||||
'item_key' => 'smtp_username',
|
'item_key' => 'smtp_username',
|
||||||
'item_value' => '',
|
'item_value' => 'xxx@163.com',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'section' => 'mail',
|
'section' => 'mail',
|
||||||
'item_key' => 'smtp_password',
|
'item_key' => 'smtp_password',
|
||||||
'item_value' => '',
|
'item_value' => 'xxx',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'section' => 'mail',
|
'section' => 'mail',
|
||||||
'item_key' => 'smtp_from_email',
|
'item_key' => 'smtp_from_email',
|
||||||
'item_value' => '',
|
'item_value' => 'xxx@163.com',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'section' => 'mail',
|
'section' => 'mail',
|
||||||
'item_key' => 'smtp_from_name',
|
'item_key' => 'smtp_from_name',
|
||||||
'item_value' => '',
|
'item_value' => 'XXX有限公司',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'section' => 'pay.alipay',
|
'section' => 'pay.alipay',
|
||||||
@ -602,18 +617,18 @@ final class V20210403184518 extends AbstractMigration
|
|||||||
[
|
[
|
||||||
'section' => 'sms',
|
'section' => 'sms',
|
||||||
'item_key' => 'signature',
|
'item_key' => 'signature',
|
||||||
'item_value' => '',
|
'item_value' => '酷瓜云课堂',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'section' => 'sms',
|
'section' => 'sms',
|
||||||
'item_key' => 'template',
|
'item_key' => 'template',
|
||||||
'item_value' => json_encode([
|
'item_value' => json_encode([
|
||||||
'verify' => ['enabled' => 1, 'id' => 0],
|
'verify' => ['enabled' => 1, 'id' => ''],
|
||||||
'order_finish' => ['enabled' => 0, 'id' => 0],
|
'order_finish' => ['enabled' => 1, 'id' => ''],
|
||||||
'refund_finish' => ['enabled' => 0, 'id' => 0],
|
'refund_finish' => ['enabled' => 1, 'id' => ''],
|
||||||
'live_begin' => ['enabled' => 0, 'id' => 0],
|
'live_begin' => ['enabled' => 1, 'id' => ''],
|
||||||
'consult_reply' => ['enabled' => 0, 'id' => 0],
|
'consult_reply' => ['enabled' => 1, 'id' => ''],
|
||||||
'goods_deliver' => ['enabled' => 0, 'id' => 0],
|
'goods_deliver' => ['enabled' => 1, 'id' => ''],
|
||||||
]),
|
]),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
@ -820,12 +835,12 @@ final class V20210403184518 extends AbstractMigration
|
|||||||
'section' => 'wechat.oa',
|
'section' => 'wechat.oa',
|
||||||
'item_key' => 'notice_template',
|
'item_key' => 'notice_template',
|
||||||
'item_value' => json_encode([
|
'item_value' => json_encode([
|
||||||
'account_login' => ['enabled' => 0, 'id' => 0],
|
'account_login' => ['enabled' => 1, 'id' => ''],
|
||||||
'order_finish' => ['enabled' => 0, 'id' => 0],
|
'order_finish' => ['enabled' => 1, 'id' => ''],
|
||||||
'refund_finish' => ['enabled' => 0, 'id' => 0],
|
'refund_finish' => ['enabled' => 1, 'id' => ''],
|
||||||
'goods_deliver' => ['enabled' => 0, 'id' => 0],
|
'goods_deliver' => ['enabled' => 1, 'id' => ''],
|
||||||
'consult_reply' => ['enabled' => 0, 'id' => 0],
|
'consult_reply' => ['enabled' => 1, 'id' => ''],
|
||||||
'live_begin' => ['enabled' => 0, 'id' => 0],
|
'live_begin' => ['enabled' => 1, 'id' => ''],
|
||||||
]),
|
]),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
@ -14,6 +14,21 @@
|
|||||||
padding-bottom: 0;
|
padding-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.layui-copyright {
|
||||||
|
position: fixed;
|
||||||
|
z-index: 999;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
width: 180px;
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: rgba(255, 255, 255, .7);
|
||||||
|
}
|
||||||
|
|
||||||
|
.layui-copyright a {
|
||||||
|
color: rgba(255, 255, 255, .7);
|
||||||
|
}
|
||||||
|
|
||||||
.red {
|
.red {
|
||||||
color: red;
|
color: red;
|
||||||
}
|
}
|
||||||
@ -285,6 +300,10 @@ img.kg-qrcode {
|
|||||||
border: 3px solid #999;
|
border: 3px solid #999;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.kg-order-date {
|
||||||
|
margin-left: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
.kg-order-item {
|
.kg-order-item {
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
padding-top: 10px;
|
padding-top: 10px;
|
||||||
|
@ -9,9 +9,28 @@ layui.use(['jquery', 'layer', 'upload'], function () {
|
|||||||
url: '/admin/upload/avatar/img',
|
url: '/admin/upload/avatar/img',
|
||||||
accept: 'images',
|
accept: 'images',
|
||||||
acceptMime: 'image/*',
|
acceptMime: 'image/*',
|
||||||
|
size: 512,
|
||||||
|
auto: false,
|
||||||
before: function () {
|
before: function () {
|
||||||
layer.load();
|
layer.load();
|
||||||
},
|
},
|
||||||
|
choose: function (obj) {
|
||||||
|
var flag = true;
|
||||||
|
obj.preview(function (index, file, result) {
|
||||||
|
var img = new Image();
|
||||||
|
img.src = result;
|
||||||
|
img.onload = function () {
|
||||||
|
if (img.width < 1000 && img.height < 1000) {
|
||||||
|
obj.upload(index, file);
|
||||||
|
} else {
|
||||||
|
flag = false;
|
||||||
|
layer.msg("图片尺寸必须小于 1000 * 1000");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return flag;
|
||||||
|
});
|
||||||
|
},
|
||||||
done: function (res, index, upload) {
|
done: function (res, index, upload) {
|
||||||
$('#img-avatar').attr('src', res.data.url);
|
$('#img-avatar').attr('src', res.data.url);
|
||||||
$('input[name=avatar]').val(res.data.url);
|
$('input[name=avatar]').val(res.data.url);
|
||||||
@ -22,4 +41,4 @@ layui.use(['jquery', 'layer', 'upload'], function () {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
@ -1,7 +0,0 @@
|
|||||||
layui.use(['util'], function () {
|
|
||||||
|
|
||||||
var util = layui.util;
|
|
||||||
|
|
||||||
util.fixbar();
|
|
||||||
|
|
||||||
});
|
|
@ -112,16 +112,6 @@
|
|||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.breadcrumb .share {
|
|
||||||
position: absolute;
|
|
||||||
top: 2px;
|
|
||||||
right: -5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.breadcrumb .share a {
|
|
||||||
margin-right: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrap {
|
.wrap {
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
@ -154,6 +144,10 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.layer .pager {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.loading {
|
.loading {
|
||||||
padding: 30px;
|
padding: 30px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@ -204,6 +198,12 @@
|
|||||||
min-height: 80px;
|
min-height: 80px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.breadcrumb .share {
|
||||||
|
position: absolute;
|
||||||
|
top: 2px;
|
||||||
|
right: -5px;
|
||||||
|
}
|
||||||
|
|
||||||
#header {
|
#header {
|
||||||
left: 0;
|
left: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
@ -313,6 +313,10 @@
|
|||||||
line-height: 30px;
|
line-height: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cs-sidebar p {
|
||||||
|
line-height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
.index-wrap {
|
.index-wrap {
|
||||||
padding-bottom: 15px;
|
padding-bottom: 15px;
|
||||||
}
|
}
|
||||||
@ -954,7 +958,11 @@
|
|||||||
padding-top: 5px;
|
padding-top: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.course-meta .info .meta {
|
.course-meta .rating {
|
||||||
|
padding-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.course-meta p {
|
||||||
line-height: 35px;
|
line-height: 35px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -969,10 +977,6 @@
|
|||||||
right: 15px;
|
right: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.course-meta .info .item {
|
|
||||||
line-height: 35px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.course-meta .info .key {
|
.course-meta .info .key {
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
}
|
}
|
||||||
@ -986,32 +990,23 @@
|
|||||||
color: red;
|
color: red;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.course-meta .info .origin-price {
|
||||||
|
text-decoration: line-through;
|
||||||
|
}
|
||||||
|
|
||||||
.course-meta .info .free {
|
.course-meta .info .free {
|
||||||
color: green;
|
color: green;
|
||||||
}
|
}
|
||||||
|
|
||||||
.course-meta .ratings {
|
.course-meta .rating span {
|
||||||
padding-top: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.course-meta .ratings .item {
|
|
||||||
line-height: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.course-meta .ratings .name {
|
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.course-meta .ratings .layui-rate {
|
.course-meta .rating .layui-icon {
|
||||||
padding: 0;
|
color: orange;
|
||||||
margin-top: -8px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.course-meta .ratings .layui-icon {
|
.course-meta .rating .score {
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.course-meta .ratings .score {
|
|
||||||
color: #666;
|
color: #666;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1044,78 +1039,50 @@
|
|||||||
font-size: 30px;
|
font-size: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.lesson-list .allow {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lesson-list .deny {
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lesson-item {
|
.lesson-item {
|
||||||
display: flex;
|
position: relative;
|
||||||
justify-content: space-between;
|
|
||||||
line-height: 35px;
|
|
||||||
padding: 0 10px;
|
padding: 0 10px;
|
||||||
|
line-height: 35px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lesson-item a {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lesson-item .deny {
|
||||||
|
cursor: default;
|
||||||
|
color: gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lesson-item .title {
|
||||||
|
margin: 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lesson-item .icon-trial {
|
||||||
|
color: red;
|
||||||
|
font-size: 24px;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lesson-item .duration, .lesson-item .live {
|
||||||
|
top: 0;
|
||||||
|
right: 10px;
|
||||||
|
position: absolute;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lesson-item .live .active {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lesson-item .study-time {
|
||||||
|
color: green;
|
||||||
}
|
}
|
||||||
|
|
||||||
.lesson-item:hover {
|
.lesson-item:hover {
|
||||||
background-color: #f2f2f2;
|
background-color: #f2f2f2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.lesson-item .title {
|
|
||||||
margin-right: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lesson-item .model {
|
|
||||||
margin-right: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lesson-item .lock {
|
|
||||||
margin-right: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lesson-item .study-time {
|
|
||||||
margin-right: 5px;
|
|
||||||
color: green;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lesson-item .flag {
|
|
||||||
padding: 2px 3px;
|
|
||||||
margin-right: 5px;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lesson-item .flag-free {
|
|
||||||
border: 1px solid red;
|
|
||||||
color: red;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lesson-item .flag-playback {
|
|
||||||
border: 1px solid orange;
|
|
||||||
color: orange;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lesson-item .flag-scheduled {
|
|
||||||
border: 1px solid green;
|
|
||||||
color: green;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lesson-item .flag-active {
|
|
||||||
border: 1px solid red;
|
|
||||||
color: red;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lesson-item .flag-inactive {
|
|
||||||
border: 1px solid gray;
|
|
||||||
color: gray;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lesson-item .flag-ended {
|
|
||||||
border: 1px solid gray;
|
|
||||||
color: gray;
|
|
||||||
}
|
|
||||||
|
|
||||||
.package-item {
|
.package-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
@ -1206,13 +1173,15 @@
|
|||||||
white-space: normal;
|
white-space: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
.review-card .info,
|
.review-card,
|
||||||
.consult-card .info {
|
.consult-card,
|
||||||
|
.answer-card {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.review-card .rating,
|
.review-card .rating,
|
||||||
.consult-card .more {
|
.consult-card .more,
|
||||||
|
.answer-card .accepted {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
@ -1236,6 +1205,11 @@
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.review-card .more {
|
||||||
|
color: #666;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
.sidebar-card .layui-card-header {
|
.sidebar-card .layui-card-header {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
@ -1318,72 +1292,80 @@
|
|||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-course-card .meta .price {
|
|
||||||
color: red;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-course-card .meta .free {
|
|
||||||
color: green;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-chapter-list {
|
.sidebar-chapter-list {
|
||||||
height: 405px;
|
height: 405px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-lesson-list .active {
|
.sidebar-chapter-list .chapter-title {
|
||||||
color: red;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-lesson-list .allow {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-lesson-list .deny {
|
|
||||||
cursor: default;
|
|
||||||
color: gray;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar-chapter {
|
|
||||||
padding-top: 10px;
|
padding-top: 10px;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
font-weight: 600;
|
|
||||||
color: #333;
|
color: #333;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-lesson {
|
.sidebar-lesson-list {
|
||||||
padding: 0 10px;
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-lesson-list .lesson-title {
|
||||||
line-height: 30px;
|
line-height: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-lesson:hover {
|
.lesson-title .active {
|
||||||
background-color: #f2f2f2;
|
color: red;
|
||||||
}
|
}
|
||||||
|
|
||||||
.live-preview {
|
.lesson-title .deny {
|
||||||
|
color: gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
.share .layui-icon {
|
||||||
|
margin-right: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.share .active,
|
||||||
|
.share .layui-icon-star-fill {
|
||||||
|
color: orange;
|
||||||
|
}
|
||||||
|
|
||||||
|
.share a {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.share i {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.share em {
|
||||||
|
font-style: normal;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.preview {
|
||||||
color: #666;
|
color: #666;
|
||||||
margin-top: 30px;
|
margin-top: 30px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.live-preview .icon {
|
.preview .icon {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.live-preview .icon .layui-icon {
|
.preview .icon .layui-icon {
|
||||||
font-size: 150px;
|
font-size: 150px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.live-preview .tips {
|
.preview .tips {
|
||||||
color: #999;
|
font-size: 16px;
|
||||||
margin: 20px 0;
|
margin: 20px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.countdown .timer .label {
|
.countdown .timer {
|
||||||
font-size: 32px;
|
font-size: 32px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.countdown .timer .value {
|
.countdown .timer span {
|
||||||
color: green;
|
color: green;
|
||||||
font-size: 36px;
|
font-size: 36px;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
@ -1402,6 +1384,7 @@
|
|||||||
height: 428px;
|
height: 428px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.play-mask {
|
.play-mask {
|
||||||
top: 50%;
|
top: 50%;
|
||||||
left: 50%;
|
left: 50%;
|
||||||
@ -1435,33 +1418,37 @@
|
|||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat {
|
.chat-msg-list .chat, .chat-msg-list .chat-sys {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
line-height: 1.5em;
|
line-height: 25px;
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
font-size: 12px;
|
|
||||||
color: #999;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat-sys {
|
.chat-sys {
|
||||||
padding: 5px;
|
color: #999;
|
||||||
background-color: black;
|
|
||||||
color: white;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat span {
|
.chat-sys span, .chat span {
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat .icon .layui-icon {
|
.chat .user {
|
||||||
font-size: 14px;
|
color: orange;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat .icon-vip {
|
||||||
|
color: orange;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat .content {
|
||||||
|
color: #666;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat-msg-form .layui-input {
|
.chat-msg-form .layui-input {
|
||||||
height: 32px;
|
height: 32px;
|
||||||
line-height: 32px;
|
line-height: 32px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: #999;
|
color: #666;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vip-header {
|
.vip-header {
|
||||||
@ -1470,12 +1457,20 @@
|
|||||||
margin-bottom: 30px;
|
margin-bottom: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vip-priv-list {
|
.vip-reason-list {
|
||||||
padding: 30px;
|
padding: 30px;
|
||||||
margin-bottom: 30px;
|
margin-bottom: 30px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.vip-reason-list .reason-badge {
|
||||||
|
height: 30px;
|
||||||
|
line-height: 30px;
|
||||||
|
padding: 0 10px;
|
||||||
|
margin-right: 15px;
|
||||||
|
background-color: #1E9FFF;
|
||||||
|
}
|
||||||
|
|
||||||
.vip-option-list {
|
.vip-option-list {
|
||||||
margin-bottom: 30px;
|
margin-bottom: 30px;
|
||||||
}
|
}
|
||||||
@ -1804,6 +1799,10 @@
|
|||||||
background-color: #f2f2f2;
|
background-color: #f2f2f2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.user-tab {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.user-tab .layui-tab-title {
|
.user-tab .layui-tab-title {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@ -1844,7 +1843,7 @@
|
|||||||
.user-card {
|
.user-card {
|
||||||
float: left;
|
float: left;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 200px;
|
height: 240px;
|
||||||
position: relative;
|
position: relative;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
@ -1877,6 +1876,32 @@
|
|||||||
color: #666;
|
color: #666;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.user-card .meta {
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-card .meta span {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-card .type {
|
||||||
|
position: absolute;
|
||||||
|
top: 18px;
|
||||||
|
right: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-list {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.teacher-list .user-card {
|
||||||
|
height: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vip-user-list .user-card {
|
||||||
|
height: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
.tag-card {
|
.tag-card {
|
||||||
float: left;
|
float: left;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@ -1922,17 +1947,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.my-profile-card {
|
.my-profile-card {
|
||||||
position: relative;
|
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.my-profile-card .vip {
|
|
||||||
position: absolute;
|
|
||||||
right: 15px;
|
|
||||||
top: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.my-profile-card .avatar {
|
.my-profile-card .avatar {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
@ -67,19 +67,19 @@ layui.use(['jquery', 'form', 'helper'], function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function showNewMessage(res) {
|
function showNewMessage(res) {
|
||||||
var html = '';
|
var html = '<div class="chat">';
|
||||||
if (res.user.vip === 1) {
|
if (res.user.vip === 1) {
|
||||||
html = getVipUserMessage(res);
|
html += '<span class="layui-icon layui-icon-diamond icon-vip"></span>';
|
||||||
} else {
|
|
||||||
html = getNormalUserMessage(res);
|
|
||||||
}
|
}
|
||||||
|
html += '<span class="user">' + res.user.name + ':</span>';
|
||||||
|
html += '<span class="content">' + res.content + '</span>';
|
||||||
|
html += '</div>';
|
||||||
$chatMsgList.append(html);
|
$chatMsgList.append(html);
|
||||||
scrollToBottom();
|
scrollToBottom();
|
||||||
}
|
}
|
||||||
|
|
||||||
function showLoginMessage(res) {
|
function showLoginMessage(res) {
|
||||||
var html = '<div class="chat chat-sys">';
|
var html = '<div class="chat chat-sys">';
|
||||||
html += '<span class="icon"><i class="layui-icon layui-icon-speaker"></i></span>';
|
|
||||||
html += '<span>' + res.user.name + '</span>';
|
html += '<span>' + res.user.name + '</span>';
|
||||||
html += '<span>进入了直播间</span>';
|
html += '<span>进入了直播间</span>';
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
@ -87,27 +87,11 @@ layui.use(['jquery', 'form', 'helper'], function () {
|
|||||||
scrollToBottom();
|
scrollToBottom();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getVipUserMessage(res) {
|
|
||||||
var html = '<div class="chat chat-vip">';
|
|
||||||
html += '<span class="icon"><i class="layui-icon layui-icon-diamond"></i></span>';
|
|
||||||
html += '<span class="user layui-badge layui-bg-orange">' + res.user.name + '</span>';
|
|
||||||
html += '<span class="content">' + res.content + '</span>';
|
|
||||||
html += '</div>';
|
|
||||||
return html;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getNormalUserMessage(res) {
|
|
||||||
var html = '<div class="chat chat-normal">';
|
|
||||||
html += '<span class="icon"><i class="layui-icon layui-icon-username"></i></span>';
|
|
||||||
html += '<span class="user layui-badge layui-bg-blue">' + res.user.name + '</span>';
|
|
||||||
html += '<span class="content">' + res.content + '</span>';
|
|
||||||
html += '</div>';
|
|
||||||
return html;
|
|
||||||
}
|
|
||||||
|
|
||||||
function scrollToBottom() {
|
function scrollToBottom() {
|
||||||
var $scrollTo = $chatMsgList.find('.chat:last');
|
var $scrollTo = $chatMsgList.find('.chat:last');
|
||||||
$chatMsgList.scrollTop($scrollTo.offset().top - $chatMsgList.offset().top + $chatMsgList.scrollTop());
|
$chatMsgList.scrollTop(
|
||||||
|
$scrollTo.offset().top - $chatMsgList.offset().top + $chatMsgList.scrollTop()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function refreshLiveStats() {
|
function refreshLiveStats() {
|
||||||
@ -121,4 +105,4 @@ layui.use(['jquery', 'form', 'helper'], function () {
|
|||||||
helper.ajaxLoadHtml($chatMsgList.data('url'), $chatMsgList.attr('id'));
|
helper.ajaxLoadHtml($chatMsgList.data('url'), $chatMsgList.attr('id'));
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
@ -7,7 +7,7 @@ layui.use(['jquery', 'util'], function () {
|
|||||||
var serverTime = $('input[name="countdown.server_time"]').val();
|
var serverTime = $('input[name="countdown.server_time"]').val();
|
||||||
var liveStatusUrl = $('input[name="live.status_url"]').val();
|
var liveStatusUrl = $('input[name="live.status_url"]').val();
|
||||||
|
|
||||||
util.countdown(1000 * parseInt(endTime), 1000 * parseInt(serverTime), function (date) {
|
util.countdown(1000 * parseInt(endTime), 1000 * parseInt(serverTime), function (date, serverTime, timer) {
|
||||||
var items = [
|
var items = [
|
||||||
{date: date[0], label: '天'},
|
{date: date[0], label: '天'},
|
||||||
{date: date[1], label: '时'},
|
{date: date[1], label: '时'},
|
||||||
@ -16,10 +16,7 @@ layui.use(['jquery', 'util'], function () {
|
|||||||
];
|
];
|
||||||
var html = '';
|
var html = '';
|
||||||
layui.each(items, function (index, item) {
|
layui.each(items, function (index, item) {
|
||||||
if (item.date > 0) {
|
html += '<span>' + item.date + '</span>' + item.label;
|
||||||
html += '<span class="value">' + item.date + '</span>';
|
|
||||||
html += '<span class="label">' + item.label + '</span>';
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
$('.countdown > .timer').html(html);
|
$('.countdown > .timer').html(html);
|
||||||
});
|
});
|
||||||
@ -32,4 +29,4 @@ layui.use(['jquery', 'util'], function () {
|
|||||||
});
|
});
|
||||||
}, 30000);
|
}, 30000);
|
||||||
|
|
||||||
});
|
});
|
@ -3,6 +3,12 @@ layui.use(['jquery', 'helper'], function () {
|
|||||||
var $ = layui.jquery;
|
var $ = layui.jquery;
|
||||||
var helper = layui.helper;
|
var helper = layui.helper;
|
||||||
|
|
||||||
|
var $commentList = $('#comment-list');
|
||||||
|
|
||||||
|
if ($commentList.length > 0) {
|
||||||
|
helper.ajaxLoadHtml($commentList.data('url'), $commentList.attr('id'));
|
||||||
|
}
|
||||||
|
|
||||||
$('.icon-praise').on('click', function () {
|
$('.icon-praise').on('click', function () {
|
||||||
var $this = $(this);
|
var $this = $(this);
|
||||||
var $parent = $this.parent();
|
var $parent = $this.parent();
|
||||||
@ -28,24 +34,8 @@ layui.use(['jquery', 'helper'], function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
$('.sidebar-lesson').on('click', function () {
|
|
||||||
if ($(this).hasClass('deny')) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
var url = $(this).data('url');
|
|
||||||
helper.checkLogin(function () {
|
|
||||||
window.location.href = url;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
$('.icon-reply').on('click', function () {
|
$('.icon-reply').on('click', function () {
|
||||||
$('html').scrollTop($('#comment-anchor').offset().top);
|
$('html').scrollTop($('#comment-anchor').offset().top);
|
||||||
});
|
});
|
||||||
|
|
||||||
var $commentList = $('#comment-list');
|
});
|
||||||
|
|
||||||
if ($commentList.length > 0) {
|
|
||||||
helper.ajaxLoadHtml($commentList.data('url'), $commentList.attr('id'));
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
@ -1,31 +1,9 @@
|
|||||||
layui.use(['jquery', 'layer', 'rate', 'helper'], function () {
|
layui.use(['jquery', 'layer', 'helper'], function () {
|
||||||
|
|
||||||
var $ = layui.jquery;
|
var $ = layui.jquery;
|
||||||
var layer = layui.layer;
|
var layer = layui.layer;
|
||||||
var rate = layui.rate;
|
|
||||||
var helper = layui.helper;
|
var helper = layui.helper;
|
||||||
|
|
||||||
rate.render({
|
|
||||||
elem: '#rating1',
|
|
||||||
value: $('#rating1').data('value'),
|
|
||||||
readonly: true,
|
|
||||||
half: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
rate.render({
|
|
||||||
elem: '#rating2',
|
|
||||||
value: $('#rating2').data('value'),
|
|
||||||
readonly: true,
|
|
||||||
half: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
rate.render({
|
|
||||||
elem: '#rating3',
|
|
||||||
value: $('#rating3').data('value'),
|
|
||||||
readonly: true,
|
|
||||||
half: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 收藏
|
* 收藏
|
||||||
*/
|
*/
|
||||||
@ -72,12 +50,9 @@ layui.use(['jquery', 'layer', 'rate', 'helper'], function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 浏览章节
|
* 购买(课程|套餐)
|
||||||
*/
|
*/
|
||||||
$('.lesson-item').on('click', function () {
|
$('body').on('click', '.btn-buy', function () {
|
||||||
if ($(this).hasClass('deny')) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
var url = $(this).data('url');
|
var url = $(this).data('url');
|
||||||
helper.checkLogin(function () {
|
helper.checkLogin(function () {
|
||||||
window.location.href = url;
|
window.location.href = url;
|
||||||
@ -85,9 +60,12 @@ layui.use(['jquery', 'layer', 'rate', 'helper'], function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 购买(课程|套餐)
|
* 浏览章节
|
||||||
*/
|
*/
|
||||||
$('body').on('click', '.btn-buy', function () {
|
$('body').on('click', '.view-lesson', function () {
|
||||||
|
if ($(this).hasClass('deny')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
var url = $(this).data('url');
|
var url = $(this).data('url');
|
||||||
helper.checkLogin(function () {
|
helper.checkLogin(function () {
|
||||||
window.location.href = url;
|
window.location.href = url;
|
||||||
@ -162,4 +140,4 @@ layui.use(['jquery', 'layer', 'rate', 'helper'], function () {
|
|||||||
helper.ajaxLoadHtml($sdRelated.data('url'), $sdRelated.attr('id'));
|
helper.ajaxLoadHtml($sdRelated.data('url'), $sdRelated.attr('id'));
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
@ -1,4 +1,4 @@
|
|||||||
layui.use(['jquery', 'util'], function () {
|
layui.use(['jquery', 'helper', 'util'], function () {
|
||||||
|
|
||||||
var $ = layui.jquery;
|
var $ = layui.jquery;
|
||||||
var util = layui.util;
|
var util = layui.util;
|
||||||
@ -47,19 +47,6 @@ layui.use(['jquery', 'util'], function () {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
var showPhoneCode = function () {
|
|
||||||
var content = '<div class="layui-font-32 layui-font-red layui-padding-5">';
|
|
||||||
content += '<i class="iconfont icon-phone layui-padding-1 layui-font-28"></i>' + window.contact.phone;
|
|
||||||
content += '</div>';
|
|
||||||
layer.open({
|
|
||||||
type: 1,
|
|
||||||
title: false,
|
|
||||||
closeBtn: 0,
|
|
||||||
shadeClose: true,
|
|
||||||
content: content,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
var bars = [];
|
var bars = [];
|
||||||
|
|
||||||
if (window.contact.wechat) {
|
if (window.contact.wechat) {
|
||||||
@ -76,13 +63,6 @@ layui.use(['jquery', 'util'], function () {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (window.contact.phone) {
|
|
||||||
bars.push({
|
|
||||||
type: 'phone',
|
|
||||||
content: '<i class="iconfont icon-phone layui-font-30"></i>',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
util.fixbar({
|
util.fixbar({
|
||||||
bars: bars,
|
bars: bars,
|
||||||
click: function (type) {
|
click: function (type) {
|
||||||
@ -90,30 +70,24 @@ layui.use(['jquery', 'util'], function () {
|
|||||||
showWechatCode();
|
showWechatCode();
|
||||||
} else if (type === 'qq') {
|
} else if (type === 'qq') {
|
||||||
showQQCode();
|
showQQCode();
|
||||||
} else if (type === 'phone') {
|
|
||||||
showPhoneCode();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$('.contact > .wechat').on('click', function () {
|
$('.icon-wechat').on('click', function () {
|
||||||
showWechatCode();
|
showWechatCode();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('.contact > .qq').on('click', function () {
|
$('.icon-qq').on('click', function () {
|
||||||
showQQCode();
|
showQQCode();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('.contact > .toutiao').on('click', function () {
|
$('.icon-toutiao').on('click', function () {
|
||||||
showTouTiaoCode();
|
showTouTiaoCode();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('.contact > .douyin').on('click', function () {
|
$('.icon-douyin').on('click', function () {
|
||||||
showDouYinCode();
|
showDouYinCode();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('.contact > .phone').on('click', function () {
|
});
|
||||||
showPhoneCode();
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
@ -1,12 +0,0 @@
|
|||||||
layui.use(['jquery', 'helper'], function () {
|
|
||||||
|
|
||||||
var $ = layui.jquery;
|
|
||||||
var helper = layui.helper;
|
|
||||||
|
|
||||||
var $courseList = $('#course-list');
|
|
||||||
|
|
||||||
if ($courseList.length > 0) {
|
|
||||||
helper.ajaxLoadHtml($courseList.data('url'), $courseList.attr('id'));
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
@ -1,12 +0,0 @@
|
|||||||
layui.use(['jquery', 'helper'], function () {
|
|
||||||
|
|
||||||
var $ = layui.jquery;
|
|
||||||
var helper = layui.helper;
|
|
||||||
|
|
||||||
var $courseList = $('#course-list');
|
|
||||||
|
|
||||||
if ($courseList.length > 0) {
|
|
||||||
helper.ajaxLoadHtml($courseList.data('url'), $courseList.attr('id'));
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
@ -1,27 +0,0 @@
|
|||||||
layui.use(['jquery', 'layer'], function () {
|
|
||||||
|
|
||||||
var $ = layui.jquery;
|
|
||||||
var layer = layui.layer;
|
|
||||||
var index = parent.layer.getFrameIndex(window.name);
|
|
||||||
|
|
||||||
parent.layer.iframeAuto(index);
|
|
||||||
|
|
||||||
$('.btn-refund-cancel').on('click', function () {
|
|
||||||
var url = $(this).data('url');
|
|
||||||
var data = {sn: $(this).data('sn')};
|
|
||||||
layer.confirm('确定要取消退款吗?', function () {
|
|
||||||
$.ajax({
|
|
||||||
type: 'POST',
|
|
||||||
url: url,
|
|
||||||
data: data,
|
|
||||||
success: function () {
|
|
||||||
layer.msg('取消退款成功', {icon: 1});
|
|
||||||
setTimeout(function () {
|
|
||||||
parent.window.location.href = '/uc/refunds';
|
|
||||||
}, 1500);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
@ -12,7 +12,7 @@ layui.use(['jquery', 'layer'], function () {
|
|||||||
type: 2,
|
type: 2,
|
||||||
title: '咨询详情',
|
title: '咨询详情',
|
||||||
content: [url, 'no'],
|
content: [url, 'no'],
|
||||||
area: ['720px', '320px'],
|
area: ['720px', '320px']
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -26,6 +26,9 @@ layui.use(['jquery', 'layer'], function () {
|
|||||||
title: '回复咨询',
|
title: '回复咨询',
|
||||||
content: [url, 'no'],
|
content: [url, 'no'],
|
||||||
area: ['720px', '300px'],
|
area: ['720px', '300px'],
|
||||||
|
cancel: function () {
|
||||||
|
parent.location.reload();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -38,8 +41,8 @@ layui.use(['jquery', 'layer'], function () {
|
|||||||
type: 2,
|
type: 2,
|
||||||
title: '直播推流',
|
title: '直播推流',
|
||||||
content: [url, 'no'],
|
content: [url, 'no'],
|
||||||
area: ['640px', '420px'],
|
area: ['640px', '420px']
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
44
public/static/home/js/user.avatar.upload.js
Normal file
44
public/static/home/js/user.avatar.upload.js
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
layui.use(['jquery', 'layer', 'upload'], function () {
|
||||||
|
|
||||||
|
var $ = layui.jquery;
|
||||||
|
var layer = layui.layer;
|
||||||
|
var upload = layui.upload;
|
||||||
|
|
||||||
|
upload.render({
|
||||||
|
elem: '#change-avatar',
|
||||||
|
url: '/upload/avatar/img',
|
||||||
|
accept: 'images',
|
||||||
|
acceptMime: 'image/*',
|
||||||
|
size: 512,
|
||||||
|
auto: false,
|
||||||
|
before: function () {
|
||||||
|
layer.load();
|
||||||
|
},
|
||||||
|
choose: function (obj) {
|
||||||
|
var flag = true;
|
||||||
|
obj.preview(function (index, file, result) {
|
||||||
|
var img = new Image();
|
||||||
|
img.src = result;
|
||||||
|
img.onload = function () {
|
||||||
|
if (img.width < 1000 && img.height < 1000) {
|
||||||
|
obj.upload(index, file);
|
||||||
|
} else {
|
||||||
|
flag = false;
|
||||||
|
layer.msg("图片尺寸必须小于 1000 * 1000");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return flag;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
done: function (res, index, upload) {
|
||||||
|
$('#img-avatar').attr('src', res.data.url);
|
||||||
|
$('input[name=avatar]').val(res.data.url);
|
||||||
|
layer.closeAll('loading');
|
||||||
|
},
|
||||||
|
error: function (index, upload) {
|
||||||
|
layer.msg('上传文件失败', {icon: 2});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
@ -12,7 +12,7 @@ layui.use(['jquery', 'layer'], function () {
|
|||||||
type: 2,
|
type: 2,
|
||||||
title: '咨询详情',
|
title: '咨询详情',
|
||||||
content: [url, 'no'],
|
content: [url, 'no'],
|
||||||
area: ['720px', '320px'],
|
area: ['720px', '320px']
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -26,6 +26,9 @@ layui.use(['jquery', 'layer'], function () {
|
|||||||
title: '编辑咨询',
|
title: '编辑咨询',
|
||||||
content: [url, 'no'],
|
content: [url, 'no'],
|
||||||
area: ['720px', '420px'],
|
area: ['720px', '420px'],
|
||||||
|
cancel: function () {
|
||||||
|
parent.location.reload();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -39,6 +42,9 @@ layui.use(['jquery', 'layer'], function () {
|
|||||||
title: '发布评价',
|
title: '发布评价',
|
||||||
content: [url, 'no'],
|
content: [url, 'no'],
|
||||||
area: ['640px', '480px'],
|
area: ['640px', '480px'],
|
||||||
|
cancel: function () {
|
||||||
|
parent.location.reload();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -52,6 +58,9 @@ layui.use(['jquery', 'layer'], function () {
|
|||||||
title: '修改评价',
|
title: '修改评价',
|
||||||
content: [url, 'no'],
|
content: [url, 'no'],
|
||||||
area: ['640px', '480px'],
|
area: ['640px', '480px'],
|
||||||
|
cancel: function () {
|
||||||
|
parent.location.reload();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -65,7 +74,7 @@ layui.use(['jquery', 'layer'], function () {
|
|||||||
title: '订单详情',
|
title: '订单详情',
|
||||||
content: [url, 'no'],
|
content: [url, 'no'],
|
||||||
area: '800px',
|
area: '800px',
|
||||||
offset: '200px',
|
offset: '200px'
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -79,7 +88,7 @@ layui.use(['jquery', 'layer'], function () {
|
|||||||
title: '退款详情',
|
title: '退款详情',
|
||||||
content: [url, 'no'],
|
content: [url, 'no'],
|
||||||
area: '800px',
|
area: '800px',
|
||||||
offset: '200px',
|
offset: '200px'
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,47 +1,7 @@
|
|||||||
layui.use(['jquery', 'upload', 'layer', 'layarea'], function () {
|
layui.use(['layarea'], function () {
|
||||||
|
|
||||||
var $ = layui.jquery;
|
|
||||||
var layer = layui.layer;
|
|
||||||
var upload = layui.upload;
|
|
||||||
var layarea = layui.layarea;
|
var layarea = layui.layarea;
|
||||||
|
|
||||||
upload.render({
|
|
||||||
elem: '#change-avatar',
|
|
||||||
url: '/upload/avatar/img',
|
|
||||||
accept: 'images',
|
|
||||||
acceptMime: 'image/*',
|
|
||||||
size: 512,
|
|
||||||
auto: false,
|
|
||||||
before: function () {
|
|
||||||
layer.load();
|
|
||||||
},
|
|
||||||
choose: function (obj) {
|
|
||||||
var flag = true;
|
|
||||||
obj.preview(function (index, file, result) {
|
|
||||||
var img = new Image();
|
|
||||||
img.src = result;
|
|
||||||
img.onload = function () {
|
|
||||||
if (img.width < 1000 && img.height < 1000) {
|
|
||||||
obj.upload(index, file);
|
|
||||||
} else {
|
|
||||||
flag = false;
|
|
||||||
layer.msg("图片尺寸必须小于 1000 * 1000");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return flag;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
done: function (res) {
|
|
||||||
$('#img-avatar').attr('src', res.data.url);
|
|
||||||
$('input[name=avatar]').val(res.data.url);
|
|
||||||
layer.closeAll('loading');
|
|
||||||
},
|
|
||||||
error: function () {
|
|
||||||
layer.msg('上传文件失败', {icon: 2});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
layarea.render({
|
layarea.render({
|
||||||
elem: '#area-picker',
|
elem: '#area-picker',
|
||||||
change: function (res) {
|
change: function (res) {
|
||||||
@ -49,4 +9,4 @@ layui.use(['jquery', 'upload', 'layer', 'layarea'], function () {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
@ -7,6 +7,10 @@ layui.use(['jquery', 'rate'], function () {
|
|||||||
var $rating2 = $('input[name=rating2]');
|
var $rating2 = $('input[name=rating2]');
|
||||||
var $rating3 = $('input[name=rating3]');
|
var $rating3 = $('input[name=rating3]');
|
||||||
|
|
||||||
|
$('.btn-cancel').on('click', function () {
|
||||||
|
parent.layer.closeAll();
|
||||||
|
});
|
||||||
|
|
||||||
rate.render({
|
rate.render({
|
||||||
elem: '#rating1',
|
elem: '#rating1',
|
||||||
value: $rating1.val(),
|
value: $rating1.val(),
|
||||||
@ -31,4 +35,4 @@ layui.use(['jquery', 'rate'], function () {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user