mirror of
https://gitee.com/koogua/course-tencent-cloud.git
synced 2025-06-25 04:07:17 +08:00
Merge branch 'koogua/v1.6.7'
This commit is contained in:
commit
8e40019939
10
CHANGELOG.md
10
CHANGELOG.md
@ -1,3 +1,13 @@
|
|||||||
|
### [v1.6.7](https://gitee.com/koogua/course-tencent-cloud/releases/v1.6.7)(2023-12-15)
|
||||||
|
|
||||||
|
- 增加文章分类功能
|
||||||
|
- 增加问题分类功能
|
||||||
|
- 增加审核等批量功能
|
||||||
|
- 增加若干业务插件埋点
|
||||||
|
- 精简重构大量业务逻辑
|
||||||
|
- 移除秒杀营销功能
|
||||||
|
- 已发现的问题修复
|
||||||
|
|
||||||
### [v1.6.6](https://gitee.com/koogua/course-tencent-cloud/releases/v1.6.6)(2023-08-30)
|
### [v1.6.6](https://gitee.com/koogua/course-tencent-cloud/releases/v1.6.6)(2023-08-30)
|
||||||
|
|
||||||
- 还原意外删除的AnswerList.php文件
|
- 还原意外删除的AnswerList.php文件
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
namespace App\Builders;
|
namespace App\Builders;
|
||||||
|
|
||||||
use App\Caches\CategoryList as CategoryListCache;
|
use App\Caches\CategoryAllList as CategoryAllListCache;
|
||||||
use App\Models\Category as CategoryModel;
|
use App\Models\Category as CategoryModel;
|
||||||
use App\Repos\User as UserRepo;
|
use App\Repos\User as UserRepo;
|
||||||
|
|
||||||
@ -47,7 +47,7 @@ class ArticleList extends Builder
|
|||||||
|
|
||||||
public function getCategories()
|
public function getCategories()
|
||||||
{
|
{
|
||||||
$cache = new CategoryListCache();
|
$cache = new CategoryAllListCache();
|
||||||
|
|
||||||
$items = $cache->get(CategoryModel::TYPE_ARTICLE);
|
$items = $cache->get(CategoryModel::TYPE_ARTICLE);
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
namespace App\Builders;
|
namespace App\Builders;
|
||||||
|
|
||||||
use App\Caches\CategoryList as CategoryListCache;
|
use App\Caches\CategoryAllList as CategoryAllListCache;
|
||||||
use App\Models\Category as CategoryModel;
|
use App\Models\Category as CategoryModel;
|
||||||
use App\Repos\User as UserRepo;
|
use App\Repos\User as UserRepo;
|
||||||
|
|
||||||
@ -38,7 +38,7 @@ class CourseList extends Builder
|
|||||||
|
|
||||||
public function getCategories()
|
public function getCategories()
|
||||||
{
|
{
|
||||||
$cache = new CategoryListCache();
|
$cache = new CategoryAllListCache();
|
||||||
|
|
||||||
$items = $cache->get(CategoryModel::TYPE_COURSE);
|
$items = $cache->get(CategoryModel::TYPE_COURSE);
|
||||||
|
|
||||||
|
@ -1,104 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* @copyright Copyright (c) 2021 深圳市酷瓜软件有限公司
|
|
||||||
* @license https://opensource.org/licenses/GPL-2.0
|
|
||||||
* @link https://www.koogua.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace App\Builders;
|
|
||||||
|
|
||||||
use App\Repos\Chapter as ChapterRepo;
|
|
||||||
use App\Repos\Course as CourseRepo;
|
|
||||||
use App\Repos\User as UserRepo;
|
|
||||||
|
|
||||||
class DanmuList extends Builder
|
|
||||||
{
|
|
||||||
|
|
||||||
public function handleCourses(array $danmus)
|
|
||||||
{
|
|
||||||
$courses = $this->getCourses($danmus);
|
|
||||||
|
|
||||||
foreach ($danmus as $key => $danmu) {
|
|
||||||
$danmus[$key]['course'] = $courses[$danmu['course_id']] ?? new \stdClass();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $danmus;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function handleChapters(array $danmus)
|
|
||||||
{
|
|
||||||
$chapters = $this->getChapters($danmus);
|
|
||||||
|
|
||||||
foreach ($danmus as $key => $danmu) {
|
|
||||||
$danmus[$key]['chapter'] = $chapters[$danmu['chapter_id']] ?? new \stdClass();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $danmus;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function handleUsers(array $danmus)
|
|
||||||
{
|
|
||||||
$users = $this->getUsers($danmus);
|
|
||||||
|
|
||||||
foreach ($danmus as $key => $danmu) {
|
|
||||||
$danmus[$key]['owner'] = $users[$danmu['owner_id']] ?? new \stdClass();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $danmus;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getCourses(array $danmus)
|
|
||||||
{
|
|
||||||
$ids = kg_array_column($danmus, 'course_id');
|
|
||||||
|
|
||||||
$courseRepo = new CourseRepo();
|
|
||||||
|
|
||||||
$courses = $courseRepo->findByIds($ids, ['id', 'title']);
|
|
||||||
|
|
||||||
$result = [];
|
|
||||||
|
|
||||||
foreach ($courses->toArray() as $course) {
|
|
||||||
$result[$course['id']] = $course;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getChapters(array $danmus)
|
|
||||||
{
|
|
||||||
$ids = kg_array_column($danmus, 'chapter_id');
|
|
||||||
|
|
||||||
$chapterRepo = new ChapterRepo();
|
|
||||||
|
|
||||||
$chapters = $chapterRepo->findByIds($ids, ['id', 'title']);
|
|
||||||
|
|
||||||
$result = [];
|
|
||||||
|
|
||||||
foreach ($chapters->toArray() as $chapter) {
|
|
||||||
$result[$chapter['id']] = $chapter;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getUsers(array $danmus)
|
|
||||||
{
|
|
||||||
$ids = kg_array_column($danmus, 'owner_id');
|
|
||||||
|
|
||||||
$userRepo = new UserRepo();
|
|
||||||
|
|
||||||
$users = $userRepo->findShallowUserByIds($ids);
|
|
||||||
|
|
||||||
$baseUrl = kg_cos_url();
|
|
||||||
|
|
||||||
$result = [];
|
|
||||||
|
|
||||||
foreach ($users->toArray() as $user) {
|
|
||||||
$user['avatar'] = $baseUrl . $user['avatar'];
|
|
||||||
$result[$user['id']] = $user;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
namespace App\Builders;
|
namespace App\Builders;
|
||||||
|
|
||||||
use App\Caches\CategoryList as CategoryListCache;
|
use App\Caches\CategoryAllList as CategoryAllListCache;
|
||||||
use App\Models\Category as CategoryModel;
|
use App\Models\Category as CategoryModel;
|
||||||
|
|
||||||
class HelpList extends Builder
|
class HelpList extends Builder
|
||||||
@ -26,7 +26,7 @@ class HelpList extends Builder
|
|||||||
|
|
||||||
public function getCategories()
|
public function getCategories()
|
||||||
{
|
{
|
||||||
$cache = new CategoryListCache();
|
$cache = new CategoryAllListCache();
|
||||||
|
|
||||||
$items = $cache->get(CategoryModel::TYPE_HELP);
|
$items = $cache->get(CategoryModel::TYPE_HELP);
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
namespace App\Builders;
|
namespace App\Builders;
|
||||||
|
|
||||||
use App\Caches\CategoryList as CategoryListCache;
|
use App\Caches\CategoryAllList as CategoryAllListCache;
|
||||||
use App\Models\Category as CategoryModel;
|
use App\Models\Category as CategoryModel;
|
||||||
use App\Repos\User as UserRepo;
|
use App\Repos\User as UserRepo;
|
||||||
|
|
||||||
@ -27,8 +27,8 @@ class QuestionList extends Builder
|
|||||||
{
|
{
|
||||||
$categories = $this->getCategories();
|
$categories = $this->getCategories();
|
||||||
|
|
||||||
foreach ($questions as $key => $article) {
|
foreach ($questions as $key => $question) {
|
||||||
$questions[$key]['category'] = $categories[$article['category_id']] ?? new \stdClass();
|
$questions[$key]['category'] = $categories[$question['category_id']] ?? new \stdClass();
|
||||||
}
|
}
|
||||||
|
|
||||||
return $questions;
|
return $questions;
|
||||||
@ -48,7 +48,7 @@ class QuestionList extends Builder
|
|||||||
|
|
||||||
public function getCategories()
|
public function getCategories()
|
||||||
{
|
{
|
||||||
$cache = new CategoryListCache();
|
$cache = new CategoryAllListCache();
|
||||||
|
|
||||||
$items = $cache->get(CategoryModel::TYPE_QUESTION);
|
$items = $cache->get(CategoryModel::TYPE_QUESTION);
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
namespace App\Builders;
|
namespace App\Builders;
|
||||||
|
|
||||||
use App\Models\User as UserModel;
|
use App\Models\User as UserModel;
|
||||||
|
use App\Repos\Account as AccountRepo;
|
||||||
use App\Repos\Role as RoleRepo;
|
use App\Repos\Role as RoleRepo;
|
||||||
|
|
||||||
class UserList extends Builder
|
class UserList extends Builder
|
||||||
@ -24,6 +25,17 @@ class UserList extends Builder
|
|||||||
return $users;
|
return $users;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function handleAccounts(array $users)
|
||||||
|
{
|
||||||
|
$accounts = $this->getAccounts($users);
|
||||||
|
|
||||||
|
foreach ($users as $key => $user) {
|
||||||
|
$users[$key]['account'] = $accounts[$user['id']] ?? new \stdClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $users;
|
||||||
|
}
|
||||||
|
|
||||||
public function handleAdminRoles(array $users)
|
public function handleAdminRoles(array $users)
|
||||||
{
|
{
|
||||||
$roles = $this->getAdminRoles($users);
|
$roles = $this->getAdminRoles($users);
|
||||||
@ -46,6 +58,26 @@ class UserList extends Builder
|
|||||||
return $users;
|
return $users;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function getAccounts(array $users)
|
||||||
|
{
|
||||||
|
$ids = kg_array_column($users, 'id');
|
||||||
|
|
||||||
|
$accountRepo = new AccountRepo();
|
||||||
|
|
||||||
|
$accounts = $accountRepo->findByIds($ids);
|
||||||
|
|
||||||
|
$result = [];
|
||||||
|
|
||||||
|
foreach ($accounts as $account) {
|
||||||
|
$result[$account->id] = [
|
||||||
|
'phone' => $account->phone,
|
||||||
|
'email' => $account->email,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
protected function getAdminRoles(array $users)
|
protected function getAdminRoles(array $users)
|
||||||
{
|
{
|
||||||
$ids = kg_array_column($users, 'admin_role');
|
$ids = kg_array_column($users, 'admin_role');
|
||||||
|
@ -27,10 +27,10 @@ class AppInfo extends Cache
|
|||||||
$appInfo = new \App\Library\AppInfo();
|
$appInfo = new \App\Library\AppInfo();
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'name' => $appInfo->name,
|
'name' => $appInfo->get('name'),
|
||||||
'alias' => $appInfo->alias,
|
'alias' => $appInfo->get('alias'),
|
||||||
'link' => $appInfo->link,
|
'link' => $appInfo->get('link'),
|
||||||
'version' => $appInfo->version,
|
'version' => $appInfo->get('version'),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
46
app/Caches/CategoryAllList.php
Normal file
46
app/Caches/CategoryAllList.php
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @copyright Copyright (c) 2021 深圳市酷瓜软件有限公司
|
||||||
|
* @license https://opensource.org/licenses/GPL-2.0
|
||||||
|
* @link https://www.koogua.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Caches;
|
||||||
|
|
||||||
|
use App\Models\Category as CategoryModel;
|
||||||
|
use Phalcon\Mvc\Model\Resultset;
|
||||||
|
|
||||||
|
class CategoryAllList extends Cache
|
||||||
|
{
|
||||||
|
|
||||||
|
protected $lifetime = 365 * 86400;
|
||||||
|
|
||||||
|
public function getLifetime()
|
||||||
|
{
|
||||||
|
return $this->lifetime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getKey($id = null)
|
||||||
|
{
|
||||||
|
return "category_all_list:{$id}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getContent($id = null)
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var Resultset $categories
|
||||||
|
*/
|
||||||
|
$categories = CategoryModel::query()
|
||||||
|
->columns(['id', 'parent_id', 'name', 'priority', 'level', 'path'])
|
||||||
|
->where('type = :type:', ['type' => $id])
|
||||||
|
->orderBy('level ASC, priority ASC')
|
||||||
|
->execute();
|
||||||
|
|
||||||
|
if ($categories->count() == 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $categories->toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -25,10 +25,6 @@ class CategoryList extends Cache
|
|||||||
return "category_list:{$id}";
|
return "category_list:{$id}";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @param null $id
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getContent($id = null)
|
public function getContent($id = null)
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
@ -1,59 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* @copyright Copyright (c) 2021 深圳市酷瓜软件有限公司
|
|
||||||
* @license https://opensource.org/licenses/GPL-2.0
|
|
||||||
* @link https://www.koogua.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace App\Caches;
|
|
||||||
|
|
||||||
use App\Models\Category as CategoryModel;
|
|
||||||
use App\Repos\Course as CourseRepo;
|
|
||||||
|
|
||||||
class CourseCategoryList extends Cache
|
|
||||||
{
|
|
||||||
|
|
||||||
protected $lifetime = 86400;
|
|
||||||
|
|
||||||
public function getLifetime()
|
|
||||||
{
|
|
||||||
return $this->lifetime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getKey($id = null)
|
|
||||||
{
|
|
||||||
return "course_category_list:{$id}";
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getContent($id = null)
|
|
||||||
{
|
|
||||||
$courseRepo = new CourseRepo();
|
|
||||||
|
|
||||||
$categories = $courseRepo->findCategories($id);
|
|
||||||
|
|
||||||
if ($categories->count() == 0) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->handleContent($categories);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param CategoryModel[] $categories
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function handleContent($categories)
|
|
||||||
{
|
|
||||||
$result = [];
|
|
||||||
|
|
||||||
foreach ($categories as $category) {
|
|
||||||
$result[] = [
|
|
||||||
'id' => $category->id,
|
|
||||||
'name' => $category->name,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,90 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* @copyright Copyright (c) 2021 深圳市酷瓜软件有限公司
|
|
||||||
* @license https://opensource.org/licenses/GPL-2.0
|
|
||||||
* @link https://www.koogua.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace App\Caches;
|
|
||||||
|
|
||||||
use App\Models\Course as CourseModel;
|
|
||||||
use Phalcon\Mvc\Model\Resultset;
|
|
||||||
use Phalcon\Mvc\Model\ResultsetInterface;
|
|
||||||
|
|
||||||
class CourseRecommendedList extends Cache
|
|
||||||
{
|
|
||||||
|
|
||||||
protected $lifetime = 86400;
|
|
||||||
|
|
||||||
public function getLifetime()
|
|
||||||
{
|
|
||||||
return $this->lifetime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getKey($id = null)
|
|
||||||
{
|
|
||||||
return "course_recommended_list:{$id}";
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getContent($id = null)
|
|
||||||
{
|
|
||||||
$courses = $this->findCourses(5);
|
|
||||||
|
|
||||||
if ($courses->count() == 0) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->handleContent($courses);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param CourseModel[] $courses
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function handleContent($courses)
|
|
||||||
{
|
|
||||||
$result = [];
|
|
||||||
|
|
||||||
foreach ($courses as $course) {
|
|
||||||
|
|
||||||
$userCount = $course->user_count;
|
|
||||||
|
|
||||||
if ($course->fake_user_count > $course->user_count) {
|
|
||||||
$userCount = $course->fake_user_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
$result[] = [
|
|
||||||
'id' => $course->id,
|
|
||||||
'title' => $course->title,
|
|
||||||
'cover' => $course->cover,
|
|
||||||
'model' => $course->model,
|
|
||||||
'level' => $course->level,
|
|
||||||
'rating' => round($course->rating, 1),
|
|
||||||
'market_price' => (float)$course->market_price,
|
|
||||||
'vip_price' => (float)$course->vip_price,
|
|
||||||
'user_count' => $userCount,
|
|
||||||
'lesson_count' => $course->lesson_count,
|
|
||||||
'review_count' => $course->review_count,
|
|
||||||
'favorite_count' => $course->favorite_count,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param int $limit
|
|
||||||
* @return ResultsetInterface|Resultset|CourseModel[]
|
|
||||||
*/
|
|
||||||
public function findCourses($limit = 5)
|
|
||||||
{
|
|
||||||
return CourseModel::query()
|
|
||||||
->where('market_price > 0')
|
|
||||||
->andWhere('published = 1')
|
|
||||||
->andWhere('deleted = 0')
|
|
||||||
->orderBy('RAND()')
|
|
||||||
->limit($limit)
|
|
||||||
->execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,63 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* @copyright Copyright (c) 2021 深圳市酷瓜软件有限公司
|
|
||||||
* @license https://opensource.org/licenses/GPL-2.0
|
|
||||||
* @link https://www.koogua.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace App\Caches;
|
|
||||||
|
|
||||||
use App\Models\User as UserModel;
|
|
||||||
use App\Repos\Course as CourseRepo;
|
|
||||||
|
|
||||||
class CourseTeacherList extends Cache
|
|
||||||
{
|
|
||||||
|
|
||||||
protected $lifetime = 86400;
|
|
||||||
|
|
||||||
public function getLifetime()
|
|
||||||
{
|
|
||||||
return $this->lifetime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getKey($id = null)
|
|
||||||
{
|
|
||||||
return "course_teacher_list:{$id}";
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getContent($id = null)
|
|
||||||
{
|
|
||||||
$courseRepo = new CourseRepo();
|
|
||||||
|
|
||||||
$users = $courseRepo->findTeachers($id);
|
|
||||||
|
|
||||||
if ($users->count() == 0) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->handleContent($users);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param UserModel[] $users
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function handleContent($users)
|
|
||||||
{
|
|
||||||
$result = [];
|
|
||||||
|
|
||||||
foreach ($users as $user) {
|
|
||||||
$result[] = [
|
|
||||||
'id' => $user->id,
|
|
||||||
'name' => $user->name,
|
|
||||||
'avatar' => $user->avatar,
|
|
||||||
'vip' => $user->vip,
|
|
||||||
'title' => $user->title,
|
|
||||||
'about' => $user->about,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -14,13 +14,13 @@ use Phalcon\Mvc\Model\ResultsetInterface;
|
|||||||
class FeaturedArticleList extends Cache
|
class FeaturedArticleList extends Cache
|
||||||
{
|
{
|
||||||
|
|
||||||
protected $lifetime = 86400;
|
protected $lifetime = 3600;
|
||||||
|
|
||||||
|
protected $limit = 5;
|
||||||
|
|
||||||
public function getLifetime()
|
public function getLifetime()
|
||||||
{
|
{
|
||||||
$tomorrow = strtotime('tomorrow');
|
return $this->lifetime;
|
||||||
|
|
||||||
return $tomorrow - time();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getKey($id = null)
|
public function getKey($id = null)
|
||||||
@ -30,9 +30,7 @@ class FeaturedArticleList extends Cache
|
|||||||
|
|
||||||
public function getContent($id = null)
|
public function getContent($id = null)
|
||||||
{
|
{
|
||||||
$limit = 8;
|
$articles = $this->findArticles($this->limit);
|
||||||
|
|
||||||
$articles = $this->findArticles($limit);
|
|
||||||
|
|
||||||
if ($articles->count() == 0) {
|
if ($articles->count() == 0) {
|
||||||
return [];
|
return [];
|
||||||
@ -41,20 +39,10 @@ class FeaturedArticleList extends Cache
|
|||||||
$result = [];
|
$result = [];
|
||||||
|
|
||||||
foreach ($articles as $article) {
|
foreach ($articles as $article) {
|
||||||
|
|
||||||
$userCount = $article->user_count;
|
|
||||||
|
|
||||||
if ($article->fake_user_count > $article->user_count) {
|
|
||||||
$userCount = $article->fake_user_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
$result[] = [
|
$result[] = [
|
||||||
'id' => $article->id,
|
'id' => $article->id,
|
||||||
'title' => $article->title,
|
'title' => $article->title,
|
||||||
'cover' => $article->cover,
|
'cover' => $article->cover,
|
||||||
'market_price' => (float)$article->market_price,
|
|
||||||
'vip_price' => (float)$article->vip_price,
|
|
||||||
'user_count' => $userCount,
|
|
||||||
'favorite_count' => $article->favorite_count,
|
'favorite_count' => $article->favorite_count,
|
||||||
'comment_count' => $article->comment_count,
|
'comment_count' => $article->comment_count,
|
||||||
'view_count' => $article->view_count,
|
'view_count' => $article->view_count,
|
||||||
@ -69,13 +57,13 @@ class FeaturedArticleList extends Cache
|
|||||||
* @param int $limit
|
* @param int $limit
|
||||||
* @return ResultsetInterface|Resultset|ArticleModel[]
|
* @return ResultsetInterface|Resultset|ArticleModel[]
|
||||||
*/
|
*/
|
||||||
protected function findArticles($limit = 8)
|
protected function findArticles($limit = 5)
|
||||||
{
|
{
|
||||||
return ArticleModel::query()
|
return ArticleModel::query()
|
||||||
->where('featured = 1')
|
->where('featured = 1')
|
||||||
->andWhere('published = 1')
|
->andWhere('published = :published:', ['published' => ArticleModel::PUBLISH_APPROVED])
|
||||||
->andWhere('deleted = 0')
|
->andWhere('deleted = 0')
|
||||||
->orderBy('id DESC')
|
->orderBy('RAND()')
|
||||||
->limit($limit)
|
->limit($limit)
|
||||||
->execute();
|
->execute();
|
||||||
}
|
}
|
||||||
|
@ -14,13 +14,13 @@ use Phalcon\Mvc\Model\ResultsetInterface;
|
|||||||
class FeaturedCourseList extends Cache
|
class FeaturedCourseList extends Cache
|
||||||
{
|
{
|
||||||
|
|
||||||
protected $lifetime = 86400;
|
protected $lifetime = 3600;
|
||||||
|
|
||||||
|
protected $limit = 5;
|
||||||
|
|
||||||
public function getLifetime()
|
public function getLifetime()
|
||||||
{
|
{
|
||||||
$tomorrow = strtotime('tomorrow');
|
return $this->lifetime;
|
||||||
|
|
||||||
return $tomorrow - time();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getKey($id = null)
|
public function getKey($id = null)
|
||||||
@ -30,9 +30,7 @@ class FeaturedCourseList extends Cache
|
|||||||
|
|
||||||
public function getContent($id = null)
|
public function getContent($id = null)
|
||||||
{
|
{
|
||||||
$limit = 8;
|
$courses = $this->findCourses($this->limit);
|
||||||
|
|
||||||
$courses = $this->findCourses($limit);
|
|
||||||
|
|
||||||
if ($courses->count() == 0) {
|
if ($courses->count() == 0) {
|
||||||
return [];
|
return [];
|
||||||
@ -71,13 +69,13 @@ class FeaturedCourseList extends Cache
|
|||||||
* @param int $limit
|
* @param int $limit
|
||||||
* @return ResultsetInterface|Resultset|CourseModel[]
|
* @return ResultsetInterface|Resultset|CourseModel[]
|
||||||
*/
|
*/
|
||||||
protected function findCourses($limit = 8)
|
protected function findCourses($limit = 5)
|
||||||
{
|
{
|
||||||
return CourseModel::query()
|
return CourseModel::query()
|
||||||
->where('featured = 1')
|
->where('featured = 1')
|
||||||
->andWhere('published = 1')
|
->andWhere('published = 1')
|
||||||
->andWhere('deleted = 0')
|
->andWhere('deleted = 0')
|
||||||
->orderBy('id DESC')
|
->orderBy('RAND()')
|
||||||
->limit($limit)
|
->limit($limit)
|
||||||
->execute();
|
->execute();
|
||||||
}
|
}
|
||||||
|
72
app/Caches/FeaturedQuestionList.php
Normal file
72
app/Caches/FeaturedQuestionList.php
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @copyright Copyright (c) 2023 深圳市酷瓜软件有限公司
|
||||||
|
* @license https://opensource.org/licenses/GPL-2.0
|
||||||
|
* @link https://www.koogua.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Caches;
|
||||||
|
|
||||||
|
use App\Models\Question as QuestionModel;
|
||||||
|
use Phalcon\Mvc\Model\Resultset;
|
||||||
|
use Phalcon\Mvc\Model\ResultsetInterface;
|
||||||
|
|
||||||
|
class FeaturedQuestionList extends Cache
|
||||||
|
{
|
||||||
|
|
||||||
|
protected $lifetime = 3600;
|
||||||
|
|
||||||
|
protected $limit = 5;
|
||||||
|
|
||||||
|
public function getLifetime()
|
||||||
|
{
|
||||||
|
return $this->lifetime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getKey($id = null)
|
||||||
|
{
|
||||||
|
return 'featured_question_list';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getContent($id = null)
|
||||||
|
{
|
||||||
|
$questions = $this->findQuestions($this->limit);
|
||||||
|
|
||||||
|
if ($questions->count() == 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = [];
|
||||||
|
|
||||||
|
foreach ($questions as $question) {
|
||||||
|
|
||||||
|
$result[] = [
|
||||||
|
'id' => $question->id,
|
||||||
|
'title' => $question->title,
|
||||||
|
'cover' => $question->cover,
|
||||||
|
'favorite_count' => $question->favorite_count,
|
||||||
|
'answer_count' => $question->answer_count,
|
||||||
|
'view_count' => $question->view_count,
|
||||||
|
'like_count' => $question->like_count,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param int $limit
|
||||||
|
* @return ResultsetInterface|Resultset|QuestionModel[]
|
||||||
|
*/
|
||||||
|
protected function findQuestions($limit = 5)
|
||||||
|
{
|
||||||
|
return QuestionModel::query()
|
||||||
|
->where('featured = 1')
|
||||||
|
->andWhere('published = :published:', ['published' => QuestionModel::PUBLISH_APPROVED])
|
||||||
|
->andWhere('deleted = 0')
|
||||||
|
->orderBy('RAND()')
|
||||||
|
->limit($limit)
|
||||||
|
->execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,36 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* @copyright Copyright (c) 2021 深圳市酷瓜软件有限公司
|
|
||||||
* @license https://opensource.org/licenses/GPL-2.0
|
|
||||||
* @link https://www.koogua.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace App\Caches;
|
|
||||||
|
|
||||||
use App\Repos\FlashSale as FlashSaleRepo;
|
|
||||||
|
|
||||||
class FlashSale extends Cache
|
|
||||||
{
|
|
||||||
|
|
||||||
protected $lifetime = 86400;
|
|
||||||
|
|
||||||
public function getLifetime()
|
|
||||||
{
|
|
||||||
return $this->lifetime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getKey($id = null)
|
|
||||||
{
|
|
||||||
return "flash_sale:{$id}";
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getContent($id = null)
|
|
||||||
{
|
|
||||||
$saleRepo = new FlashSaleRepo();
|
|
||||||
|
|
||||||
$sale = $saleRepo->findById($id);
|
|
||||||
|
|
||||||
return $sale ?: null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -15,7 +15,7 @@ use Phalcon\Mvc\Model\ResultsetInterface;
|
|||||||
class HelpList extends Cache
|
class HelpList extends Cache
|
||||||
{
|
{
|
||||||
|
|
||||||
protected $lifetime = 365 * 86400;
|
protected $lifetime = 7 * 86400;
|
||||||
|
|
||||||
public function getLifetime()
|
public function getLifetime()
|
||||||
{
|
{
|
||||||
|
@ -14,13 +14,11 @@ use Phalcon\Mvc\Model\ResultsetInterface;
|
|||||||
class HotQuestionList extends Cache
|
class HotQuestionList extends Cache
|
||||||
{
|
{
|
||||||
|
|
||||||
protected $lifetime = 86400;
|
protected $lifetime = 3600;
|
||||||
|
|
||||||
public function getLifetime()
|
public function getLifetime()
|
||||||
{
|
{
|
||||||
$tomorrow = strtotime('tomorrow');
|
return $this->lifetime;
|
||||||
|
|
||||||
return $tomorrow - time();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getKey($id = null)
|
public function getKey($id = null)
|
||||||
|
@ -14,7 +14,7 @@ use App\Services\Logic\Article\ArticleList as ArticleListService;
|
|||||||
class IndexArticleList extends Cache
|
class IndexArticleList extends Cache
|
||||||
{
|
{
|
||||||
|
|
||||||
protected $lifetime = 15 * 60;
|
protected $lifetime = 3600;
|
||||||
|
|
||||||
public function getLifetime()
|
public function getLifetime()
|
||||||
{
|
{
|
||||||
|
@ -19,7 +19,7 @@ use Phalcon\Mvc\Model\ResultsetInterface;
|
|||||||
class IndexFeaturedCourseList extends Cache
|
class IndexFeaturedCourseList extends Cache
|
||||||
{
|
{
|
||||||
|
|
||||||
protected $lifetime = 86400;
|
protected $lifetime = 3600;
|
||||||
|
|
||||||
public function getLifetime()
|
public function getLifetime()
|
||||||
{
|
{
|
||||||
|
@ -1,36 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* @copyright Copyright (c) 2021 深圳市酷瓜软件有限公司
|
|
||||||
* @license https://opensource.org/licenses/GPL-2.0
|
|
||||||
* @link https://www.koogua.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace App\Caches;
|
|
||||||
|
|
||||||
use App\Services\Logic\FlashSale\SaleList;
|
|
||||||
|
|
||||||
class IndexFlashSaleList extends Cache
|
|
||||||
{
|
|
||||||
|
|
||||||
protected $lifetime = 86400;
|
|
||||||
|
|
||||||
public function getLifetime()
|
|
||||||
{
|
|
||||||
return strtotime('tomorrow') - time();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getKey($id = null)
|
|
||||||
{
|
|
||||||
return 'index_flash_sale_list';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getContent($id = null)
|
|
||||||
{
|
|
||||||
$service = new SaleList();
|
|
||||||
|
|
||||||
$sales = $service->handle();
|
|
||||||
|
|
||||||
return $sales[0]['items'] ?? [];
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -19,7 +19,7 @@ use Phalcon\Mvc\Model\ResultsetInterface;
|
|||||||
class IndexFreeCourseList extends Cache
|
class IndexFreeCourseList extends Cache
|
||||||
{
|
{
|
||||||
|
|
||||||
protected $lifetime = 86400;
|
protected $lifetime = 3600;
|
||||||
|
|
||||||
public function getLifetime()
|
public function getLifetime()
|
||||||
{
|
{
|
||||||
|
@ -18,7 +18,7 @@ use Phalcon\Mvc\Model\ResultsetInterface;
|
|||||||
class IndexLiveList extends Cache
|
class IndexLiveList extends Cache
|
||||||
{
|
{
|
||||||
|
|
||||||
protected $lifetime = 86400;
|
protected $lifetime = 3600;
|
||||||
|
|
||||||
public function getLifetime()
|
public function getLifetime()
|
||||||
{
|
{
|
||||||
|
@ -19,7 +19,7 @@ use Phalcon\Mvc\Model\ResultsetInterface;
|
|||||||
class IndexNewCourseList extends Cache
|
class IndexNewCourseList extends Cache
|
||||||
{
|
{
|
||||||
|
|
||||||
protected $lifetime = 86400;
|
protected $lifetime = 3600;
|
||||||
|
|
||||||
public function getLifetime()
|
public function getLifetime()
|
||||||
{
|
{
|
||||||
|
@ -14,7 +14,7 @@ use App\Services\Logic\Question\QuestionList as QuestionListService;
|
|||||||
class IndexQuestionList extends Cache
|
class IndexQuestionList extends Cache
|
||||||
{
|
{
|
||||||
|
|
||||||
protected $lifetime = 15 * 60;
|
protected $lifetime = 3600;
|
||||||
|
|
||||||
public function getLifetime()
|
public function getLifetime()
|
||||||
{
|
{
|
||||||
|
@ -17,7 +17,7 @@ use Phalcon\Mvc\Model\ResultsetInterface;
|
|||||||
class IndexSimpleFeaturedCourseList extends Cache
|
class IndexSimpleFeaturedCourseList extends Cache
|
||||||
{
|
{
|
||||||
|
|
||||||
protected $lifetime = 86400;
|
protected $lifetime = 3600;
|
||||||
|
|
||||||
public function getLifetime()
|
public function getLifetime()
|
||||||
{
|
{
|
||||||
|
@ -17,7 +17,7 @@ use Phalcon\Mvc\Model\ResultsetInterface;
|
|||||||
class IndexSimpleFreeCourseList extends Cache
|
class IndexSimpleFreeCourseList extends Cache
|
||||||
{
|
{
|
||||||
|
|
||||||
protected $lifetime = 86400;
|
protected $lifetime = 3600;
|
||||||
|
|
||||||
public function getLifetime()
|
public function getLifetime()
|
||||||
{
|
{
|
||||||
|
@ -17,7 +17,7 @@ use Phalcon\Mvc\Model\ResultsetInterface;
|
|||||||
class IndexSimpleNewCourseList extends Cache
|
class IndexSimpleNewCourseList extends Cache
|
||||||
{
|
{
|
||||||
|
|
||||||
protected $lifetime = 86400;
|
protected $lifetime = 3600;
|
||||||
|
|
||||||
public function getLifetime()
|
public function getLifetime()
|
||||||
{
|
{
|
||||||
|
@ -17,7 +17,7 @@ use Phalcon\Mvc\Model\ResultsetInterface;
|
|||||||
class IndexSimpleVipCourseList extends Cache
|
class IndexSimpleVipCourseList extends Cache
|
||||||
{
|
{
|
||||||
|
|
||||||
protected $lifetime = 86400;
|
protected $lifetime = 3600;
|
||||||
|
|
||||||
public function getLifetime()
|
public function getLifetime()
|
||||||
{
|
{
|
||||||
|
@ -14,7 +14,7 @@ use Phalcon\Mvc\Model\ResultsetInterface;
|
|||||||
class IndexSlideList extends Cache
|
class IndexSlideList extends Cache
|
||||||
{
|
{
|
||||||
|
|
||||||
protected $lifetime = 365 * 86400;
|
protected $lifetime = 3600;
|
||||||
|
|
||||||
public function getLifetime()
|
public function getLifetime()
|
||||||
{
|
{
|
||||||
|
@ -19,7 +19,7 @@ use Phalcon\Mvc\Model\ResultsetInterface;
|
|||||||
class IndexVipCourseList extends Cache
|
class IndexVipCourseList extends Cache
|
||||||
{
|
{
|
||||||
|
|
||||||
protected $lifetime = 86400;
|
protected $lifetime = 3600;
|
||||||
|
|
||||||
public function getLifetime()
|
public function getLifetime()
|
||||||
{
|
{
|
||||||
|
@ -1,34 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* @copyright Copyright (c) 2021 深圳市酷瓜软件有限公司
|
|
||||||
* @license https://opensource.org/licenses/GPL-2.0
|
|
||||||
* @link https://www.koogua.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace App\Caches;
|
|
||||||
|
|
||||||
use App\Models\FlashSale as FlashSaleModel;
|
|
||||||
|
|
||||||
class MaxFlashSaleId extends Cache
|
|
||||||
{
|
|
||||||
|
|
||||||
protected $lifetime = 365 * 86400;
|
|
||||||
|
|
||||||
public function getLifetime()
|
|
||||||
{
|
|
||||||
return $this->lifetime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getKey($id = null)
|
|
||||||
{
|
|
||||||
return 'max_flash_sale_id';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getContent($id = null)
|
|
||||||
{
|
|
||||||
$sale = FlashSaleModel::findFirst(['order' => 'id DESC']);
|
|
||||||
|
|
||||||
return $sale->id ?? 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -13,9 +13,9 @@ use App\Repos\Article as ArticleRepo;
|
|||||||
class TaggedArticleList extends Cache
|
class TaggedArticleList extends Cache
|
||||||
{
|
{
|
||||||
|
|
||||||
protected $limit = 5;
|
protected $limit = 15;
|
||||||
|
|
||||||
protected $lifetime = 86400;
|
protected $lifetime = 3600;
|
||||||
|
|
||||||
public function getLifetime()
|
public function getLifetime()
|
||||||
{
|
{
|
||||||
|
@ -13,9 +13,9 @@ use App\Repos\Question as QuestionRepo;
|
|||||||
class TaggedQuestionList extends Cache
|
class TaggedQuestionList extends Cache
|
||||||
{
|
{
|
||||||
|
|
||||||
protected $limit = 5;
|
protected $limit = 15;
|
||||||
|
|
||||||
protected $lifetime = 86400;
|
protected $lifetime = 3600;
|
||||||
|
|
||||||
public function getLifetime()
|
public function getLifetime()
|
||||||
{
|
{
|
||||||
|
@ -16,7 +16,7 @@ use Phalcon\Mvc\Model\ResultsetInterface;
|
|||||||
class TopAnswererList extends Cache
|
class TopAnswererList extends Cache
|
||||||
{
|
{
|
||||||
|
|
||||||
protected $lifetime = 86400;
|
protected $lifetime = 3600;
|
||||||
|
|
||||||
public function getLifetime()
|
public function getLifetime()
|
||||||
{
|
{
|
||||||
|
@ -16,7 +16,7 @@ use Phalcon\Mvc\Model\ResultsetInterface;
|
|||||||
class TopAuthorList extends Cache
|
class TopAuthorList extends Cache
|
||||||
{
|
{
|
||||||
|
|
||||||
protected $lifetime = 86400;
|
protected $lifetime = 3600;
|
||||||
|
|
||||||
public function getLifetime()
|
public function getLifetime()
|
||||||
{
|
{
|
||||||
|
@ -8,12 +8,13 @@
|
|||||||
namespace App\Console\Tasks;
|
namespace App\Console\Tasks;
|
||||||
|
|
||||||
use App\Caches\CategoryList as CategoryListCache;
|
use App\Caches\CategoryList as CategoryListCache;
|
||||||
|
use App\Caches\CategoryAllList as CategoryAllListCache;
|
||||||
use App\Caches\CategoryTreeList as CategoryTreeListCache;
|
use App\Caches\CategoryTreeList as CategoryTreeListCache;
|
||||||
use App\Caches\IndexSlideList as IndexSlideListCache;
|
use App\Caches\IndexSlideList as IndexSlideListCache;
|
||||||
use App\Models\Account as AccountModel;
|
use App\Models\Account as AccountModel;
|
||||||
use App\Models\Category as CategoryModel;
|
use App\Models\Category as CategoryModel;
|
||||||
use App\Repos\User as UserRepo;
|
use App\Repos\User as UserRepo;
|
||||||
use App\Services\Utils\IndexCourseCache as IndexCourseCacheUtil;
|
use App\Services\Utils\IndexPageCache as IndexPageCacheUtil;
|
||||||
|
|
||||||
class CleanDemoDataTask extends Task
|
class CleanDemoDataTask extends Task
|
||||||
{
|
{
|
||||||
@ -81,17 +82,19 @@ class CleanDemoDataTask extends Task
|
|||||||
|
|
||||||
protected function cleanCache()
|
protected function cleanCache()
|
||||||
{
|
{
|
||||||
$util = new IndexCourseCacheUtil();
|
$util = new IndexPageCacheUtil();
|
||||||
$util->rebuild();
|
$util->rebuild();
|
||||||
|
|
||||||
$slideListCache = new IndexSlideListCache();
|
$slideListCache = new IndexSlideListCache();
|
||||||
$slideListCache->rebuild();
|
$slideListCache->rebuild();
|
||||||
|
|
||||||
$categoryListCache = new CategoryListCache();
|
$categoryListCache = new CategoryListCache();
|
||||||
|
$categoryAllListCache = new CategoryAllListCache();
|
||||||
$categoryTreeListCache = new CategoryTreeListCache();
|
$categoryTreeListCache = new CategoryTreeListCache();
|
||||||
|
|
||||||
foreach (CategoryModel::types() as $key => $value) {
|
foreach (CategoryModel::types() as $key => $value) {
|
||||||
$categoryListCache->rebuild($key);
|
$categoryListCache->rebuild($key);
|
||||||
|
$categoryAllListCache->rebuild($key);
|
||||||
$categoryTreeListCache->rebuild($key);
|
$categoryTreeListCache->rebuild($key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -114,7 +117,7 @@ class CleanDemoDataTask extends Task
|
|||||||
|
|
||||||
$user = $userRepo->findById(100015);
|
$user = $userRepo->findById(100015);
|
||||||
|
|
||||||
return $user ? true : false;
|
return (bool)$user;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,86 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* @copyright Copyright (c) 2021 深圳市酷瓜软件有限公司
|
|
||||||
* @license https://opensource.org/licenses/GPL-2.0
|
|
||||||
* @link https://www.koogua.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace App\Console\Tasks;
|
|
||||||
|
|
||||||
use App\Models\Order as OrderModel;
|
|
||||||
use App\Repos\FlashSale as FlashSaleRepo;
|
|
||||||
use App\Services\Logic\FlashSale\Queue as FlashSaleQueue;
|
|
||||||
use App\Services\Logic\FlashSale\UserOrderCache;
|
|
||||||
use Phalcon\Mvc\Model\Resultset;
|
|
||||||
use Phalcon\Mvc\Model\ResultsetInterface;
|
|
||||||
|
|
||||||
class CloseFlashSaleOrderTask extends Task
|
|
||||||
{
|
|
||||||
|
|
||||||
public function mainAction()
|
|
||||||
{
|
|
||||||
$orders = $this->findOrders();
|
|
||||||
|
|
||||||
echo sprintf('pending orders: %s', $orders->count()) . PHP_EOL;
|
|
||||||
|
|
||||||
if ($orders->count() == 0) return;
|
|
||||||
|
|
||||||
echo '------ start close order task ------' . PHP_EOL;
|
|
||||||
|
|
||||||
foreach ($orders as $order) {
|
|
||||||
$this->incrFlashSaleStock($order->promotion_id);
|
|
||||||
$this->pushFlashSaleQueue($order->promotion_id);
|
|
||||||
$this->deleteUserOrderCache($order->owner_id, $order->promotion_id);
|
|
||||||
$order->status = OrderModel::STATUS_CLOSED;
|
|
||||||
$order->update();
|
|
||||||
}
|
|
||||||
|
|
||||||
echo '------ end close order task ------' . PHP_EOL;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function incrFlashSaleStock($saleId)
|
|
||||||
{
|
|
||||||
$flashSaleRepo = new FlashSaleRepo();
|
|
||||||
|
|
||||||
$flashSale = $flashSaleRepo->findById($saleId);
|
|
||||||
|
|
||||||
$flashSale->stock += 1;
|
|
||||||
|
|
||||||
$flashSale->update();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function pushFlashSaleQueue($saleId)
|
|
||||||
{
|
|
||||||
$queue = new FlashSaleQueue();
|
|
||||||
|
|
||||||
$queue->push($saleId);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function deleteUserOrderCache($userId, $saleId)
|
|
||||||
{
|
|
||||||
$cache = new UserOrderCache();
|
|
||||||
|
|
||||||
$cache->delete($userId, $saleId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查找待关闭订单
|
|
||||||
*
|
|
||||||
* @param int $limit
|
|
||||||
* @return ResultsetInterface|Resultset|OrderModel[]
|
|
||||||
*/
|
|
||||||
protected function findOrders($limit = 1000)
|
|
||||||
{
|
|
||||||
$status = OrderModel::STATUS_PENDING;
|
|
||||||
$type = OrderModel::PROMOTION_FLASH_SALE;
|
|
||||||
$time = time() - 15 * 60;
|
|
||||||
|
|
||||||
return OrderModel::query()
|
|
||||||
->where('status = :status:', ['status' => $status])
|
|
||||||
->andWhere('promotion_type = :type:', ['type' => $type])
|
|
||||||
->andWhere('create_time < :time:', ['time' => $time])
|
|
||||||
->limit($limit)
|
|
||||||
->execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -42,11 +42,9 @@ class CloseOrderTask extends Task
|
|||||||
{
|
{
|
||||||
$status = OrderModel::STATUS_PENDING;
|
$status = OrderModel::STATUS_PENDING;
|
||||||
$time = time() - 12 * 3600;
|
$time = time() - 12 * 3600;
|
||||||
$type = 0;
|
|
||||||
|
|
||||||
return OrderModel::query()
|
return OrderModel::query()
|
||||||
->where('status = :status:', ['status' => $status])
|
->where('status = :status:', ['status' => $status])
|
||||||
->andWhere('promotion_type = :type:', ['type' => $type])
|
|
||||||
->andWhere('create_time < :time:', ['time' => $time])
|
->andWhere('create_time < :time:', ['time' => $time])
|
||||||
->limit($limit)
|
->limit($limit)
|
||||||
->execute();
|
->execute();
|
||||||
|
@ -172,9 +172,7 @@ class DeliverTask extends Task
|
|||||||
];
|
];
|
||||||
|
|
||||||
foreach ($orders as $order) {
|
foreach ($orders as $order) {
|
||||||
$case1 = in_array($order->item_type, $itemTypes);
|
if (in_array($order->item_type, $itemTypes)) {
|
||||||
$case2 = $order->promotion_type == 0;
|
|
||||||
if ($case1 && $case2) {
|
|
||||||
$order->status = OrderModel::STATUS_CLOSED;
|
$order->status = OrderModel::STATUS_CLOSED;
|
||||||
$order->update();
|
$order->update();
|
||||||
}
|
}
|
||||||
|
@ -168,7 +168,8 @@ class RefundTask extends Task
|
|||||||
protected function handleCourseOrderRefund(OrderModel $order)
|
protected function handleCourseOrderRefund(OrderModel $order)
|
||||||
{
|
{
|
||||||
$courseUserRepo = new CourseUserRepo();
|
$courseUserRepo = new CourseUserRepo();
|
||||||
$courseUser = $courseUserRepo->findCourseStudent($order->item_id, $order->owner_id);
|
|
||||||
|
$courseUser = $courseUserRepo->findCourseUser($order->item_id, $order->owner_id);
|
||||||
|
|
||||||
if ($courseUser) {
|
if ($courseUser) {
|
||||||
$courseUser->deleted = 1;
|
$courseUser->deleted = 1;
|
||||||
@ -191,7 +192,7 @@ class RefundTask extends Task
|
|||||||
|
|
||||||
foreach ($itemInfo['courses'] as $course) {
|
foreach ($itemInfo['courses'] as $course) {
|
||||||
|
|
||||||
$courseUser = $courseUserRepo->findCourseStudent($course['id'], $order->owner_id);
|
$courseUser = $courseUserRepo->findCourseUser($course['id'], $order->owner_id);
|
||||||
|
|
||||||
if ($courseUser) {
|
if ($courseUser) {
|
||||||
$courseUser->deleted = 1;
|
$courseUser->deleted = 1;
|
||||||
|
@ -61,12 +61,15 @@ class AnswerController extends Controller
|
|||||||
{
|
{
|
||||||
$answerService = new AnswerService();
|
$answerService = new AnswerService();
|
||||||
|
|
||||||
|
$publishTypes = $answerService->getPublishTypes();
|
||||||
|
|
||||||
$answer = $answerService->getAnswer($id);
|
$answer = $answerService->getAnswer($id);
|
||||||
|
|
||||||
$questionService = new QuestionService();
|
$questionService = new QuestionService();
|
||||||
|
|
||||||
$question = $questionService->getQuestion($answer->question_id);
|
$question = $questionService->getQuestion($answer->question_id);
|
||||||
|
|
||||||
|
$this->view->setVar('publish_types', $publishTypes);
|
||||||
$this->view->setVar('question', $question);
|
$this->view->setVar('question', $question);
|
||||||
$this->view->setVar('answer', $answer);
|
$this->view->setVar('answer', $answer);
|
||||||
}
|
}
|
||||||
@ -219,4 +222,40 @@ class AnswerController extends Controller
|
|||||||
$this->view->setVar('reports', $reports);
|
$this->view->setVar('reports', $reports);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Post("/moderate/batch", name="admin.answer.batch_moderate")
|
||||||
|
*/
|
||||||
|
public function batchModerateAction()
|
||||||
|
{
|
||||||
|
$answerService = new AnswerService();
|
||||||
|
|
||||||
|
$answerService->batchModerate();
|
||||||
|
|
||||||
|
$location = $this->url->get(['for' => 'admin.mod.answers']);
|
||||||
|
|
||||||
|
$content = [
|
||||||
|
'location' => $location,
|
||||||
|
'msg' => '批量审核成功',
|
||||||
|
];
|
||||||
|
|
||||||
|
return $this->jsonSuccess($content);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Post("/delete/batch", name="admin.answer.batch_delete")
|
||||||
|
*/
|
||||||
|
public function batchDeleteAction()
|
||||||
|
{
|
||||||
|
$answerService = new AnswerService();
|
||||||
|
|
||||||
|
$answerService->batchDelete();
|
||||||
|
|
||||||
|
$content = [
|
||||||
|
'location' => $this->request->getHTTPReferer(),
|
||||||
|
'msg' => '批量删除成功',
|
||||||
|
];
|
||||||
|
|
||||||
|
return $this->jsonSuccess($content);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -38,12 +38,12 @@ class ArticleController extends Controller
|
|||||||
|
|
||||||
$publishTypes = $articleService->getPublishTypes();
|
$publishTypes = $articleService->getPublishTypes();
|
||||||
$sourceTypes = $articleService->getSourceTypes();
|
$sourceTypes = $articleService->getSourceTypes();
|
||||||
$categories = $articleService->getCategories();
|
$categoryOptions = $articleService->getCategoryOptions();
|
||||||
$xmTags = $articleService->getXmTags(0);
|
$xmTags = $articleService->getXmTags(0);
|
||||||
|
|
||||||
$this->view->setVar('publish_types', $publishTypes);
|
$this->view->setVar('publish_types', $publishTypes);
|
||||||
$this->view->setVar('source_types', $sourceTypes);
|
$this->view->setVar('source_types', $sourceTypes);
|
||||||
$this->view->setVar('categories', $categories);
|
$this->view->setVar('category_options', $categoryOptions);
|
||||||
$this->view->setVar('xm_tags', $xmTags);
|
$this->view->setVar('xm_tags', $xmTags);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,11 +64,7 @@ class ArticleController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function addAction()
|
public function addAction()
|
||||||
{
|
{
|
||||||
$articleService = new ArticleService();
|
|
||||||
|
|
||||||
$categories = $articleService->getCategories();
|
|
||||||
|
|
||||||
$this->view->setVar('categories', $categories);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -80,14 +76,14 @@ class ArticleController extends Controller
|
|||||||
|
|
||||||
$publishTypes = $articleService->getPublishTypes();
|
$publishTypes = $articleService->getPublishTypes();
|
||||||
$sourceTypes = $articleService->getSourceTypes();
|
$sourceTypes = $articleService->getSourceTypes();
|
||||||
$categories = $articleService->getCategories();
|
$categoryOptions = $articleService->getCategoryOptions();
|
||||||
$article = $articleService->getArticle($id);
|
$article = $articleService->getArticle($id);
|
||||||
$xmTags = $articleService->getXmTags($id);
|
$xmTags = $articleService->getXmTags($id);
|
||||||
|
|
||||||
|
$this->view->setVar('article', $article);
|
||||||
$this->view->setVar('publish_types', $publishTypes);
|
$this->view->setVar('publish_types', $publishTypes);
|
||||||
$this->view->setVar('source_types', $sourceTypes);
|
$this->view->setVar('source_types', $sourceTypes);
|
||||||
$this->view->setVar('categories', $categories);
|
$this->view->setVar('category_options', $categoryOptions);
|
||||||
$this->view->setVar('article', $article);
|
|
||||||
$this->view->setVar('xm_tags', $xmTags);
|
$this->view->setVar('xm_tags', $xmTags);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,4 +225,40 @@ class ArticleController extends Controller
|
|||||||
$this->view->setVar('article', $article);
|
$this->view->setVar('article', $article);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Post("/moderate/batch", name="admin.article.batch_moderate")
|
||||||
|
*/
|
||||||
|
public function batchModerateAction()
|
||||||
|
{
|
||||||
|
$articleService = new ArticleService();
|
||||||
|
|
||||||
|
$articleService->batchModerate();
|
||||||
|
|
||||||
|
$location = $this->url->get(['for' => 'admin.mod.articles']);
|
||||||
|
|
||||||
|
$content = [
|
||||||
|
'location' => $location,
|
||||||
|
'msg' => '批量审核成功',
|
||||||
|
];
|
||||||
|
|
||||||
|
return $this->jsonSuccess($content);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Post("/delete/batch", name="admin.article.batch_delete")
|
||||||
|
*/
|
||||||
|
public function batchDeleteAction()
|
||||||
|
{
|
||||||
|
$articleService = new ArticleService();
|
||||||
|
|
||||||
|
$articleService->batchDelete();
|
||||||
|
|
||||||
|
$content = [
|
||||||
|
'location' => $this->request->getHTTPReferer(),
|
||||||
|
'msg' => '批量删除成功',
|
||||||
|
];
|
||||||
|
|
||||||
|
return $this->jsonSuccess($content);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -139,4 +139,40 @@ class CommentController extends Controller
|
|||||||
$this->view->setVar('reports', $reports);
|
$this->view->setVar('reports', $reports);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Post("/moderate/batch", name="admin.comment.batch_moderate")
|
||||||
|
*/
|
||||||
|
public function batchModerateAction()
|
||||||
|
{
|
||||||
|
$commentService = new CommentService();
|
||||||
|
|
||||||
|
$commentService->batchModerate();
|
||||||
|
|
||||||
|
$location = $this->url->get(['for' => 'admin.mod.comments']);
|
||||||
|
|
||||||
|
$content = [
|
||||||
|
'location' => $location,
|
||||||
|
'msg' => '批量审核成功',
|
||||||
|
];
|
||||||
|
|
||||||
|
return $this->jsonSuccess($content);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Post("/delete/batch", name="admin.comment.batch_delete")
|
||||||
|
*/
|
||||||
|
public function batchDeleteAction()
|
||||||
|
{
|
||||||
|
$commentService = new CommentService();
|
||||||
|
|
||||||
|
$commentService->batchDelete();
|
||||||
|
|
||||||
|
$content = [
|
||||||
|
'location' => $this->request->getHTTPReferer(),
|
||||||
|
'msg' => '批量删除成功',
|
||||||
|
];
|
||||||
|
|
||||||
|
return $this->jsonSuccess($content);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -23,8 +23,10 @@ class ConsultController extends Controller
|
|||||||
$consultService = new ConsultService();
|
$consultService = new ConsultService();
|
||||||
|
|
||||||
$publishTypes = $consultService->getPublishTypes();
|
$publishTypes = $consultService->getPublishTypes();
|
||||||
|
$xmCourses = $consultService->getXmCourses();
|
||||||
|
|
||||||
$this->view->setVar('publish_types', $publishTypes);
|
$this->view->setVar('publish_types', $publishTypes);
|
||||||
|
$this->view->setVar('xm_courses', $xmCourses);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -55,8 +57,11 @@ class ConsultController extends Controller
|
|||||||
{
|
{
|
||||||
$consultService = new ConsultService();
|
$consultService = new ConsultService();
|
||||||
|
|
||||||
|
$publishTypes = $consultService->getPublishTypes();
|
||||||
|
|
||||||
$consult = $consultService->getConsult($id);
|
$consult = $consultService->getConsult($id);
|
||||||
|
|
||||||
|
$this->view->setVar('publish_types', $publishTypes);
|
||||||
$this->view->setVar('consult', $consult);
|
$this->view->setVar('consult', $consult);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,9 +140,47 @@ class ConsultController extends Controller
|
|||||||
return $this->jsonSuccess($content);
|
return $this->jsonSuccess($content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$reasons = $consultService->getReasons();
|
||||||
$consult = $consultService->getConsultInfo($id);
|
$consult = $consultService->getConsultInfo($id);
|
||||||
|
|
||||||
|
$this->view->setVar('reasons', $reasons);
|
||||||
$this->view->setVar('consult', $consult);
|
$this->view->setVar('consult', $consult);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Post("/moderate/batch", name="admin.consult.batch_moderate")
|
||||||
|
*/
|
||||||
|
public function batchModerateAction()
|
||||||
|
{
|
||||||
|
$consultService = new ConsultService();
|
||||||
|
|
||||||
|
$consultService->batchModerate();
|
||||||
|
|
||||||
|
$location = $this->url->get(['for' => 'admin.mod.consults']);
|
||||||
|
|
||||||
|
$content = [
|
||||||
|
'location' => $location,
|
||||||
|
'msg' => '批量审核成功',
|
||||||
|
];
|
||||||
|
|
||||||
|
return $this->jsonSuccess($content);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Post("/delete/batch", name="admin.consult.batch_delete")
|
||||||
|
*/
|
||||||
|
public function batchDeleteAction()
|
||||||
|
{
|
||||||
|
$consultService = new ConsultService();
|
||||||
|
|
||||||
|
$consultService->batchDelete();
|
||||||
|
|
||||||
|
$content = [
|
||||||
|
'location' => $this->request->getHTTPReferer(),
|
||||||
|
'msg' => '批量删除成功',
|
||||||
|
];
|
||||||
|
|
||||||
|
return $this->jsonSuccess($content);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
namespace App\Http\Admin\Controllers;
|
namespace App\Http\Admin\Controllers;
|
||||||
|
|
||||||
use App\Http\Admin\Services\Course as CourseService;
|
use App\Http\Admin\Services\Course as CourseService;
|
||||||
|
use App\Http\Admin\Services\CourseLearning as CourseLearningService;
|
||||||
|
use App\Http\Admin\Services\CourseUser as CourseUserService;
|
||||||
use App\Models\Category as CategoryModel;
|
use App\Models\Category as CategoryModel;
|
||||||
use Phalcon\Mvc\View;
|
use Phalcon\Mvc\View;
|
||||||
|
|
||||||
@ -37,13 +39,13 @@ class CourseController extends Controller
|
|||||||
{
|
{
|
||||||
$courseService = new CourseService();
|
$courseService = new CourseService();
|
||||||
|
|
||||||
$xmCategories = $courseService->getXmCategories(0);
|
$categoryOptions = $courseService->getCategoryOptions();
|
||||||
$xmTeachers = $courseService->getXmTeachers(0);
|
$teacherOptions = $courseService->getTeacherOptions();
|
||||||
$modelTypes = $courseService->getModelTypes();
|
$modelTypes = $courseService->getModelTypes();
|
||||||
$levelTypes = $courseService->getLevelTypes();
|
$levelTypes = $courseService->getLevelTypes();
|
||||||
|
|
||||||
$this->view->setVar('xm_categories', $xmCategories);
|
$this->view->setVar('category_options', $categoryOptions);
|
||||||
$this->view->setVar('xm_teachers', $xmTeachers);
|
$this->view->setVar('teacher_options', $teacherOptions);
|
||||||
$this->view->setVar('model_types', $modelTypes);
|
$this->view->setVar('model_types', $modelTypes);
|
||||||
$this->view->setVar('level_types', $levelTypes);
|
$this->view->setVar('level_types', $levelTypes);
|
||||||
}
|
}
|
||||||
@ -103,17 +105,21 @@ class CourseController extends Controller
|
|||||||
|
|
||||||
$cos = $courseService->getSettings('cos');
|
$cos = $courseService->getSettings('cos');
|
||||||
$course = $courseService->getCourse($id);
|
$course = $courseService->getCourse($id);
|
||||||
$xmTeachers = $courseService->getXmTeachers($id);
|
$xmTags = $courseService->getXmTags($id);
|
||||||
$xmCategories = $courseService->getXmCategories($id);
|
|
||||||
$xmCourses = $courseService->getXmCourses($id);
|
$xmCourses = $courseService->getXmCourses($id);
|
||||||
|
$levelTypes = $courseService->getLevelTypes();
|
||||||
|
$categoryOptions = $courseService->getCategoryOptions();
|
||||||
|
$teacherOptions = $courseService->getTeacherOptions();
|
||||||
$studyExpiryOptions = $courseService->getStudyExpiryOptions();
|
$studyExpiryOptions = $courseService->getStudyExpiryOptions();
|
||||||
$refundExpiryOptions = $courseService->getRefundExpiryOptions();
|
$refundExpiryOptions = $courseService->getRefundExpiryOptions();
|
||||||
|
|
||||||
$this->view->setVar('cos', $cos);
|
$this->view->setVar('cos', $cos);
|
||||||
$this->view->setVar('course', $course);
|
$this->view->setVar('course', $course);
|
||||||
$this->view->setVar('xm_teachers', $xmTeachers);
|
$this->view->setVar('xm_tags', $xmTags);
|
||||||
$this->view->setVar('xm_categories', $xmCategories);
|
|
||||||
$this->view->setVar('xm_courses', $xmCourses);
|
$this->view->setVar('xm_courses', $xmCourses);
|
||||||
|
$this->view->setVar('level_types', $levelTypes);
|
||||||
|
$this->view->setVar('category_options', $categoryOptions);
|
||||||
|
$this->view->setVar('teacher_options', $teacherOptions);
|
||||||
$this->view->setVar('study_expiry_options', $studyExpiryOptions);
|
$this->view->setVar('study_expiry_options', $studyExpiryOptions);
|
||||||
$this->view->setVar('refund_expiry_options', $refundExpiryOptions);
|
$this->view->setVar('refund_expiry_options', $refundExpiryOptions);
|
||||||
}
|
}
|
||||||
@ -193,4 +199,78 @@ class CourseController extends Controller
|
|||||||
$this->view->setVar('resources', $resources);
|
$this->view->setVar('resources', $resources);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Get("/{id:[0-9]+}/learnings", name="admin.course.learnings")
|
||||||
|
*/
|
||||||
|
public function learningsAction($id)
|
||||||
|
{
|
||||||
|
$service = new CourseLearningService();
|
||||||
|
|
||||||
|
$pager = $service->getLearnings($id);
|
||||||
|
|
||||||
|
$this->view->setVar('pager', $pager);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Get("/{id:[0-9]+}/users", name="admin.course.users")
|
||||||
|
*/
|
||||||
|
public function usersAction($id)
|
||||||
|
{
|
||||||
|
$service = new CourseService();
|
||||||
|
$course = $service->getCourse($id);
|
||||||
|
|
||||||
|
$service = new CourseUserService();
|
||||||
|
$pager = $service->getUsers($id);
|
||||||
|
|
||||||
|
$this->view->setVar('course', $course);
|
||||||
|
$this->view->setVar('pager', $pager);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Get("/{id:[0-9]+}/user/search", name="admin.course.search_user")
|
||||||
|
*/
|
||||||
|
public function searchUserAction($id)
|
||||||
|
{
|
||||||
|
$service = new CourseService();
|
||||||
|
$course = $service->getCourse($id);
|
||||||
|
|
||||||
|
$service = new CourseUserService();
|
||||||
|
$sourceTypes = $service->getSourceTypes();
|
||||||
|
|
||||||
|
$this->view->pick('course/search_user');
|
||||||
|
$this->view->setVar('source_types', $sourceTypes);
|
||||||
|
$this->view->setVar('course', $course);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Get("/{id:[0-9]+}/user/add", name="admin.course.add_user")
|
||||||
|
*/
|
||||||
|
public function addUserAction($id)
|
||||||
|
{
|
||||||
|
$service = new CourseService();
|
||||||
|
$course = $service->getCourse($id);
|
||||||
|
|
||||||
|
$this->view->pick('course/add_user');
|
||||||
|
$this->view->setVar('course', $course);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Post("/{id:[0-9]+}/user/create", name="admin.course.create_user")
|
||||||
|
*/
|
||||||
|
public function createUserAction($id)
|
||||||
|
{
|
||||||
|
$service = new CourseUserService();
|
||||||
|
|
||||||
|
$service->create($id);
|
||||||
|
|
||||||
|
$location = $this->url->get(['for' => 'admin.course.users']);
|
||||||
|
|
||||||
|
$content = [
|
||||||
|
'location' => $location,
|
||||||
|
'msg' => '添加学员成功',
|
||||||
|
];
|
||||||
|
|
||||||
|
return $this->jsonSuccess($content);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,153 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* @copyright Copyright (c) 2021 深圳市酷瓜软件有限公司
|
|
||||||
* @license https://opensource.org/licenses/GPL-2.0
|
|
||||||
* @link https://www.koogua.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace App\Http\Admin\Controllers;
|
|
||||||
|
|
||||||
use App\Http\Admin\Services\FlashSale as FlashSaleService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @RoutePrefix("/admin/flash/sale")
|
|
||||||
*/
|
|
||||||
class FlashSaleController extends Controller
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Get("/list", name="admin.flash_sale.list")
|
|
||||||
*/
|
|
||||||
public function listAction()
|
|
||||||
{
|
|
||||||
$service = new FlashSaleService();
|
|
||||||
|
|
||||||
$pager = $service->getFlashSales();
|
|
||||||
|
|
||||||
$this->view->setVar('pager', $pager);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Get("/search", name="admin.flash_sale.search")
|
|
||||||
*/
|
|
||||||
public function searchAction()
|
|
||||||
{
|
|
||||||
$service = new FlashSaleService();
|
|
||||||
|
|
||||||
$itemTypes = $service->getItemTypes();
|
|
||||||
|
|
||||||
$this->view->setVar('item_types', $itemTypes);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Get("/add", name="admin.flash_sale.add")
|
|
||||||
*/
|
|
||||||
public function addAction()
|
|
||||||
{
|
|
||||||
$service = new FlashSaleService();
|
|
||||||
|
|
||||||
$itemTypes = $service->getItemTypes();
|
|
||||||
$xmPackages = $service->getXmPackages();
|
|
||||||
$xmCourses = $service->getXmCourses();
|
|
||||||
$xmVips = $service->getXmVips();
|
|
||||||
|
|
||||||
$this->view->setVar('item_types', $itemTypes);
|
|
||||||
$this->view->setVar('xm_packages', $xmPackages);
|
|
||||||
$this->view->setVar('xm_courses', $xmCourses);
|
|
||||||
$this->view->setVar('xm_vips', $xmVips);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Get("/{id:[0-9]+}/edit", name="admin.flash_sale.edit")
|
|
||||||
*/
|
|
||||||
public function editAction($id)
|
|
||||||
{
|
|
||||||
$service = new FlashSaleService();
|
|
||||||
|
|
||||||
$sale = $service->getFlashSale($id);
|
|
||||||
$xmSchedules = $service->getXmSchedules($id);
|
|
||||||
|
|
||||||
$this->view->setVar('sale', $sale);
|
|
||||||
$this->view->setVar('xm_schedules', $xmSchedules);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Post("/create", name="admin.flash_sale.create")
|
|
||||||
*/
|
|
||||||
public function createAction()
|
|
||||||
{
|
|
||||||
$service = new FlashSaleService();
|
|
||||||
|
|
||||||
$sale = $service->createFlashSale();
|
|
||||||
|
|
||||||
$location = $this->url->get([
|
|
||||||
'for' => 'admin.flash_sale.edit',
|
|
||||||
'id' => $sale->id,
|
|
||||||
]);
|
|
||||||
|
|
||||||
$content = [
|
|
||||||
'location' => $location,
|
|
||||||
'msg' => '添加商品成功',
|
|
||||||
];
|
|
||||||
|
|
||||||
return $this->jsonSuccess($content);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Post("/{id:[0-9]+}/update", name="admin.flash_sale.update")
|
|
||||||
*/
|
|
||||||
public function updateAction($id)
|
|
||||||
{
|
|
||||||
$service = new FlashSaleService();
|
|
||||||
|
|
||||||
$service->updateFlashSale($id);
|
|
||||||
|
|
||||||
$location = $this->url->get(['for' => 'admin.flash_sale.list']);
|
|
||||||
|
|
||||||
$content = [
|
|
||||||
'location' => $location,
|
|
||||||
'msg' => '更新商品成功',
|
|
||||||
];
|
|
||||||
|
|
||||||
return $this->jsonSuccess($content);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Post("/{id:[0-9]+}/delete", name="admin.flash_sale.delete")
|
|
||||||
*/
|
|
||||||
public function deleteAction($id)
|
|
||||||
{
|
|
||||||
$service = new FlashSaleService();
|
|
||||||
|
|
||||||
$service->deleteFlashSale($id);
|
|
||||||
|
|
||||||
$location = $this->request->getHTTPReferer();
|
|
||||||
|
|
||||||
$content = [
|
|
||||||
'location' => $location,
|
|
||||||
'msg' => '删除商品成功',
|
|
||||||
];
|
|
||||||
|
|
||||||
return $this->jsonSuccess($content);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Post("/{id:[0-9]+}/restore", name="admin.flash_sale.restore")
|
|
||||||
*/
|
|
||||||
public function restoreAction($id)
|
|
||||||
{
|
|
||||||
$service = new FlashSaleService();
|
|
||||||
|
|
||||||
$service->restoreFlashSale($id);
|
|
||||||
|
|
||||||
$location = $this->request->getHTTPReferer();
|
|
||||||
|
|
||||||
$content = [
|
|
||||||
'location' => $location,
|
|
||||||
'msg' => '还原商品成功',
|
|
||||||
];
|
|
||||||
|
|
||||||
return $this->jsonSuccess($content);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -23,7 +23,7 @@ class QuestionController extends Controller
|
|||||||
{
|
{
|
||||||
$location = $this->url->get(
|
$location = $this->url->get(
|
||||||
['for' => 'admin.category.list'],
|
['for' => 'admin.category.list'],
|
||||||
['type' => CategoryModel::TYPE_ARTICLE]
|
['type' => CategoryModel::TYPE_QUESTION]
|
||||||
);
|
);
|
||||||
|
|
||||||
return $this->response->redirect($location);
|
return $this->response->redirect($location);
|
||||||
@ -37,12 +37,10 @@ class QuestionController extends Controller
|
|||||||
$questionService = new QuestionService();
|
$questionService = new QuestionService();
|
||||||
|
|
||||||
$publishTypes = $questionService->getPublishTypes();
|
$publishTypes = $questionService->getPublishTypes();
|
||||||
$categories = $questionService->getCategories();
|
$categoryOptions = $questionService->getCategoryOptions();
|
||||||
$xmTags = $questionService->getXmTags(0);
|
|
||||||
|
|
||||||
|
$this->view->setVar('category_options', $categoryOptions);
|
||||||
$this->view->setVar('publish_types', $publishTypes);
|
$this->view->setVar('publish_types', $publishTypes);
|
||||||
$this->view->setVar('categories', $categories);
|
|
||||||
$this->view->setVar('xm_tags', $xmTags);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -62,11 +60,7 @@ class QuestionController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function addAction()
|
public function addAction()
|
||||||
{
|
{
|
||||||
$questionService = new QuestionService();
|
|
||||||
|
|
||||||
$categories = $questionService->getCategories();
|
|
||||||
|
|
||||||
$this->view->setVar('categories', $categories);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -77,12 +71,12 @@ class QuestionController extends Controller
|
|||||||
$questionService = new QuestionService();
|
$questionService = new QuestionService();
|
||||||
|
|
||||||
$publishTypes = $questionService->getPublishTypes();
|
$publishTypes = $questionService->getPublishTypes();
|
||||||
$categories = $questionService->getCategories();
|
$categoryOptions = $questionService->getCategoryOptions();
|
||||||
$question = $questionService->getQuestion($id);
|
$question = $questionService->getQuestion($id);
|
||||||
$xmTags = $questionService->getXmTags($id);
|
$xmTags = $questionService->getXmTags($id);
|
||||||
|
|
||||||
$this->view->setVar('publish_types', $publishTypes);
|
$this->view->setVar('publish_types', $publishTypes);
|
||||||
$this->view->setVar('categories', $categories);
|
$this->view->setVar('category_options', $categoryOptions);
|
||||||
$this->view->setVar('question', $question);
|
$this->view->setVar('question', $question);
|
||||||
$this->view->setVar('xm_tags', $xmTags);
|
$this->view->setVar('xm_tags', $xmTags);
|
||||||
}
|
}
|
||||||
@ -225,4 +219,41 @@ class QuestionController extends Controller
|
|||||||
$this->view->setVar('reports', $reports);
|
$this->view->setVar('reports', $reports);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Post("/moderate/batch", name="admin.question.batch_moderate")
|
||||||
|
*/
|
||||||
|
public function batchModerateAction()
|
||||||
|
{
|
||||||
|
$questionService = new QuestionService();
|
||||||
|
|
||||||
|
$questionService->batchModerate();
|
||||||
|
|
||||||
|
$location = $this->url->get(['for' => 'admin.mod.questions']);
|
||||||
|
|
||||||
|
$content = [
|
||||||
|
'location' => $location,
|
||||||
|
'msg' => '批量审核成功',
|
||||||
|
];
|
||||||
|
|
||||||
|
return $this->jsonSuccess($content);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Post("/delete/batch", name="admin.question.batch_delete")
|
||||||
|
*/
|
||||||
|
public function batchDeleteAction()
|
||||||
|
{
|
||||||
|
$questionService = new QuestionService();
|
||||||
|
|
||||||
|
$questionService->batchDelete();
|
||||||
|
|
||||||
|
$content = [
|
||||||
|
'location' => $this->request->getHTTPReferer(),
|
||||||
|
'msg' => '批量删除成功',
|
||||||
|
];
|
||||||
|
|
||||||
|
return $this->jsonSuccess($content);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -23,8 +23,10 @@ class ReviewController extends Controller
|
|||||||
$reviewService = new ReviewService();
|
$reviewService = new ReviewService();
|
||||||
|
|
||||||
$publishTypes = $reviewService->getPublishTypes();
|
$publishTypes = $reviewService->getPublishTypes();
|
||||||
|
$xmCourses = $reviewService->getXmCourses();
|
||||||
|
|
||||||
$this->view->setVar('publish_types', $publishTypes);
|
$this->view->setVar('publish_types', $publishTypes);
|
||||||
|
$this->view->setVar('xm_courses', $xmCourses);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -56,8 +58,10 @@ class ReviewController extends Controller
|
|||||||
$reviewService = new ReviewService();
|
$reviewService = new ReviewService();
|
||||||
|
|
||||||
$review = $reviewService->getReview($id);
|
$review = $reviewService->getReview($id);
|
||||||
|
$publishTypes = $reviewService->getPublishTypes();
|
||||||
|
|
||||||
$this->view->setVar('review', $review);
|
$this->view->setVar('review', $review);
|
||||||
|
$this->view->setVar('publish_types', $publishTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -135,9 +139,47 @@ class ReviewController extends Controller
|
|||||||
return $this->jsonSuccess($content);
|
return $this->jsonSuccess($content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$reasons = $reviewService->getReasons();
|
||||||
$review = $reviewService->getReviewInfo($id);
|
$review = $reviewService->getReviewInfo($id);
|
||||||
|
|
||||||
|
$this->view->setVar('reasons', $reasons);
|
||||||
$this->view->setVar('review', $review);
|
$this->view->setVar('review', $review);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Post("/moderate/batch", name="admin.review.batch_moderate")
|
||||||
|
*/
|
||||||
|
public function batchModerateAction()
|
||||||
|
{
|
||||||
|
$reviewService = new ReviewService();
|
||||||
|
|
||||||
|
$reviewService->batchModerate();
|
||||||
|
|
||||||
|
$location = $this->url->get(['for' => 'admin.mod.reviews']);
|
||||||
|
|
||||||
|
$content = [
|
||||||
|
'location' => $location,
|
||||||
|
'msg' => '批量审核成功',
|
||||||
|
];
|
||||||
|
|
||||||
|
return $this->jsonSuccess($content);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Post("/delete/batch", name="admin.review.batch_delete")
|
||||||
|
*/
|
||||||
|
public function batchDeleteAction()
|
||||||
|
{
|
||||||
|
$reviewService = new ReviewService();
|
||||||
|
|
||||||
|
$reviewService->batchDelete();
|
||||||
|
|
||||||
|
$content = [
|
||||||
|
'location' => $this->request->getHTTPReferer(),
|
||||||
|
'msg' => '批量删除成功',
|
||||||
|
];
|
||||||
|
|
||||||
|
return $this->jsonSuccess($content);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,141 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* @copyright Copyright (c) 2021 深圳市酷瓜软件有限公司
|
|
||||||
* @license https://opensource.org/licenses/GPL-2.0
|
|
||||||
* @link https://www.koogua.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace App\Http\Admin\Controllers;
|
|
||||||
|
|
||||||
use App\Http\Admin\Services\Student as StudentService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @RoutePrefix("/admin/student")
|
|
||||||
*/
|
|
||||||
class StudentController extends Controller
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Get("/search", name="admin.student.search")
|
|
||||||
*/
|
|
||||||
public function searchAction()
|
|
||||||
{
|
|
||||||
$courseId = $this->request->getQuery('course_id', 'int', 0);
|
|
||||||
|
|
||||||
$studentService = new StudentService();
|
|
||||||
|
|
||||||
$sourceTypes = $studentService->getSourceTypes();
|
|
||||||
|
|
||||||
$xmCourses = $studentService->getXmCourses('all', $courseId);
|
|
||||||
|
|
||||||
$this->view->setVar('source_types', $sourceTypes);
|
|
||||||
$this->view->setVar('xm_courses', $xmCourses);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Get("/list", name="admin.student.list")
|
|
||||||
*/
|
|
||||||
public function listAction()
|
|
||||||
{
|
|
||||||
$courseId = $this->request->getQuery('course_id', 'int', 0);
|
|
||||||
|
|
||||||
$studentService = new StudentService();
|
|
||||||
|
|
||||||
$pager = $studentService->getRelations();
|
|
||||||
|
|
||||||
$course = null;
|
|
||||||
|
|
||||||
if ($courseId > 0) {
|
|
||||||
$course = $studentService->getCourse($courseId);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->view->setVar('pager', $pager);
|
|
||||||
$this->view->setVar('course', $course);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Get("/add", name="admin.student.add")
|
|
||||||
*/
|
|
||||||
public function addAction()
|
|
||||||
{
|
|
||||||
$courseId = $this->request->getQuery('course_id', 'int', 0);
|
|
||||||
|
|
||||||
$studentService = new StudentService();
|
|
||||||
|
|
||||||
$xmCourses = $studentService->getXmCourses('all', $courseId);
|
|
||||||
|
|
||||||
$this->view->setVar('xm_courses', $xmCourses);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Post("/create", name="admin.student.create")
|
|
||||||
*/
|
|
||||||
public function createAction()
|
|
||||||
{
|
|
||||||
$studentService = new StudentService();
|
|
||||||
|
|
||||||
$student = $studentService->createRelation();
|
|
||||||
|
|
||||||
$location = $this->url->get(
|
|
||||||
['for' => 'admin.student.list'],
|
|
||||||
['course_id' => $student->course_id]
|
|
||||||
);
|
|
||||||
|
|
||||||
$content = [
|
|
||||||
'location' => $location,
|
|
||||||
'msg' => '添加学员成功',
|
|
||||||
];
|
|
||||||
|
|
||||||
return $this->jsonSuccess($content);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Get("/edit", name="admin.student.edit")
|
|
||||||
*/
|
|
||||||
public function editAction()
|
|
||||||
{
|
|
||||||
$relationId = $this->request->getQuery('relation_id', 'int');
|
|
||||||
|
|
||||||
$studentService = new StudentService();
|
|
||||||
|
|
||||||
$relation = $studentService->getRelation($relationId);
|
|
||||||
$course = $studentService->getCourse($relation->course_id);
|
|
||||||
$student = $studentService->getStudent($relation->user_id);
|
|
||||||
|
|
||||||
$this->view->setVar('relation', $relation);
|
|
||||||
$this->view->setVar('course', $course);
|
|
||||||
$this->view->setVar('student', $student);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Post("/update", name="admin.student.update")
|
|
||||||
*/
|
|
||||||
public function updateAction()
|
|
||||||
{
|
|
||||||
$studentService = new StudentService();
|
|
||||||
|
|
||||||
$studentService->updateRelation();
|
|
||||||
|
|
||||||
$location = $this->url->get(['for' => 'admin.student.list']);
|
|
||||||
|
|
||||||
$content = [
|
|
||||||
'location' => $location,
|
|
||||||
'msg' => '更新学员成功',
|
|
||||||
];
|
|
||||||
|
|
||||||
return $this->jsonSuccess($content);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @Get("/learning", name="admin.student.learning")
|
|
||||||
*/
|
|
||||||
public function learningAction()
|
|
||||||
{
|
|
||||||
$studentService = new StudentService();
|
|
||||||
|
|
||||||
$pager = $studentService->getLearnings();
|
|
||||||
|
|
||||||
$this->view->setVar('pager', $pager);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
126
app/Http/Admin/Controllers/VipController.php
Normal file
126
app/Http/Admin/Controllers/VipController.php
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @copyright Copyright (c) 2021 深圳市酷瓜软件有限公司
|
||||||
|
* @license https://opensource.org/licenses/GPL-2.0
|
||||||
|
* @link https://www.koogua.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Admin\Controllers;
|
||||||
|
|
||||||
|
use App\Http\Admin\Services\Vip as VipService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @RoutePrefix("/admin/vip")
|
||||||
|
*/
|
||||||
|
class VipController extends Controller
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Get("/list", name="admin.vip.list")
|
||||||
|
*/
|
||||||
|
public function listAction()
|
||||||
|
{
|
||||||
|
$vipService = new VipService();
|
||||||
|
|
||||||
|
$pager = $vipService->getVips();
|
||||||
|
|
||||||
|
$this->view->setVar('pager', $pager);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Get("/add", name="admin.vip.add")
|
||||||
|
*/
|
||||||
|
public function addAction()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Post("/create", name="admin.vip.create")
|
||||||
|
*/
|
||||||
|
public function createAction()
|
||||||
|
{
|
||||||
|
$vipService = new VipService();
|
||||||
|
|
||||||
|
$vipService->createVip();
|
||||||
|
|
||||||
|
$location = $this->url->get(['for' => 'admin.vip.list']);
|
||||||
|
|
||||||
|
$content = [
|
||||||
|
'location' => $location,
|
||||||
|
'msg' => '创建套餐成功',
|
||||||
|
];
|
||||||
|
|
||||||
|
return $this->jsonSuccess($content);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Get("/{id:[0-9]+}/edit", name="admin.vip.edit")
|
||||||
|
*/
|
||||||
|
public function editAction($id)
|
||||||
|
{
|
||||||
|
$vipService = new VipService();
|
||||||
|
|
||||||
|
$vip = $vipService->getVip($id);
|
||||||
|
|
||||||
|
$this->view->setVar('vip', $vip);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Post("/{id:[0-9]+}/update", name="admin.vip.update")
|
||||||
|
*/
|
||||||
|
public function updateAction($id)
|
||||||
|
{
|
||||||
|
$vipService = new VipService();
|
||||||
|
|
||||||
|
$vipService->updateVip($id);
|
||||||
|
|
||||||
|
$location = $this->url->get(['for' => 'admin.vip.list']);
|
||||||
|
|
||||||
|
$content = [
|
||||||
|
'location' => $location,
|
||||||
|
'msg' => '更新套餐成功',
|
||||||
|
];
|
||||||
|
|
||||||
|
return $this->jsonSuccess($content);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Post("/{id:[0-9]+}/delete", name="admin.vip.delete")
|
||||||
|
*/
|
||||||
|
public function deleteAction($id)
|
||||||
|
{
|
||||||
|
$vipService = new VipService();
|
||||||
|
|
||||||
|
$vipService->deleteVip($id);
|
||||||
|
|
||||||
|
$location = $this->request->getHTTPReferer();
|
||||||
|
|
||||||
|
$content = [
|
||||||
|
'location' => $location,
|
||||||
|
'msg' => '删除套餐成功',
|
||||||
|
];
|
||||||
|
|
||||||
|
return $this->jsonSuccess($content);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Post("/{id:[0-9]+}/restore", name="admin.vip.restore")
|
||||||
|
*/
|
||||||
|
public function restoreAction($id)
|
||||||
|
{
|
||||||
|
$vipService = new VipService();
|
||||||
|
|
||||||
|
$vipService->restoreVip($id);
|
||||||
|
|
||||||
|
$location = $this->request->getHTTPReferer();
|
||||||
|
|
||||||
|
$content = [
|
||||||
|
'location' => $location,
|
||||||
|
'msg' => '还原套餐成功',
|
||||||
|
];
|
||||||
|
|
||||||
|
return $this->jsonSuccess($content);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -213,30 +213,15 @@ class Answer extends Service
|
|||||||
$reason = $this->request->getPost('reason', ['trim', 'string']);
|
$reason = $this->request->getPost('reason', ['trim', 'string']);
|
||||||
|
|
||||||
$answer = $this->findOrFail($id);
|
$answer = $this->findOrFail($id);
|
||||||
|
|
||||||
$validator = new AnswerValidator();
|
|
||||||
|
|
||||||
if ($type == 'approve') {
|
|
||||||
$answer->published = AnswerModel::PUBLISH_APPROVED;
|
|
||||||
} elseif ($type == 'reject') {
|
|
||||||
$validator->checkRejectReason($reason);
|
|
||||||
$answer->published = AnswerModel::PUBLISH_REJECTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
$answer->update();
|
|
||||||
|
|
||||||
$question = $this->findQuestion($answer->question_id);
|
$question = $this->findQuestion($answer->question_id);
|
||||||
|
|
||||||
$this->recountQuestionAnswers($question);
|
|
||||||
|
|
||||||
$owner = $this->findUser($answer->owner_id);
|
$owner = $this->findUser($answer->owner_id);
|
||||||
|
|
||||||
$this->recountUserAnswers($owner);
|
|
||||||
|
|
||||||
$sender = $this->getLoginUser();
|
$sender = $this->getLoginUser();
|
||||||
|
|
||||||
if ($type == 'approve') {
|
if ($type == 'approve') {
|
||||||
|
|
||||||
|
$answer->published = AnswerModel::PUBLISH_APPROVED;
|
||||||
|
$answer->update();
|
||||||
|
|
||||||
if ($answer->owner_id != $question->owner_id) {
|
if ($answer->owner_id != $question->owner_id) {
|
||||||
$this->handleAnswerPostPoint($answer);
|
$this->handleAnswerPostPoint($answer);
|
||||||
$this->handleQuestionAnsweredNotice($answer);
|
$this->handleQuestionAnsweredNotice($answer);
|
||||||
@ -248,17 +233,17 @@ class Answer extends Service
|
|||||||
|
|
||||||
} elseif ($type == 'reject') {
|
} elseif ($type == 'reject') {
|
||||||
|
|
||||||
$options = ReasonModel::answerRejectOptions();
|
$answer->published = AnswerModel::PUBLISH_REJECTED;
|
||||||
|
$answer->update();
|
||||||
if (array_key_exists($reason, $options)) {
|
|
||||||
$reason = $options[$reason];
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->handleAnswerRejectedNotice($answer, $sender, $reason);
|
$this->handleAnswerRejectedNotice($answer, $sender, $reason);
|
||||||
|
|
||||||
$this->eventsManager->fire('Answer:afterReject', $this, $answer);
|
$this->eventsManager->fire('Answer:afterReject', $this, $answer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->recountQuestionAnswers($question);
|
||||||
|
$this->recountUserAnswers($owner);
|
||||||
|
|
||||||
return $answer;
|
return $answer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -298,6 +283,78 @@ class Answer extends Service
|
|||||||
$this->recountUserAnswers($user);
|
$this->recountUserAnswers($user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function batchModerate()
|
||||||
|
{
|
||||||
|
$type = $this->request->getQuery('type', ['trim', 'string']);
|
||||||
|
$ids = $this->request->getPost('ids', ['trim', 'int']);
|
||||||
|
|
||||||
|
$answerRepo = new AnswerRepo();
|
||||||
|
|
||||||
|
$answers = $answerRepo->findByIds($ids);
|
||||||
|
|
||||||
|
if ($answers->count() == 0) return;
|
||||||
|
|
||||||
|
$sender = $this->getLoginUser();
|
||||||
|
|
||||||
|
foreach ($answers as $answer) {
|
||||||
|
|
||||||
|
$question = $this->findQuestion($answer->question_id);
|
||||||
|
$owner = $this->findUser($answer->owner_id);
|
||||||
|
|
||||||
|
if ($type == 'approve') {
|
||||||
|
|
||||||
|
$answer->published = AnswerModel::PUBLISH_APPROVED;
|
||||||
|
$answer->update();
|
||||||
|
|
||||||
|
if ($answer->owner_id != $question->owner_id) {
|
||||||
|
$this->handleAnswerPostPoint($answer);
|
||||||
|
$this->handleQuestionAnsweredNotice($answer);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->handleAnswerApprovedNotice($answer, $sender);
|
||||||
|
|
||||||
|
} elseif ($type == 'reject') {
|
||||||
|
|
||||||
|
$answer->published = AnswerModel::PUBLISH_REJECTED;
|
||||||
|
$answer->update();
|
||||||
|
|
||||||
|
$this->handleAnswerRejectedNotice($answer, $sender, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->recountQuestionAnswers($question);
|
||||||
|
$this->recountUserAnswers($owner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function batchDelete()
|
||||||
|
{
|
||||||
|
$ids = $this->request->getPost('ids', ['trim', 'int']);
|
||||||
|
|
||||||
|
$answerRepo = new AnswerRepo();
|
||||||
|
|
||||||
|
$answers = $answerRepo->findByIds($ids);
|
||||||
|
|
||||||
|
if ($answers->count() == 0) return;
|
||||||
|
|
||||||
|
$sender = $this->getLoginUser();
|
||||||
|
|
||||||
|
foreach ($answers as $answer) {
|
||||||
|
|
||||||
|
$answer->deleted = 1;
|
||||||
|
$answer->update();
|
||||||
|
|
||||||
|
$this->handleAnswerDeletedNotice($answer, $sender);
|
||||||
|
|
||||||
|
$question = $this->findQuestion($answer->question_id);
|
||||||
|
|
||||||
|
$this->recountQuestionAnswers($question);
|
||||||
|
|
||||||
|
$owner = $this->findUser($answer->owner_id);
|
||||||
|
|
||||||
|
$this->recountUserAnswers($owner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected function findOrFail($id)
|
protected function findOrFail($id)
|
||||||
{
|
{
|
||||||
$validator = new AnswerValidator();
|
$validator = new AnswerValidator();
|
||||||
@ -390,7 +447,7 @@ class Answer extends Service
|
|||||||
$notice->handle($answer, $sender);
|
$notice->handle($answer, $sender);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function handleAnswerRejectedNotice(AnswerModel $answer, UserModel $sender, $reason)
|
protected function handleAnswerRejectedNotice(AnswerModel $answer, UserModel $sender, $reason = '')
|
||||||
{
|
{
|
||||||
$notice = new AnswerRejectedNotice();
|
$notice = new AnswerRejectedNotice();
|
||||||
|
|
||||||
@ -398,6 +455,11 @@ class Answer extends Service
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function handleAnswerDeletedNotice(AnswerModel $answer, UserModel $sender, $reason = '')
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
protected function handleAnswerPostPoint(AnswerModel $answer)
|
protected function handleAnswerPostPoint(AnswerModel $answer)
|
||||||
{
|
{
|
||||||
$service = new AnswerPostPointHistory();
|
$service = new AnswerPostPointHistory();
|
||||||
|
@ -18,9 +18,9 @@ use App\Models\Reason as ReasonModel;
|
|||||||
use App\Models\Report as ReportModel;
|
use App\Models\Report as ReportModel;
|
||||||
use App\Models\User as UserModel;
|
use App\Models\User as UserModel;
|
||||||
use App\Repos\Article as ArticleRepo;
|
use App\Repos\Article as ArticleRepo;
|
||||||
use App\Repos\Category as CategoryRepo;
|
|
||||||
use App\Repos\Report as ReportRepo;
|
use App\Repos\Report as ReportRepo;
|
||||||
use App\Repos\User as UserRepo;
|
use App\Repos\User as UserRepo;
|
||||||
|
use App\Services\Category as CategoryService;
|
||||||
use App\Services\Logic\Article\ArticleDataTrait;
|
use App\Services\Logic\Article\ArticleDataTrait;
|
||||||
use App\Services\Logic\Article\ArticleInfo as ArticleInfoService;
|
use App\Services\Logic\Article\ArticleInfo as ArticleInfoService;
|
||||||
use App\Services\Logic\Article\XmTagList as XmTagListService;
|
use App\Services\Logic\Article\XmTagList as XmTagListService;
|
||||||
@ -42,16 +42,11 @@ class Article extends Service
|
|||||||
return $service->handle($id);
|
return $service->handle($id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCategories()
|
public function getCategoryOptions()
|
||||||
{
|
{
|
||||||
$categoryRepo = new CategoryRepo();
|
$categoryService = new CategoryService();
|
||||||
|
|
||||||
return $categoryRepo->findAll([
|
return $categoryService->getCategoryOptions(CategoryModel::TYPE_ARTICLE);
|
||||||
'type' => CategoryModel::TYPE_ARTICLE,
|
|
||||||
'level' => 1,
|
|
||||||
'published' => 1,
|
|
||||||
'deleted' => 0,
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPublishTypes()
|
public function getPublishTypes()
|
||||||
@ -161,15 +156,18 @@ class Article extends Service
|
|||||||
|
|
||||||
$data = [];
|
$data = [];
|
||||||
|
|
||||||
if (isset($post['category_id'])) {
|
|
||||||
$category = $validator->checkCategory($post['category_id']);
|
|
||||||
$data['category_id'] = $category->id;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($post['title'])) {
|
if (isset($post['title'])) {
|
||||||
$data['title'] = $validator->checkTitle($post['title']);
|
$data['title'] = $validator->checkTitle($post['title']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isset($post['cover'])) {
|
||||||
|
$data['cover'] = $validator->checkCover($post['cover']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($post['summary'])) {
|
||||||
|
$data['summary'] = $validator->checkSummary($post['summary']);
|
||||||
|
}
|
||||||
|
|
||||||
if (isset($post['keywords'])) {
|
if (isset($post['keywords'])) {
|
||||||
$data['keywords'] = $validator->checkKeywords($post['keywords']);
|
$data['keywords'] = $validator->checkKeywords($post['keywords']);
|
||||||
}
|
}
|
||||||
@ -186,22 +184,23 @@ class Article extends Service
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($post['closed'])) {
|
|
||||||
$data['closed'] = $validator->checkCloseStatus($post['closed']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($post['private'])) {
|
|
||||||
$data['private'] = $validator->checkPrivateStatus($post['private']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($post['featured'])) {
|
if (isset($post['featured'])) {
|
||||||
$data['featured'] = $validator->checkFeatureStatus($post['featured']);
|
$data['featured'] = $validator->checkFeatureStatus($post['featured']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isset($post['closed'])) {
|
||||||
|
$data['closed'] = $validator->checkCloseStatus($post['closed']);
|
||||||
|
}
|
||||||
|
|
||||||
if (isset($post['published'])) {
|
if (isset($post['published'])) {
|
||||||
$data['published'] = $validator->checkPublishStatus($post['published']);
|
$data['published'] = $validator->checkPublishStatus($post['published']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isset($post['category_id'])) {
|
||||||
|
$category = $validator->checkCategory($post['category_id']);
|
||||||
|
$data['category_id'] = $category->id;
|
||||||
|
}
|
||||||
|
|
||||||
if (isset($post['xm_tag_ids'])) {
|
if (isset($post['xm_tag_ids'])) {
|
||||||
$this->saveTags($article, $post['xm_tag_ids']);
|
$this->saveTags($article, $post['xm_tag_ids']);
|
||||||
}
|
}
|
||||||
@ -266,31 +265,12 @@ class Article extends Service
|
|||||||
$reason = $this->request->getPost('reason', ['trim', 'string']);
|
$reason = $this->request->getPost('reason', ['trim', 'string']);
|
||||||
|
|
||||||
$article = $this->findOrFail($id);
|
$article = $this->findOrFail($id);
|
||||||
|
$sender = $this->getLoginUser();
|
||||||
$validator = new ArticleValidator();
|
|
||||||
|
|
||||||
if ($type == 'approve') {
|
if ($type == 'approve') {
|
||||||
|
|
||||||
$article->published = ArticleModel::PUBLISH_APPROVED;
|
$article->published = ArticleModel::PUBLISH_APPROVED;
|
||||||
|
$article->update();
|
||||||
} elseif ($type == 'reject') {
|
|
||||||
|
|
||||||
$validator->checkRejectReason($reason);
|
|
||||||
|
|
||||||
$article->published = ArticleModel::PUBLISH_REJECTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
$article->update();
|
|
||||||
|
|
||||||
$owner = $this->findUser($article->owner_id);
|
|
||||||
|
|
||||||
$this->rebuildArticleCache($article);
|
|
||||||
$this->rebuildArticleIndex($article);
|
|
||||||
$this->recountUserArticles($owner);
|
|
||||||
|
|
||||||
$sender = $this->getLoginUser();
|
|
||||||
|
|
||||||
if ($type == 'approve') {
|
|
||||||
|
|
||||||
$this->handleArticlePostPoint($article);
|
$this->handleArticlePostPoint($article);
|
||||||
$this->handleArticleApprovedNotice($article, $sender);
|
$this->handleArticleApprovedNotice($article, $sender);
|
||||||
@ -299,17 +279,20 @@ class Article extends Service
|
|||||||
|
|
||||||
} elseif ($type == 'reject') {
|
} elseif ($type == 'reject') {
|
||||||
|
|
||||||
$options = ReasonModel::articleRejectOptions();
|
$article->published = ArticleModel::PUBLISH_REJECTED;
|
||||||
|
$article->update();
|
||||||
if (array_key_exists($reason, $options)) {
|
|
||||||
$reason = $options[$reason];
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->handleArticleRejectedNotice($article, $sender, $reason);
|
$this->handleArticleRejectedNotice($article, $sender, $reason);
|
||||||
|
|
||||||
$this->eventsManager->fire('Article:afterReject', $this, $article);
|
$this->eventsManager->fire('Article:afterReject', $this, $article);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$owner = $this->findUser($article->owner_id);
|
||||||
|
|
||||||
|
$this->rebuildArticleCache($article);
|
||||||
|
$this->rebuildArticleIndex($article);
|
||||||
|
$this->recountUserArticles($owner);
|
||||||
|
|
||||||
return $article;
|
return $article;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -347,6 +330,72 @@ class Article extends Service
|
|||||||
$this->recountUserArticles($owner);
|
$this->recountUserArticles($owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function batchModerate()
|
||||||
|
{
|
||||||
|
$type = $this->request->getQuery('type', ['trim', 'string']);
|
||||||
|
$ids = $this->request->getPost('ids', ['trim', 'int']);
|
||||||
|
|
||||||
|
$articleRepo = new ArticleRepo();
|
||||||
|
|
||||||
|
$articles = $articleRepo->findByIds($ids);
|
||||||
|
|
||||||
|
if ($articles->count() == 0) return;
|
||||||
|
|
||||||
|
$sender = $this->getLoginUser();
|
||||||
|
|
||||||
|
foreach ($articles as $article) {
|
||||||
|
|
||||||
|
if ($type == 'approve') {
|
||||||
|
|
||||||
|
$article->published = ArticleModel::PUBLISH_APPROVED;
|
||||||
|
$article->update();
|
||||||
|
|
||||||
|
$this->handleArticlePostPoint($article);
|
||||||
|
$this->handleArticleApprovedNotice($article, $sender);
|
||||||
|
|
||||||
|
} elseif ($type == 'reject') {
|
||||||
|
|
||||||
|
$article->published = ArticleModel::PUBLISH_REJECTED;
|
||||||
|
$article->update();
|
||||||
|
|
||||||
|
$this->handleArticleRejectedNotice($article, $sender);
|
||||||
|
}
|
||||||
|
|
||||||
|
$owner = $this->findUser($article->owner_id);
|
||||||
|
|
||||||
|
$this->recountUserArticles($owner);
|
||||||
|
$this->rebuildArticleCache($article);
|
||||||
|
$this->rebuildArticleIndex($article);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function batchDelete()
|
||||||
|
{
|
||||||
|
$ids = $this->request->getPost('ids', ['trim', 'int']);
|
||||||
|
|
||||||
|
$articleRepo = new ArticleRepo();
|
||||||
|
|
||||||
|
$articles = $articleRepo->findByIds($ids);
|
||||||
|
|
||||||
|
if ($articles->count() == 0) return;
|
||||||
|
|
||||||
|
$sender = $this->getLoginUser();
|
||||||
|
|
||||||
|
foreach ($articles as $article) {
|
||||||
|
|
||||||
|
$article->deleted = 1;
|
||||||
|
$article->update();
|
||||||
|
|
||||||
|
$this->handleArticleDeletedNotice($article, $sender);
|
||||||
|
|
||||||
|
$owner = $this->findUser($article->owner_id);
|
||||||
|
|
||||||
|
$this->recountUserArticles($owner);
|
||||||
|
$this->rebuildArticleCache($article);
|
||||||
|
$this->rebuildArticleIndex($article);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected function findOrFail($id)
|
protected function findOrFail($id)
|
||||||
{
|
{
|
||||||
$validator = new ArticleValidator();
|
$validator = new ArticleValidator();
|
||||||
@ -402,13 +451,18 @@ class Article extends Service
|
|||||||
$notice->handle($article, $sender);
|
$notice->handle($article, $sender);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function handleArticleRejectedNotice(ArticleModel $article, UserModel $sender, $reason)
|
protected function handleArticleRejectedNotice(ArticleModel $article, UserModel $sender, $reason = '')
|
||||||
{
|
{
|
||||||
$notice = new ArticleRejectedNotice();
|
$notice = new ArticleRejectedNotice();
|
||||||
|
|
||||||
$notice->handle($article, $sender, $reason);
|
$notice->handle($article, $sender, $reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function handleArticleDeletedNotice(ArticleModel $article, UserModel $sender, $reason = '')
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
protected function handleArticles($pager)
|
protected function handleArticles($pager)
|
||||||
{
|
{
|
||||||
if ($pager->total_items > 0) {
|
if ($pager->total_items > 0) {
|
||||||
|
@ -55,6 +55,80 @@ class AuthNode extends Service
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
'id' => '1-6',
|
||||||
|
'title' => '文章管理',
|
||||||
|
'type' => 'menu',
|
||||||
|
'children' => [
|
||||||
|
[
|
||||||
|
'id' => '1-6-1',
|
||||||
|
'title' => '文章列表',
|
||||||
|
'type' => 'menu',
|
||||||
|
'route' => 'admin.article.list',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => '1-6-2',
|
||||||
|
'title' => '搜索文章',
|
||||||
|
'type' => 'menu',
|
||||||
|
'route' => 'admin.article.search',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => '1-6-3',
|
||||||
|
'title' => '添加文章',
|
||||||
|
'type' => 'menu',
|
||||||
|
'route' => 'admin.article.add',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => '1-6-4',
|
||||||
|
'title' => '编辑文章',
|
||||||
|
'type' => 'button',
|
||||||
|
'route' => 'admin.article.edit',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => '1-6-5',
|
||||||
|
'title' => '删除文章',
|
||||||
|
'type' => 'button',
|
||||||
|
'route' => 'admin.article.delete',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => '1-6-6',
|
||||||
|
'title' => '文章详情',
|
||||||
|
'type' => 'button',
|
||||||
|
'route' => 'admin.article.show',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => '1-6-7',
|
||||||
|
'title' => '审核文章',
|
||||||
|
'type' => 'button',
|
||||||
|
'route' => 'admin.article.moderate',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => '1-6-8',
|
||||||
|
'title' => '审核举报',
|
||||||
|
'type' => 'button',
|
||||||
|
'route' => 'admin.article.report',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => '1-7',
|
||||||
|
'title' => '问答管理',
|
||||||
|
'type' => 'menu',
|
||||||
|
'children' => [
|
||||||
|
[
|
||||||
|
'id' => '1-7-1',
|
||||||
|
'title' => '问题列表',
|
||||||
|
'type' => 'menu',
|
||||||
|
'route' => 'admin.question.list',
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'id' => '1-7-2',
|
||||||
|
'title' => '答案列表',
|
||||||
|
'type' => 'menu',
|
||||||
|
'route' => 'admin.answer.list',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
[
|
[
|
||||||
'id' => '1-2',
|
'id' => '1-2',
|
||||||
'title' => '导航管理',
|
'title' => '导航管理',
|
||||||
@ -191,80 +265,6 @@ class AuthNode extends Service
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
[
|
|
||||||
'id' => '1-6',
|
|
||||||
'title' => '文章管理',
|
|
||||||
'type' => 'menu',
|
|
||||||
'children' => [
|
|
||||||
[
|
|
||||||
'id' => '1-6-1',
|
|
||||||
'title' => '文章列表',
|
|
||||||
'type' => 'menu',
|
|
||||||
'route' => 'admin.article.list',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'id' => '1-6-2',
|
|
||||||
'title' => '搜索文章',
|
|
||||||
'type' => 'menu',
|
|
||||||
'route' => 'admin.article.search',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'id' => '1-6-3',
|
|
||||||
'title' => '添加文章',
|
|
||||||
'type' => 'menu',
|
|
||||||
'route' => 'admin.article.add',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'id' => '1-6-4',
|
|
||||||
'title' => '编辑文章',
|
|
||||||
'type' => 'button',
|
|
||||||
'route' => 'admin.article.edit',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'id' => '1-6-5',
|
|
||||||
'title' => '删除文章',
|
|
||||||
'type' => 'button',
|
|
||||||
'route' => 'admin.article.delete',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'id' => '1-6-6',
|
|
||||||
'title' => '文章详情',
|
|
||||||
'type' => 'button',
|
|
||||||
'route' => 'admin.article.show',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'id' => '1-6-7',
|
|
||||||
'title' => '审核文章',
|
|
||||||
'type' => 'button',
|
|
||||||
'route' => 'admin.article.moderate',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'id' => '1-6-8',
|
|
||||||
'title' => '审核举报',
|
|
||||||
'type' => 'button',
|
|
||||||
'route' => 'admin.article.report',
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'id' => '1-7',
|
|
||||||
'title' => '问答管理',
|
|
||||||
'type' => 'menu',
|
|
||||||
'children' => [
|
|
||||||
[
|
|
||||||
'id' => '1-7-1',
|
|
||||||
'title' => '问题列表',
|
|
||||||
'type' => 'menu',
|
|
||||||
'route' => 'admin.question.list',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'id' => '1-7-2',
|
|
||||||
'title' => '答案列表',
|
|
||||||
'type' => 'menu',
|
|
||||||
'route' => 'admin.answer.list',
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
[
|
[
|
||||||
'id' => '1-20',
|
'id' => '1-20',
|
||||||
'title' => '分类管理',
|
'title' => '分类管理',
|
||||||
@ -624,7 +624,7 @@ class AuthNode extends Service
|
|||||||
'id' => '2-2-1',
|
'id' => '2-2-1',
|
||||||
'title' => '会员套餐',
|
'title' => '会员套餐',
|
||||||
'type' => 'menu',
|
'type' => 'menu',
|
||||||
'route' => 'admin.setting.vip',
|
'route' => 'admin.vip.list',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => '2-2-2',
|
'id' => '2-2-2',
|
||||||
@ -632,43 +632,6 @@ class AuthNode extends Service
|
|||||||
'type' => 'menu',
|
'type' => 'menu',
|
||||||
'route' => 'admin.point_gift.list',
|
'route' => 'admin.point_gift.list',
|
||||||
],
|
],
|
||||||
[
|
|
||||||
'id' => '2-2-3',
|
|
||||||
'title' => '限时秒杀',
|
|
||||||
'type' => 'menu',
|
|
||||||
'route' => 'admin.flash_sale.list',
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'id' => '2-3',
|
|
||||||
'title' => '学员管理',
|
|
||||||
'type' => 'menu',
|
|
||||||
'children' => [
|
|
||||||
[
|
|
||||||
'id' => '2-3-1',
|
|
||||||
'title' => '学员列表',
|
|
||||||
'type' => 'menu',
|
|
||||||
'route' => 'admin.student.list',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'id' => '2-3-2',
|
|
||||||
'title' => '搜索学员',
|
|
||||||
'type' => 'menu',
|
|
||||||
'route' => 'admin.student.search',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'id' => '2-3-3',
|
|
||||||
'title' => '添加学员',
|
|
||||||
'type' => 'menu',
|
|
||||||
'route' => 'admin.student.add',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'id' => '2-3-4',
|
|
||||||
'title' => '编辑学员',
|
|
||||||
'type' => 'button',
|
|
||||||
'route' => 'admin.student.edit',
|
|
||||||
],
|
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
@ -901,38 +864,32 @@ class AuthNode extends Service
|
|||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => '2-21',
|
'id' => '2-21',
|
||||||
'title' => '限时秒杀',
|
'title' => '会员套餐',
|
||||||
'type' => 'button',
|
'type' => 'button',
|
||||||
'children' => [
|
'children' => [
|
||||||
[
|
[
|
||||||
'id' => '2-21-1',
|
'id' => '2-21-1',
|
||||||
'title' => '商品列表',
|
'title' => '套餐列表',
|
||||||
'type' => 'button',
|
'type' => 'button',
|
||||||
'route' => 'admin.flash_sale.list',
|
'route' => 'admin.vip.list',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => '2-21-2',
|
'id' => '2-21-2',
|
||||||
'title' => '添加商品',
|
'title' => '添加套餐',
|
||||||
'type' => 'button',
|
'type' => 'button',
|
||||||
'route' => 'admin.flash_sale.add',
|
'route' => 'admin.vip.add',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => '2-21-3',
|
'id' => '2-21-3',
|
||||||
'title' => '搜索商品',
|
'title' => '编辑套餐',
|
||||||
'type' => 'button',
|
'type' => 'button',
|
||||||
'route' => 'admin.flash_sale.search',
|
'route' => 'admin.vip.edit',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'id' => '2-21-4',
|
'id' => '2-21-4',
|
||||||
'title' => '编辑商品',
|
'title' => '删除套餐',
|
||||||
'type' => 'button',
|
'type' => 'button',
|
||||||
'route' => 'admin.flash_sale.edit',
|
'route' => 'admin.vip.delete',
|
||||||
],
|
|
||||||
[
|
|
||||||
'id' => '2-21-5',
|
|
||||||
'title' => '删除商品',
|
|
||||||
'type' => 'button',
|
|
||||||
'route' => 'admin.flash_sale.delete',
|
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
namespace App\Http\Admin\Services;
|
namespace App\Http\Admin\Services;
|
||||||
|
|
||||||
use App\Caches\Category as CategoryCache;
|
use App\Caches\Category as CategoryCache;
|
||||||
|
use App\Caches\CategoryAllList as CategoryAllListCache;
|
||||||
use App\Caches\CategoryList as CategoryListCache;
|
use App\Caches\CategoryList as CategoryListCache;
|
||||||
use App\Caches\CategoryTreeList as CategoryTreeListCache;
|
use App\Caches\CategoryTreeList as CategoryTreeListCache;
|
||||||
use App\Models\Category as CategoryModel;
|
use App\Models\Category as CategoryModel;
|
||||||
@ -140,7 +141,6 @@ class Category extends Service
|
|||||||
$category->update();
|
$category->update();
|
||||||
|
|
||||||
$this->updateCategoryStats($category);
|
$this->updateCategoryStats($category);
|
||||||
|
|
||||||
$this->rebuildCategoryCache($category);
|
$this->rebuildCategoryCache($category);
|
||||||
|
|
||||||
return $category;
|
return $category;
|
||||||
@ -182,7 +182,6 @@ class Category extends Service
|
|||||||
$category->update($data);
|
$category->update($data);
|
||||||
|
|
||||||
$this->updateCategoryStats($category);
|
$this->updateCategoryStats($category);
|
||||||
|
|
||||||
$this->rebuildCategoryCache($category);
|
$this->rebuildCategoryCache($category);
|
||||||
|
|
||||||
return $category;
|
return $category;
|
||||||
@ -201,7 +200,6 @@ class Category extends Service
|
|||||||
$category->update();
|
$category->update();
|
||||||
|
|
||||||
$this->updateCategoryStats($category);
|
$this->updateCategoryStats($category);
|
||||||
|
|
||||||
$this->rebuildCategoryCache($category);
|
$this->rebuildCategoryCache($category);
|
||||||
|
|
||||||
return $category;
|
return $category;
|
||||||
@ -216,7 +214,6 @@ class Category extends Service
|
|||||||
$category->update();
|
$category->update();
|
||||||
|
|
||||||
$this->updateCategoryStats($category);
|
$this->updateCategoryStats($category);
|
||||||
|
|
||||||
$this->rebuildCategoryCache($category);
|
$this->rebuildCategoryCache($category);
|
||||||
|
|
||||||
return $category;
|
return $category;
|
||||||
@ -250,6 +247,10 @@ class Category extends Service
|
|||||||
$cache = new CategoryTreeListCache();
|
$cache = new CategoryTreeListCache();
|
||||||
|
|
||||||
$cache->rebuild($category->type);
|
$cache->rebuild($category->type);
|
||||||
|
|
||||||
|
$cache = new CategoryAllListCache();
|
||||||
|
|
||||||
|
$cache->rebuild($category->type);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function enableChildCategories($parentId)
|
protected function enableChildCategories($parentId)
|
||||||
|
@ -201,7 +201,9 @@ class Chapter extends Service
|
|||||||
}
|
}
|
||||||
|
|
||||||
$lessonCount = $chapterRepo->countLessons($chapter->id);
|
$lessonCount = $chapterRepo->countLessons($chapter->id);
|
||||||
|
|
||||||
$chapter->lesson_count = $lessonCount;
|
$chapter->lesson_count = $lessonCount;
|
||||||
|
|
||||||
$chapter->update();
|
$chapter->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ use App\Library\Paginator\Query as PagerQuery;
|
|||||||
use App\Models\Comment as CommentModel;
|
use App\Models\Comment as CommentModel;
|
||||||
use App\Models\Reason as ReasonModel;
|
use App\Models\Reason as ReasonModel;
|
||||||
use App\Models\Report as ReportModel;
|
use App\Models\Report as ReportModel;
|
||||||
|
use App\Models\User as UserModel;
|
||||||
use App\Repos\Comment as CommentRepo;
|
use App\Repos\Comment as CommentRepo;
|
||||||
use App\Repos\Report as ReportRepo;
|
use App\Repos\Report as ReportRepo;
|
||||||
use App\Repos\User as UserRepo;
|
use App\Repos\User as UserRepo;
|
||||||
@ -126,6 +127,12 @@ class Comment extends Service
|
|||||||
|
|
||||||
$this->decrUserCommentCount($owner);
|
$this->decrUserCommentCount($owner);
|
||||||
|
|
||||||
|
$sender = $this->getLoginUser();
|
||||||
|
|
||||||
|
$this->handleCommentDeletedNotice($comment, $sender);
|
||||||
|
|
||||||
|
$this->eventsManager->fire('Comment:afterDelete', $this, $comment);
|
||||||
|
|
||||||
return $comment;
|
return $comment;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,23 +171,14 @@ class Comment extends Service
|
|||||||
|
|
||||||
$validator = new CommentValidator();
|
$validator = new CommentValidator();
|
||||||
|
|
||||||
|
$sender = $this->getLoginUser();
|
||||||
|
|
||||||
if ($type == 'approve') {
|
if ($type == 'approve') {
|
||||||
|
|
||||||
$comment->published = CommentModel::PUBLISH_APPROVED;
|
$comment->published = CommentModel::PUBLISH_APPROVED;
|
||||||
|
$comment->update();
|
||||||
} elseif ($type == 'reject') {
|
|
||||||
|
|
||||||
$validator->checkRejectReason($reason);
|
|
||||||
|
|
||||||
$comment->published = CommentModel::PUBLISH_REJECTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
$comment->update();
|
|
||||||
|
|
||||||
if ($type == 'approve') {
|
|
||||||
|
|
||||||
$owner = $this->findUser($comment->owner_id);
|
$owner = $this->findUser($comment->owner_id);
|
||||||
|
|
||||||
$item = $validator->checkItem($comment->item_id, $comment->item_type);
|
$item = $validator->checkItem($comment->item_id, $comment->item_type);
|
||||||
|
|
||||||
$this->incrItemCommentCount($item);
|
$this->incrItemCommentCount($item);
|
||||||
@ -197,11 +195,17 @@ class Comment extends Service
|
|||||||
}
|
}
|
||||||
|
|
||||||
$this->handleCommentPostPoint($comment);
|
$this->handleCommentPostPoint($comment);
|
||||||
|
$this->handleCommentApprovedNotice($comment, $sender);
|
||||||
|
|
||||||
$this->eventsManager->fire('Comment:afterApprove', $this, $comment);
|
$this->eventsManager->fire('Comment:afterApprove', $this, $comment);
|
||||||
|
|
||||||
} elseif ($type == 'reject') {
|
} elseif ($type == 'reject') {
|
||||||
|
|
||||||
|
$comment->published = CommentModel::PUBLISH_REJECTED;
|
||||||
|
$comment->update();
|
||||||
|
|
||||||
|
$this->handleCommentRejectedNotice($comment, $sender, $reason);
|
||||||
|
|
||||||
$this->eventsManager->fire('Comment:afterReject', $this, $comment);
|
$this->eventsManager->fire('Comment:afterReject', $this, $comment);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,6 +240,93 @@ class Comment extends Service
|
|||||||
$comment->update();
|
$comment->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function batchModerate()
|
||||||
|
{
|
||||||
|
$type = $this->request->getQuery('type', ['trim', 'string']);
|
||||||
|
$ids = $this->request->getPost('ids', ['trim', 'int']);
|
||||||
|
|
||||||
|
$commentRepo = new CommentRepo();
|
||||||
|
|
||||||
|
$comments = $commentRepo->findByIds($ids);
|
||||||
|
|
||||||
|
if ($comments->count() == 0) return;
|
||||||
|
|
||||||
|
$validator = new CommentValidator();
|
||||||
|
|
||||||
|
$sender = $this->getLoginUser();
|
||||||
|
|
||||||
|
foreach ($comments as $comment) {
|
||||||
|
|
||||||
|
if ($type == 'approve') {
|
||||||
|
|
||||||
|
$owner = $this->findUser($comment->owner_id);
|
||||||
|
$item = $validator->checkItem($comment->item_id, $comment->item_type);
|
||||||
|
|
||||||
|
$this->incrItemCommentCount($item);
|
||||||
|
$this->incrUserCommentCount($owner);
|
||||||
|
|
||||||
|
$comment->published = CommentModel::PUBLISH_APPROVED;
|
||||||
|
$comment->update();
|
||||||
|
|
||||||
|
if ($comment->parent_id == 0) {
|
||||||
|
$this->handleItemCommentedNotice($item, $comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($comment->parent_id > 0) {
|
||||||
|
$parent = $validator->checkParent($comment->parent_id);
|
||||||
|
$this->incrCommentReplyCount($parent);
|
||||||
|
$this->handleCommentRepliedNotice($comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->handleCommentPostPoint($comment);
|
||||||
|
$this->handleCommentApprovedNotice($comment, $sender);
|
||||||
|
|
||||||
|
} elseif ($type == 'reject') {
|
||||||
|
|
||||||
|
$comment->published = CommentModel::PUBLISH_REJECTED;
|
||||||
|
$comment->update();
|
||||||
|
|
||||||
|
$this->handleCommentRejectedNotice($comment, $sender);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function batchDelete()
|
||||||
|
{
|
||||||
|
$ids = $this->request->getPost('ids', ['trim', 'int']);
|
||||||
|
|
||||||
|
$commentRepo = new CommentRepo();
|
||||||
|
|
||||||
|
$comments = $commentRepo->findByIds($ids);
|
||||||
|
|
||||||
|
if ($comments->count() == 0) return;
|
||||||
|
|
||||||
|
$validator = new CommentValidator();
|
||||||
|
|
||||||
|
$sender = $this->getLoginUser();
|
||||||
|
|
||||||
|
foreach ($comments as $comment) {
|
||||||
|
|
||||||
|
$comment->deleted = 1;
|
||||||
|
$comment->update();
|
||||||
|
|
||||||
|
if ($comment->parent_id > 0) {
|
||||||
|
$parent = $validator->checkParent($comment->parent_id);
|
||||||
|
$this->decrCommentReplyCount($parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->handleCommentDeletedNotice($comment, $sender);
|
||||||
|
|
||||||
|
$item = $validator->checkItem($comment->item_id, $comment->item_type);
|
||||||
|
|
||||||
|
$this->decrItemCommentCount($item);
|
||||||
|
|
||||||
|
$owner = $this->findUser($comment->owner_id);
|
||||||
|
|
||||||
|
$this->decrUserCommentCount($owner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected function findOrFail($id)
|
protected function findOrFail($id)
|
||||||
{
|
{
|
||||||
$validator = new CommentValidator();
|
$validator = new CommentValidator();
|
||||||
@ -250,6 +341,21 @@ class Comment extends Service
|
|||||||
return $userRepo->findById($id);
|
return $userRepo->findById($id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function handleCommentApprovedNotice(CommentModel $comment, UserModel $sender)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function handleCommentRejectedNotice(CommentModel $comment, UserModel $sender, $reason = '')
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function handleCommentDeletedNotice(CommentModel $comment, UserModel $sender, $reason = '')
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
protected function handleComments($pager)
|
protected function handleComments($pager)
|
||||||
{
|
{
|
||||||
if ($pager->total_items > 0) {
|
if ($pager->total_items > 0) {
|
||||||
|
@ -9,9 +9,13 @@ namespace App\Http\Admin\Services;
|
|||||||
|
|
||||||
use App\Builders\ConsultList as ConsultListBuilder;
|
use App\Builders\ConsultList as ConsultListBuilder;
|
||||||
use App\Library\Paginator\Query as PagerQuery;
|
use App\Library\Paginator\Query as PagerQuery;
|
||||||
|
use App\Library\Validators\Common as CommonValidator;
|
||||||
use App\Models\Chapter as ChapterModel;
|
use App\Models\Chapter as ChapterModel;
|
||||||
use App\Models\Consult as ConsultModel;
|
use App\Models\Consult as ConsultModel;
|
||||||
use App\Models\Course as CourseModel;
|
use App\Models\Course as CourseModel;
|
||||||
|
use App\Models\Reason as ReasonModel;
|
||||||
|
use App\Models\User as UserModel;
|
||||||
|
use App\Repos\Account as AccountRepo;
|
||||||
use App\Repos\Chapter as ChapterRepo;
|
use App\Repos\Chapter as ChapterRepo;
|
||||||
use App\Repos\Consult as ConsultRepo;
|
use App\Repos\Consult as ConsultRepo;
|
||||||
use App\Repos\Course as CourseRepo;
|
use App\Repos\Course as CourseRepo;
|
||||||
@ -27,6 +31,34 @@ class Consult extends Service
|
|||||||
return ConsultModel::publishTypes();
|
return ConsultModel::publishTypes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getReasons()
|
||||||
|
{
|
||||||
|
return ReasonModel::consultRejectOptions();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getXmCourses()
|
||||||
|
{
|
||||||
|
$courseRepo = new CourseRepo();
|
||||||
|
|
||||||
|
$items = $courseRepo->findAll([
|
||||||
|
'published' => 1,
|
||||||
|
'deleted' => 0,
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($items->count() == 0) return [];
|
||||||
|
|
||||||
|
$result = [];
|
||||||
|
|
||||||
|
foreach ($items as $item) {
|
||||||
|
$result[] = [
|
||||||
|
'name' => sprintf('%s - %s(¥%0.2f)', $item->id, $item->title, $item->market_price),
|
||||||
|
'value' => $item->id,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
public function getConsults()
|
public function getConsults()
|
||||||
{
|
{
|
||||||
$pagerQuery = new PagerQuery();
|
$pagerQuery = new PagerQuery();
|
||||||
@ -35,6 +67,21 @@ class Consult extends Service
|
|||||||
|
|
||||||
$params['deleted'] = $params['deleted'] ?? 0;
|
$params['deleted'] = $params['deleted'] ?? 0;
|
||||||
|
|
||||||
|
$accountRepo = new AccountRepo();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 兼容用户编号|手机号码|邮箱地址查询
|
||||||
|
*/
|
||||||
|
if (!empty($params['owner_id'])) {
|
||||||
|
if (CommonValidator::phone($params['owner_id'])) {
|
||||||
|
$account = $accountRepo->findByPhone($params['owner_id']);
|
||||||
|
$params['owner_id'] = $account ? $account->id : -1000;
|
||||||
|
} elseif (CommonValidator::email($params['owner_id'])) {
|
||||||
|
$account = $accountRepo->findByEmail($params['owner_id']);
|
||||||
|
$params['owner_id'] = $account ? $account->id : -1000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$sort = $pagerQuery->getSort();
|
$sort = $pagerQuery->getSort();
|
||||||
$page = $pagerQuery->getPage();
|
$page = $pagerQuery->getPage();
|
||||||
$limit = $pagerQuery->getLimit();
|
$limit = $pagerQuery->getLimit();
|
||||||
@ -95,7 +142,6 @@ class Consult extends Service
|
|||||||
|
|
||||||
if (isset($post['published'])) {
|
if (isset($post['published'])) {
|
||||||
$data['published'] = $validator->checkPublishStatus($post['published']);
|
$data['published'] = $validator->checkPublishStatus($post['published']);
|
||||||
$this->handleItemConsults($consult);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$consult->update($data);
|
$consult->update($data);
|
||||||
@ -104,6 +150,10 @@ class Consult extends Service
|
|||||||
$this->handleReplyNotice($consult);
|
$this->handleReplyNotice($consult);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->recountItemConsults($consult);
|
||||||
|
|
||||||
|
$this->eventsManager->fire('Consult:afterUpdate', $this, $consult);
|
||||||
|
|
||||||
return $consult;
|
return $consult;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,7 +165,13 @@ class Consult extends Service
|
|||||||
|
|
||||||
$consult->update();
|
$consult->update();
|
||||||
|
|
||||||
$this->handleItemConsults($consult);
|
$this->recountItemConsults($consult);
|
||||||
|
|
||||||
|
$sender = $this->getLoginUser();
|
||||||
|
|
||||||
|
$this->handleConsultDeletedNotice($consult, $sender);
|
||||||
|
|
||||||
|
$this->eventsManager->fire('Consult:afterDelete', $this, $consult);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function restoreConsult($id)
|
public function restoreConsult($id)
|
||||||
@ -126,52 +182,97 @@ class Consult extends Service
|
|||||||
|
|
||||||
$consult->update();
|
$consult->update();
|
||||||
|
|
||||||
$this->handleItemConsults($consult);
|
$this->recountItemConsults($consult);
|
||||||
|
|
||||||
|
$this->eventsManager->fire('Consult:afterRestore', $this, $consult);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function moderate($id)
|
public function moderate($id)
|
||||||
{
|
{
|
||||||
$type = $this->request->getPost('type', ['trim', 'string']);
|
$type = $this->request->getPost('type', ['trim', 'string']);
|
||||||
|
$reason = $this->request->getPost('reason', ['trim', 'string']);
|
||||||
|
|
||||||
$consult = $this->findOrFail($id);
|
$consult = $this->findOrFail($id);
|
||||||
|
$sender = $this->getLoginUser();
|
||||||
|
|
||||||
if ($type == 'approve') {
|
if ($type == 'approve') {
|
||||||
|
|
||||||
$consult->published = ConsultModel::PUBLISH_APPROVED;
|
$consult->published = ConsultModel::PUBLISH_APPROVED;
|
||||||
} elseif ($type == 'reject') {
|
$consult->update();
|
||||||
$consult->published = ConsultModel::PUBLISH_REJECTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
$consult->update();
|
$this->handleConsultApprovedNotice($consult, $sender);
|
||||||
|
|
||||||
$this->handleItemConsults($consult);
|
|
||||||
|
|
||||||
if ($type == 'approve') {
|
|
||||||
$this->eventsManager->fire('Consult:afterApprove', $this, $consult);
|
$this->eventsManager->fire('Consult:afterApprove', $this, $consult);
|
||||||
|
|
||||||
} elseif ($type == 'reject') {
|
} elseif ($type == 'reject') {
|
||||||
|
|
||||||
|
$consult->published = ConsultModel::PUBLISH_REJECTED;
|
||||||
|
$consult->update();
|
||||||
|
|
||||||
|
$this->handleConsultRejectedNotice($consult, $sender, $reason);
|
||||||
|
|
||||||
$this->eventsManager->fire('Consult:afterReject', $this, $consult);
|
$this->eventsManager->fire('Consult:afterReject', $this, $consult);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->recountItemConsults($consult);
|
||||||
|
|
||||||
return $consult;
|
return $consult;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function handleItemConsults(ConsultModel $consult)
|
public function batchModerate()
|
||||||
{
|
{
|
||||||
if ($consult->course_id > 0) {
|
$type = $this->request->getQuery('type', ['trim', 'string']);
|
||||||
$course = $this->findCourse($consult->course_id);
|
$ids = $this->request->getPost('ids', ['trim', 'int']);
|
||||||
$this->recountCourseConsults($course);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($consult->chapter_id > 0) {
|
$consultRepo = new ConsultRepo();
|
||||||
$chapter = $this->findChapter($consult->chapter_id);
|
|
||||||
$this->recountChapterConsults($chapter);
|
$consults = $consultRepo->findByIds($ids);
|
||||||
|
|
||||||
|
if ($consults->count() == 0) return;
|
||||||
|
|
||||||
|
$sender = $this->getLoginUser();
|
||||||
|
|
||||||
|
foreach ($consults as $consult) {
|
||||||
|
|
||||||
|
if ($type == 'approve') {
|
||||||
|
|
||||||
|
$consult->published = ConsultModel::PUBLISH_APPROVED;
|
||||||
|
$consult->update();
|
||||||
|
|
||||||
|
$this->handleConsultApprovedNotice($consult, $sender);
|
||||||
|
|
||||||
|
} elseif ($type == 'reject') {
|
||||||
|
|
||||||
|
$consult->published = ConsultModel::PUBLISH_REJECTED;
|
||||||
|
$consult->update();
|
||||||
|
|
||||||
|
$this->handleConsultRejectedNotice($consult, $sender);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->recountItemConsults($consult);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function handleReplyNotice(ConsultModel $consult)
|
public function batchDelete()
|
||||||
{
|
{
|
||||||
$notice = new ConsultReplyNotice();
|
$ids = $this->request->getPost('ids', ['trim', 'int']);
|
||||||
|
|
||||||
$notice->createTask($consult);
|
$consultRepo = new ConsultRepo();
|
||||||
|
|
||||||
|
$consults = $consultRepo->findByIds($ids);
|
||||||
|
|
||||||
|
if ($consults->count() == 0) return;
|
||||||
|
|
||||||
|
$sender = $this->getLoginUser();
|
||||||
|
|
||||||
|
foreach ($consults as $consult) {
|
||||||
|
|
||||||
|
$consult->deleted = 1;
|
||||||
|
$consult->update();
|
||||||
|
|
||||||
|
$this->handleConsultDeletedNotice($consult, $sender);
|
||||||
|
$this->recountItemConsults($consult);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function findOrFail($id)
|
protected function findOrFail($id)
|
||||||
@ -195,6 +296,41 @@ class Consult extends Service
|
|||||||
return $chapterRepo->findById($id);
|
return $chapterRepo->findById($id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function handleReplyNotice(ConsultModel $consult)
|
||||||
|
{
|
||||||
|
$notice = new ConsultReplyNotice();
|
||||||
|
|
||||||
|
$notice->createTask($consult);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function handleConsultApprovedNotice(ConsultModel $review, UserModel $sender)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function handleConsultRejectedNotice(ConsultModel $review, UserModel $sender, $reason = '')
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function handleConsultDeletedNotice(ConsultModel $review, UserModel $sender, $reason = '')
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function recountItemConsults(ConsultModel $consult)
|
||||||
|
{
|
||||||
|
if ($consult->course_id > 0) {
|
||||||
|
$course = $this->findCourse($consult->course_id);
|
||||||
|
$this->recountCourseConsults($course);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($consult->chapter_id > 0) {
|
||||||
|
$chapter = $this->findChapter($consult->chapter_id);
|
||||||
|
$this->recountChapterConsults($chapter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected function recountCourseConsults(CourseModel $course)
|
protected function recountCourseConsults(CourseModel $course)
|
||||||
{
|
{
|
||||||
$courseRepo = new CourseRepo();
|
$courseRepo = new CourseRepo();
|
||||||
|
@ -10,22 +10,20 @@ namespace App\Http\Admin\Services;
|
|||||||
use App\Builders\CourseList as CourseListBuilder;
|
use App\Builders\CourseList as CourseListBuilder;
|
||||||
use App\Builders\ResourceList as ResourceListBuilder;
|
use App\Builders\ResourceList as ResourceListBuilder;
|
||||||
use App\Caches\Course as CourseCache;
|
use App\Caches\Course as CourseCache;
|
||||||
use App\Caches\CourseCategoryList as CourseCategoryListCache;
|
|
||||||
use App\Caches\CourseRelatedList as CourseRelatedListCache;
|
use App\Caches\CourseRelatedList as CourseRelatedListCache;
|
||||||
use App\Caches\CourseTeacherList as CourseTeacherListCache;
|
|
||||||
use App\Library\Paginator\Query as PagerQuery;
|
use App\Library\Paginator\Query as PagerQuery;
|
||||||
use App\Models\Category as CategoryModel;
|
use App\Models\Category as CategoryModel;
|
||||||
use App\Models\Course as CourseModel;
|
use App\Models\Course as CourseModel;
|
||||||
use App\Models\CourseCategory as CourseCategoryModel;
|
|
||||||
use App\Models\CourseRelated as CourseRelatedModel;
|
use App\Models\CourseRelated as CourseRelatedModel;
|
||||||
use App\Models\CourseUser as CourseUserModel;
|
use App\Models\CourseTag as CourseTagModel;
|
||||||
use App\Repos\Category as CategoryRepo;
|
|
||||||
use App\Repos\Chapter as ChapterRepo;
|
use App\Repos\Chapter as ChapterRepo;
|
||||||
use App\Repos\Course as CourseRepo;
|
use App\Repos\Course as CourseRepo;
|
||||||
use App\Repos\CourseCategory as CourseCategoryRepo;
|
|
||||||
use App\Repos\CourseRelated as CourseRelatedRepo;
|
use App\Repos\CourseRelated as CourseRelatedRepo;
|
||||||
use App\Repos\CourseUser as CourseUserRepo;
|
use App\Repos\CourseTag as CourseTagRepo;
|
||||||
|
use App\Repos\Tag as TagRepo;
|
||||||
use App\Repos\User as UserRepo;
|
use App\Repos\User as UserRepo;
|
||||||
|
use App\Services\Category as CategoryService;
|
||||||
|
use App\Services\Logic\Course\XmTagList as XmTagListService;
|
||||||
use App\Services\Sync\CourseIndex as CourseIndexSync;
|
use App\Services\Sync\CourseIndex as CourseIndexSync;
|
||||||
use App\Validators\Course as CourseValidator;
|
use App\Validators\Course as CourseValidator;
|
||||||
use App\Validators\CourseOffline as CourseOfflineValidator;
|
use App\Validators\CourseOffline as CourseOfflineValidator;
|
||||||
@ -39,12 +37,8 @@ class Course extends Service
|
|||||||
|
|
||||||
$params = $pagerQuery->getParams();
|
$params = $pagerQuery->getParams();
|
||||||
|
|
||||||
if (!empty($params['xm_category_ids'])) {
|
if (!empty($params['xm_tag_ids'])) {
|
||||||
$params['category_id'] = explode(',', $params['xm_category_ids']);
|
$params['tag_id'] = explode(',', $params['xm_tag_ids']);
|
||||||
}
|
|
||||||
|
|
||||||
if (!empty($params['xm_teacher_ids'])) {
|
|
||||||
$params['teacher_id'] = explode(',', $params['xm_teacher_ids']);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$params['deleted'] = $params['deleted'] ?? 0;
|
$params['deleted'] = $params['deleted'] ?? 0;
|
||||||
@ -155,10 +149,6 @@ class Course extends Service
|
|||||||
$data['refund_expiry'] = $validator->checkRefundExpiry($post['refund_expiry']);
|
$data['refund_expiry'] = $validator->checkRefundExpiry($post['refund_expiry']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($post['origin_price'])) {
|
|
||||||
$data['origin_price'] = $validator->checkOriginPrice($post['origin_price']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($post['market_price'])) {
|
if (isset($post['market_price'])) {
|
||||||
$data['market_price'] = $validator->checkMarketPrice($post['market_price']);
|
$data['market_price'] = $validator->checkMarketPrice($post['market_price']);
|
||||||
}
|
}
|
||||||
@ -173,17 +163,20 @@ class Course extends Service
|
|||||||
|
|
||||||
if (isset($post['published'])) {
|
if (isset($post['published'])) {
|
||||||
$data['published'] = $validator->checkPublishStatus($post['published']);
|
$data['published'] = $validator->checkPublishStatus($post['published']);
|
||||||
if ($post['published'] == 1) {
|
|
||||||
$validator->checkPublishAbility($course);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($post['xm_category_ids'])) {
|
if (isset($post['category_id'])) {
|
||||||
$this->saveCategories($course, $post['xm_category_ids']);
|
$category = $validator->checkCategory($post['category_id']);
|
||||||
|
$data['category_id'] = $category->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($post['xm_teacher_ids'])) {
|
if (isset($post['teacher_id'])) {
|
||||||
$this->saveTeachers($course, $post['xm_teacher_ids']);
|
$teacher = $validator->checkTeacher($post['teacher_id']);
|
||||||
|
$data['teacher_id'] = $teacher->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($post['xm_tag_ids'])) {
|
||||||
|
$this->saveTags($course, $post['xm_tag_ids']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($post['xm_course_ids'])) {
|
if (isset($post['xm_course_ids'])) {
|
||||||
@ -258,6 +251,33 @@ class Course extends Service
|
|||||||
return CourseModel::levelTypes();
|
return CourseModel::levelTypes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getTeacherOptions()
|
||||||
|
{
|
||||||
|
$userRepo = new UserRepo();
|
||||||
|
|
||||||
|
$teachers = $userRepo->findTeachers();
|
||||||
|
|
||||||
|
if ($teachers->count() == 0) return [];
|
||||||
|
|
||||||
|
$options = [];
|
||||||
|
|
||||||
|
foreach ($teachers as $teacher) {
|
||||||
|
$options[] = [
|
||||||
|
'id' => $teacher->id,
|
||||||
|
'name' => $teacher->name,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $options;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCategoryOptions()
|
||||||
|
{
|
||||||
|
$categoryService = new CategoryService();
|
||||||
|
|
||||||
|
return $categoryService->getCategoryOptions(CategoryModel::TYPE_COURSE);
|
||||||
|
}
|
||||||
|
|
||||||
public function getStudyExpiryOptions()
|
public function getStudyExpiryOptions()
|
||||||
{
|
{
|
||||||
return CourseModel::studyExpiryOptions();
|
return CourseModel::studyExpiryOptions();
|
||||||
@ -268,92 +288,11 @@ class Course extends Service
|
|||||||
return CourseModel::refundExpiryOptions();
|
return CourseModel::refundExpiryOptions();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getXmCategories($id)
|
public function getXmTags($id)
|
||||||
{
|
{
|
||||||
$categoryRepo = new CategoryRepo();
|
$service = new XmTagListService();
|
||||||
|
|
||||||
$allCategories = $categoryRepo->findAll([
|
return $service->handle($id);
|
||||||
'type' => CategoryModel::TYPE_COURSE,
|
|
||||||
'published' => 1,
|
|
||||||
'deleted' => 0,
|
|
||||||
]);
|
|
||||||
|
|
||||||
if ($allCategories->count() == 0) return [];
|
|
||||||
|
|
||||||
$courseCategoryIds = [];
|
|
||||||
|
|
||||||
if ($id > 0) {
|
|
||||||
$courseRepo = new CourseRepo();
|
|
||||||
$courseCategories = $courseRepo->findCategories($id);
|
|
||||||
if ($courseCategories->count() > 0) {
|
|
||||||
foreach ($courseCategories as $category) {
|
|
||||||
$courseCategoryIds[] = $category->id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$list = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 没有二级分类的不显示
|
|
||||||
*/
|
|
||||||
foreach ($allCategories as $category) {
|
|
||||||
if ($category->level == 1 && $category->child_count > 0) {
|
|
||||||
$list[$category->id] = [
|
|
||||||
'name' => $category->name,
|
|
||||||
'value' => $category->id,
|
|
||||||
'children' => [],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($allCategories as $category) {
|
|
||||||
$selected = in_array($category->id, $courseCategoryIds);
|
|
||||||
$parentId = $category->parent_id;
|
|
||||||
if ($category->level == 2) {
|
|
||||||
$list[$parentId]['children'][] = [
|
|
||||||
'name' => $category->name,
|
|
||||||
'value' => $category->id,
|
|
||||||
'selected' => $selected,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return array_values($list);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getXmTeachers($id)
|
|
||||||
{
|
|
||||||
$userRepo = new UserRepo();
|
|
||||||
|
|
||||||
$allTeachers = $userRepo->findTeachers();
|
|
||||||
|
|
||||||
if ($allTeachers->count() == 0) return [];
|
|
||||||
|
|
||||||
$courseTeacherIds = [];
|
|
||||||
|
|
||||||
if ($id > 0) {
|
|
||||||
$courseRepo = new CourseRepo();
|
|
||||||
$courseTeachers = $courseRepo->findTeachers($id);
|
|
||||||
if ($courseTeachers->count() > 0) {
|
|
||||||
foreach ($courseTeachers as $teacher) {
|
|
||||||
$courseTeacherIds[] = $teacher->id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$list = [];
|
|
||||||
|
|
||||||
foreach ($allTeachers as $teacher) {
|
|
||||||
$selected = in_array($teacher->id, $courseTeacherIds);
|
|
||||||
$list[] = [
|
|
||||||
'name' => $teacher->name,
|
|
||||||
'value' => $teacher->id,
|
|
||||||
'selected' => $selected,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $list;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getXmCourses($id)
|
public function getXmCourses($id)
|
||||||
@ -409,7 +348,7 @@ class Course extends Service
|
|||||||
{
|
{
|
||||||
$courseRepo = new CourseRepo();
|
$courseRepo = new CourseRepo();
|
||||||
|
|
||||||
$resources = $courseRepo->findResources($id);
|
$resources = $courseRepo->findResources($id);
|
||||||
|
|
||||||
if ($resources->count() == 0) return [];
|
if ($resources->count() == 0) return [];
|
||||||
|
|
||||||
@ -429,106 +368,65 @@ class Course extends Service
|
|||||||
return $validator->checkCourse($id);
|
return $validator->checkCourse($id);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function saveTeachers(CourseModel $course, $teacherIds)
|
protected function saveTags(CourseModel $course, $tagIds)
|
||||||
{
|
{
|
||||||
$courseRepo = new CourseRepo();
|
/**
|
||||||
|
* 修改数据后,afterFetch设置的属性会失效,重新执行
|
||||||
|
*/
|
||||||
|
$course->afterFetch();
|
||||||
|
|
||||||
$courseTeachers = $courseRepo->findTeachers($course->id);
|
if (is_string($tagIds) && strlen($tagIds) > 0) {
|
||||||
|
$tagIds = explode(',', $tagIds);
|
||||||
|
}
|
||||||
|
|
||||||
$originTeacherIds = [];
|
$originTagIds = [];
|
||||||
|
|
||||||
if ($courseTeachers->count() > 0) {
|
if ($course->tags) {
|
||||||
foreach ($courseTeachers as $teacher) {
|
$originTagIds = kg_array_column($course->tags, 'id');
|
||||||
$originTeacherIds[] = $teacher->id;
|
}
|
||||||
|
|
||||||
|
$newTagIds = $tagIds ?: [];
|
||||||
|
$addedTagIds = array_diff($newTagIds, $originTagIds);
|
||||||
|
|
||||||
|
if ($addedTagIds) {
|
||||||
|
foreach ($addedTagIds as $tagId) {
|
||||||
|
$courseTag = new CourseTagModel();
|
||||||
|
$courseTag->course_id = $course->id;
|
||||||
|
$courseTag->tag_id = $tagId;
|
||||||
|
$courseTag->create();
|
||||||
|
$this->recountTagCourses($tagId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$newTeacherIds = $teacherIds ? explode(',', $teacherIds) : [];
|
$deletedTagIds = array_diff($originTagIds, $newTagIds);
|
||||||
$addedTeacherIds = array_diff($newTeacherIds, $originTeacherIds);
|
|
||||||
|
|
||||||
if ($addedTeacherIds) {
|
if ($deletedTagIds) {
|
||||||
foreach ($addedTeacherIds as $teacherId) {
|
$courseTagRepo = new CourseTagRepo();
|
||||||
$courseTeacher = new CourseUserModel();
|
foreach ($deletedTagIds as $tagId) {
|
||||||
$courseTeacher->course_id = $course->id;
|
$courseTag = $courseTagRepo->findCourseTag($course->id, $tagId);
|
||||||
$courseTeacher->user_id = $teacherId;
|
if ($courseTag) {
|
||||||
$courseTeacher->role_type = CourseUserModel::ROLE_TEACHER;
|
$courseTag->delete();
|
||||||
$courseTeacher->source_type = CourseUserModel::SOURCE_IMPORT;
|
$this->recountTagCourses($tagId);
|
||||||
$courseTeacher->create();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$deletedTeacherIds = array_diff($originTeacherIds, $newTeacherIds);
|
|
||||||
|
|
||||||
if ($deletedTeacherIds) {
|
|
||||||
$courseUserRepo = new CourseUserRepo();
|
|
||||||
foreach ($deletedTeacherIds as $teacherId) {
|
|
||||||
$courseTeacher = $courseUserRepo->findCourseTeacher($course->id, $teacherId);
|
|
||||||
if ($courseTeacher) {
|
|
||||||
$courseTeacher->delete();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$teacherId = $newTeacherIds[0] ?? 0;
|
$courseTags = [];
|
||||||
|
|
||||||
if ($teacherId) {
|
if ($newTagIds) {
|
||||||
$course->teacher_id = $teacherId;
|
$tagRepo = new TagRepo();
|
||||||
$course->update();
|
$tags = $tagRepo->findByIds($newTagIds);
|
||||||
}
|
if ($tags->count() > 0) {
|
||||||
|
foreach ($tags as $tag) {
|
||||||
$cache = new CourseTeacherListCache();
|
$courseTags[] = ['id' => $tag->id, 'name' => $tag->name];
|
||||||
|
$this->recountTagCourses($tag->id);
|
||||||
$cache->rebuild($course->id);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function saveCategories(CourseModel $course, $categoryIds)
|
|
||||||
{
|
|
||||||
$courseRepo = new CourseRepo();
|
|
||||||
|
|
||||||
$courseCategories = $courseRepo->findCategories($course->id);
|
|
||||||
|
|
||||||
$originCategoryIds = [];
|
|
||||||
|
|
||||||
if ($courseCategories->count() > 0) {
|
|
||||||
foreach ($courseCategories as $category) {
|
|
||||||
$originCategoryIds[] = $category->id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$newCategoryIds = $categoryIds ? explode(',', $categoryIds) : [];
|
|
||||||
$addedCategoryIds = array_diff($newCategoryIds, $originCategoryIds);
|
|
||||||
|
|
||||||
if ($addedCategoryIds) {
|
|
||||||
foreach ($addedCategoryIds as $categoryId) {
|
|
||||||
$courseCategory = new CourseCategoryModel();
|
|
||||||
$courseCategory->course_id = $course->id;
|
|
||||||
$courseCategory->category_id = $categoryId;
|
|
||||||
$courseCategory->create();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$deletedCategoryIds = array_diff($originCategoryIds, $newCategoryIds);
|
|
||||||
|
|
||||||
if ($deletedCategoryIds) {
|
|
||||||
$courseCategoryRepo = new CourseCategoryRepo();
|
|
||||||
foreach ($deletedCategoryIds as $categoryId) {
|
|
||||||
$courseCategory = $courseCategoryRepo->findCourseCategory($course->id, $categoryId);
|
|
||||||
if ($courseCategory) {
|
|
||||||
$courseCategory->delete();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$categoryId = $newCategoryIds[0] ?? 0;
|
$course->tags = $courseTags;
|
||||||
|
|
||||||
if ($categoryId) {
|
$course->update();
|
||||||
$course->category_id = $categoryId;
|
|
||||||
$course->update();
|
|
||||||
}
|
|
||||||
|
|
||||||
$cache = new CourseCategoryListCache();
|
|
||||||
|
|
||||||
$cache->rebuild($course->id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function saveRelatedCourses(CourseModel $course, $courseIds)
|
protected function saveRelatedCourses(CourseModel $course, $courseIds)
|
||||||
@ -608,6 +506,21 @@ class Course extends Service
|
|||||||
$sync->addItem($course->id);
|
$sync->addItem($course->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function recountTagCourses($tagId)
|
||||||
|
{
|
||||||
|
$tagRepo = new TagRepo();
|
||||||
|
|
||||||
|
$tag = $tagRepo->findById($tagId);
|
||||||
|
|
||||||
|
if (!$tag) return;
|
||||||
|
|
||||||
|
$courseCount = $tagRepo->countCourses($tagId);
|
||||||
|
|
||||||
|
$tag->course_count = $courseCount;
|
||||||
|
|
||||||
|
$tag->update();
|
||||||
|
}
|
||||||
|
|
||||||
protected function handleCourses($pager)
|
protected function handleCourses($pager)
|
||||||
{
|
{
|
||||||
if ($pager->total_items > 0) {
|
if ($pager->total_items > 0) {
|
||||||
|
64
app/Http/Admin/Services/CourseLearning.php
Normal file
64
app/Http/Admin/Services/CourseLearning.php
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @copyright Copyright (c) 2021 深圳市酷瓜软件有限公司
|
||||||
|
* @license https://opensource.org/licenses/GPL-2.0
|
||||||
|
* @link https://www.koogua.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Admin\Services;
|
||||||
|
|
||||||
|
use App\Builders\LearningList as LearningListBuilder;
|
||||||
|
use App\Library\Paginator\Query as PagerQuery;
|
||||||
|
use App\Repos\Learning as LearningRepo;
|
||||||
|
use App\Validators\Course as CourseValidator;
|
||||||
|
|
||||||
|
class CourseLearning extends Service
|
||||||
|
{
|
||||||
|
|
||||||
|
public function getLearnings($id)
|
||||||
|
{
|
||||||
|
$course = $this->findCourseOrFail($id);
|
||||||
|
|
||||||
|
$pagerQuery = new PagerQuery();
|
||||||
|
|
||||||
|
$params = $pagerQuery->getParams();
|
||||||
|
|
||||||
|
$params['course_id'] = $course->id;
|
||||||
|
|
||||||
|
$sort = $pagerQuery->getSort();
|
||||||
|
$page = $pagerQuery->getPage();
|
||||||
|
$limit = $pagerQuery->getLimit();
|
||||||
|
|
||||||
|
$learningRepo = new LearningRepo();
|
||||||
|
|
||||||
|
$pager = $learningRepo->paginate($params, $sort, $page, $limit);
|
||||||
|
|
||||||
|
return $this->handleLearnings($pager);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function findCourseOrFail($id)
|
||||||
|
{
|
||||||
|
$validator = new CourseValidator();
|
||||||
|
|
||||||
|
return $validator->checkCourse($id);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function handleLearnings($pager)
|
||||||
|
{
|
||||||
|
if ($pager->total_items > 0) {
|
||||||
|
|
||||||
|
$builder = new LearningListBuilder();
|
||||||
|
|
||||||
|
$pipeA = $pager->items->toArray();
|
||||||
|
$pipeB = $builder->handleCourses($pipeA);
|
||||||
|
$pipeC = $builder->handleChapters($pipeB);
|
||||||
|
$pipeD = $builder->handleUsers($pipeC);
|
||||||
|
$pipeE = $builder->objects($pipeD);
|
||||||
|
|
||||||
|
$pager->items = $pipeE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $pager;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
101
app/Http/Admin/Services/CourseUser.php
Normal file
101
app/Http/Admin/Services/CourseUser.php
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @copyright Copyright (c) 2021 深圳市酷瓜软件有限公司
|
||||||
|
* @license https://opensource.org/licenses/GPL-2.0
|
||||||
|
* @link https://www.koogua.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Admin\Services;
|
||||||
|
|
||||||
|
use App\Builders\CourseUserList as CourseUserListBuilder;
|
||||||
|
use App\Library\Paginator\Query as PagerQuery;
|
||||||
|
use App\Library\Validators\Common as CommonValidator;
|
||||||
|
use App\Models\CourseUser as CourseUserModel;
|
||||||
|
use App\Repos\Account as AccountRepo;
|
||||||
|
use App\Repos\CourseUser as CourseUserRepo;
|
||||||
|
use App\Services\Logic\Course\CourseUserTrait;
|
||||||
|
use App\Validators\CourseUser as CourseUserValidator;
|
||||||
|
|
||||||
|
class CourseUser extends Service
|
||||||
|
{
|
||||||
|
|
||||||
|
use CourseUserTrait;
|
||||||
|
|
||||||
|
public function getSourceTypes()
|
||||||
|
{
|
||||||
|
return CourseUserModel::sourceTypes();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function create($id)
|
||||||
|
{
|
||||||
|
$post = $this->request->getPost();
|
||||||
|
|
||||||
|
$validator = new CourseUserValidator();
|
||||||
|
|
||||||
|
$course = $validator->checkCourse($id);
|
||||||
|
|
||||||
|
$user = $validator->checkUser($post['user_id']);
|
||||||
|
|
||||||
|
$expiryTime = $validator->checkExpiryTime($post['expiry_time']);
|
||||||
|
|
||||||
|
$sourceType = CourseUserModel::SOURCE_MANUAL;
|
||||||
|
|
||||||
|
return $this->assignUserCourse($course, $user, $expiryTime, $sourceType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUsers($id)
|
||||||
|
{
|
||||||
|
$validator = new CourseUserValidator();
|
||||||
|
|
||||||
|
$course = $validator->checkCourse($id);
|
||||||
|
|
||||||
|
$pagerQuery = new PagerQuery();
|
||||||
|
|
||||||
|
$params = $pagerQuery->getParams();
|
||||||
|
|
||||||
|
$params['course_id'] = $course->id;
|
||||||
|
$params['deleted'] = 0;
|
||||||
|
|
||||||
|
$accountRepo = new AccountRepo();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 兼容用户编号|手机号码|邮箱地址查询
|
||||||
|
*/
|
||||||
|
if (!empty($params['user_id'])) {
|
||||||
|
if (CommonValidator::phone($params['user_id'])) {
|
||||||
|
$account = $accountRepo->findByPhone($params['user_id']);
|
||||||
|
$params['user_id'] = $account ? $account->id : -1000;
|
||||||
|
} elseif (CommonValidator::email($params['user_id'])) {
|
||||||
|
$account = $accountRepo->findByEmail($params['user_id']);
|
||||||
|
$params['user_id'] = $account ? $account->id : -1000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$sort = $pagerQuery->getSort();
|
||||||
|
$page = $pagerQuery->getPage();
|
||||||
|
$limit = $pagerQuery->getLimit();
|
||||||
|
|
||||||
|
$repo = new CourseUserRepo();
|
||||||
|
|
||||||
|
$pager = $repo->paginate($params, $sort, $page, $limit);
|
||||||
|
|
||||||
|
return $this->handleUsers($pager);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function handleUsers($pager)
|
||||||
|
{
|
||||||
|
if ($pager->total_items > 0) {
|
||||||
|
|
||||||
|
$builder = new CourseUserListBuilder();
|
||||||
|
|
||||||
|
$items = $pager->items->toArray();
|
||||||
|
$pipeA = $builder->handleUsers($items);
|
||||||
|
$pipeB = $builder->objects($pipeA);
|
||||||
|
|
||||||
|
$pager->items = $pipeB;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $pager;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,380 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* @copyright Copyright (c) 2021 深圳市酷瓜软件有限公司
|
|
||||||
* @license https://opensource.org/licenses/GPL-2.0
|
|
||||||
* @link https://www.koogua.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace App\Http\Admin\Services;
|
|
||||||
|
|
||||||
use App\Caches\FlashSale as FlashSaleCache;
|
|
||||||
use App\Library\Paginator\Query as PagerQuery;
|
|
||||||
use App\Models\Course as CourseModel;
|
|
||||||
use App\Models\FlashSale as FlashSaleModel;
|
|
||||||
use App\Models\Package as PackageModel;
|
|
||||||
use App\Models\Vip as VipModel;
|
|
||||||
use App\Repos\Course as CourseRepo;
|
|
||||||
use App\Repos\FlashSale as FlashSaleRepo;
|
|
||||||
use App\Repos\Package as PackageRepo;
|
|
||||||
use App\Repos\Vip as VipRepo;
|
|
||||||
use App\Services\Logic\FlashSale\Queue as FlashSaleQueue;
|
|
||||||
use App\Validators\FlashSale as FlashSaleValidator;
|
|
||||||
|
|
||||||
class FlashSale extends Service
|
|
||||||
{
|
|
||||||
|
|
||||||
public function getItemTypes()
|
|
||||||
{
|
|
||||||
return FlashSaleModel::itemTypes();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getXmSchedules($id)
|
|
||||||
{
|
|
||||||
$schedules = FlashSaleModel::schedules();
|
|
||||||
|
|
||||||
$sale = $this->findOrFail($id);
|
|
||||||
|
|
||||||
$result = [];
|
|
||||||
|
|
||||||
foreach ($schedules as $schedule) {
|
|
||||||
$result[] = [
|
|
||||||
'name' => $schedule['name'],
|
|
||||||
'value' => $schedule['hour'],
|
|
||||||
'selected' => in_array($schedule['hour'], $sale->schedules),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getXmCourses()
|
|
||||||
{
|
|
||||||
$courseRepo = new CourseRepo();
|
|
||||||
|
|
||||||
$items = $courseRepo->findAll([
|
|
||||||
'free' => 0,
|
|
||||||
'published' => 1,
|
|
||||||
'deleted' => 0,
|
|
||||||
]);
|
|
||||||
|
|
||||||
if ($items->count() == 0) return [];
|
|
||||||
|
|
||||||
$result = [];
|
|
||||||
|
|
||||||
foreach ($items as $item) {
|
|
||||||
$result[] = [
|
|
||||||
'name' => sprintf('%s(¥%0.2f)', $item->title, $item->market_price),
|
|
||||||
'value' => $item->id,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getXmPackages()
|
|
||||||
{
|
|
||||||
$packageRepo = new PackageRepo();
|
|
||||||
|
|
||||||
$items = $packageRepo->findAll([
|
|
||||||
'published' => 1,
|
|
||||||
'deleted' => 0,
|
|
||||||
]);
|
|
||||||
|
|
||||||
if ($items->count() == 0) return [];
|
|
||||||
|
|
||||||
$result = [];
|
|
||||||
|
|
||||||
foreach ($items as $item) {
|
|
||||||
$result[] = [
|
|
||||||
'name' => sprintf('%s(¥%0.2f)', $item->title, $item->market_price),
|
|
||||||
'value' => $item->id,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getXmVips()
|
|
||||||
{
|
|
||||||
$vipRepo = new VipRepo();
|
|
||||||
|
|
||||||
$items = $vipRepo->findAll();
|
|
||||||
|
|
||||||
if ($items->count() == 0) return [];
|
|
||||||
|
|
||||||
$result = [];
|
|
||||||
|
|
||||||
foreach ($items as $item) {
|
|
||||||
$result[] = [
|
|
||||||
'name' => sprintf('%s(¥%0.2f)', $item->title, $item->price),
|
|
||||||
'value' => $item->id,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getFlashSales()
|
|
||||||
{
|
|
||||||
$pagerQuery = new PagerQuery();
|
|
||||||
|
|
||||||
$params = $pagerQuery->getParams();
|
|
||||||
|
|
||||||
$params['deleted'] = $params['deleted'] ?? 0;
|
|
||||||
|
|
||||||
$sort = $pagerQuery->getSort();
|
|
||||||
$page = $pagerQuery->getPage();
|
|
||||||
$limit = $pagerQuery->getLimit();
|
|
||||||
|
|
||||||
$saleRepo = new FlashSaleRepo();
|
|
||||||
|
|
||||||
return $saleRepo->paginate($params, $sort, $page, $limit);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getFlashSale($id)
|
|
||||||
{
|
|
||||||
return $this->findOrFail($id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function createFlashSale()
|
|
||||||
{
|
|
||||||
$post = $this->request->getPost();
|
|
||||||
|
|
||||||
$validator = new FlashSaleValidator();
|
|
||||||
|
|
||||||
$post['item_type'] = $validator->checkItemType($post['item_type']);
|
|
||||||
|
|
||||||
$sale = new FlashSaleModel();
|
|
||||||
|
|
||||||
switch ($post['item_type']) {
|
|
||||||
case FlashSaleModel::ITEM_COURSE:
|
|
||||||
$sale = $this->createCourseFlashSale($post);
|
|
||||||
break;
|
|
||||||
case FlashSaleModel::ITEM_PACKAGE:
|
|
||||||
$sale = $this->createPackageFlashSale($post);
|
|
||||||
break;
|
|
||||||
case FlashSaleModel::ITEM_VIP:
|
|
||||||
$sale = $this->createVipFlashSale($post);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->rebuildFlashSaleCache($sale);
|
|
||||||
|
|
||||||
return $sale;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function updateFlashSale($id)
|
|
||||||
{
|
|
||||||
$sale = $this->findOrFail($id);
|
|
||||||
|
|
||||||
$post = $this->request->getPost();
|
|
||||||
|
|
||||||
$originInfo = $this->getOriginInfo($sale->item_id, $sale->item_type);
|
|
||||||
|
|
||||||
$validator = new FlashSaleValidator();
|
|
||||||
|
|
||||||
$data = [];
|
|
||||||
|
|
||||||
$data['item_info'] = $originInfo['item_info'];
|
|
||||||
|
|
||||||
if (isset($post['start_time']) && isset($post['end_time'])) {
|
|
||||||
$data['start_time'] = $validator->checkStartTime($post['start_time']);
|
|
||||||
$data['end_time'] = $validator->checkEndTime($post['end_time']);
|
|
||||||
$validator->checkTimeRange($data['start_time'], $data['end_time']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($post['xm_schedules'])) {
|
|
||||||
$data['schedules'] = $validator->checkSchedules($post['xm_schedules']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($post['stock'])) {
|
|
||||||
$data['stock'] = $validator->checkStock($post['stock']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($post['price'])) {
|
|
||||||
$data['price'] = $validator->checkPrice($originInfo['item_price'], $post['price']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($post['published'])) {
|
|
||||||
$data['published'] = $validator->checkPublishStatus($post['published']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$sale->update($data);
|
|
||||||
|
|
||||||
$this->initFlashSaleQueue($sale);
|
|
||||||
$this->rebuildFlashSaleCache($sale);
|
|
||||||
|
|
||||||
return $sale;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function deleteFlashSale($id)
|
|
||||||
{
|
|
||||||
$sale = $this->findOrFail($id);
|
|
||||||
|
|
||||||
$sale->deleted = 1;
|
|
||||||
|
|
||||||
$sale->update();
|
|
||||||
|
|
||||||
$this->rebuildFlashSaleCache($sale);
|
|
||||||
|
|
||||||
return $sale;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function restoreFlashSale($id)
|
|
||||||
{
|
|
||||||
$sale = $this->findOrFail($id);
|
|
||||||
|
|
||||||
$sale->deleted = 0;
|
|
||||||
|
|
||||||
$sale->update();
|
|
||||||
|
|
||||||
$this->rebuildFlashSaleCache($sale);
|
|
||||||
|
|
||||||
return $sale;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function findOrFail($id)
|
|
||||||
{
|
|
||||||
$validator = new FlashSaleValidator();
|
|
||||||
|
|
||||||
return $validator->checkFlashSale($id);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function initFlashSaleQueue(FlashSaleModel $sale)
|
|
||||||
{
|
|
||||||
$queue = new FlashSaleQueue();
|
|
||||||
|
|
||||||
$queue->init($sale->id);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function rebuildFlashSaleCache(FlashSaleModel $sale)
|
|
||||||
{
|
|
||||||
$cache = new FlashSaleCache();
|
|
||||||
|
|
||||||
$cache->rebuild($sale->id);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function createCourseFlashSale($post)
|
|
||||||
{
|
|
||||||
$validator = new FlashSaleValidator();
|
|
||||||
|
|
||||||
$course = $validator->checkCourse($post['xm_course_id']);
|
|
||||||
|
|
||||||
$originInfo = $this->getOriginInfo($course->id, FlashSaleModel::ITEM_COURSE);
|
|
||||||
|
|
||||||
$sale = new FlashSaleModel();
|
|
||||||
|
|
||||||
$sale->item_id = $course->id;
|
|
||||||
$sale->item_type = FlashSaleModel::ITEM_COURSE;
|
|
||||||
$sale->item_info = $originInfo['item_info'];
|
|
||||||
|
|
||||||
$sale->create();
|
|
||||||
|
|
||||||
return $sale;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function createPackageFlashSale($post)
|
|
||||||
{
|
|
||||||
$validator = new FlashSaleValidator();
|
|
||||||
|
|
||||||
$package = $validator->checkPackage($post['xm_package_id']);
|
|
||||||
|
|
||||||
$originInfo = $this->getOriginInfo($package->id, FlashSaleModel::ITEM_PACKAGE);
|
|
||||||
|
|
||||||
$sale = new FlashSaleModel();
|
|
||||||
|
|
||||||
$sale->item_id = $package->id;
|
|
||||||
$sale->item_type = FlashSaleModel::ITEM_PACKAGE;
|
|
||||||
$sale->item_info = $originInfo['item_info'];
|
|
||||||
|
|
||||||
$sale->create();
|
|
||||||
|
|
||||||
return $sale;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function createVipFlashSale($post)
|
|
||||||
{
|
|
||||||
$validator = new FlashSaleValidator();
|
|
||||||
|
|
||||||
$vip = $validator->checkVip($post['xm_vip_id']);
|
|
||||||
|
|
||||||
$originInfo = $this->getOriginInfo($vip->id, FlashSaleModel::ITEM_VIP);
|
|
||||||
|
|
||||||
$sale = new FlashSaleModel();
|
|
||||||
|
|
||||||
$sale->item_id = $vip->id;
|
|
||||||
$sale->item_type = FlashSaleModel::ITEM_VIP;
|
|
||||||
$sale->item_info = $originInfo['item_info'];
|
|
||||||
|
|
||||||
$sale->create();
|
|
||||||
|
|
||||||
return $sale;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getOriginInfo($itemId, $itemType)
|
|
||||||
{
|
|
||||||
$result = [
|
|
||||||
'item_info' => [],
|
|
||||||
'item_price' => 0.00,
|
|
||||||
];
|
|
||||||
|
|
||||||
if ($itemType == FlashSaleModel::ITEM_COURSE) {
|
|
||||||
|
|
||||||
$courseRepo = new CourseRepo();
|
|
||||||
|
|
||||||
$course = $courseRepo->findById($itemId);
|
|
||||||
|
|
||||||
$result = [
|
|
||||||
'item_info' => [
|
|
||||||
'course' => [
|
|
||||||
'id' => $course->id,
|
|
||||||
'title' => $course->title,
|
|
||||||
'cover' => CourseModel::getCoverPath($course->cover),
|
|
||||||
'market_price' => $course->market_price,
|
|
||||||
],
|
|
||||||
],
|
|
||||||
'item_price' => $course->market_price,
|
|
||||||
];
|
|
||||||
|
|
||||||
} elseif ($itemType == FlashSaleModel::ITEM_PACKAGE) {
|
|
||||||
|
|
||||||
$packageRepo = new PackageRepo();
|
|
||||||
|
|
||||||
$package = $packageRepo->findById($itemId);
|
|
||||||
|
|
||||||
$result = [
|
|
||||||
'item_info' => [
|
|
||||||
'package' => [
|
|
||||||
'id' => $package->id,
|
|
||||||
'title' => $package->title,
|
|
||||||
'cover' => PackageModel::getCoverPath($package->cover),
|
|
||||||
'market_price' => $package->market_price,
|
|
||||||
],
|
|
||||||
],
|
|
||||||
'item_price' => $package->market_price,
|
|
||||||
];
|
|
||||||
|
|
||||||
} elseif ($itemType == FlashSaleModel::ITEM_VIP) {
|
|
||||||
|
|
||||||
$vipRepo = new VipRepo();
|
|
||||||
|
|
||||||
$vip = $vipRepo->findById($itemId);
|
|
||||||
|
|
||||||
$result = [
|
|
||||||
'item_info' => [
|
|
||||||
'vip' => [
|
|
||||||
'id' => $vip->id,
|
|
||||||
'title' => $vip->title,
|
|
||||||
'cover' => VipModel::getCoverPath($vip->cover),
|
|
||||||
'expiry' => $vip->expiry,
|
|
||||||
'price' => $vip->price,
|
|
||||||
],
|
|
||||||
],
|
|
||||||
'item_price' => $vip->price,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -9,6 +9,7 @@ namespace App\Http\Admin\Services;
|
|||||||
|
|
||||||
use App\Builders\OrderList as OrderListBuilder;
|
use App\Builders\OrderList as OrderListBuilder;
|
||||||
use App\Library\Paginator\Query as PaginateQuery;
|
use App\Library\Paginator\Query as PaginateQuery;
|
||||||
|
use App\Library\Validators\Common as CommonValidator;
|
||||||
use App\Models\Order as OrderModel;
|
use App\Models\Order as OrderModel;
|
||||||
use App\Repos\Account as AccountRepo;
|
use App\Repos\Account as AccountRepo;
|
||||||
use App\Repos\Order as OrderRepo;
|
use App\Repos\Order as OrderRepo;
|
||||||
@ -36,6 +37,30 @@ class Order extends Service
|
|||||||
|
|
||||||
$params['deleted'] = $params['deleted'] ?? 0;
|
$params['deleted'] = $params['deleted'] ?? 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 兼容订单编号或订单序号查询
|
||||||
|
*/
|
||||||
|
if (isset($params['id']) && strlen($params['id']) > 10) {
|
||||||
|
$orderRepo = new OrderRepo();
|
||||||
|
$order = $orderRepo->findBySn($params['id']);
|
||||||
|
$params['id'] = $order ? $order->id : -1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
$accountRepo = new AccountRepo();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 兼容用户编号|手机号码|邮箱地址查询
|
||||||
|
*/
|
||||||
|
if (!empty($params['owner_id'])) {
|
||||||
|
if (CommonValidator::phone($params['owner_id'])) {
|
||||||
|
$account = $accountRepo->findByPhone($params['owner_id']);
|
||||||
|
$params['owner_id'] = $account ? $account->id : -1000;
|
||||||
|
} elseif (CommonValidator::email($params['owner_id'])) {
|
||||||
|
$account = $accountRepo->findByEmail($params['owner_id']);
|
||||||
|
$params['owner_id'] = $account ? $account->id : -1000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$sort = $pageQuery->getSort();
|
$sort = $pageQuery->getSort();
|
||||||
$page = $pageQuery->getPage();
|
$page = $pageQuery->getPage();
|
||||||
$limit = $pageQuery->getLimit();
|
$limit = $pageQuery->getLimit();
|
||||||
|
@ -16,10 +16,10 @@ use App\Models\Question as QuestionModel;
|
|||||||
use App\Models\Reason as ReasonModel;
|
use App\Models\Reason as ReasonModel;
|
||||||
use App\Models\Report as ReportModel;
|
use App\Models\Report as ReportModel;
|
||||||
use App\Models\User as UserModel;
|
use App\Models\User as UserModel;
|
||||||
use App\Repos\Category as CategoryRepo;
|
|
||||||
use App\Repos\Question as QuestionRepo;
|
use App\Repos\Question as QuestionRepo;
|
||||||
use App\Repos\Report as ReportRepo;
|
use App\Repos\Report as ReportRepo;
|
||||||
use App\Repos\User as UserRepo;
|
use App\Repos\User as UserRepo;
|
||||||
|
use App\Services\Category as CategoryService;
|
||||||
use App\Services\Logic\Notice\Internal\QuestionApproved as QuestionApprovedNotice;
|
use App\Services\Logic\Notice\Internal\QuestionApproved as QuestionApprovedNotice;
|
||||||
use App\Services\Logic\Notice\Internal\QuestionRejected as QuestionRejectedNotice;
|
use App\Services\Logic\Notice\Internal\QuestionRejected as QuestionRejectedNotice;
|
||||||
use App\Services\Logic\Point\History\QuestionPost as QuestionPostPointHistory;
|
use App\Services\Logic\Point\History\QuestionPost as QuestionPostPointHistory;
|
||||||
@ -41,16 +41,11 @@ class Question extends Service
|
|||||||
return $service->handle($id);
|
return $service->handle($id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getCategories()
|
public function getCategoryOptions()
|
||||||
{
|
{
|
||||||
$categoryRepo = new CategoryRepo();
|
$categoryService = new CategoryService();
|
||||||
|
|
||||||
return $categoryRepo->findAll([
|
return $categoryService->getCategoryOptions(CategoryModel::TYPE_QUESTION);
|
||||||
'type' => CategoryModel::TYPE_QUESTION,
|
|
||||||
'level' => 1,
|
|
||||||
'published' => 1,
|
|
||||||
'deleted' => 0,
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getPublishTypes()
|
public function getPublishTypes()
|
||||||
@ -155,11 +150,6 @@ class Question extends Service
|
|||||||
|
|
||||||
$data = [];
|
$data = [];
|
||||||
|
|
||||||
if (isset($post['category_id'])) {
|
|
||||||
$category = $validator->checkCategory($post['category_id']);
|
|
||||||
$data['category_id'] = $category->id;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($post['title'])) {
|
if (isset($post['title'])) {
|
||||||
$data['title'] = $validator->checkTitle($post['title']);
|
$data['title'] = $validator->checkTitle($post['title']);
|
||||||
}
|
}
|
||||||
@ -172,10 +162,18 @@ class Question extends Service
|
|||||||
$data['keywords'] = $validator->checkKeywords($post['keywords']);
|
$data['keywords'] = $validator->checkKeywords($post['keywords']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isset($post['summary'])) {
|
||||||
|
$data['summary'] = $validator->checkSummary($post['keywords']);
|
||||||
|
}
|
||||||
|
|
||||||
if (isset($post['anonymous'])) {
|
if (isset($post['anonymous'])) {
|
||||||
$data['anonymous'] = $validator->checkAnonymousStatus($post['anonymous']);
|
$data['anonymous'] = $validator->checkAnonymousStatus($post['anonymous']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isset($post['featured'])) {
|
||||||
|
$data['featured'] = $validator->checkFeatureStatus($post['featured']);
|
||||||
|
}
|
||||||
|
|
||||||
if (isset($post['closed'])) {
|
if (isset($post['closed'])) {
|
||||||
$data['closed'] = $validator->checkCloseStatus($post['closed']);
|
$data['closed'] = $validator->checkCloseStatus($post['closed']);
|
||||||
}
|
}
|
||||||
@ -184,6 +182,11 @@ class Question extends Service
|
|||||||
$data['published'] = $validator->checkPublishStatus($post['published']);
|
$data['published'] = $validator->checkPublishStatus($post['published']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isset($post['category_id'])) {
|
||||||
|
$category = $validator->checkCategory($post['category_id']);
|
||||||
|
$data['category_id'] = $category->id;
|
||||||
|
}
|
||||||
|
|
||||||
if (isset($post['xm_tag_ids'])) {
|
if (isset($post['xm_tag_ids'])) {
|
||||||
$this->saveTags($question, $post['xm_tag_ids']);
|
$this->saveTags($question, $post['xm_tag_ids']);
|
||||||
}
|
}
|
||||||
@ -210,6 +213,10 @@ class Question extends Service
|
|||||||
|
|
||||||
$question->update();
|
$question->update();
|
||||||
|
|
||||||
|
$sender = $this->getLoginUser();
|
||||||
|
|
||||||
|
$this->handleQuestionDeletedNotice($question, $sender);
|
||||||
|
|
||||||
$owner = $this->findUser($question->owner_id);
|
$owner = $this->findUser($question->owner_id);
|
||||||
|
|
||||||
$this->saveDynamicAttrs($question);
|
$this->saveDynamicAttrs($question);
|
||||||
@ -247,28 +254,13 @@ class Question extends Service
|
|||||||
$reason = $this->request->getPost('reason', ['trim', 'string']);
|
$reason = $this->request->getPost('reason', ['trim', 'string']);
|
||||||
|
|
||||||
$question = $this->findOrFail($id);
|
$question = $this->findOrFail($id);
|
||||||
|
|
||||||
$validator = new QuestionValidator();
|
|
||||||
|
|
||||||
if ($type == 'approve') {
|
|
||||||
$question->published = QuestionModel::PUBLISH_APPROVED;
|
|
||||||
} elseif ($type == 'reject') {
|
|
||||||
$validator->checkRejectReason($reason);
|
|
||||||
$question->published = QuestionModel::PUBLISH_REJECTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
$question->update();
|
|
||||||
|
|
||||||
$owner = $this->findUser($question->owner_id);
|
|
||||||
|
|
||||||
$this->rebuildQuestionCache($question);
|
|
||||||
$this->rebuildQuestionIndex($question);
|
|
||||||
$this->recountUserQuestions($owner);
|
|
||||||
|
|
||||||
$sender = $this->getLoginUser();
|
$sender = $this->getLoginUser();
|
||||||
|
|
||||||
if ($type == 'approve') {
|
if ($type == 'approve') {
|
||||||
|
|
||||||
|
$question->published = QuestionModel::PUBLISH_APPROVED;
|
||||||
|
$question->update();
|
||||||
|
|
||||||
$this->handleQuestionPostPoint($question);
|
$this->handleQuestionPostPoint($question);
|
||||||
$this->handleQuestionApprovedNotice($question, $sender);
|
$this->handleQuestionApprovedNotice($question, $sender);
|
||||||
|
|
||||||
@ -276,17 +268,20 @@ class Question extends Service
|
|||||||
|
|
||||||
} elseif ($type == 'reject') {
|
} elseif ($type == 'reject') {
|
||||||
|
|
||||||
$options = ReasonModel::questionRejectOptions();
|
$question->published = QuestionModel::PUBLISH_REJECTED;
|
||||||
|
$question->update();
|
||||||
if (array_key_exists($reason, $options)) {
|
|
||||||
$reason = $options[$reason];
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->handleQuestionRejectedNotice($question, $sender, $reason);
|
$this->handleQuestionRejectedNotice($question, $sender, $reason);
|
||||||
|
|
||||||
$this->eventsManager->fire('Question:afterReject', $this, $question);
|
$this->eventsManager->fire('Question:afterReject', $this, $question);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$owner = $this->findUser($question->owner_id);
|
||||||
|
|
||||||
|
$this->recountUserQuestions($owner);
|
||||||
|
$this->rebuildQuestionCache($question);
|
||||||
|
$this->rebuildQuestionIndex($question);
|
||||||
|
|
||||||
return $question;
|
return $question;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -324,6 +319,72 @@ class Question extends Service
|
|||||||
$this->recountUserQuestions($owner);
|
$this->recountUserQuestions($owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function batchModerate()
|
||||||
|
{
|
||||||
|
$type = $this->request->getQuery('type', ['trim', 'string']);
|
||||||
|
$ids = $this->request->getPost('ids', ['trim', 'int']);
|
||||||
|
|
||||||
|
$questionRepo = new QuestionRepo();
|
||||||
|
|
||||||
|
$questions = $questionRepo->findByIds($ids);
|
||||||
|
|
||||||
|
if ($questions->count() == 0) return;
|
||||||
|
|
||||||
|
$sender = $this->getLoginUser();
|
||||||
|
|
||||||
|
foreach ($questions as $question) {
|
||||||
|
|
||||||
|
if ($type == 'approve') {
|
||||||
|
|
||||||
|
$question->published = QuestionModel::PUBLISH_APPROVED;
|
||||||
|
$question->update();
|
||||||
|
|
||||||
|
$this->handleQuestionPostPoint($question);
|
||||||
|
$this->handleQuestionApprovedNotice($question, $sender);
|
||||||
|
|
||||||
|
} elseif ($type == 'reject') {
|
||||||
|
|
||||||
|
$question->published = QuestionModel::PUBLISH_REJECTED;
|
||||||
|
$question->update();
|
||||||
|
|
||||||
|
$this->handleQuestionRejectedNotice($question, $sender);
|
||||||
|
}
|
||||||
|
|
||||||
|
$owner = $this->findUser($question->owner_id);
|
||||||
|
|
||||||
|
$this->recountUserQuestions($owner);
|
||||||
|
$this->rebuildQuestionCache($question);
|
||||||
|
$this->rebuildQuestionIndex($question);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function batchDelete()
|
||||||
|
{
|
||||||
|
$ids = $this->request->getPost('ids', ['trim', 'int']);
|
||||||
|
|
||||||
|
$questionRepo = new QuestionRepo();
|
||||||
|
|
||||||
|
$questions = $questionRepo->findByIds($ids);
|
||||||
|
|
||||||
|
if ($questions->count() == 0) return;
|
||||||
|
|
||||||
|
$sender = $this->getLoginUser();
|
||||||
|
|
||||||
|
foreach ($questions as $question) {
|
||||||
|
|
||||||
|
$question->deleted = 1;
|
||||||
|
$question->update();
|
||||||
|
|
||||||
|
$this->handleQuestionDeletedNotice($question, $sender);
|
||||||
|
|
||||||
|
$owner = $this->findUser($question->owner_id);
|
||||||
|
|
||||||
|
$this->recountUserQuestions($owner);
|
||||||
|
$this->rebuildQuestionCache($question);
|
||||||
|
$this->rebuildQuestionIndex($question);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected function findOrFail($id)
|
protected function findOrFail($id)
|
||||||
{
|
{
|
||||||
$validator = new QuestionValidator();
|
$validator = new QuestionValidator();
|
||||||
@ -379,13 +440,18 @@ class Question extends Service
|
|||||||
$notice->handle($question, $sender);
|
$notice->handle($question, $sender);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function handleQuestionRejectedNotice(QuestionModel $question, UserModel $sender, $reason)
|
protected function handleQuestionRejectedNotice(QuestionModel $question, UserModel $sender, $reason = '')
|
||||||
{
|
{
|
||||||
$notice = new QuestionRejectedNotice();
|
$notice = new QuestionRejectedNotice();
|
||||||
|
|
||||||
$notice->handle($question, $sender, $reason);
|
$notice->handle($question, $sender, $reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function handleQuestionDeletedNotice(QuestionModel $question, UserModel $sender, $reason = '')
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
protected function handleQuestions($pager)
|
protected function handleQuestions($pager)
|
||||||
{
|
{
|
||||||
if ($pager->total_items > 0) {
|
if ($pager->total_items > 0) {
|
||||||
|
@ -9,6 +9,7 @@ namespace App\Http\Admin\Services;
|
|||||||
|
|
||||||
use App\Builders\RefundList as RefundListBuilder;
|
use App\Builders\RefundList as RefundListBuilder;
|
||||||
use App\Library\Paginator\Query as PaginateQuery;
|
use App\Library\Paginator\Query as PaginateQuery;
|
||||||
|
use App\Library\Validators\Common as CommonValidator;
|
||||||
use App\Models\Refund as RefundModel;
|
use App\Models\Refund as RefundModel;
|
||||||
use App\Models\Task as TaskModel;
|
use App\Models\Task as TaskModel;
|
||||||
use App\Repos\Account as AccountRepo;
|
use App\Repos\Account as AccountRepo;
|
||||||
@ -43,6 +44,21 @@ class Refund extends Service
|
|||||||
$params['order_id'] = $order ? $order->id : -1000;
|
$params['order_id'] = $order ? $order->id : -1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$accountRepo = new AccountRepo();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 兼容用户编号|手机号码|邮箱地址查询
|
||||||
|
*/
|
||||||
|
if (!empty($params['owner_id'])) {
|
||||||
|
if (CommonValidator::phone($params['owner_id'])) {
|
||||||
|
$account = $accountRepo->findByPhone($params['owner_id']);
|
||||||
|
$params['owner_id'] = $account ? $account->id : -1000;
|
||||||
|
} elseif (CommonValidator::email($params['owner_id'])) {
|
||||||
|
$account = $accountRepo->findByEmail($params['owner_id']);
|
||||||
|
$params['owner_id'] = $account ? $account->id : -1000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$sort = $pageQuery->getSort();
|
$sort = $pageQuery->getSort();
|
||||||
$page = $pageQuery->getPage();
|
$page = $pageQuery->getPage();
|
||||||
$limit = $pageQuery->getLimit();
|
$limit = $pageQuery->getLimit();
|
||||||
|
@ -9,8 +9,12 @@ namespace App\Http\Admin\Services;
|
|||||||
|
|
||||||
use App\Builders\ReviewList as ReviewListBuilder;
|
use App\Builders\ReviewList as ReviewListBuilder;
|
||||||
use App\Library\Paginator\Query as PagerQuery;
|
use App\Library\Paginator\Query as PagerQuery;
|
||||||
|
use App\Library\Validators\Common as CommonValidator;
|
||||||
use App\Models\Course as CourseModel;
|
use App\Models\Course as CourseModel;
|
||||||
|
use App\Models\Reason as ReasonModel;
|
||||||
use App\Models\Review as ReviewModel;
|
use App\Models\Review as ReviewModel;
|
||||||
|
use App\Models\User as UserModel;
|
||||||
|
use App\Repos\Account as AccountRepo;
|
||||||
use App\Repos\Course as CourseRepo;
|
use App\Repos\Course as CourseRepo;
|
||||||
use App\Repos\Review as ReviewRepo;
|
use App\Repos\Review as ReviewRepo;
|
||||||
use App\Services\CourseStat as CourseStatService;
|
use App\Services\CourseStat as CourseStatService;
|
||||||
@ -25,6 +29,34 @@ class Review extends Service
|
|||||||
return ReviewModel::publishTypes();
|
return ReviewModel::publishTypes();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getReasons()
|
||||||
|
{
|
||||||
|
return ReasonModel::reviewRejectOptions();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getXmCourses()
|
||||||
|
{
|
||||||
|
$courseRepo = new CourseRepo();
|
||||||
|
|
||||||
|
$items = $courseRepo->findAll([
|
||||||
|
'published' => 1,
|
||||||
|
'deleted' => 0,
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($items->count() == 0) return [];
|
||||||
|
|
||||||
|
$result = [];
|
||||||
|
|
||||||
|
foreach ($items as $item) {
|
||||||
|
$result[] = [
|
||||||
|
'name' => sprintf('%s - %s(¥%0.2f)', $item->id, $item->title, $item->market_price),
|
||||||
|
'value' => $item->id,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
public function getReviews()
|
public function getReviews()
|
||||||
{
|
{
|
||||||
$pagerQuery = new PagerQuery();
|
$pagerQuery = new PagerQuery();
|
||||||
@ -33,6 +65,21 @@ class Review extends Service
|
|||||||
|
|
||||||
$params['deleted'] = $params['deleted'] ?? 0;
|
$params['deleted'] = $params['deleted'] ?? 0;
|
||||||
|
|
||||||
|
$accountRepo = new AccountRepo();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 兼容用户编号|手机号码|邮箱地址查询
|
||||||
|
*/
|
||||||
|
if (!empty($params['owner_id'])) {
|
||||||
|
if (CommonValidator::phone($params['owner_id'])) {
|
||||||
|
$account = $accountRepo->findByPhone($params['owner_id']);
|
||||||
|
$params['owner_id'] = $account ? $account->id : -1000;
|
||||||
|
} elseif (CommonValidator::email($params['owner_id'])) {
|
||||||
|
$account = $accountRepo->findByEmail($params['owner_id']);
|
||||||
|
$params['owner_id'] = $account ? $account->id : -1000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$sort = $pagerQuery->getSort();
|
$sort = $pagerQuery->getSort();
|
||||||
$page = $pagerQuery->getPage();
|
$page = $pagerQuery->getPage();
|
||||||
$limit = $pagerQuery->getLimit();
|
$limit = $pagerQuery->getLimit();
|
||||||
@ -91,6 +138,10 @@ class Review extends Service
|
|||||||
$data['rating3'] = $validator->checkRating($post['rating3']);
|
$data['rating3'] = $validator->checkRating($post['rating3']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isset($post['anonymous'])) {
|
||||||
|
$data['anonymous'] = $validator->checkAnonymous($post['anonymous']);
|
||||||
|
}
|
||||||
|
|
||||||
if (isset($post['published'])) {
|
if (isset($post['published'])) {
|
||||||
$data['published'] = $validator->checkPublishStatus($post['published']);
|
$data['published'] = $validator->checkPublishStatus($post['published']);
|
||||||
$this->recountCourseReviews($course);
|
$this->recountCourseReviews($course);
|
||||||
@ -99,6 +150,7 @@ class Review extends Service
|
|||||||
$review->update($data);
|
$review->update($data);
|
||||||
|
|
||||||
$this->updateCourseRating($course);
|
$this->updateCourseRating($course);
|
||||||
|
$this->recountCourseReviews($course);
|
||||||
|
|
||||||
$this->eventsManager->fire('Review:afterUpdate', $this, $review);
|
$this->eventsManager->fire('Review:afterUpdate', $this, $review);
|
||||||
|
|
||||||
@ -117,6 +169,12 @@ class Review extends Service
|
|||||||
|
|
||||||
$this->recountCourseReviews($course);
|
$this->recountCourseReviews($course);
|
||||||
|
|
||||||
|
$this->updateCourseRating($course);
|
||||||
|
|
||||||
|
$sender = $this->getLoginUser();
|
||||||
|
|
||||||
|
$this->handleReviewDeletedNotice($review, $sender);
|
||||||
|
|
||||||
$this->eventsManager->fire('Review:afterReview', $this, $review);
|
$this->eventsManager->fire('Review:afterReview', $this, $review);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,30 +196,102 @@ class Review extends Service
|
|||||||
public function moderate($id)
|
public function moderate($id)
|
||||||
{
|
{
|
||||||
$type = $this->request->getPost('type', ['trim', 'string']);
|
$type = $this->request->getPost('type', ['trim', 'string']);
|
||||||
|
$reason = $this->request->getPost('reason', ['trim', 'string']);
|
||||||
|
|
||||||
$review = $this->findOrFail($id);
|
$review = $this->findOrFail($id);
|
||||||
|
|
||||||
if ($type == 'approve') {
|
$sender = $this->getLoginUser();
|
||||||
$review->published = ReviewModel::PUBLISH_APPROVED;
|
|
||||||
} elseif ($type == 'reject') {
|
|
||||||
$review->published = ReviewModel::PUBLISH_REJECTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
$review->update();
|
if ($type == 'approve') {
|
||||||
|
|
||||||
|
$review->published = ReviewModel::PUBLISH_APPROVED;
|
||||||
|
$review->update();
|
||||||
|
|
||||||
|
$this->handleReviewApprovedNotice($review, $sender);
|
||||||
|
|
||||||
|
$this->eventsManager->fire('Review:afterApprove', $this, $review);
|
||||||
|
|
||||||
|
} elseif ($type == 'reject') {
|
||||||
|
|
||||||
|
$review->published = ReviewModel::PUBLISH_REJECTED;
|
||||||
|
$review->update();
|
||||||
|
|
||||||
|
$this->handleReviewRejectedNotice($review, $sender, $reason);
|
||||||
|
|
||||||
|
$this->eventsManager->fire('Review:afterReject', $this, $review);
|
||||||
|
}
|
||||||
|
|
||||||
$course = $this->findCourse($review->course_id);
|
$course = $this->findCourse($review->course_id);
|
||||||
|
|
||||||
$this->recountCourseReviews($course);
|
$this->recountCourseReviews($course);
|
||||||
|
$this->updateCourseRating($course);
|
||||||
if ($type == 'approve') {
|
|
||||||
$this->eventsManager->fire('Review:afterApprove', $this, $review);
|
|
||||||
} elseif ($type == 'reject') {
|
|
||||||
$this->eventsManager->fire('Review:afterReject', $this, $review);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $review;
|
return $review;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function batchModerate()
|
||||||
|
{
|
||||||
|
$type = $this->request->getQuery('type', ['trim', 'string']);
|
||||||
|
$ids = $this->request->getPost('ids', ['trim', 'int']);
|
||||||
|
|
||||||
|
$reviewRepo = new ReviewRepo();
|
||||||
|
|
||||||
|
$reviews = $reviewRepo->findByIds($ids);
|
||||||
|
|
||||||
|
if ($reviews->count() == 0) return;
|
||||||
|
|
||||||
|
$sender = $this->getLoginUser();
|
||||||
|
|
||||||
|
foreach ($reviews as $review) {
|
||||||
|
|
||||||
|
if ($type == 'approve') {
|
||||||
|
|
||||||
|
$review->published = ReviewModel::PUBLISH_APPROVED;
|
||||||
|
$review->update();
|
||||||
|
|
||||||
|
$this->handleReviewApprovedNotice($review, $sender);
|
||||||
|
|
||||||
|
} elseif ($type == 'reject') {
|
||||||
|
|
||||||
|
$review->published = ReviewModel::PUBLISH_REJECTED;
|
||||||
|
$review->update();
|
||||||
|
|
||||||
|
$this->handleReviewRejectedNotice($review, $sender);
|
||||||
|
}
|
||||||
|
|
||||||
|
$course = $this->findCourse($review->course_id);
|
||||||
|
|
||||||
|
$this->recountCourseReviews($course);
|
||||||
|
$this->updateCourseRating($course);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function batchDelete()
|
||||||
|
{
|
||||||
|
$ids = $this->request->getPost('ids', ['trim', 'int']);
|
||||||
|
|
||||||
|
$reviewRepo = new ReviewRepo();
|
||||||
|
|
||||||
|
$reviews = $reviewRepo->findByIds($ids);
|
||||||
|
|
||||||
|
if ($reviews->count() == 0) return;
|
||||||
|
|
||||||
|
$sender = $this->getLoginUser();
|
||||||
|
|
||||||
|
foreach ($reviews as $review) {
|
||||||
|
|
||||||
|
$review->deleted = 1;
|
||||||
|
$review->update();
|
||||||
|
|
||||||
|
$this->handleReviewDeletedNotice($review, $sender);
|
||||||
|
|
||||||
|
$course = $this->findCourse($review->course_id);
|
||||||
|
|
||||||
|
$this->recountCourseReviews($course);
|
||||||
|
$this->updateCourseRating($course);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected function findOrFail($id)
|
protected function findOrFail($id)
|
||||||
{
|
{
|
||||||
$validator = new ReviewValidator();
|
$validator = new ReviewValidator();
|
||||||
@ -176,6 +306,21 @@ class Review extends Service
|
|||||||
return $courseRepo->findById($id);
|
return $courseRepo->findById($id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function handleReviewApprovedNotice(ReviewModel $review, UserModel $sender)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function handleReviewRejectedNotice(ReviewModel $review, UserModel $sender, $reason = '')
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function handleReviewDeletedNotice(ReviewModel $review, UserModel $sender, $reason = '')
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
protected function recountCourseReviews(CourseModel $course)
|
protected function recountCourseReviews(CourseModel $course)
|
||||||
{
|
{
|
||||||
$courseRepo = new CourseRepo();
|
$courseRepo = new CourseRepo();
|
||||||
|
@ -140,6 +140,9 @@ class Role extends Service
|
|||||||
$list[] = str_replace('.edit', '.list', $route);
|
$list[] = str_replace('.edit', '.list', $route);
|
||||||
} elseif (strpos($route, '.delete')) {
|
} elseif (strpos($route, '.delete')) {
|
||||||
$list[] = str_replace('.delete', '.restore', $route);
|
$list[] = str_replace('.delete', '.restore', $route);
|
||||||
|
$list[] = str_replace('.delete', '.batch_delete', $route);
|
||||||
|
} elseif (strpos($route, '.moderate')) {
|
||||||
|
$list[] = str_replace('.moderate', '.batch_moderate', $route);
|
||||||
} elseif (strpos($route, '.search')) {
|
} elseif (strpos($route, '.search')) {
|
||||||
$list[] = str_replace('.search', '.list', $route);
|
$list[] = str_replace('.search', '.list', $route);
|
||||||
}
|
}
|
||||||
|
@ -1,223 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* @copyright Copyright (c) 2021 深圳市酷瓜软件有限公司
|
|
||||||
* @license https://opensource.org/licenses/GPL-2.0
|
|
||||||
* @link https://www.koogua.com
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace App\Http\Admin\Services;
|
|
||||||
|
|
||||||
use App\Builders\CourseUserList as CourseUserListBuilder;
|
|
||||||
use App\Builders\LearningList as LearningListBuilder;
|
|
||||||
use App\Library\Paginator\Query as PagerQuery;
|
|
||||||
use App\Models\CourseUser as CourseUserModel;
|
|
||||||
use App\Repos\Course as CourseRepo;
|
|
||||||
use App\Repos\CourseUser as CourseUserRepo;
|
|
||||||
use App\Repos\Learning as LearningRepo;
|
|
||||||
use App\Repos\User as UserRepo;
|
|
||||||
use App\Validators\CourseUser as CourseUserValidator;
|
|
||||||
|
|
||||||
class Student extends Service
|
|
||||||
{
|
|
||||||
|
|
||||||
public function getXmCourses($scope = 'all', $courseId = 0)
|
|
||||||
{
|
|
||||||
$courseRepo = new CourseRepo();
|
|
||||||
|
|
||||||
$where = [
|
|
||||||
'published' => 1,
|
|
||||||
'deleted' => 0,
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 过滤付费课程
|
|
||||||
*/
|
|
||||||
if ($scope == 'charge') {
|
|
||||||
$where['free'] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
$items = $courseRepo->findAll($where);
|
|
||||||
|
|
||||||
if ($items->count() == 0) return [];
|
|
||||||
|
|
||||||
$result = [];
|
|
||||||
|
|
||||||
foreach ($items as $item) {
|
|
||||||
$result[] = [
|
|
||||||
'name' => sprintf('%s - %s(¥%0.2f)', $item->id, $item->title, $item->market_price),
|
|
||||||
'value' => $item->id,
|
|
||||||
'selected' => $item->id == $courseId,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getSourceTypes()
|
|
||||||
{
|
|
||||||
return CourseUserModel::sourceTypes();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getCourse($id)
|
|
||||||
{
|
|
||||||
$repo = new CourseRepo();
|
|
||||||
|
|
||||||
return $repo->findById($id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getStudent($id)
|
|
||||||
{
|
|
||||||
$repo = new UserRepo();
|
|
||||||
|
|
||||||
return $repo->findById($id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getRelations()
|
|
||||||
{
|
|
||||||
$pagerQuery = new PagerQuery();
|
|
||||||
|
|
||||||
$params = $pagerQuery->getParams();
|
|
||||||
|
|
||||||
$params['role_type'] = CourseUserModel::ROLE_STUDENT;
|
|
||||||
|
|
||||||
$validator = new CourseUserValidator();
|
|
||||||
|
|
||||||
if (!empty($params['xm_course_id'])) {
|
|
||||||
$course = $validator->checkCourse($params['xm_course_id']);
|
|
||||||
$params['course_id'] = $course->id;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!empty($params['xm_user_id'])) {
|
|
||||||
$user = $validator->checkUser($params['xm_user_id']);
|
|
||||||
$params['user_id'] = $user->id;
|
|
||||||
}
|
|
||||||
|
|
||||||
$sort = $pagerQuery->getSort();
|
|
||||||
$page = $pagerQuery->getPage();
|
|
||||||
$limit = $pagerQuery->getLimit();
|
|
||||||
|
|
||||||
$courseUserRepo = new CourseUserRepo();
|
|
||||||
|
|
||||||
$pager = $courseUserRepo->paginate($params, $sort, $page, $limit);
|
|
||||||
|
|
||||||
return $this->handleRelations($pager);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getLearnings()
|
|
||||||
{
|
|
||||||
$pagerQuery = new PagerQuery();
|
|
||||||
|
|
||||||
$params = $pagerQuery->getParams();
|
|
||||||
|
|
||||||
$sort = $pagerQuery->getSort();
|
|
||||||
$page = $pagerQuery->getPage();
|
|
||||||
$limit = $pagerQuery->getLimit();
|
|
||||||
|
|
||||||
$learningRepo = new LearningRepo();
|
|
||||||
|
|
||||||
$pager = $learningRepo->paginate($params, $sort, $page, $limit);
|
|
||||||
|
|
||||||
return $this->handleLearnings($pager);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getRelation($id)
|
|
||||||
{
|
|
||||||
return $this->findOrFail($id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function createRelation()
|
|
||||||
{
|
|
||||||
$post = $this->request->getPost();
|
|
||||||
|
|
||||||
$validator = new CourseUserValidator();
|
|
||||||
|
|
||||||
$data = [
|
|
||||||
'role_type' => CourseUserModel::ROLE_STUDENT,
|
|
||||||
'source_type' => CourseUserModel::SOURCE_IMPORT,
|
|
||||||
];
|
|
||||||
|
|
||||||
$course = $validator->checkCourse($post['xm_course_id']);
|
|
||||||
$user = $validator->checkUser($post['xm_user_id']);
|
|
||||||
$expiryTime = $validator->checkExpiryTime($post['expiry_time']);
|
|
||||||
|
|
||||||
$data['course_id'] = $course->id;
|
|
||||||
$data['user_id'] = $user->id;
|
|
||||||
$data['expiry_time'] = $expiryTime;
|
|
||||||
|
|
||||||
$validator->checkIfImported($course->id, $user->id);
|
|
||||||
|
|
||||||
$courseUser = new CourseUserModel();
|
|
||||||
|
|
||||||
$courseUser->create($data);
|
|
||||||
|
|
||||||
$course->user_count += 1;
|
|
||||||
$course->update();
|
|
||||||
|
|
||||||
$user->course_count += 1;
|
|
||||||
$user->update();
|
|
||||||
|
|
||||||
return $courseUser;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function updateRelation()
|
|
||||||
{
|
|
||||||
$post = $this->request->getPost();
|
|
||||||
|
|
||||||
$relation = $this->findOrFail($post['relation_id']);
|
|
||||||
|
|
||||||
$validator = new CourseUserValidator();
|
|
||||||
|
|
||||||
$data = [];
|
|
||||||
|
|
||||||
if (isset($post['expiry_time'])) {
|
|
||||||
$data['expiry_time'] = $validator->checkExpiryTime($post['expiry_time']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$relation->update($data);
|
|
||||||
|
|
||||||
return $relation;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function findOrFail($id)
|
|
||||||
{
|
|
||||||
$validator = new CourseUserValidator();
|
|
||||||
|
|
||||||
return $validator->checkRelation($id);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function handleRelations($pager)
|
|
||||||
{
|
|
||||||
if ($pager->total_items > 0) {
|
|
||||||
|
|
||||||
$builder = new CourseUserListBuilder();
|
|
||||||
|
|
||||||
$pipeA = $pager->items->toArray();
|
|
||||||
$pipeB = $builder->handleCourses($pipeA);
|
|
||||||
$pipeC = $builder->handleUsers($pipeB);
|
|
||||||
$pipeD = $builder->objects($pipeC);
|
|
||||||
|
|
||||||
$pager->items = $pipeD;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $pager;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function handleLearnings($pager)
|
|
||||||
{
|
|
||||||
if ($pager->total_items > 0) {
|
|
||||||
|
|
||||||
$builder = new LearningListBuilder();
|
|
||||||
|
|
||||||
$pipeA = $pager->items->toArray();
|
|
||||||
$pipeB = $builder->handleCourses($pipeA);
|
|
||||||
$pipeC = $builder->handleChapters($pipeB);
|
|
||||||
$pipeD = $builder->handleUsers($pipeC);
|
|
||||||
$pipeE = $builder->objects($pipeD);
|
|
||||||
|
|
||||||
$pager->items = $pipeE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $pager;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -9,6 +9,7 @@ namespace App\Http\Admin\Services;
|
|||||||
|
|
||||||
use App\Builders\TradeList as TradeListBuilder;
|
use App\Builders\TradeList as TradeListBuilder;
|
||||||
use App\Library\Paginator\Query as PaginateQuery;
|
use App\Library\Paginator\Query as PaginateQuery;
|
||||||
|
use App\Library\Validators\Common as CommonValidator;
|
||||||
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\Account as AccountRepo;
|
use App\Repos\Account as AccountRepo;
|
||||||
@ -46,6 +47,21 @@ class Trade extends Service
|
|||||||
$params['order_id'] = $order ? $order->id : -1000;
|
$params['order_id'] = $order ? $order->id : -1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$accountRepo = new AccountRepo();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 兼容用户编号|手机号码|邮箱地址查询
|
||||||
|
*/
|
||||||
|
if (!empty($params['owner_id'])) {
|
||||||
|
if (CommonValidator::phone($params['owner_id'])) {
|
||||||
|
$account = $accountRepo->findByPhone($params['owner_id']);
|
||||||
|
$params['owner_id'] = $account ? $account->id : -1000;
|
||||||
|
} elseif (CommonValidator::email($params['owner_id'])) {
|
||||||
|
$account = $accountRepo->findByEmail($params['owner_id']);
|
||||||
|
$params['owner_id'] = $account ? $account->id : -1000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$sort = $pageQuery->getSort();
|
$sort = $pageQuery->getSort();
|
||||||
$page = $pageQuery->getPage();
|
$page = $pageQuery->getPage();
|
||||||
$limit = $pageQuery->getLimit();
|
$limit = $pageQuery->getLimit();
|
||||||
|
@ -335,11 +335,12 @@ class User extends Service
|
|||||||
$items = $pager->items->toArray();
|
$items = $pager->items->toArray();
|
||||||
|
|
||||||
$pipeA = $builder->handleUsers($items);
|
$pipeA = $builder->handleUsers($items);
|
||||||
$pipeB = $builder->handleAdminRoles($pipeA);
|
$pipeB = $builder->handleAccounts($pipeA);
|
||||||
$pipeC = $builder->handleEduRoles($pipeB);
|
$pipeC = $builder->handleAdminRoles($pipeB);
|
||||||
$pipeD = $builder->objects($pipeC);
|
$pipeD = $builder->handleEduRoles($pipeC);
|
||||||
|
$pipeE = $builder->objects($pipeD);
|
||||||
|
|
||||||
$pager->items = $pipeD;
|
$pager->items = $pipeE;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $pager;
|
return $pager;
|
||||||
|
@ -7,8 +7,7 @@
|
|||||||
|
|
||||||
namespace App\Http\Admin\Services;
|
namespace App\Http\Admin\Services;
|
||||||
|
|
||||||
use App\Caches\IndexSlideList as IndexSlideListCache;
|
use App\Services\Utils\IndexPageCache as IndexPageCacheUtil;
|
||||||
use App\Services\Utils\IndexCourseCache as IndexCourseCacheUtil;
|
|
||||||
|
|
||||||
class Util extends Service
|
class Util extends Service
|
||||||
{
|
{
|
||||||
@ -17,29 +16,25 @@ class Util extends Service
|
|||||||
{
|
{
|
||||||
$items = $this->request->getPost('items');
|
$items = $this->request->getPost('items');
|
||||||
|
|
||||||
if ($items['slide'] == 1) {
|
$sections = [
|
||||||
$cache = new IndexSlideListCache();
|
'slide',
|
||||||
$cache->rebuild();
|
'featured_course',
|
||||||
|
'new_course',
|
||||||
|
'free_course',
|
||||||
|
'vip_course',
|
||||||
|
];
|
||||||
|
|
||||||
|
if (empty($items)) {
|
||||||
|
$items = $sections;
|
||||||
}
|
}
|
||||||
|
|
||||||
$util = new IndexCourseCacheUtil();
|
$util = new IndexPageCacheUtil();
|
||||||
|
|
||||||
if ($items['featured_course'] == 1) {
|
foreach ($sections as $section) {
|
||||||
$util->rebuild('featured_course');
|
if (in_array($section, $items)) {
|
||||||
|
$util->rebuild($section);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($items['new_course'] == 1) {
|
|
||||||
$util->rebuild('new_course');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($items['free_course'] == 1) {
|
|
||||||
$util->rebuild('free_course');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($items['vip_course'] == 1) {
|
|
||||||
$util->rebuild('vip_course');
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
120
app/Http/Admin/Services/Vip.php
Normal file
120
app/Http/Admin/Services/Vip.php
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @copyright Copyright (c) 2021 深圳市酷瓜软件有限公司
|
||||||
|
* @license https://opensource.org/licenses/GPL-2.0
|
||||||
|
* @link https://www.koogua.com
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Http\Admin\Services;
|
||||||
|
|
||||||
|
use App\Library\Paginator\Query as PagerQuery;
|
||||||
|
use App\Models\Vip as VipModel;
|
||||||
|
use App\Repos\Vip as VipRepo;
|
||||||
|
use App\Validators\Vip as VipValidator;
|
||||||
|
|
||||||
|
class Vip extends Service
|
||||||
|
{
|
||||||
|
|
||||||
|
public function getVips()
|
||||||
|
{
|
||||||
|
$pagerQuery = new PagerQuery();
|
||||||
|
|
||||||
|
$params = $pagerQuery->getParams();
|
||||||
|
|
||||||
|
$params['deleted'] = $params['deleted'] ?? 0;
|
||||||
|
|
||||||
|
$sort = $pagerQuery->getSort();
|
||||||
|
$page = $pagerQuery->getPage();
|
||||||
|
$limit = $pagerQuery->getLimit();
|
||||||
|
|
||||||
|
$vipRepo = new VipRepo();
|
||||||
|
|
||||||
|
return $vipRepo->paginate($params, $sort, $page, $limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getVip($id)
|
||||||
|
{
|
||||||
|
return $this->findOrFail($id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createVip()
|
||||||
|
{
|
||||||
|
$post = $this->request->getPost();
|
||||||
|
|
||||||
|
$validator = new VipValidator();
|
||||||
|
|
||||||
|
$data = [];
|
||||||
|
|
||||||
|
$data['expiry'] = $validator->checkExpiry($post['expiry']);
|
||||||
|
$data['price'] = $validator->checkPrice($post['price']);
|
||||||
|
$data['title'] = sprintf('%s个月', $data['expiry']);
|
||||||
|
|
||||||
|
$vip = new VipModel();
|
||||||
|
|
||||||
|
$vip->create($data);
|
||||||
|
|
||||||
|
return $vip;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateVip($id)
|
||||||
|
{
|
||||||
|
$vip = $this->findOrFail($id);
|
||||||
|
|
||||||
|
$post = $this->request->getPost();
|
||||||
|
|
||||||
|
$validator = new VipValidator();
|
||||||
|
|
||||||
|
$data = [];
|
||||||
|
|
||||||
|
if (isset($post['cover'])) {
|
||||||
|
$data['cover'] = $validator->checkCover($post['cover']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($post['expiry'])) {
|
||||||
|
$data['expiry'] = $validator->checkExpiry($post['expiry']);
|
||||||
|
$data['title'] = sprintf('%s个月', $data['expiry']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($post['price'])) {
|
||||||
|
$data['price'] = $validator->checkPrice($post['price']);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($post['published'])) {
|
||||||
|
$data['published'] = $validator->checkPublishStatus($post['published']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$vip->update($data);
|
||||||
|
|
||||||
|
return $vip;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function deleteVip($id)
|
||||||
|
{
|
||||||
|
$vip = $this->findOrFail($id);
|
||||||
|
|
||||||
|
$vip->deleted = 1;
|
||||||
|
|
||||||
|
$vip->update();
|
||||||
|
|
||||||
|
return $vip;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function restoreVip($id)
|
||||||
|
{
|
||||||
|
$vip = $this->findOrFail($id);
|
||||||
|
|
||||||
|
$vip->deleted = 0;
|
||||||
|
|
||||||
|
$vip->update();
|
||||||
|
|
||||||
|
return $vip;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function findOrFail($id)
|
||||||
|
{
|
||||||
|
$validator = new VipValidator();
|
||||||
|
|
||||||
|
return $validator->checkVip($id);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -7,16 +7,27 @@
|
|||||||
<legend>编辑答案</legend>
|
<legend>编辑答案</legend>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<div class="layui-form-item">
|
<div class="layui-form-item">
|
||||||
<div class="layui-input-block" style="margin:0;">
|
<label class="layui-form-label">问题标题</label>
|
||||||
<input class="layui-input" type="text" name="title" value="{{ question.title }}" readonly="readonly">
|
<div class="layui-input-block">
|
||||||
|
<div class="layui-form-mid layui-word-aux">{{ question.title }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-form-item">
|
<div class="layui-form-item">
|
||||||
<div class="layui-input-block" style="margin:0;">
|
<label class="layui-form-label">回答内容</label>
|
||||||
|
<div class="layui-input-block">
|
||||||
<textarea name="content" class="layui-hide" id="editor-textarea">{{ answer.content }}</textarea>
|
<textarea name="content" class="layui-hide" id="editor-textarea">{{ answer.content }}</textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-input-block kg-center" style="margin:0;">
|
<div class="layui-form-item">
|
||||||
|
<label class="layui-form-label">发布状态</label>
|
||||||
|
<div class="layui-input-block">
|
||||||
|
{% for value,title in publish_types %}
|
||||||
|
{% set checked = value == answer.published ? 'checked="checked"' : '' %}
|
||||||
|
<input type="radio" name="published" value="{{ value }}" title="{{ title }}" {{ checked }}>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layui-input-block">
|
||||||
<button class="layui-btn kg-submit" lay-submit="true" lay-filter="go">提交</button>
|
<button class="layui-btn kg-submit" lay-submit="true" lay-filter="go">提交</button>
|
||||||
<button type="button" class="kg-back layui-btn layui-btn-primary">返回</button>
|
<button type="button" class="kg-back layui-btn layui-btn-primary">返回</button>
|
||||||
<input type="hidden" name="referer" value="{{ request.getHTTPReferer() }}">
|
<input type="hidden" name="referer" value="{{ request.getHTTPReferer() }}">
|
||||||
|
@ -5,12 +5,17 @@
|
|||||||
{{ partial('macros/answer') }}
|
{{ partial('macros/answer') }}
|
||||||
|
|
||||||
{% set search_url = url({'for':'admin.answer.search'}) %}
|
{% set search_url = url({'for':'admin.answer.search'}) %}
|
||||||
|
{% set batch_delete_url = url({'for':'admin.answer.batch_delete'}) %}
|
||||||
|
|
||||||
<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">
|
||||||
|
{% if request.get('course_id') > 0 %}
|
||||||
|
<a class="kg-back"><i class="layui-icon layui-icon-return"></i>返回</a>
|
||||||
|
{% endif %}
|
||||||
<a><cite>回答管理</cite></a>
|
<a><cite>回答管理</cite></a>
|
||||||
</span>
|
</span>
|
||||||
|
<span class="layui-btn layui-btn-sm layui-bg-red kg-batch" data-url="{{ batch_delete_url }}">批量删除</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="kg-nav-right">
|
<div class="kg-nav-right">
|
||||||
<a class="layui-btn layui-btn-sm" href="{{ search_url }}">
|
<a class="layui-btn layui-btn-sm" href="{{ search_url }}">
|
||||||
@ -19,8 +24,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table class="layui-table kg-table layui-form">
|
<table class="layui-table layui-form kg-table">
|
||||||
<colgroup>
|
<colgroup>
|
||||||
|
<col width="5%">
|
||||||
|
<col>
|
||||||
<col>
|
<col>
|
||||||
<col>
|
<col>
|
||||||
<col>
|
<col>
|
||||||
@ -29,7 +36,9 @@
|
|||||||
</colgroup>
|
</colgroup>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>信息</th>
|
<th><input class="all" type="checkbox" lay-filter="all"></th>
|
||||||
|
<th>作者信息</th>
|
||||||
|
<th>问答信息</th>
|
||||||
<th>评论</th>
|
<th>评论</th>
|
||||||
<th>点赞</th>
|
<th>点赞</th>
|
||||||
<th>状态</th>
|
<th>状态</th>
|
||||||
@ -46,10 +55,15 @@
|
|||||||
{% set restore_url = url({'for':'admin.answer.restore','id':item.id}) %}
|
{% set restore_url = url({'for':'admin.answer.restore','id':item.id}) %}
|
||||||
{% set moderate_url = url({'for':'admin.answer.moderate','id':item.id}) %}
|
{% set moderate_url = url({'for':'admin.answer.moderate','id':item.id}) %}
|
||||||
<tr>
|
<tr>
|
||||||
|
<td><input class="item" type="checkbox" value="{{ item.id }}" lay-filter="item"></td>
|
||||||
<td>
|
<td>
|
||||||
<P>问题:<a href="{{ question_url }}" target="_blank">{{ item.question.title }}</a></P>
|
<p>昵称:<a href="{{ owner_url }}">{{ item.owner.name }}</a></p>
|
||||||
<p>回答:<a href="{{ answer_url }}" title="{{ item.summary }}" target="_blank">{{ substr(item.summary,0,32) }}</a></p>
|
<p>编号:{{ item.owner.id }}</p>
|
||||||
<p>作者:<a href="{{ owner_url }}" target="_blank">{{ item.owner.name }}</a> 创建:{{ date('Y-m-d',item.create_time) }}</p>
|
</td>
|
||||||
|
<td>
|
||||||
|
<P>问题:<a href="{{ question_url }}" target="_blank">{{ item.question.title }}</a>({{ item.question.id }})</P>
|
||||||
|
<p class="layui-elip kg-item-elip" title="{{ item.summary }}">回答:{{ item.summary }}({{ item.id }})</p>
|
||||||
|
<p>创建:{{ date('Y-m-d',item.create_time) }}</p>
|
||||||
</td>
|
</td>
|
||||||
<td>{{ item.comment_count }}</td>
|
<td>{{ item.comment_count }}</td>
|
||||||
<td>{{ item.like_count }}</td>
|
<td>{{ item.like_count }}</td>
|
||||||
|
@ -37,8 +37,8 @@
|
|||||||
<div class="layui-input-block">
|
<div class="layui-input-block">
|
||||||
<select name="reason">
|
<select name="reason">
|
||||||
<option value="">请选择</option>
|
<option value="">请选择</option>
|
||||||
{% for value,name in reasons %}
|
{% for reason in reasons %}
|
||||||
<option value="{{ value }}">{{ name }}</option>
|
<option value="{{ reason }}">{{ reason }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
@ -23,13 +23,13 @@
|
|||||||
<div class="title">{{ answer.question.title }}</div>
|
<div class="title">{{ answer.question.title }}</div>
|
||||||
<div class="meta">
|
<div class="meta">
|
||||||
<span><a href="{{ owner_url }}" target="_blank">{{ answer.owner.name }}</a></span>
|
<span><a href="{{ owner_url }}" target="_blank">{{ answer.owner.name }}</a></span>
|
||||||
<span>{{ date('Y-m-d H:i',answer.create_time) }}</span>
|
<span>{{ date('Y-m-d H:i:s',answer.create_time) }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="content ke-content">{{ answer.content }}</div>
|
<div class="content ke-content">{{ answer.content }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-tab-item">
|
<div class="layui-tab-item">
|
||||||
<table class="layui-table kg-table" style="width:80%;">
|
<table class="layui-table kg-table">
|
||||||
<colgroup>
|
<colgroup>
|
||||||
<col>
|
<col>
|
||||||
<col>
|
<col>
|
||||||
@ -73,7 +73,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">
|
||||||
<button id="kg-submit" class="layui-btn" lay-submit="true" lay-filter="go">提交</button>
|
<button class="layui-btn" lay-submit="true" lay-filter="go">提交</button>
|
||||||
<button type="button" class="kg-back layui-btn layui-btn-primary">返回</button>
|
<button type="button" class="kg-back layui-btn layui-btn-primary">返回</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -24,21 +24,24 @@
|
|||||||
<input class="layui-input" type="text" name="owner_id" placeholder="用户编号精确匹配">
|
<input class="layui-input" type="text" name="owner_id" placeholder="用户编号精确匹配">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="layui-form-item" id="time-range">
|
||||||
|
<label class="layui-form-label">创建时间</label>
|
||||||
|
<div class="layui-input-inline">
|
||||||
|
<input class="layui-input" id="start-time" type="text" name="create_time[]" autocomplete="off">
|
||||||
|
</div>
|
||||||
|
<div class="layui-form-mid">-</div>
|
||||||
|
<div class="layui-input-inline">
|
||||||
|
<input class="layui-input" id="end-time" type="text" name="create_time[]" autocomplete="off">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<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">
|
||||||
{% for value,title in publish_types %}
|
{% for value,title in publish_types %}
|
||||||
<input type="radio" name="published" value="{{ value }}" title="{{ title }}">
|
<input type="checkbox" name="published[]" value="{{ value }}" title="{{ title }}">
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-form-item">
|
|
||||||
<label class="layui-form-label">匿名</label>
|
|
||||||
<div class="layui-input-block">
|
|
||||||
<input type="radio" name="anonymous" value="1" title="是">
|
|
||||||
<input type="radio" name="anonymous" value="0" title="否">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<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">
|
||||||
@ -55,4 +58,24 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block inline_js %}
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
layui.use(['jquery', 'laydate'], function () {
|
||||||
|
|
||||||
|
var laydate = layui.laydate;
|
||||||
|
|
||||||
|
laydate.render({
|
||||||
|
elem: '#time-range',
|
||||||
|
type: 'datetime',
|
||||||
|
range: ['#start-time', '#end-time'],
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
|
{% set update_url = url({'for':'admin.article.update','id':article.id}) %}
|
||||||
|
|
||||||
<fieldset class="layui-elem-field layui-field-title">
|
<fieldset class="layui-elem-field layui-field-title">
|
||||||
<legend>编辑文章</legend>
|
<legend>编辑文章</legend>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
@ -9,12 +11,16 @@
|
|||||||
<div class="layui-tab layui-tab-brief">
|
<div class="layui-tab layui-tab-brief">
|
||||||
<ul class="layui-tab-title kg-tab-title">
|
<ul class="layui-tab-title kg-tab-title">
|
||||||
<li class="layui-this">基本信息</li>
|
<li class="layui-this">基本信息</li>
|
||||||
|
<li>搜索优化</li>
|
||||||
<li>文章内容</li>
|
<li>文章内容</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="layui-tab-content">
|
<div class="layui-tab-content">
|
||||||
<div class="layui-tab-item layui-show">
|
<div class="layui-tab-item layui-show">
|
||||||
{{ partial('article/edit_basic') }}
|
{{ partial('article/edit_basic') }}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="layui-tab-item">
|
||||||
|
{{ partial('article/edit_seo') }}
|
||||||
|
</div>
|
||||||
<div class="layui-tab-item">
|
<div class="layui-tab-item">
|
||||||
{{ partial('article/edit_desc') }}
|
{{ partial('article/edit_desc') }}
|
||||||
</div>
|
</div>
|
||||||
@ -29,6 +35,7 @@
|
|||||||
{{ js_include('lib/kindeditor/kindeditor.min.js') }}
|
{{ js_include('lib/kindeditor/kindeditor.min.js') }}
|
||||||
{{ js_include('lib/kindeditor/lang/zh-CN.js') }}
|
{{ js_include('lib/kindeditor/lang/zh-CN.js') }}
|
||||||
{{ js_include('admin/js/content.editor.js') }}
|
{{ js_include('admin/js/content.editor.js') }}
|
||||||
|
{{ js_include('admin/js/cover.upload.js') }}
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
@ -1,6 +1,16 @@
|
|||||||
{% set source_url_display = article.source_type == 1 ? 'display:none' : 'display:block' %}
|
{% set source_url_display = article.source_type == 1 ? 'display:none' : 'display:block' %}
|
||||||
|
|
||||||
<form class="layui-form kg-form" method="POST" action="{{ url({'for':'admin.article.update','id':article.id}) }}">
|
<form class="layui-form kg-form" method="POST" action="{{ update_url }}">
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<label class="layui-form-label">封面</label>
|
||||||
|
<div class="layui-input-inline">
|
||||||
|
<img id="img-cover" class="kg-cover" src="{{ article.cover }}">
|
||||||
|
<input type="hidden" name="cover" value="{{ article.cover }}">
|
||||||
|
</div>
|
||||||
|
<div class="layui-input-inline" style="padding-top:35px;">
|
||||||
|
<button id="change-cover" class="layui-btn layui-btn-sm" type="button">更换</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<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">
|
||||||
@ -8,15 +18,21 @@
|
|||||||
</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">分类</label>
|
||||||
<div class="layui-input-block">
|
<div class="layui-input-block">
|
||||||
<div id="xm-tag-ids"></div>
|
<select name="category_id" lay-search="true">
|
||||||
|
<option value="">请选择</option>
|
||||||
|
{% for option in category_options %}
|
||||||
|
{% set selected = article.category_id == option.id ? 'selected="selected"' : '' %}
|
||||||
|
<option value="{{ option.id }}" {{ selected }}>{{ option.name }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
</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">标签</label>
|
||||||
<div class="layui-input-block">
|
<div class="layui-input-block">
|
||||||
<input class="layui-input" type="text" name="keywords" value="{{ article.keywords }}" placeholder="多个关键字用逗号分隔">
|
<div id="xm-tag-ids"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-form-item">
|
<div class="layui-form-item">
|
||||||
@ -35,6 +51,22 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<label class="layui-form-label">发布状态</label>
|
||||||
|
<div class="layui-input-block">
|
||||||
|
{% for value,title in publish_types %}
|
||||||
|
{% set checked = value == article.published ? 'checked="checked"' : '' %}
|
||||||
|
<input type="radio" name="published" value="{{ value }}" title="{{ title }}" {{ checked }}>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<label class="layui-form-label">推荐文章</label>
|
||||||
|
<div class="layui-input-block">
|
||||||
|
<input type="radio" name="featured" value="1" title="是" {% if article.featured == 1 %}checked="checked"{% endif %}>
|
||||||
|
<input type="radio" name="featured" value="0" title="否" {% if article.featured == 0 %}checked="checked"{% endif %}>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<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">
|
||||||
@ -42,17 +74,10 @@
|
|||||||
<input type="radio" name="closed" value="0" title="否" {% if article.closed == 0 %}checked="checked"{% endif %}>
|
<input type="radio" name="closed" value="0" title="否" {% if article.closed == 0 %}checked="checked"{% endif %}>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-form-item">
|
|
||||||
<label class="layui-form-label">仅我可见</label>
|
|
||||||
<div class="layui-input-block">
|
|
||||||
<input type="radio" name="private" value="1" title="是" {% if article.private == 1 %}checked="checked"{% endif %}>
|
|
||||||
<input type="radio" name="private" value="0" title="否" {% if article.private == 0 %}checked="checked"{% endif %}>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="layui-form-item">
|
<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">
|
||||||
<button class="layui-btn kg-submit" lay-submit="true" lay-filter="go">提交</button>
|
<button class="layui-btn" lay-submit="true" lay-filter="go">提交</button>
|
||||||
<button type="button" class="kg-back layui-btn layui-btn-primary">返回</button>
|
<button type="button" class="kg-back layui-btn layui-btn-primary">返回</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<form class="layui-form kg-form" method="POST" action="{{ url({'for':'admin.article.update','id':article.id}) }}">
|
<form class="layui-form kg-form" method="POST" action="{{ update_url }}">
|
||||||
<div class="layui-form-item">
|
<div class="layui-form-item">
|
||||||
<div class="layui-input-block" style="margin:0;">
|
<div class="layui-input-block" style="margin:0;">
|
||||||
<textarea name="content" class="layui-hide" id="editor-textarea">{{ article.content }}</textarea>
|
<textarea name="content" class="layui-hide" id="editor-textarea">{{ article.content }}</textarea>
|
||||||
|
21
app/Http/Admin/Views/article/edit_seo.volt
Normal file
21
app/Http/Admin/Views/article/edit_seo.volt
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<form class="layui-form kg-form" method="POST" action="{{ update_url }}">
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<label class="layui-form-label">关键字</label>
|
||||||
|
<div class="layui-input-block">
|
||||||
|
<input class="layui-input" type="text" name="keywords" value="{{ article.keywords }}" placeholder="多个关键字用逗号分隔">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<label class="layui-form-label">内容摘要</label>
|
||||||
|
<div class="layui-input-block">
|
||||||
|
<textarea class="layui-textarea" name="summary">{{ article.summary }}</textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<label class="layui-form-label"></label>
|
||||||
|
<div class="layui-input-block">
|
||||||
|
<button class="layui-btn kg-submit" lay-submit="true" lay-filter="go">提交</button>
|
||||||
|
<button type="button" class="kg-back layui-btn layui-btn-primary">返回</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
@ -6,14 +6,20 @@
|
|||||||
|
|
||||||
{% set add_url = url({'for':'admin.article.add'}) %}
|
{% set add_url = url({'for':'admin.article.add'}) %}
|
||||||
{% set search_url = url({'for':'admin.article.search'}) %}
|
{% set search_url = url({'for':'admin.article.search'}) %}
|
||||||
|
{% set category_url = url({'for':'admin.article.category'}) %}
|
||||||
|
{% set batch_delete_url = url({'for':'admin.article.batch_delete'}) %}
|
||||||
|
|
||||||
<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><cite>文章管理</cite></a>
|
<a><cite>文章管理</cite></a>
|
||||||
</span>
|
</span>
|
||||||
|
<span class="layui-btn layui-btn-sm layui-bg-red kg-batch" data-url="{{ batch_delete_url }}">批量删除</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="kg-nav-right">
|
<div class="kg-nav-right">
|
||||||
|
<a class="layui-btn layui-btn-sm" href="{{ category_url }}">
|
||||||
|
<i class="layui-icon layui-icon-add-1"></i>文章分类
|
||||||
|
</a>
|
||||||
<a class="layui-btn layui-btn-sm" href="{{ add_url }}">
|
<a class="layui-btn layui-btn-sm" href="{{ add_url }}">
|
||||||
<i class="layui-icon layui-icon-add-1"></i>添加文章
|
<i class="layui-icon layui-icon-add-1"></i>添加文章
|
||||||
</a>
|
</a>
|
||||||
@ -23,10 +29,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table class="layui-table kg-table layui-form">
|
<table class="layui-table layui-form kg-table">
|
||||||
<colgroup>
|
<colgroup>
|
||||||
<col>
|
<col width="5%">
|
||||||
<col>
|
|
||||||
<col>
|
<col>
|
||||||
<col>
|
<col>
|
||||||
<col>
|
<col>
|
||||||
@ -37,11 +42,10 @@
|
|||||||
</colgroup>
|
</colgroup>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>文章</th>
|
<th><input class="all" type="checkbox" lay-filter="all"></th>
|
||||||
<th>浏览</th>
|
<th>作者信息</th>
|
||||||
<th>评论</th>
|
<th>文章信息</th>
|
||||||
<th>点赞</th>
|
<th>统计信息</th>
|
||||||
<th>收藏</th>
|
|
||||||
<th>状态</th>
|
<th>状态</th>
|
||||||
<th>推荐</th>
|
<th>推荐</th>
|
||||||
<th>关闭</th>
|
<th>关闭</th>
|
||||||
@ -59,29 +63,35 @@
|
|||||||
{% set moderate_url = url({'for':'admin.article.moderate','id':item.id}) %}
|
{% set moderate_url = url({'for':'admin.article.moderate','id':item.id}) %}
|
||||||
{% set comment_url = url({'for':'admin.comment.list'},{'item_id':item.id,'item_type':2}) %}
|
{% set comment_url = url({'for':'admin.comment.list'},{'item_id':item.id,'item_type':2}) %}
|
||||||
<tr>
|
<tr>
|
||||||
|
<td><input class="item" type="checkbox" value="{{ item.id }}" lay-filter="item"></td>
|
||||||
|
<td>
|
||||||
|
<p>昵称:<a href="{{ owner_url }}" target="_blank">{{ item.owner.name }}</a></p>
|
||||||
|
<p>编号:{{ item.owner.id }}</p>
|
||||||
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<p>标题:<a href="{{ edit_url }}">{{ item.title }}</a>({{ item.id }})</p>
|
<p>标题:<a href="{{ edit_url }}">{{ item.title }}</a>({{ item.id }})</p>
|
||||||
<p class="meta">
|
<p class="meta">
|
||||||
{% if item.category.id is defined %}
|
{% if item.category.id is defined %}
|
||||||
<span>分类:{{ item.category.name }}</span>
|
<span>分类:{{ item.category.name }}</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if item.tags %}
|
|
||||||
<span>标签:{{ tags_info(item.tags) }}</span>
|
|
||||||
{% endif %}
|
|
||||||
</p>
|
|
||||||
<p class="meta">
|
|
||||||
<span>来源:{{ source_type(item.source_type) }}</span>
|
|
||||||
<span>作者:<a href="{{ owner_url }}" target="_blank">{{ item.owner.name }}</a></span>
|
|
||||||
<span>创建:{{ date('Y-m-d',item.create_time) }}</span>
|
<span>创建:{{ date('Y-m-d',item.create_time) }}</span>
|
||||||
</p>
|
</p>
|
||||||
</td>
|
</td>
|
||||||
<td>{{ item.view_count }}</td>
|
<td>
|
||||||
<td>{{ item.comment_count }}</td>
|
<p class="meta">
|
||||||
<td>{{ item.like_count }}</td>
|
<span>浏览:{{ item.view_count }}</span>
|
||||||
<td>{{ item.favorite_count }}</td>
|
<span>评论:{{ item.comment_count }}</span>
|
||||||
|
</p>
|
||||||
|
<p class="meta">
|
||||||
|
<span>点赞:{{ item.like_count }}</span>
|
||||||
|
<span>收藏:{{ item.favorite_count }}</span>
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
<td>{{ publish_status(item.published) }}</td>
|
<td>{{ publish_status(item.published) }}</td>
|
||||||
<td><input type="checkbox" name="featured" value="1" lay-skin="switch" lay-text="是|否" lay-filter="featured" data-url="{{ update_url }}" {% if item.featured == 1 %}checked="checked"{% endif %}></td>
|
<td><input type="checkbox" name="featured" value="1" lay-text="是|否" lay-skin="switch" lay-filter="go" data-url="{{ update_url }}"
|
||||||
<td><input type="checkbox" name="comment" value="1" lay-skin="switch" lay-text="是|否" lay-filter="closed" data-url="{{ update_url }}" {% if item.closed == 1 %}checked="checked"{% endif %}></td>
|
{% if item.featured == 1 %}checked="checked"{% endif %}></td>
|
||||||
|
<td><input type="checkbox" name="closed" value="1" lay-text="是|否" lay-skin="switch" lay-filter="go" data-url="{{ update_url }}"
|
||||||
|
{% if item.closed == 1 %}checked="checked"{% endif %}></td>
|
||||||
<td class="center">
|
<td class="center">
|
||||||
<div class="kg-dropdown">
|
<div class="kg-dropdown">
|
||||||
<button class="layui-btn layui-btn-sm">操作 <i class="layui-icon layui-icon-triangle-d"></i></button>
|
<button class="layui-btn layui-btn-sm">操作 <i class="layui-icon layui-icon-triangle-d"></i></button>
|
||||||
@ -115,64 +125,11 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
layui.define(['jquery', 'form', 'layer'], function () {
|
layui.define(['jquery', 'layer'], function () {
|
||||||
|
|
||||||
var $ = layui.jquery;
|
var $ = layui.jquery;
|
||||||
var form = layui.form;
|
|
||||||
var layer = layui.layer;
|
var layer = layui.layer;
|
||||||
|
|
||||||
form.on('switch(featured)', function (data) {
|
|
||||||
var checked = $(this).is(':checked');
|
|
||||||
var featured = checked ? 1 : 0;
|
|
||||||
var url = $(this).data('url');
|
|
||||||
var tips = featured === 1 ? '确定要推荐?' : '确定要取消推荐?';
|
|
||||||
layer.confirm(tips, function () {
|
|
||||||
$.ajax({
|
|
||||||
type: 'POST',
|
|
||||||
url: url,
|
|
||||||
data: {featured: featured},
|
|
||||||
success: function (res) {
|
|
||||||
layer.msg(res.msg, {icon: 1});
|
|
||||||
},
|
|
||||||
error: function (xhr) {
|
|
||||||
var json = JSON.parse(xhr.responseText);
|
|
||||||
layer.msg(json.msg, {icon: 2});
|
|
||||||
data.elem.checked = !checked;
|
|
||||||
form.render();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, function () {
|
|
||||||
data.elem.checked = !checked;
|
|
||||||
form.render();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
form.on('switch(closed)', function (data) {
|
|
||||||
var checked = $(this).is(':checked');
|
|
||||||
var closed = checked ? 1 : 0;
|
|
||||||
var url = $(this).data('url');
|
|
||||||
var tips = closed === 1 ? '确定要关闭评论?' : '确定要开启评论?';
|
|
||||||
layer.confirm(tips, function () {
|
|
||||||
$.ajax({
|
|
||||||
type: 'POST',
|
|
||||||
url: url,
|
|
||||||
data: {closed: closed},
|
|
||||||
success: function (res) {
|
|
||||||
layer.msg(res.msg, {icon: 1});
|
|
||||||
},
|
|
||||||
error: function (xhr) {
|
|
||||||
var json = JSON.parse(xhr.responseText);
|
|
||||||
layer.msg(json.msg, {icon: 2});
|
|
||||||
data.elem.checked = !checked;
|
|
||||||
form.render();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, function () {
|
|
||||||
data.elem.checked = !checked;
|
|
||||||
form.render();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
$('.kg-comment').on('click', function () {
|
$('.kg-comment').on('click', function () {
|
||||||
var url = $(this).data('url');
|
var url = $(this).data('url');
|
||||||
layer.open({
|
layer.open({
|
||||||
|
@ -51,8 +51,8 @@
|
|||||||
<div class="layui-input-block">
|
<div class="layui-input-block">
|
||||||
<select name="reason">
|
<select name="reason">
|
||||||
<option value="">请选择</option>
|
<option value="">请选择</option>
|
||||||
{% for value,name in reasons %}
|
{% for reason in reasons %}
|
||||||
<option value="{{ value }}">{{ name }}</option>
|
<option value="{{ reason }}">{{ reason }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
@ -60,7 +60,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">
|
||||||
<button id="kg-submit" class="layui-btn" lay-submit="true" lay-filter="go">提交</button>
|
<button class="layui-btn" lay-submit="true" lay-filter="go">提交</button>
|
||||||
<button type="button" class="kg-back layui-btn layui-btn-primary">返回</button>
|
<button type="button" class="kg-back layui-btn layui-btn-primary">返回</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
<div class="meta">
|
<div class="meta">
|
||||||
<span class="layui-badge layui-bg-green">{{ source_type(article.source_type) }}</span>
|
<span class="layui-badge layui-bg-green">{{ source_type(article.source_type) }}</span>
|
||||||
<span><a href="{{ owner_url }}" target="_blank">{{ article.owner.name }}</a></span>
|
<span><a href="{{ owner_url }}" target="_blank">{{ article.owner.name }}</a></span>
|
||||||
<span>{{ date('Y-m-d H:i',article.create_time) }}</span>
|
<span>{{ date('Y-m-d H:i:s',article.create_time) }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="content ke-content">{{ article.content }}</div>
|
<div class="content ke-content">{{ article.content }}</div>
|
||||||
{% if article.tags %}
|
{% if article.tags %}
|
||||||
@ -42,7 +42,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-tab-item">
|
<div class="layui-tab-item">
|
||||||
<table class="layui-table kg-table" style="width:80%;">
|
<table class="layui-table kg-table">
|
||||||
<colgroup>
|
<colgroup>
|
||||||
<col>
|
<col>
|
||||||
<col>
|
<col>
|
||||||
@ -61,7 +61,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td><a href="{{ owner_url }}" target="_blank">{{ item.owner.name }}</a></td>
|
<td><a href="{{ owner_url }}" target="_blank">{{ item.owner.name }}</a></td>
|
||||||
<td>{{ item.reason }}</td>
|
<td>{{ item.reason }}</td>
|
||||||
<td>{{ date('Y-m-d',item.create_time) }}</td>
|
<td>{{ date('Y-m-d H:i:s',item.create_time) }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
@ -86,7 +86,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">
|
||||||
<button id="kg-submit" class="layui-btn" lay-submit="true" lay-filter="go">提交</button>
|
<button class="layui-btn" lay-submit="true" lay-filter="go">提交</button>
|
||||||
<button type="button" class="kg-back layui-btn layui-btn-primary">返回</button>
|
<button type="button" class="kg-back layui-btn layui-btn-primary">返回</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -19,30 +19,45 @@
|
|||||||
</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">文章标题</label>
|
||||||
<div class="layui-input-block">
|
<div class="layui-input-block">
|
||||||
<input class="layui-input" type="text" name="title" placeholder="标题模糊匹配">
|
<input class="layui-input" type="text" name="title" placeholder="标题模糊匹配">
|
||||||
</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">文章分类</label>
|
||||||
<div class="layui-input-block">
|
<div class="layui-input-block">
|
||||||
<div id="xm-tag-ids"></div>
|
<select name="category_id" lay-search="true">
|
||||||
|
<option value="">请选择</option>
|
||||||
|
{% for option in category_options %}
|
||||||
|
<option value="{{ option.id }}">{{ option.name }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-form-item">
|
<div class="layui-form-item" id="time-range">
|
||||||
<label class="layui-form-label">发布状态</label>
|
<label class="layui-form-label">创建时间</label>
|
||||||
<div class="layui-input-block">
|
<div class="layui-input-inline">
|
||||||
{% for value,title in publish_types %}
|
<input class="layui-input" id="start-time" type="text" name="create_time[]" autocomplete="off">
|
||||||
<input type="radio" name="published" value="{{ value }}" title="{{ title }}">
|
</div>
|
||||||
{% endfor %}
|
<div class="layui-form-mid">-</div>
|
||||||
|
<div class="layui-input-inline">
|
||||||
|
<input class="layui-input" id="end-time" type="text" name="create_time[]" autocomplete="off">
|
||||||
</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">来源类型</label>
|
||||||
<div class="layui-input-block">
|
<div class="layui-input-block">
|
||||||
{% for value,title in source_types %}
|
{% for value,title in source_types %}
|
||||||
<input type="radio" name="source_type" value="{{ value }}" title="{{ title }}">
|
<input type="checkbox" name="source_type[]" value="{{ value }}" title="{{ title }}">
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<label class="layui-form-label">发布状态</label>
|
||||||
|
<div class="layui-input-block">
|
||||||
|
{% for value,title in publish_types %}
|
||||||
|
<input type="checkbox" name="published[]" value="{{ value }}" title="{{ title }}">
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -53,13 +68,6 @@
|
|||||||
<input type="radio" name="closed" value="1" title="否">
|
<input type="radio" name="closed" value="1" title="否">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-form-item">
|
|
||||||
<label class="layui-form-label">仅我可见</label>
|
|
||||||
<div class="layui-input-block">
|
|
||||||
<input type="radio" name="private" value="1" title="是">
|
|
||||||
<input type="radio" name="private" value="0" title="否">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<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">
|
||||||
@ -85,22 +93,20 @@
|
|||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block include_js %}
|
|
||||||
|
|
||||||
{{ js_include('lib/xm-select.js') }}
|
|
||||||
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block inline_js %}
|
{% block inline_js %}
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
xmSelect.render({
|
layui.use(['jquery', 'laydate'], function () {
|
||||||
el: '#xm-tag-ids',
|
|
||||||
name: 'xm_tag_ids',
|
var laydate = layui.laydate;
|
||||||
max: 5,
|
|
||||||
filterable: true,
|
laydate.render({
|
||||||
data: {{ xm_tags|json_encode }}
|
elem: '#time-range',
|
||||||
|
type: 'datetime',
|
||||||
|
range: ['#start-time', '#end-time'],
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
<div class="layui-input-inline">
|
<div class="layui-input-inline">
|
||||||
<input class="layui-input time-range" type="text" name="start_time" autocomplete="off">
|
<input class="layui-input time-range" type="text" name="start_time" autocomplete="off">
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-form-mid"> -</div>
|
<div class="layui-form-mid">-</div>
|
||||||
<div class="layui-input-inline">
|
<div class="layui-input-inline">
|
||||||
<input class="layui-input time-range" type="text" name="end_time" autocomplete="off">
|
<input class="layui-input time-range" type="text" name="end_time" autocomplete="off">
|
||||||
</div>
|
</div>
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table class="layui-table kg-table layui-form">
|
<table class="layui-table layui-form kg-table">
|
||||||
<colgroup>
|
<colgroup>
|
||||||
<col>
|
<col>
|
||||||
<col>
|
<col>
|
||||||
@ -54,20 +54,21 @@
|
|||||||
{% set restore_url = url({'for':'admin.category.restore','id':item.id}) %}
|
{% set restore_url = url({'for':'admin.category.restore','id':item.id}) %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ item.id }}</td>
|
<td>{{ item.id }}</td>
|
||||||
<td><img class="kg-icon" src="{{ item.icon }}" alt="{{ item.name }}"></td>
|
<td><img class="kg-icon-sm" src="{{ item.icon }}" alt="{{ item.name }}"></td>
|
||||||
{% if item.type == 1 %}
|
{% if item.type in [1,3,4] %}
|
||||||
{% if item.level == 1 %}
|
{% if item.level == 1 %}
|
||||||
<td><a href="{{ child_url }}"><i class="layui-icon layui-icon-add-circle"></i> {{ item.name }}</a></td>
|
<td><a href="{{ child_url }}"><i class="layui-icon layui-icon-add-circle"></i> {{ item.name }}</a></td>
|
||||||
{% else %}
|
{% else %}
|
||||||
<td><a href="{{ edit_url }}">{{ item.name }}</a></td>
|
<td><a href="{{ edit_url }}">{{ item.name }}</a></td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% elseif item.type == 2 %}
|
{% else %}
|
||||||
<td><a href="{{ edit_url }}">{{ item.name }}</a></td>
|
<td><a href="{{ edit_url }}">{{ item.name }}</a></td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<td>{{ item.level }}</td>
|
<td>{{ item.level }}</td>
|
||||||
<td>{{ item.child_count }}</td>
|
<td>{{ item.child_count }}</td>
|
||||||
<td><input class="layui-input kg-priority" type="text" name="priority" title="数值越小排序越靠前" value="{{ item.priority }}" data-url="{{ update_url }}"></td>
|
<td><input class="layui-input kg-priority" type="text" name="priority" title="数值越小排序越靠前" value="{{ item.priority }}" data-url="{{ update_url }}"></td>
|
||||||
<td><input type="checkbox" name="published" value="1" lay-skin="switch" lay-text="是|否" lay-filter="published" data-url="{{ update_url }}" {% if item.published == 1 %}checked="checked"{% endif %}></td>
|
<td><input type="checkbox" name="published" value="1" lay-text="是|否" lay-skin="switch" lay-filter="go" data-url="{{ update_url }}"
|
||||||
|
{% if item.published == 1 %}checked="checked"{% endif %}></td>
|
||||||
<td class="center">
|
<td class="center">
|
||||||
<div class="kg-dropdown">
|
<div class="kg-dropdown">
|
||||||
<button class="layui-btn layui-btn-sm">操作 <i class="layui-icon layui-icon-triangle-d"></i></button>
|
<button class="layui-btn layui-btn-sm">操作 <i class="layui-icon layui-icon-triangle-d"></i></button>
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
||||||
<table class="layui-table kg-table layui-form">
|
<table class="layui-table layui-form kg-table">
|
||||||
<colgroup>
|
<colgroup>
|
||||||
<col>
|
<col>
|
||||||
<col>
|
<col>
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
||||||
<table class="layui-table kg-table layui-form">
|
<table class="layui-table layui-form kg-table">
|
||||||
<colgroup>
|
<colgroup>
|
||||||
<col>
|
<col>
|
||||||
<col>
|
<col>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<table class="layui-table kg-table layui-form">
|
<table class="layui-table layui-form kg-table">
|
||||||
<colgroup>
|
<colgroup>
|
||||||
<col>
|
<col>
|
||||||
<col>
|
<col>
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
||||||
<table class="layui-table kg-table layui-form">
|
<table class="layui-table layui-form kg-table">
|
||||||
<colgroup>
|
<colgroup>
|
||||||
<col>
|
<col>
|
||||||
<col>
|
<col>
|
||||||
|
@ -4,20 +4,36 @@
|
|||||||
|
|
||||||
{{ partial('macros/common') }}
|
{{ partial('macros/common') }}
|
||||||
|
|
||||||
<table class="layui-table kg-table layui-form" lay-size="lg">
|
{% set batch_delete_url = url({'for':'admin.comment.batch_delete'}) %}
|
||||||
|
|
||||||
|
<div class="kg-nav">
|
||||||
|
<div class="kg-nav-left">
|
||||||
|
<span class="layui-breadcrumb">
|
||||||
|
{% if request.get('item_id') > 0 %}
|
||||||
|
<a class="kg-back"><i class="layui-icon layui-icon-return"></i>返回</a>
|
||||||
|
{% endif %}
|
||||||
|
<a><cite>评论管理</cite></a>
|
||||||
|
</span>
|
||||||
|
<span class="layui-btn layui-btn-sm layui-bg-red kg-batch" data-url="{{ batch_delete_url }}">批量删除</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table class="layui-table layui-form kg-table">
|
||||||
<colgroup>
|
<colgroup>
|
||||||
<col width="50%">
|
<col width="50%">
|
||||||
<col>
|
<col>
|
||||||
<col>
|
<col>
|
||||||
<col>
|
<col>
|
||||||
|
<col>
|
||||||
<col width="10%">
|
<col width="10%">
|
||||||
</colgroup>
|
</colgroup>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>评论</th>
|
<th>作者</th>
|
||||||
|
<th>内容</th>
|
||||||
|
<th>回复</th>
|
||||||
<th>点赞</th>
|
<th>点赞</th>
|
||||||
<th>用户</th>
|
<th>创建</th>
|
||||||
<th>时间</th>
|
|
||||||
<th>操作</th>
|
<th>操作</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@ -28,9 +44,12 @@
|
|||||||
{% set delete_url = url({'for':'admin.comment.delete','id':item.id}) %}
|
{% set delete_url = url({'for':'admin.comment.delete','id':item.id}) %}
|
||||||
{% set restore_url = url({'for':'admin.comment.restore','id':item.id}) %}
|
{% set restore_url = url({'for':'admin.comment.restore','id':item.id}) %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ item.content }}</td>
|
<td><a href="{{ owner_url }}" target="_blank">{{ item.owner.name }}</a>({{ item.owner.id }})</td>
|
||||||
|
<td>
|
||||||
|
<p class="layui-elip kg-item-elip" title="{{ item.content }}">{{ item.content }}</p>
|
||||||
|
</td>
|
||||||
|
<td>{{ item.reply_count }}</td>
|
||||||
<td>{{ item.like_count }}</td>
|
<td>{{ item.like_count }}</td>
|
||||||
<td><a href="{{ owner_url }}" target="_blank">{{ item.owner.name }}</a></td>
|
|
||||||
<td>{{ date('Y-m-d',item.create_time) }}</td>
|
<td>{{ date('Y-m-d',item.create_time) }}</td>
|
||||||
<td class="center">
|
<td class="center">
|
||||||
{% if item.deleted == 0 %}
|
{% if item.deleted == 0 %}
|
||||||
|
@ -37,8 +37,8 @@
|
|||||||
<div class="layui-input-block">
|
<div class="layui-input-block">
|
||||||
<select name="reason">
|
<select name="reason">
|
||||||
<option value="">请选择</option>
|
<option value="">请选择</option>
|
||||||
{% for value,name in reasons %}
|
{% for reason in reasons %}
|
||||||
<option value="{{ value }}">{{ name }}</option>
|
<option value="{{ reason }}">{{ reason }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
@ -46,7 +46,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">
|
||||||
<button id="kg-submit" class="layui-btn" lay-submit="true" lay-filter="go">提交</button>
|
<button class="layui-btn" lay-submit="true" lay-filter="go">提交</button>
|
||||||
<button type="button" class="kg-back layui-btn layui-btn-primary">返回</button>
|
<button type="button" class="kg-back layui-btn layui-btn-primary">返回</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -22,13 +22,13 @@
|
|||||||
<div class="kg-mod-preview">
|
<div class="kg-mod-preview">
|
||||||
<div class="meta">
|
<div class="meta">
|
||||||
<span><a href="{{ owner_url }}" target="_blank">{{ comment.owner.name }}</a></span>
|
<span><a href="{{ owner_url }}" target="_blank">{{ comment.owner.name }}</a></span>
|
||||||
<span>{{ date('Y-m-d H:i',comment.create_time) }}</span>
|
<span>{{ date('Y-m-d H:i:s',comment.create_time) }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="content ke-content">{{ comment.content }}</div>
|
<div class="content ke-content">{{ comment.content }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-tab-item">
|
<div class="layui-tab-item">
|
||||||
<table class="layui-table kg-table" style="width:80%;">
|
<table class="layui-table kg-table">
|
||||||
<colgroup>
|
<colgroup>
|
||||||
<col>
|
<col>
|
||||||
<col>
|
<col>
|
||||||
@ -47,7 +47,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td><a href="{{ owner_url }}" target="_blank">{{ item.owner.name }}</a></td>
|
<td><a href="{{ owner_url }}" target="_blank">{{ item.owner.name }}</a></td>
|
||||||
<td>{{ item.reason }}</td>
|
<td>{{ item.reason }}</td>
|
||||||
<td>{{ date('Y-m-d',item.create_time) }}</td>
|
<td>{{ date('Y-m-d H:i:s',item.create_time) }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
@ -72,7 +72,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">
|
||||||
<button id="kg-submit" class="layui-btn" lay-submit="true" lay-filter="go">提交</button>
|
<button class="layui-btn" lay-submit="true" lay-filter="go">提交</button>
|
||||||
<button type="button" class="kg-back layui-btn layui-btn-primary">返回</button>
|
<button type="button" class="kg-back layui-btn layui-btn-primary">返回</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -18,6 +18,22 @@
|
|||||||
<textarea name="answer" class="layui-textarea">{{ consult.answer }}</textarea>
|
<textarea name="answer" class="layui-textarea">{{ consult.answer }}</textarea>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<label class="layui-form-label">发布</label>
|
||||||
|
<div class="layui-input-block">
|
||||||
|
{% for value,title in publish_types %}
|
||||||
|
{% set checked = value == consult.published ? 'checked="checked"' : '' %}
|
||||||
|
<input type="radio" name="published" value="{{ value }}" title="{{ title }}" {{ checked }}>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<label class="layui-form-label">私密</label>
|
||||||
|
<div class="layui-input-block">
|
||||||
|
<input type="radio" name="private" value="1" title="是" {% if consult.private == 1 %}checked="checked"{% endif %}>
|
||||||
|
<input type="radio" name="private" value="0" title="否" {% if consult.private == 0 %}checked="checked"{% endif %}>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<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">
|
||||||
|
@ -2,19 +2,20 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
{{ partial('macros/consult') }}
|
{{ partial('macros/consult') }}
|
||||||
|
|
||||||
{% set search_url = url({'for':'admin.consult.search'}) %}
|
{% set search_url = url({'for':'admin.consult.search'}) %}
|
||||||
|
{% set batch_delete_url = url({'for':'admin.consult.batch_delete'}) %}
|
||||||
|
|
||||||
<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 class="kg-back"><i class="layui-icon layui-icon-return"></i>返回</a>
|
{% if request.get('course_id') > 0 %}
|
||||||
{% if course %}
|
<a class="kg-back"><i class="layui-icon layui-icon-return"></i>返回</a>
|
||||||
<a><cite>{{ course.title }}</cite></a>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a><cite>咨询管理</cite></a>
|
<a><cite>咨询管理</cite></a>
|
||||||
</span>
|
</span>
|
||||||
|
<span class="layui-btn layui-btn-sm layui-bg-red kg-batch" data-url="{{ batch_delete_url }}">批量删除</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="kg-nav-right">
|
<div class="kg-nav-right">
|
||||||
<a class="layui-btn layui-btn-sm" href="{{ search_url }}">
|
<a class="layui-btn layui-btn-sm" href="{{ search_url }}">
|
||||||
@ -23,8 +24,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table class="layui-table kg-table layui-form">
|
<table class="layui-table layui-form kg-table">
|
||||||
<colgroup>
|
<colgroup>
|
||||||
|
<col width="5%">
|
||||||
|
<col>
|
||||||
<col>
|
<col>
|
||||||
<col>
|
<col>
|
||||||
<col>
|
<col>
|
||||||
@ -33,42 +36,47 @@
|
|||||||
</colgroup>
|
</colgroup>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>问答</th>
|
<th><input class="all" type="checkbox" lay-filter="all"></th>
|
||||||
<th>用户</th>
|
<th>用户</th>
|
||||||
|
<th>内容</th>
|
||||||
<th>时间</th>
|
<th>时间</th>
|
||||||
<th>状态</th>
|
<th>状态</th>
|
||||||
|
<th>私密</th>
|
||||||
<th>操作</th>
|
<th>操作</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for item in pager.items %}
|
{% for item in pager.items %}
|
||||||
{% set item.answer = item.answer ? item.answer : 'N/A' %}
|
{% set item.answer = item.answer ? item.answer : 'N/A' %}
|
||||||
{% set list_by_course_url = url({'for':'admin.consult.list'},{'course_id':item.course.id}) %}
|
{% set course_url = url({'for':'home.course.show','id':item.course.id}) %}
|
||||||
{% set list_by_user_url = url({'for':'admin.consult.list'},{'owner_id':item.owner.id}) %}
|
{% set owner_url = url({'for':'home.user.show','id':item.owner.id}) %}
|
||||||
{% set moderate_url = url({'for':'admin.consult.moderate','id':item.id}) %}
|
{% set moderate_url = url({'for':'admin.consult.moderate','id':item.id}) %}
|
||||||
{% set edit_url = url({'for':'admin.consult.edit','id':item.id}) %}
|
{% set edit_url = url({'for':'admin.consult.edit','id':item.id}) %}
|
||||||
{% set update_url = url({'for':'admin.consult.update','id':item.id}) %}
|
{% set update_url = url({'for':'admin.consult.update','id':item.id}) %}
|
||||||
{% set delete_url = url({'for':'admin.consult.delete','id':item.id}) %}
|
{% set delete_url = url({'for':'admin.consult.delete','id':item.id}) %}
|
||||||
{% set restore_url = url({'for':'admin.consult.restore','id':item.id}) %}
|
{% set restore_url = url({'for':'admin.consult.restore','id':item.id}) %}
|
||||||
<tr>
|
<tr>
|
||||||
|
<td><input class="item" type="checkbox" value="{{ item.id }}" lay-filter="item"></td>
|
||||||
<td>
|
<td>
|
||||||
<p>课程:<a href="{{ list_by_course_url }}">{{ item.course.title }}</a>({{ item.course.id }}){{ private_info(item.private) }}</p>
|
<p>昵称:<a href="{{ owner_url }}">{{ item.owner.name }}</a></p>
|
||||||
|
<p>编号:{{ item.owner.id }}</p>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<p>课程:<a href="{{ course_url }}">{{ item.course.title }}</a>({{ item.course.id }})</p>
|
||||||
<p class="layui-elip kg-item-elip" title="{{ item.question }}">提问:{{ item.question }}</p>
|
<p class="layui-elip kg-item-elip" title="{{ item.question }}">提问:{{ item.question }}</p>
|
||||||
<p class="layui-elip kg-item-elip" title="{{ item.answer }}">回复:{{ item.answer }}</p>
|
<p class="layui-elip kg-item-elip" title="{{ item.answer }}">回复:{{ item.answer }}</p>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<p>昵称:<a href="{{ list_by_user_url }}">{{ item.owner.name }}</a></p>
|
<p>提问:{{ date('Y-m-d',item.create_time) }}</p>
|
||||||
<p>编号:{{ item.owner.id }}</p>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<p>提问:{{ date('Y-m-d H:i:s',item.create_time) }}</p>
|
|
||||||
{% if item.reply_time > 0 %}
|
{% if item.reply_time > 0 %}
|
||||||
<p>回复:{{ date('Y-m-d H:i:s',item.reply_time) }}</p>
|
<p>回复:{{ date('Y-m-d',item.reply_time) }}</p>
|
||||||
{% else %}
|
{% else %}
|
||||||
<p>回复:N/A</p>
|
<p>回复:N/A</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td>{{ publish_status(item.published) }}</td>
|
<td>{{ publish_status(item.published) }}</td>
|
||||||
|
<td><input type="checkbox" name="private" value="1" lay-text="是|否" lay-skin="switch" lay-filter="go" data-url="{{ update_url }}"
|
||||||
|
{% if item.private == 1 %}checked="checked"{% endif %}></td>
|
||||||
<td class="center">
|
<td class="center">
|
||||||
<div class="kg-dropdown">
|
<div class="kg-dropdown">
|
||||||
<button class="layui-btn layui-btn-sm">操作 <i class="layui-icon layui-icon-triangle-d"></i></button>
|
<button class="layui-btn layui-btn-sm">操作 <i class="layui-icon layui-icon-triangle-d"></i></button>
|
||||||
|
@ -7,22 +7,12 @@
|
|||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<form class="layui-form kg-form">
|
<form class="layui-form kg-form">
|
||||||
{% if consult.course.id is defined %}
|
<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">
|
<div class="layui-form-mid">{{ consult.course.title }}</div>
|
||||||
<div class="layui-form-mid">{{ consult.course.title }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
</div>
|
||||||
{% if consult.chapter.id is defined %}
|
|
||||||
<div class="layui-form-item">
|
|
||||||
<label class="layui-form-label">章节名称</label>
|
|
||||||
<div class="layui-input-block">
|
|
||||||
<div class="layui-form-mid">{{ consult.chapter.title }}</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
<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">
|
||||||
@ -45,13 +35,50 @@
|
|||||||
<input type="radio" name="type" value="reject" title="拒绝">
|
<input type="radio" name="type" value="reject" title="拒绝">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="reason-block" style="display:none;">
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<label class="layui-form-label">理由</label>
|
||||||
|
<div class="layui-input-block">
|
||||||
|
<select name="reason">
|
||||||
|
<option value="">请选择</option>
|
||||||
|
{% for reason in reasons %}
|
||||||
|
<option value="{{ reason }}">{{ reason }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<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">
|
||||||
<button id="kg-submit" class="layui-btn" lay-submit="true" lay-filter="go">提交</button>
|
<button class="layui-btn" lay-submit="true" lay-filter="go">提交</button>
|
||||||
<button type="button" class="kg-back layui-btn layui-btn-primary">返回</button>
|
<button type="button" class="kg-back layui-btn layui-btn-primary">返回</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block inline_js %}
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
layui.use(['jquery', 'form'], function () {
|
||||||
|
|
||||||
|
var $ = layui.jquery;
|
||||||
|
var form = layui.form;
|
||||||
|
|
||||||
|
form.on('radio(review)', function (data) {
|
||||||
|
var block = $('#reason-block');
|
||||||
|
if (data.value === 'approve') {
|
||||||
|
block.hide();
|
||||||
|
} else {
|
||||||
|
block.show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -13,22 +13,32 @@
|
|||||||
</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">用户帐号</label>
|
||||||
<div class="layui-input-block">
|
<div class="layui-input-block">
|
||||||
<input class="layui-input" type="text" name="course_id" placeholder="课程编号精确匹配">
|
<input class="layui-input" type="text" name="owner_id" placeholder="用户编号 / 手机号码 / 邮箱地址 精确匹配">
|
||||||
</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">所属课程</label>
|
||||||
<div class="layui-input-block">
|
<div class="layui-input-block">
|
||||||
<input class="layui-input" type="text" name="owner_id" placeholder="用户编号精确匹配">
|
<div id="xm-course-id"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layui-form-item" id="time-range">
|
||||||
|
<label class="layui-form-label">创建时间</label>
|
||||||
|
<div class="layui-input-inline">
|
||||||
|
<input class="layui-input" id="start-time" type="text" name="create_time[]" autocomplete="off">
|
||||||
|
</div>
|
||||||
|
<div class="layui-form-mid">-</div>
|
||||||
|
<div class="layui-input-inline">
|
||||||
|
<input class="layui-input" id="end-time" type="text" name="create_time[]" autocomplete="off">
|
||||||
</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">发布状态</label>
|
||||||
<div class="layui-input-block">
|
<div class="layui-input-block">
|
||||||
{% for value,title in publish_types %}
|
{% for value,title in publish_types %}
|
||||||
<input type="radio" name="published" value="{{ value }}" title="{{ title }}">
|
<input type="checkbox" name="published[]" value="{{ value }}" title="{{ title }}">
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -55,4 +65,41 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block include_js %}
|
||||||
|
|
||||||
|
{{ js_include('lib/xm-select.js') }}
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block inline_js %}
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
layui.use(['jquery', 'laydate'], function () {
|
||||||
|
|
||||||
|
xmSelect.render({
|
||||||
|
el: '#xm-course-id',
|
||||||
|
name: 'course_id',
|
||||||
|
filterable: true,
|
||||||
|
radio: true,
|
||||||
|
filterMethod: function (val, item, index, prop) {
|
||||||
|
return item.name.toLowerCase().indexOf(val.toLowerCase()) !== -1;
|
||||||
|
},
|
||||||
|
data: {{ xm_courses|json_encode }}
|
||||||
|
});
|
||||||
|
|
||||||
|
var laydate = layui.laydate;
|
||||||
|
|
||||||
|
laydate.render({
|
||||||
|
elem: '#time-range',
|
||||||
|
type: 'datetime',
|
||||||
|
range: ['#start-time', '#end-time'],
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -2,20 +2,23 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<form class="layui-form kg-form" method="POST" action="{{ url({'for':'admin.student.create'}) }}">
|
{% set create_url = url({'for':'admin.course.create_user','id':course.id}) %}
|
||||||
<fieldset class="layui-elem-field layui-field-title">
|
|
||||||
<legend>添加学员</legend>
|
<fieldset class="layui-elem-field layui-field-title">
|
||||||
</fieldset>
|
<legend>添加学员</legend>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
<form class="layui-form kg-form" method="POST" action="{{ create_url }}">
|
||||||
<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">
|
||||||
<div id="xm-course-id"></div>
|
<div class="layui-form-mid">{{ course.title }}</div>
|
||||||
</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">用户帐号</label>
|
||||||
<div class="layui-input-block">
|
<div class="layui-input-block">
|
||||||
<input class="layui-input" type="text" name="xm_user_id" placeholder="用户编号 / 手机号码 / 邮箱地址" lay-verify="required">
|
<input class="layui-input" type="text" name="user_id" placeholder="用户编号 / 手机号码 / 邮箱地址" lay-verify="required">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="layui-form-item">
|
<div class="layui-form-item">
|
||||||
@ -35,12 +38,6 @@
|
|||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block include_js %}
|
|
||||||
|
|
||||||
{{ js_include('lib/xm-select.js') }}
|
|
||||||
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block inline_js %}
|
{% block inline_js %}
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@ -49,17 +46,6 @@
|
|||||||
|
|
||||||
var laydate = layui.laydate;
|
var laydate = layui.laydate;
|
||||||
|
|
||||||
xmSelect.render({
|
|
||||||
el: '#xm-course-id',
|
|
||||||
name: 'xm_course_id',
|
|
||||||
radio: true,
|
|
||||||
filterable: true,
|
|
||||||
filterMethod: function (val, item, index, prop) {
|
|
||||||
return item.name.toLowerCase().indexOf(val.toLowerCase()) !== -1;
|
|
||||||
},
|
|
||||||
data: {{ xm_courses|json_encode }}
|
|
||||||
});
|
|
||||||
|
|
||||||
laydate.render({
|
laydate.render({
|
||||||
elem: 'input[name=expiry_time]',
|
elem: 'input[name=expiry_time]',
|
||||||
type: 'datetime'
|
type: 'datetime'
|
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