diff --git a/CHANGELOG.md b/CHANGELOG.md index 505a5ed3..3e1502d6 100644 --- a/CHANGELOG.md +++ b/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) - 还原意外删除的AnswerList.php文件 diff --git a/app/Builders/ArticleList.php b/app/Builders/ArticleList.php index 7ef8ca46..68a78f5d 100644 --- a/app/Builders/ArticleList.php +++ b/app/Builders/ArticleList.php @@ -7,7 +7,7 @@ namespace App\Builders; -use App\Caches\CategoryList as CategoryListCache; +use App\Caches\CategoryAllList as CategoryAllListCache; use App\Models\Category as CategoryModel; use App\Repos\User as UserRepo; @@ -47,7 +47,7 @@ class ArticleList extends Builder public function getCategories() { - $cache = new CategoryListCache(); + $cache = new CategoryAllListCache(); $items = $cache->get(CategoryModel::TYPE_ARTICLE); diff --git a/app/Builders/CourseList.php b/app/Builders/CourseList.php index e5a3c383..d0dffdf4 100644 --- a/app/Builders/CourseList.php +++ b/app/Builders/CourseList.php @@ -7,7 +7,7 @@ namespace App\Builders; -use App\Caches\CategoryList as CategoryListCache; +use App\Caches\CategoryAllList as CategoryAllListCache; use App\Models\Category as CategoryModel; use App\Repos\User as UserRepo; @@ -38,7 +38,7 @@ class CourseList extends Builder public function getCategories() { - $cache = new CategoryListCache(); + $cache = new CategoryAllListCache(); $items = $cache->get(CategoryModel::TYPE_COURSE); diff --git a/app/Builders/DanmuList.php b/app/Builders/DanmuList.php deleted file mode 100644 index 2ee29569..00000000 --- a/app/Builders/DanmuList.php +++ /dev/null @@ -1,104 +0,0 @@ -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; - } - -} diff --git a/app/Builders/HelpList.php b/app/Builders/HelpList.php index f451548d..bc0ee1c2 100644 --- a/app/Builders/HelpList.php +++ b/app/Builders/HelpList.php @@ -7,7 +7,7 @@ namespace App\Builders; -use App\Caches\CategoryList as CategoryListCache; +use App\Caches\CategoryAllList as CategoryAllListCache; use App\Models\Category as CategoryModel; class HelpList extends Builder @@ -26,7 +26,7 @@ class HelpList extends Builder public function getCategories() { - $cache = new CategoryListCache(); + $cache = new CategoryAllListCache(); $items = $cache->get(CategoryModel::TYPE_HELP); diff --git a/app/Builders/QuestionList.php b/app/Builders/QuestionList.php index aeabd0e8..b4d25292 100644 --- a/app/Builders/QuestionList.php +++ b/app/Builders/QuestionList.php @@ -7,7 +7,7 @@ namespace App\Builders; -use App\Caches\CategoryList as CategoryListCache; +use App\Caches\CategoryAllList as CategoryAllListCache; use App\Models\Category as CategoryModel; use App\Repos\User as UserRepo; @@ -27,8 +27,8 @@ class QuestionList extends Builder { $categories = $this->getCategories(); - foreach ($questions as $key => $article) { - $questions[$key]['category'] = $categories[$article['category_id']] ?? new \stdClass(); + foreach ($questions as $key => $question) { + $questions[$key]['category'] = $categories[$question['category_id']] ?? new \stdClass(); } return $questions; @@ -48,7 +48,7 @@ class QuestionList extends Builder public function getCategories() { - $cache = new CategoryListCache(); + $cache = new CategoryAllListCache(); $items = $cache->get(CategoryModel::TYPE_QUESTION); diff --git a/app/Builders/UserList.php b/app/Builders/UserList.php index 7dbb1f27..fcee87c5 100644 --- a/app/Builders/UserList.php +++ b/app/Builders/UserList.php @@ -8,6 +8,7 @@ namespace App\Builders; use App\Models\User as UserModel; +use App\Repos\Account as AccountRepo; use App\Repos\Role as RoleRepo; class UserList extends Builder @@ -24,6 +25,17 @@ class UserList extends Builder 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) { $roles = $this->getAdminRoles($users); @@ -46,6 +58,26 @@ class UserList extends Builder 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) { $ids = kg_array_column($users, 'admin_role'); diff --git a/app/Caches/AppInfo.php b/app/Caches/AppInfo.php index 0803bb9a..dd93d1b2 100644 --- a/app/Caches/AppInfo.php +++ b/app/Caches/AppInfo.php @@ -27,10 +27,10 @@ class AppInfo extends Cache $appInfo = new \App\Library\AppInfo(); return [ - 'name' => $appInfo->name, - 'alias' => $appInfo->alias, - 'link' => $appInfo->link, - 'version' => $appInfo->version, + 'name' => $appInfo->get('name'), + 'alias' => $appInfo->get('alias'), + 'link' => $appInfo->get('link'), + 'version' => $appInfo->get('version'), ]; } diff --git a/app/Caches/CategoryAllList.php b/app/Caches/CategoryAllList.php new file mode 100644 index 00000000..01866cc0 --- /dev/null +++ b/app/Caches/CategoryAllList.php @@ -0,0 +1,46 @@ +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(); + } + +} diff --git a/app/Caches/CategoryList.php b/app/Caches/CategoryList.php index 78a203eb..aede8d99 100644 --- a/app/Caches/CategoryList.php +++ b/app/Caches/CategoryList.php @@ -25,10 +25,6 @@ class CategoryList extends Cache return "category_list:{$id}"; } - /** - * @param null $id - * @return array - */ public function getContent($id = null) { /** diff --git a/app/Caches/CourseCategoryList.php b/app/Caches/CourseCategoryList.php deleted file mode 100644 index 12681a06..00000000 --- a/app/Caches/CourseCategoryList.php +++ /dev/null @@ -1,59 +0,0 @@ -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; - } - -} diff --git a/app/Caches/CourseRecommendedList.php b/app/Caches/CourseRecommendedList.php deleted file mode 100644 index c810082f..00000000 --- a/app/Caches/CourseRecommendedList.php +++ /dev/null @@ -1,90 +0,0 @@ -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(); - } - -} diff --git a/app/Caches/CourseTeacherList.php b/app/Caches/CourseTeacherList.php deleted file mode 100644 index 1c676f1a..00000000 --- a/app/Caches/CourseTeacherList.php +++ /dev/null @@ -1,63 +0,0 @@ -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; - } - -} diff --git a/app/Caches/FeaturedArticleList.php b/app/Caches/FeaturedArticleList.php index bd5fc0f2..bdf4d92d 100644 --- a/app/Caches/FeaturedArticleList.php +++ b/app/Caches/FeaturedArticleList.php @@ -14,13 +14,13 @@ use Phalcon\Mvc\Model\ResultsetInterface; class FeaturedArticleList extends Cache { - protected $lifetime = 86400; + protected $lifetime = 3600; + + protected $limit = 5; public function getLifetime() { - $tomorrow = strtotime('tomorrow'); - - return $tomorrow - time(); + return $this->lifetime; } public function getKey($id = null) @@ -30,9 +30,7 @@ class FeaturedArticleList extends Cache public function getContent($id = null) { - $limit = 8; - - $articles = $this->findArticles($limit); + $articles = $this->findArticles($this->limit); if ($articles->count() == 0) { return []; @@ -41,20 +39,10 @@ class FeaturedArticleList extends Cache $result = []; foreach ($articles as $article) { - - $userCount = $article->user_count; - - if ($article->fake_user_count > $article->user_count) { - $userCount = $article->fake_user_count; - } - $result[] = [ 'id' => $article->id, 'title' => $article->title, 'cover' => $article->cover, - 'market_price' => (float)$article->market_price, - 'vip_price' => (float)$article->vip_price, - 'user_count' => $userCount, 'favorite_count' => $article->favorite_count, 'comment_count' => $article->comment_count, 'view_count' => $article->view_count, @@ -69,13 +57,13 @@ class FeaturedArticleList extends Cache * @param int $limit * @return ResultsetInterface|Resultset|ArticleModel[] */ - protected function findArticles($limit = 8) + protected function findArticles($limit = 5) { return ArticleModel::query() ->where('featured = 1') - ->andWhere('published = 1') + ->andWhere('published = :published:', ['published' => ArticleModel::PUBLISH_APPROVED]) ->andWhere('deleted = 0') - ->orderBy('id DESC') + ->orderBy('RAND()') ->limit($limit) ->execute(); } diff --git a/app/Caches/FeaturedCourseList.php b/app/Caches/FeaturedCourseList.php index cb2817a8..d9b26459 100644 --- a/app/Caches/FeaturedCourseList.php +++ b/app/Caches/FeaturedCourseList.php @@ -14,13 +14,13 @@ use Phalcon\Mvc\Model\ResultsetInterface; class FeaturedCourseList extends Cache { - protected $lifetime = 86400; + protected $lifetime = 3600; + + protected $limit = 5; public function getLifetime() { - $tomorrow = strtotime('tomorrow'); - - return $tomorrow - time(); + return $this->lifetime; } public function getKey($id = null) @@ -30,9 +30,7 @@ class FeaturedCourseList extends Cache public function getContent($id = null) { - $limit = 8; - - $courses = $this->findCourses($limit); + $courses = $this->findCourses($this->limit); if ($courses->count() == 0) { return []; @@ -71,13 +69,13 @@ class FeaturedCourseList extends Cache * @param int $limit * @return ResultsetInterface|Resultset|CourseModel[] */ - protected function findCourses($limit = 8) + protected function findCourses($limit = 5) { return CourseModel::query() ->where('featured = 1') ->andWhere('published = 1') ->andWhere('deleted = 0') - ->orderBy('id DESC') + ->orderBy('RAND()') ->limit($limit) ->execute(); } diff --git a/app/Caches/FeaturedQuestionList.php b/app/Caches/FeaturedQuestionList.php new file mode 100644 index 00000000..4508b6ec --- /dev/null +++ b/app/Caches/FeaturedQuestionList.php @@ -0,0 +1,72 @@ +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(); + } + +} diff --git a/app/Caches/FlashSale.php b/app/Caches/FlashSale.php deleted file mode 100644 index d8b89f43..00000000 --- a/app/Caches/FlashSale.php +++ /dev/null @@ -1,36 +0,0 @@ -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; - } - -} diff --git a/app/Caches/HelpList.php b/app/Caches/HelpList.php index 2899bbd8..5c30bea4 100644 --- a/app/Caches/HelpList.php +++ b/app/Caches/HelpList.php @@ -15,7 +15,7 @@ use Phalcon\Mvc\Model\ResultsetInterface; class HelpList extends Cache { - protected $lifetime = 365 * 86400; + protected $lifetime = 7 * 86400; public function getLifetime() { diff --git a/app/Caches/HotQuestionList.php b/app/Caches/HotQuestionList.php index 64220fd8..3afbec0b 100644 --- a/app/Caches/HotQuestionList.php +++ b/app/Caches/HotQuestionList.php @@ -14,13 +14,11 @@ use Phalcon\Mvc\Model\ResultsetInterface; class HotQuestionList extends Cache { - protected $lifetime = 86400; + protected $lifetime = 3600; public function getLifetime() { - $tomorrow = strtotime('tomorrow'); - - return $tomorrow - time(); + return $this->lifetime; } public function getKey($id = null) diff --git a/app/Caches/IndexArticleList.php b/app/Caches/IndexArticleList.php index c892923f..43075b7c 100644 --- a/app/Caches/IndexArticleList.php +++ b/app/Caches/IndexArticleList.php @@ -14,7 +14,7 @@ use App\Services\Logic\Article\ArticleList as ArticleListService; class IndexArticleList extends Cache { - protected $lifetime = 15 * 60; + protected $lifetime = 3600; public function getLifetime() { diff --git a/app/Caches/IndexFeaturedCourseList.php b/app/Caches/IndexFeaturedCourseList.php index f7d0e6ae..77bb347b 100644 --- a/app/Caches/IndexFeaturedCourseList.php +++ b/app/Caches/IndexFeaturedCourseList.php @@ -19,7 +19,7 @@ use Phalcon\Mvc\Model\ResultsetInterface; class IndexFeaturedCourseList extends Cache { - protected $lifetime = 86400; + protected $lifetime = 3600; public function getLifetime() { diff --git a/app/Caches/IndexFlashSaleList.php b/app/Caches/IndexFlashSaleList.php deleted file mode 100644 index 7fd379b6..00000000 --- a/app/Caches/IndexFlashSaleList.php +++ /dev/null @@ -1,36 +0,0 @@ -handle(); - - return $sales[0]['items'] ?? []; - } - -} diff --git a/app/Caches/IndexFreeCourseList.php b/app/Caches/IndexFreeCourseList.php index bc20a9dc..9ae4226c 100644 --- a/app/Caches/IndexFreeCourseList.php +++ b/app/Caches/IndexFreeCourseList.php @@ -19,7 +19,7 @@ use Phalcon\Mvc\Model\ResultsetInterface; class IndexFreeCourseList extends Cache { - protected $lifetime = 86400; + protected $lifetime = 3600; public function getLifetime() { diff --git a/app/Caches/IndexLiveList.php b/app/Caches/IndexLiveList.php index 734150a1..ae3dff4e 100644 --- a/app/Caches/IndexLiveList.php +++ b/app/Caches/IndexLiveList.php @@ -18,7 +18,7 @@ use Phalcon\Mvc\Model\ResultsetInterface; class IndexLiveList extends Cache { - protected $lifetime = 86400; + protected $lifetime = 3600; public function getLifetime() { diff --git a/app/Caches/IndexNewCourseList.php b/app/Caches/IndexNewCourseList.php index 4975cb27..457eb8ce 100644 --- a/app/Caches/IndexNewCourseList.php +++ b/app/Caches/IndexNewCourseList.php @@ -19,7 +19,7 @@ use Phalcon\Mvc\Model\ResultsetInterface; class IndexNewCourseList extends Cache { - protected $lifetime = 86400; + protected $lifetime = 3600; public function getLifetime() { diff --git a/app/Caches/IndexQuestionList.php b/app/Caches/IndexQuestionList.php index b79db98b..12bb02c1 100644 --- a/app/Caches/IndexQuestionList.php +++ b/app/Caches/IndexQuestionList.php @@ -14,7 +14,7 @@ use App\Services\Logic\Question\QuestionList as QuestionListService; class IndexQuestionList extends Cache { - protected $lifetime = 15 * 60; + protected $lifetime = 3600; public function getLifetime() { diff --git a/app/Caches/IndexSimpleFeaturedCourseList.php b/app/Caches/IndexSimpleFeaturedCourseList.php index b5433216..616a37bd 100644 --- a/app/Caches/IndexSimpleFeaturedCourseList.php +++ b/app/Caches/IndexSimpleFeaturedCourseList.php @@ -17,7 +17,7 @@ use Phalcon\Mvc\Model\ResultsetInterface; class IndexSimpleFeaturedCourseList extends Cache { - protected $lifetime = 86400; + protected $lifetime = 3600; public function getLifetime() { diff --git a/app/Caches/IndexSimpleFreeCourseList.php b/app/Caches/IndexSimpleFreeCourseList.php index 34a6d4f7..16b0e64f 100644 --- a/app/Caches/IndexSimpleFreeCourseList.php +++ b/app/Caches/IndexSimpleFreeCourseList.php @@ -17,7 +17,7 @@ use Phalcon\Mvc\Model\ResultsetInterface; class IndexSimpleFreeCourseList extends Cache { - protected $lifetime = 86400; + protected $lifetime = 3600; public function getLifetime() { diff --git a/app/Caches/IndexSimpleNewCourseList.php b/app/Caches/IndexSimpleNewCourseList.php index 7dffa5af..9dbd225c 100644 --- a/app/Caches/IndexSimpleNewCourseList.php +++ b/app/Caches/IndexSimpleNewCourseList.php @@ -17,7 +17,7 @@ use Phalcon\Mvc\Model\ResultsetInterface; class IndexSimpleNewCourseList extends Cache { - protected $lifetime = 86400; + protected $lifetime = 3600; public function getLifetime() { diff --git a/app/Caches/IndexSimpleVipCourseList.php b/app/Caches/IndexSimpleVipCourseList.php index 6756b39e..90f8b493 100644 --- a/app/Caches/IndexSimpleVipCourseList.php +++ b/app/Caches/IndexSimpleVipCourseList.php @@ -17,7 +17,7 @@ use Phalcon\Mvc\Model\ResultsetInterface; class IndexSimpleVipCourseList extends Cache { - protected $lifetime = 86400; + protected $lifetime = 3600; public function getLifetime() { diff --git a/app/Caches/IndexSlideList.php b/app/Caches/IndexSlideList.php index abc7d28c..00f15ae1 100644 --- a/app/Caches/IndexSlideList.php +++ b/app/Caches/IndexSlideList.php @@ -14,7 +14,7 @@ use Phalcon\Mvc\Model\ResultsetInterface; class IndexSlideList extends Cache { - protected $lifetime = 365 * 86400; + protected $lifetime = 3600; public function getLifetime() { diff --git a/app/Caches/IndexVipCourseList.php b/app/Caches/IndexVipCourseList.php index 6b268160..e11ce1b2 100644 --- a/app/Caches/IndexVipCourseList.php +++ b/app/Caches/IndexVipCourseList.php @@ -19,7 +19,7 @@ use Phalcon\Mvc\Model\ResultsetInterface; class IndexVipCourseList extends Cache { - protected $lifetime = 86400; + protected $lifetime = 3600; public function getLifetime() { diff --git a/app/Caches/MaxFlashSaleId.php b/app/Caches/MaxFlashSaleId.php deleted file mode 100644 index b6a7030c..00000000 --- a/app/Caches/MaxFlashSaleId.php +++ /dev/null @@ -1,34 +0,0 @@ -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; - } - -} diff --git a/app/Caches/TaggedArticleList.php b/app/Caches/TaggedArticleList.php index d57faf7b..05640fff 100644 --- a/app/Caches/TaggedArticleList.php +++ b/app/Caches/TaggedArticleList.php @@ -13,9 +13,9 @@ use App\Repos\Article as ArticleRepo; class TaggedArticleList extends Cache { - protected $limit = 5; + protected $limit = 15; - protected $lifetime = 86400; + protected $lifetime = 3600; public function getLifetime() { diff --git a/app/Caches/TaggedQuestionList.php b/app/Caches/TaggedQuestionList.php index 7495823b..f6adb8b4 100644 --- a/app/Caches/TaggedQuestionList.php +++ b/app/Caches/TaggedQuestionList.php @@ -13,9 +13,9 @@ use App\Repos\Question as QuestionRepo; class TaggedQuestionList extends Cache { - protected $limit = 5; + protected $limit = 15; - protected $lifetime = 86400; + protected $lifetime = 3600; public function getLifetime() { diff --git a/app/Caches/TopAnswererList.php b/app/Caches/TopAnswererList.php index 37991604..4acaa8e7 100644 --- a/app/Caches/TopAnswererList.php +++ b/app/Caches/TopAnswererList.php @@ -16,7 +16,7 @@ use Phalcon\Mvc\Model\ResultsetInterface; class TopAnswererList extends Cache { - protected $lifetime = 86400; + protected $lifetime = 3600; public function getLifetime() { diff --git a/app/Caches/TopAuthorList.php b/app/Caches/TopAuthorList.php index 882e4cab..1e6a2404 100644 --- a/app/Caches/TopAuthorList.php +++ b/app/Caches/TopAuthorList.php @@ -16,7 +16,7 @@ use Phalcon\Mvc\Model\ResultsetInterface; class TopAuthorList extends Cache { - protected $lifetime = 86400; + protected $lifetime = 3600; public function getLifetime() { diff --git a/app/Console/Tasks/CleanDemoDataTask.php b/app/Console/Tasks/CleanDemoDataTask.php index 24cba3df..fabd6a6d 100644 --- a/app/Console/Tasks/CleanDemoDataTask.php +++ b/app/Console/Tasks/CleanDemoDataTask.php @@ -8,12 +8,13 @@ namespace App\Console\Tasks; use App\Caches\CategoryList as CategoryListCache; +use App\Caches\CategoryAllList as CategoryAllListCache; use App\Caches\CategoryTreeList as CategoryTreeListCache; use App\Caches\IndexSlideList as IndexSlideListCache; use App\Models\Account as AccountModel; use App\Models\Category as CategoryModel; use App\Repos\User as UserRepo; -use App\Services\Utils\IndexCourseCache as IndexCourseCacheUtil; +use App\Services\Utils\IndexPageCache as IndexPageCacheUtil; class CleanDemoDataTask extends Task { @@ -81,17 +82,19 @@ class CleanDemoDataTask extends Task protected function cleanCache() { - $util = new IndexCourseCacheUtil(); + $util = new IndexPageCacheUtil(); $util->rebuild(); $slideListCache = new IndexSlideListCache(); $slideListCache->rebuild(); $categoryListCache = new CategoryListCache(); + $categoryAllListCache = new CategoryAllListCache(); $categoryTreeListCache = new CategoryTreeListCache(); foreach (CategoryModel::types() as $key => $value) { $categoryListCache->rebuild($key); + $categoryAllListCache->rebuild($key); $categoryTreeListCache->rebuild($key); } } @@ -114,7 +117,7 @@ class CleanDemoDataTask extends Task $user = $userRepo->findById(100015); - return $user ? true : false; + return (bool)$user; } } diff --git a/app/Console/Tasks/CloseFlashSaleOrderTask.php b/app/Console/Tasks/CloseFlashSaleOrderTask.php deleted file mode 100644 index b83afe2b..00000000 --- a/app/Console/Tasks/CloseFlashSaleOrderTask.php +++ /dev/null @@ -1,86 +0,0 @@ -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(); - } - -} diff --git a/app/Console/Tasks/CloseOrderTask.php b/app/Console/Tasks/CloseOrderTask.php index f56c9077..8b17ed81 100644 --- a/app/Console/Tasks/CloseOrderTask.php +++ b/app/Console/Tasks/CloseOrderTask.php @@ -42,11 +42,9 @@ class CloseOrderTask extends Task { $status = OrderModel::STATUS_PENDING; $time = time() - 12 * 3600; - $type = 0; return OrderModel::query() ->where('status = :status:', ['status' => $status]) - ->andWhere('promotion_type = :type:', ['type' => $type]) ->andWhere('create_time < :time:', ['time' => $time]) ->limit($limit) ->execute(); diff --git a/app/Console/Tasks/DeliverTask.php b/app/Console/Tasks/DeliverTask.php index 1e34d458..6fe6c8a3 100644 --- a/app/Console/Tasks/DeliverTask.php +++ b/app/Console/Tasks/DeliverTask.php @@ -172,9 +172,7 @@ class DeliverTask extends Task ]; foreach ($orders as $order) { - $case1 = in_array($order->item_type, $itemTypes); - $case2 = $order->promotion_type == 0; - if ($case1 && $case2) { + if (in_array($order->item_type, $itemTypes)) { $order->status = OrderModel::STATUS_CLOSED; $order->update(); } diff --git a/app/Console/Tasks/RefundTask.php b/app/Console/Tasks/RefundTask.php index 108cc60e..d28dc013 100644 --- a/app/Console/Tasks/RefundTask.php +++ b/app/Console/Tasks/RefundTask.php @@ -168,7 +168,8 @@ class RefundTask extends Task protected function handleCourseOrderRefund(OrderModel $order) { $courseUserRepo = new CourseUserRepo(); - $courseUser = $courseUserRepo->findCourseStudent($order->item_id, $order->owner_id); + + $courseUser = $courseUserRepo->findCourseUser($order->item_id, $order->owner_id); if ($courseUser) { $courseUser->deleted = 1; @@ -191,7 +192,7 @@ class RefundTask extends Task foreach ($itemInfo['courses'] as $course) { - $courseUser = $courseUserRepo->findCourseStudent($course['id'], $order->owner_id); + $courseUser = $courseUserRepo->findCourseUser($course['id'], $order->owner_id); if ($courseUser) { $courseUser->deleted = 1; diff --git a/app/Http/Admin/Controllers/AnswerController.php b/app/Http/Admin/Controllers/AnswerController.php index 0e1a1fec..d592c327 100644 --- a/app/Http/Admin/Controllers/AnswerController.php +++ b/app/Http/Admin/Controllers/AnswerController.php @@ -61,12 +61,15 @@ class AnswerController extends Controller { $answerService = new AnswerService(); + $publishTypes = $answerService->getPublishTypes(); + $answer = $answerService->getAnswer($id); $questionService = new QuestionService(); $question = $questionService->getQuestion($answer->question_id); + $this->view->setVar('publish_types', $publishTypes); $this->view->setVar('question', $question); $this->view->setVar('answer', $answer); } @@ -219,4 +222,40 @@ class AnswerController extends Controller $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); + } + } diff --git a/app/Http/Admin/Controllers/ArticleController.php b/app/Http/Admin/Controllers/ArticleController.php index d6d8a7b9..2da839d3 100644 --- a/app/Http/Admin/Controllers/ArticleController.php +++ b/app/Http/Admin/Controllers/ArticleController.php @@ -38,12 +38,12 @@ class ArticleController extends Controller $publishTypes = $articleService->getPublishTypes(); $sourceTypes = $articleService->getSourceTypes(); - $categories = $articleService->getCategories(); + $categoryOptions = $articleService->getCategoryOptions(); $xmTags = $articleService->getXmTags(0); $this->view->setVar('publish_types', $publishTypes); $this->view->setVar('source_types', $sourceTypes); - $this->view->setVar('categories', $categories); + $this->view->setVar('category_options', $categoryOptions); $this->view->setVar('xm_tags', $xmTags); } @@ -64,11 +64,7 @@ class ArticleController extends Controller */ 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(); $sourceTypes = $articleService->getSourceTypes(); - $categories = $articleService->getCategories(); + $categoryOptions = $articleService->getCategoryOptions(); $article = $articleService->getArticle($id); $xmTags = $articleService->getXmTags($id); + $this->view->setVar('article', $article); $this->view->setVar('publish_types', $publishTypes); $this->view->setVar('source_types', $sourceTypes); - $this->view->setVar('categories', $categories); - $this->view->setVar('article', $article); + $this->view->setVar('category_options', $categoryOptions); $this->view->setVar('xm_tags', $xmTags); } @@ -229,4 +225,40 @@ class ArticleController extends Controller $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); + } + } diff --git a/app/Http/Admin/Controllers/CommentController.php b/app/Http/Admin/Controllers/CommentController.php index ec0ad6b0..eea1a474 100644 --- a/app/Http/Admin/Controllers/CommentController.php +++ b/app/Http/Admin/Controllers/CommentController.php @@ -139,4 +139,40 @@ class CommentController extends Controller $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); + } + } diff --git a/app/Http/Admin/Controllers/ConsultController.php b/app/Http/Admin/Controllers/ConsultController.php index c0cbdb9c..92a22c0d 100644 --- a/app/Http/Admin/Controllers/ConsultController.php +++ b/app/Http/Admin/Controllers/ConsultController.php @@ -23,8 +23,10 @@ class ConsultController extends Controller $consultService = new ConsultService(); $publishTypes = $consultService->getPublishTypes(); + $xmCourses = $consultService->getXmCourses(); $this->view->setVar('publish_types', $publishTypes); + $this->view->setVar('xm_courses', $xmCourses); } /** @@ -55,8 +57,11 @@ class ConsultController extends Controller { $consultService = new ConsultService(); + $publishTypes = $consultService->getPublishTypes(); + $consult = $consultService->getConsult($id); + $this->view->setVar('publish_types', $publishTypes); $this->view->setVar('consult', $consult); } @@ -135,9 +140,47 @@ class ConsultController extends Controller return $this->jsonSuccess($content); } + $reasons = $consultService->getReasons(); $consult = $consultService->getConsultInfo($id); + $this->view->setVar('reasons', $reasons); $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); + } + } diff --git a/app/Http/Admin/Controllers/CourseController.php b/app/Http/Admin/Controllers/CourseController.php index 2121110f..84d7c264 100644 --- a/app/Http/Admin/Controllers/CourseController.php +++ b/app/Http/Admin/Controllers/CourseController.php @@ -8,6 +8,8 @@ namespace App\Http\Admin\Controllers; 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 Phalcon\Mvc\View; @@ -37,13 +39,13 @@ class CourseController extends Controller { $courseService = new CourseService(); - $xmCategories = $courseService->getXmCategories(0); - $xmTeachers = $courseService->getXmTeachers(0); + $categoryOptions = $courseService->getCategoryOptions(); + $teacherOptions = $courseService->getTeacherOptions(); $modelTypes = $courseService->getModelTypes(); $levelTypes = $courseService->getLevelTypes(); - $this->view->setVar('xm_categories', $xmCategories); - $this->view->setVar('xm_teachers', $xmTeachers); + $this->view->setVar('category_options', $categoryOptions); + $this->view->setVar('teacher_options', $teacherOptions); $this->view->setVar('model_types', $modelTypes); $this->view->setVar('level_types', $levelTypes); } @@ -103,17 +105,21 @@ class CourseController extends Controller $cos = $courseService->getSettings('cos'); $course = $courseService->getCourse($id); - $xmTeachers = $courseService->getXmTeachers($id); - $xmCategories = $courseService->getXmCategories($id); + $xmTags = $courseService->getXmTags($id); $xmCourses = $courseService->getXmCourses($id); + $levelTypes = $courseService->getLevelTypes(); + $categoryOptions = $courseService->getCategoryOptions(); + $teacherOptions = $courseService->getTeacherOptions(); $studyExpiryOptions = $courseService->getStudyExpiryOptions(); $refundExpiryOptions = $courseService->getRefundExpiryOptions(); $this->view->setVar('cos', $cos); $this->view->setVar('course', $course); - $this->view->setVar('xm_teachers', $xmTeachers); - $this->view->setVar('xm_categories', $xmCategories); + $this->view->setVar('xm_tags', $xmTags); $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('refund_expiry_options', $refundExpiryOptions); } @@ -193,4 +199,78 @@ class CourseController extends Controller $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); + } + } diff --git a/app/Http/Admin/Controllers/FlashSaleController.php b/app/Http/Admin/Controllers/FlashSaleController.php deleted file mode 100644 index 9249d971..00000000 --- a/app/Http/Admin/Controllers/FlashSaleController.php +++ /dev/null @@ -1,153 +0,0 @@ -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); - } - -} diff --git a/app/Http/Admin/Controllers/QuestionController.php b/app/Http/Admin/Controllers/QuestionController.php index 0bc2aebf..f6140c1f 100644 --- a/app/Http/Admin/Controllers/QuestionController.php +++ b/app/Http/Admin/Controllers/QuestionController.php @@ -23,7 +23,7 @@ class QuestionController extends Controller { $location = $this->url->get( ['for' => 'admin.category.list'], - ['type' => CategoryModel::TYPE_ARTICLE] + ['type' => CategoryModel::TYPE_QUESTION] ); return $this->response->redirect($location); @@ -37,12 +37,10 @@ class QuestionController extends Controller $questionService = new QuestionService(); $publishTypes = $questionService->getPublishTypes(); - $categories = $questionService->getCategories(); - $xmTags = $questionService->getXmTags(0); + $categoryOptions = $questionService->getCategoryOptions(); + $this->view->setVar('category_options', $categoryOptions); $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() { - $questionService = new QuestionService(); - $categories = $questionService->getCategories(); - - $this->view->setVar('categories', $categories); } /** @@ -77,12 +71,12 @@ class QuestionController extends Controller $questionService = new QuestionService(); $publishTypes = $questionService->getPublishTypes(); - $categories = $questionService->getCategories(); + $categoryOptions = $questionService->getCategoryOptions(); $question = $questionService->getQuestion($id); $xmTags = $questionService->getXmTags($id); $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('xm_tags', $xmTags); } @@ -225,4 +219,41 @@ class QuestionController extends Controller $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); + } + } diff --git a/app/Http/Admin/Controllers/ReviewController.php b/app/Http/Admin/Controllers/ReviewController.php index b76c569e..3013dd78 100644 --- a/app/Http/Admin/Controllers/ReviewController.php +++ b/app/Http/Admin/Controllers/ReviewController.php @@ -23,8 +23,10 @@ class ReviewController extends Controller $reviewService = new ReviewService(); $publishTypes = $reviewService->getPublishTypes(); + $xmCourses = $reviewService->getXmCourses(); $this->view->setVar('publish_types', $publishTypes); + $this->view->setVar('xm_courses', $xmCourses); } /** @@ -56,8 +58,10 @@ class ReviewController extends Controller $reviewService = new ReviewService(); $review = $reviewService->getReview($id); + $publishTypes = $reviewService->getPublishTypes(); $this->view->setVar('review', $review); + $this->view->setVar('publish_types', $publishTypes); } /** @@ -135,9 +139,47 @@ class ReviewController extends Controller return $this->jsonSuccess($content); } + $reasons = $reviewService->getReasons(); $review = $reviewService->getReviewInfo($id); + $this->view->setVar('reasons', $reasons); $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); + } + } diff --git a/app/Http/Admin/Controllers/StudentController.php b/app/Http/Admin/Controllers/StudentController.php deleted file mode 100644 index 324c6943..00000000 --- a/app/Http/Admin/Controllers/StudentController.php +++ /dev/null @@ -1,141 +0,0 @@ -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); - } - -} diff --git a/app/Http/Admin/Controllers/VipController.php b/app/Http/Admin/Controllers/VipController.php new file mode 100644 index 00000000..047070b6 --- /dev/null +++ b/app/Http/Admin/Controllers/VipController.php @@ -0,0 +1,126 @@ +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); + } + +} diff --git a/app/Http/Admin/Services/Answer.php b/app/Http/Admin/Services/Answer.php index 1b2f527a..c705c432 100644 --- a/app/Http/Admin/Services/Answer.php +++ b/app/Http/Admin/Services/Answer.php @@ -213,30 +213,15 @@ class Answer extends Service $reason = $this->request->getPost('reason', ['trim', 'string']); $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); - - $this->recountQuestionAnswers($question); - $owner = $this->findUser($answer->owner_id); - - $this->recountUserAnswers($owner); - $sender = $this->getLoginUser(); if ($type == 'approve') { + $answer->published = AnswerModel::PUBLISH_APPROVED; + $answer->update(); + if ($answer->owner_id != $question->owner_id) { $this->handleAnswerPostPoint($answer); $this->handleQuestionAnsweredNotice($answer); @@ -248,17 +233,17 @@ class Answer extends Service } elseif ($type == 'reject') { - $options = ReasonModel::answerRejectOptions(); - - if (array_key_exists($reason, $options)) { - $reason = $options[$reason]; - } + $answer->published = AnswerModel::PUBLISH_REJECTED; + $answer->update(); $this->handleAnswerRejectedNotice($answer, $sender, $reason); $this->eventsManager->fire('Answer:afterReject', $this, $answer); } + $this->recountQuestionAnswers($question); + $this->recountUserAnswers($owner); + return $answer; } @@ -298,6 +283,78 @@ class Answer extends Service $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) { $validator = new AnswerValidator(); @@ -390,7 +447,7 @@ class Answer extends Service $notice->handle($answer, $sender); } - protected function handleAnswerRejectedNotice(AnswerModel $answer, UserModel $sender, $reason) + protected function handleAnswerRejectedNotice(AnswerModel $answer, UserModel $sender, $reason = '') { $notice = new AnswerRejectedNotice(); @@ -398,6 +455,11 @@ class Answer extends Service } + protected function handleAnswerDeletedNotice(AnswerModel $answer, UserModel $sender, $reason = '') + { + + } + protected function handleAnswerPostPoint(AnswerModel $answer) { $service = new AnswerPostPointHistory(); diff --git a/app/Http/Admin/Services/Article.php b/app/Http/Admin/Services/Article.php index 42cc02a1..fb9c0b03 100644 --- a/app/Http/Admin/Services/Article.php +++ b/app/Http/Admin/Services/Article.php @@ -18,9 +18,9 @@ use App\Models\Reason as ReasonModel; use App\Models\Report as ReportModel; use App\Models\User as UserModel; use App\Repos\Article as ArticleRepo; -use App\Repos\Category as CategoryRepo; use App\Repos\Report as ReportRepo; use App\Repos\User as UserRepo; +use App\Services\Category as CategoryService; use App\Services\Logic\Article\ArticleDataTrait; use App\Services\Logic\Article\ArticleInfo as ArticleInfoService; use App\Services\Logic\Article\XmTagList as XmTagListService; @@ -42,16 +42,11 @@ class Article extends Service return $service->handle($id); } - public function getCategories() + public function getCategoryOptions() { - $categoryRepo = new CategoryRepo(); + $categoryService = new CategoryService(); - return $categoryRepo->findAll([ - 'type' => CategoryModel::TYPE_ARTICLE, - 'level' => 1, - 'published' => 1, - 'deleted' => 0, - ]); + return $categoryService->getCategoryOptions(CategoryModel::TYPE_ARTICLE); } public function getPublishTypes() @@ -161,15 +156,18 @@ class Article extends Service $data = []; - if (isset($post['category_id'])) { - $category = $validator->checkCategory($post['category_id']); - $data['category_id'] = $category->id; - } - if (isset($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'])) { $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'])) { $data['featured'] = $validator->checkFeatureStatus($post['featured']); } + if (isset($post['closed'])) { + $data['closed'] = $validator->checkCloseStatus($post['closed']); + } + if (isset($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'])) { $this->saveTags($article, $post['xm_tag_ids']); } @@ -266,31 +265,12 @@ class Article extends Service $reason = $this->request->getPost('reason', ['trim', 'string']); $article = $this->findOrFail($id); - - $validator = new ArticleValidator(); + $sender = $this->getLoginUser(); if ($type == 'approve') { $article->published = ArticleModel::PUBLISH_APPROVED; - - } 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') { + $article->update(); $this->handleArticlePostPoint($article); $this->handleArticleApprovedNotice($article, $sender); @@ -299,17 +279,20 @@ class Article extends Service } elseif ($type == 'reject') { - $options = ReasonModel::articleRejectOptions(); - - if (array_key_exists($reason, $options)) { - $reason = $options[$reason]; - } + $article->published = ArticleModel::PUBLISH_REJECTED; + $article->update(); $this->handleArticleRejectedNotice($article, $sender, $reason); $this->eventsManager->fire('Article:afterReject', $this, $article); } + $owner = $this->findUser($article->owner_id); + + $this->rebuildArticleCache($article); + $this->rebuildArticleIndex($article); + $this->recountUserArticles($owner); + return $article; } @@ -347,6 +330,72 @@ class Article extends Service $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) { $validator = new ArticleValidator(); @@ -402,13 +451,18 @@ class Article extends Service $notice->handle($article, $sender); } - protected function handleArticleRejectedNotice(ArticleModel $article, UserModel $sender, $reason) + protected function handleArticleRejectedNotice(ArticleModel $article, UserModel $sender, $reason = '') { $notice = new ArticleRejectedNotice(); $notice->handle($article, $sender, $reason); } + protected function handleArticleDeletedNotice(ArticleModel $article, UserModel $sender, $reason = '') + { + + } + protected function handleArticles($pager) { if ($pager->total_items > 0) { diff --git a/app/Http/Admin/Services/AuthNode.php b/app/Http/Admin/Services/AuthNode.php index 35c59e85..319c1f2d 100644 --- a/app/Http/Admin/Services/AuthNode.php +++ b/app/Http/Admin/Services/AuthNode.php @@ -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', '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', 'title' => '分类管理', @@ -624,7 +624,7 @@ class AuthNode extends Service 'id' => '2-2-1', 'title' => '会员套餐', 'type' => 'menu', - 'route' => 'admin.setting.vip', + 'route' => 'admin.vip.list', ], [ 'id' => '2-2-2', @@ -632,43 +632,6 @@ class AuthNode extends Service 'type' => 'menu', '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', - 'title' => '限时秒杀', + 'title' => '会员套餐', 'type' => 'button', 'children' => [ [ 'id' => '2-21-1', - 'title' => '商品列表', + 'title' => '套餐列表', 'type' => 'button', - 'route' => 'admin.flash_sale.list', + 'route' => 'admin.vip.list', ], [ 'id' => '2-21-2', - 'title' => '添加商品', + 'title' => '添加套餐', 'type' => 'button', - 'route' => 'admin.flash_sale.add', + 'route' => 'admin.vip.add', ], [ 'id' => '2-21-3', - 'title' => '搜索商品', + 'title' => '编辑套餐', 'type' => 'button', - 'route' => 'admin.flash_sale.search', + 'route' => 'admin.vip.edit', ], [ 'id' => '2-21-4', - 'title' => '编辑商品', + 'title' => '删除套餐', 'type' => 'button', - 'route' => 'admin.flash_sale.edit', - ], - [ - 'id' => '2-21-5', - 'title' => '删除商品', - 'type' => 'button', - 'route' => 'admin.flash_sale.delete', + 'route' => 'admin.vip.delete', ], ], ], diff --git a/app/Http/Admin/Services/Category.php b/app/Http/Admin/Services/Category.php index 92e8caf8..2401fa99 100644 --- a/app/Http/Admin/Services/Category.php +++ b/app/Http/Admin/Services/Category.php @@ -8,6 +8,7 @@ namespace App\Http\Admin\Services; use App\Caches\Category as CategoryCache; +use App\Caches\CategoryAllList as CategoryAllListCache; use App\Caches\CategoryList as CategoryListCache; use App\Caches\CategoryTreeList as CategoryTreeListCache; use App\Models\Category as CategoryModel; @@ -140,7 +141,6 @@ class Category extends Service $category->update(); $this->updateCategoryStats($category); - $this->rebuildCategoryCache($category); return $category; @@ -182,7 +182,6 @@ class Category extends Service $category->update($data); $this->updateCategoryStats($category); - $this->rebuildCategoryCache($category); return $category; @@ -201,7 +200,6 @@ class Category extends Service $category->update(); $this->updateCategoryStats($category); - $this->rebuildCategoryCache($category); return $category; @@ -216,7 +214,6 @@ class Category extends Service $category->update(); $this->updateCategoryStats($category); - $this->rebuildCategoryCache($category); return $category; @@ -250,6 +247,10 @@ class Category extends Service $cache = new CategoryTreeListCache(); $cache->rebuild($category->type); + + $cache = new CategoryAllListCache(); + + $cache->rebuild($category->type); } protected function enableChildCategories($parentId) diff --git a/app/Http/Admin/Services/Chapter.php b/app/Http/Admin/Services/Chapter.php index 5b01ce92..5df3290a 100644 --- a/app/Http/Admin/Services/Chapter.php +++ b/app/Http/Admin/Services/Chapter.php @@ -201,7 +201,9 @@ class Chapter extends Service } $lessonCount = $chapterRepo->countLessons($chapter->id); + $chapter->lesson_count = $lessonCount; + $chapter->update(); } diff --git a/app/Http/Admin/Services/Comment.php b/app/Http/Admin/Services/Comment.php index b97f29cd..6f48a764 100644 --- a/app/Http/Admin/Services/Comment.php +++ b/app/Http/Admin/Services/Comment.php @@ -13,6 +13,7 @@ use App\Library\Paginator\Query as PagerQuery; use App\Models\Comment as CommentModel; use App\Models\Reason as ReasonModel; use App\Models\Report as ReportModel; +use App\Models\User as UserModel; use App\Repos\Comment as CommentRepo; use App\Repos\Report as ReportRepo; use App\Repos\User as UserRepo; @@ -126,6 +127,12 @@ class Comment extends Service $this->decrUserCommentCount($owner); + $sender = $this->getLoginUser(); + + $this->handleCommentDeletedNotice($comment, $sender); + + $this->eventsManager->fire('Comment:afterDelete', $this, $comment); + return $comment; } @@ -164,23 +171,14 @@ class Comment extends Service $validator = new CommentValidator(); + $sender = $this->getLoginUser(); + if ($type == 'approve') { $comment->published = CommentModel::PUBLISH_APPROVED; - - } elseif ($type == 'reject') { - - $validator->checkRejectReason($reason); - - $comment->published = CommentModel::PUBLISH_REJECTED; - } - - $comment->update(); - - if ($type == 'approve') { + $comment->update(); $owner = $this->findUser($comment->owner_id); - $item = $validator->checkItem($comment->item_id, $comment->item_type); $this->incrItemCommentCount($item); @@ -197,11 +195,17 @@ class Comment extends Service } $this->handleCommentPostPoint($comment); + $this->handleCommentApprovedNotice($comment, $sender); $this->eventsManager->fire('Comment:afterApprove', $this, $comment); } elseif ($type == 'reject') { + $comment->published = CommentModel::PUBLISH_REJECTED; + $comment->update(); + + $this->handleCommentRejectedNotice($comment, $sender, $reason); + $this->eventsManager->fire('Comment:afterReject', $this, $comment); } @@ -236,6 +240,93 @@ class Comment extends Service $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) { $validator = new CommentValidator(); @@ -250,6 +341,21 @@ class Comment extends Service 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) { if ($pager->total_items > 0) { diff --git a/app/Http/Admin/Services/Consult.php b/app/Http/Admin/Services/Consult.php index 4934ff69..44ae915c 100644 --- a/app/Http/Admin/Services/Consult.php +++ b/app/Http/Admin/Services/Consult.php @@ -9,9 +9,13 @@ namespace App\Http\Admin\Services; use App\Builders\ConsultList as ConsultListBuilder; use App\Library\Paginator\Query as PagerQuery; +use App\Library\Validators\Common as CommonValidator; use App\Models\Chapter as ChapterModel; use App\Models\Consult as ConsultModel; 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\Consult as ConsultRepo; use App\Repos\Course as CourseRepo; @@ -27,6 +31,34 @@ class Consult extends Service 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() { $pagerQuery = new PagerQuery(); @@ -35,6 +67,21 @@ class Consult extends Service $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(); $page = $pagerQuery->getPage(); $limit = $pagerQuery->getLimit(); @@ -95,7 +142,6 @@ class Consult extends Service if (isset($post['published'])) { $data['published'] = $validator->checkPublishStatus($post['published']); - $this->handleItemConsults($consult); } $consult->update($data); @@ -104,6 +150,10 @@ class Consult extends Service $this->handleReplyNotice($consult); } + $this->recountItemConsults($consult); + + $this->eventsManager->fire('Consult:afterUpdate', $this, $consult); + return $consult; } @@ -115,7 +165,13 @@ class Consult extends Service $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) @@ -126,52 +182,97 @@ class Consult extends Service $consult->update(); - $this->handleItemConsults($consult); + $this->recountItemConsults($consult); + + $this->eventsManager->fire('Consult:afterRestore', $this, $consult); } public function moderate($id) { $type = $this->request->getPost('type', ['trim', 'string']); + $reason = $this->request->getPost('reason', ['trim', 'string']); $consult = $this->findOrFail($id); + $sender = $this->getLoginUser(); if ($type == 'approve') { + $consult->published = ConsultModel::PUBLISH_APPROVED; - } elseif ($type == 'reject') { - $consult->published = ConsultModel::PUBLISH_REJECTED; - } + $consult->update(); - $consult->update(); + $this->handleConsultApprovedNotice($consult, $sender); - $this->handleItemConsults($consult); - - if ($type == 'approve') { $this->eventsManager->fire('Consult:afterApprove', $this, $consult); + } elseif ($type == 'reject') { + + $consult->published = ConsultModel::PUBLISH_REJECTED; + $consult->update(); + + $this->handleConsultRejectedNotice($consult, $sender, $reason); + $this->eventsManager->fire('Consult:afterReject', $this, $consult); } + $this->recountItemConsults($consult); + return $consult; } - protected function handleItemConsults(ConsultModel $consult) + public function batchModerate() { - if ($consult->course_id > 0) { - $course = $this->findCourse($consult->course_id); - $this->recountCourseConsults($course); - } + $type = $this->request->getQuery('type', ['trim', 'string']); + $ids = $this->request->getPost('ids', ['trim', 'int']); - if ($consult->chapter_id > 0) { - $chapter = $this->findChapter($consult->chapter_id); - $this->recountChapterConsults($chapter); + $consultRepo = new ConsultRepo(); + + $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) @@ -195,6 +296,41 @@ class Consult extends Service 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) { $courseRepo = new CourseRepo(); diff --git a/app/Http/Admin/Services/Course.php b/app/Http/Admin/Services/Course.php index 7e8bd99f..1d4ade92 100644 --- a/app/Http/Admin/Services/Course.php +++ b/app/Http/Admin/Services/Course.php @@ -10,22 +10,20 @@ namespace App\Http\Admin\Services; use App\Builders\CourseList as CourseListBuilder; use App\Builders\ResourceList as ResourceListBuilder; use App\Caches\Course as CourseCache; -use App\Caches\CourseCategoryList as CourseCategoryListCache; use App\Caches\CourseRelatedList as CourseRelatedListCache; -use App\Caches\CourseTeacherList as CourseTeacherListCache; use App\Library\Paginator\Query as PagerQuery; use App\Models\Category as CategoryModel; use App\Models\Course as CourseModel; -use App\Models\CourseCategory as CourseCategoryModel; use App\Models\CourseRelated as CourseRelatedModel; -use App\Models\CourseUser as CourseUserModel; -use App\Repos\Category as CategoryRepo; +use App\Models\CourseTag as CourseTagModel; use App\Repos\Chapter as ChapterRepo; use App\Repos\Course as CourseRepo; -use App\Repos\CourseCategory as CourseCategoryRepo; 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\Services\Category as CategoryService; +use App\Services\Logic\Course\XmTagList as XmTagListService; use App\Services\Sync\CourseIndex as CourseIndexSync; use App\Validators\Course as CourseValidator; use App\Validators\CourseOffline as CourseOfflineValidator; @@ -39,12 +37,8 @@ class Course extends Service $params = $pagerQuery->getParams(); - if (!empty($params['xm_category_ids'])) { - $params['category_id'] = explode(',', $params['xm_category_ids']); - } - - if (!empty($params['xm_teacher_ids'])) { - $params['teacher_id'] = explode(',', $params['xm_teacher_ids']); + if (!empty($params['xm_tag_ids'])) { + $params['tag_id'] = explode(',', $params['xm_tag_ids']); } $params['deleted'] = $params['deleted'] ?? 0; @@ -155,10 +149,6 @@ class Course extends Service $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'])) { $data['market_price'] = $validator->checkMarketPrice($post['market_price']); } @@ -173,17 +163,20 @@ class Course extends Service if (isset($post['published'])) { $data['published'] = $validator->checkPublishStatus($post['published']); - if ($post['published'] == 1) { - $validator->checkPublishAbility($course); - } } - if (isset($post['xm_category_ids'])) { - $this->saveCategories($course, $post['xm_category_ids']); + if (isset($post['category_id'])) { + $category = $validator->checkCategory($post['category_id']); + $data['category_id'] = $category->id; } - if (isset($post['xm_teacher_ids'])) { - $this->saveTeachers($course, $post['xm_teacher_ids']); + if (isset($post['teacher_id'])) { + $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'])) { @@ -258,6 +251,33 @@ class Course extends Service 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() { return CourseModel::studyExpiryOptions(); @@ -268,92 +288,11 @@ class Course extends Service return CourseModel::refundExpiryOptions(); } - public function getXmCategories($id) + public function getXmTags($id) { - $categoryRepo = new CategoryRepo(); + $service = new XmTagListService(); - $allCategories = $categoryRepo->findAll([ - '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; + return $service->handle($id); } public function getXmCourses($id) @@ -409,7 +348,7 @@ class Course extends Service { $courseRepo = new CourseRepo(); - $resources = $courseRepo->findResources($id); + $resources = $courseRepo->findResources($id); if ($resources->count() == 0) return []; @@ -429,106 +368,65 @@ class Course extends Service 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) { - foreach ($courseTeachers as $teacher) { - $originTeacherIds[] = $teacher->id; + if ($course->tags) { + $originTagIds = kg_array_column($course->tags, '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) : []; - $addedTeacherIds = array_diff($newTeacherIds, $originTeacherIds); + $deletedTagIds = array_diff($originTagIds, $newTagIds); - if ($addedTeacherIds) { - foreach ($addedTeacherIds as $teacherId) { - $courseTeacher = new CourseUserModel(); - $courseTeacher->course_id = $course->id; - $courseTeacher->user_id = $teacherId; - $courseTeacher->role_type = CourseUserModel::ROLE_TEACHER; - $courseTeacher->source_type = CourseUserModel::SOURCE_IMPORT; - $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(); + if ($deletedTagIds) { + $courseTagRepo = new CourseTagRepo(); + foreach ($deletedTagIds as $tagId) { + $courseTag = $courseTagRepo->findCourseTag($course->id, $tagId); + if ($courseTag) { + $courseTag->delete(); + $this->recountTagCourses($tagId); } } } - $teacherId = $newTeacherIds[0] ?? 0; + $courseTags = []; - if ($teacherId) { - $course->teacher_id = $teacherId; - $course->update(); - } - - $cache = new CourseTeacherListCache(); - - $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(); + if ($newTagIds) { + $tagRepo = new TagRepo(); + $tags = $tagRepo->findByIds($newTagIds); + if ($tags->count() > 0) { + foreach ($tags as $tag) { + $courseTags[] = ['id' => $tag->id, 'name' => $tag->name]; + $this->recountTagCourses($tag->id); } } } - $categoryId = $newCategoryIds[0] ?? 0; + $course->tags = $courseTags; - if ($categoryId) { - $course->category_id = $categoryId; - $course->update(); - } - - $cache = new CourseCategoryListCache(); - - $cache->rebuild($course->id); + $course->update(); } protected function saveRelatedCourses(CourseModel $course, $courseIds) @@ -608,6 +506,21 @@ class Course extends Service $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) { if ($pager->total_items > 0) { diff --git a/app/Http/Admin/Services/CourseLearning.php b/app/Http/Admin/Services/CourseLearning.php new file mode 100644 index 00000000..02113df1 --- /dev/null +++ b/app/Http/Admin/Services/CourseLearning.php @@ -0,0 +1,64 @@ +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; + } + +} diff --git a/app/Http/Admin/Services/CourseUser.php b/app/Http/Admin/Services/CourseUser.php new file mode 100644 index 00000000..a3963d47 --- /dev/null +++ b/app/Http/Admin/Services/CourseUser.php @@ -0,0 +1,101 @@ +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; + } + +} diff --git a/app/Http/Admin/Services/FlashSale.php b/app/Http/Admin/Services/FlashSale.php deleted file mode 100644 index b903a6c6..00000000 --- a/app/Http/Admin/Services/FlashSale.php +++ /dev/null @@ -1,380 +0,0 @@ -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; - } - -} diff --git a/app/Http/Admin/Services/Order.php b/app/Http/Admin/Services/Order.php index 995cf065..b69745d9 100644 --- a/app/Http/Admin/Services/Order.php +++ b/app/Http/Admin/Services/Order.php @@ -9,6 +9,7 @@ namespace App\Http\Admin\Services; use App\Builders\OrderList as OrderListBuilder; use App\Library\Paginator\Query as PaginateQuery; +use App\Library\Validators\Common as CommonValidator; use App\Models\Order as OrderModel; use App\Repos\Account as AccountRepo; use App\Repos\Order as OrderRepo; @@ -36,6 +37,30 @@ class Order extends Service $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(); $page = $pageQuery->getPage(); $limit = $pageQuery->getLimit(); diff --git a/app/Http/Admin/Services/Question.php b/app/Http/Admin/Services/Question.php index ad1450b7..e17a687d 100644 --- a/app/Http/Admin/Services/Question.php +++ b/app/Http/Admin/Services/Question.php @@ -16,10 +16,10 @@ use App\Models\Question as QuestionModel; use App\Models\Reason as ReasonModel; use App\Models\Report as ReportModel; use App\Models\User as UserModel; -use App\Repos\Category as CategoryRepo; use App\Repos\Question as QuestionRepo; use App\Repos\Report as ReportRepo; 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\QuestionRejected as QuestionRejectedNotice; use App\Services\Logic\Point\History\QuestionPost as QuestionPostPointHistory; @@ -41,16 +41,11 @@ class Question extends Service return $service->handle($id); } - public function getCategories() + public function getCategoryOptions() { - $categoryRepo = new CategoryRepo(); + $categoryService = new CategoryService(); - return $categoryRepo->findAll([ - 'type' => CategoryModel::TYPE_QUESTION, - 'level' => 1, - 'published' => 1, - 'deleted' => 0, - ]); + return $categoryService->getCategoryOptions(CategoryModel::TYPE_QUESTION); } public function getPublishTypes() @@ -155,11 +150,6 @@ class Question extends Service $data = []; - if (isset($post['category_id'])) { - $category = $validator->checkCategory($post['category_id']); - $data['category_id'] = $category->id; - } - if (isset($post['title'])) { $data['title'] = $validator->checkTitle($post['title']); } @@ -172,10 +162,18 @@ class Question extends Service $data['keywords'] = $validator->checkKeywords($post['keywords']); } + if (isset($post['summary'])) { + $data['summary'] = $validator->checkSummary($post['keywords']); + } + if (isset($post['anonymous'])) { $data['anonymous'] = $validator->checkAnonymousStatus($post['anonymous']); } + if (isset($post['featured'])) { + $data['featured'] = $validator->checkFeatureStatus($post['featured']); + } + if (isset($post['closed'])) { $data['closed'] = $validator->checkCloseStatus($post['closed']); } @@ -184,6 +182,11 @@ class Question extends Service $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'])) { $this->saveTags($question, $post['xm_tag_ids']); } @@ -210,6 +213,10 @@ class Question extends Service $question->update(); + $sender = $this->getLoginUser(); + + $this->handleQuestionDeletedNotice($question, $sender); + $owner = $this->findUser($question->owner_id); $this->saveDynamicAttrs($question); @@ -247,28 +254,13 @@ class Question extends Service $reason = $this->request->getPost('reason', ['trim', 'string']); $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(); if ($type == 'approve') { + $question->published = QuestionModel::PUBLISH_APPROVED; + $question->update(); + $this->handleQuestionPostPoint($question); $this->handleQuestionApprovedNotice($question, $sender); @@ -276,17 +268,20 @@ class Question extends Service } elseif ($type == 'reject') { - $options = ReasonModel::questionRejectOptions(); - - if (array_key_exists($reason, $options)) { - $reason = $options[$reason]; - } + $question->published = QuestionModel::PUBLISH_REJECTED; + $question->update(); $this->handleQuestionRejectedNotice($question, $sender, $reason); $this->eventsManager->fire('Question:afterReject', $this, $question); } + $owner = $this->findUser($question->owner_id); + + $this->recountUserQuestions($owner); + $this->rebuildQuestionCache($question); + $this->rebuildQuestionIndex($question); + return $question; } @@ -324,6 +319,72 @@ class Question extends Service $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) { $validator = new QuestionValidator(); @@ -379,13 +440,18 @@ class Question extends Service $notice->handle($question, $sender); } - protected function handleQuestionRejectedNotice(QuestionModel $question, UserModel $sender, $reason) + protected function handleQuestionRejectedNotice(QuestionModel $question, UserModel $sender, $reason = '') { $notice = new QuestionRejectedNotice(); $notice->handle($question, $sender, $reason); } + protected function handleQuestionDeletedNotice(QuestionModel $question, UserModel $sender, $reason = '') + { + + } + protected function handleQuestions($pager) { if ($pager->total_items > 0) { diff --git a/app/Http/Admin/Services/Refund.php b/app/Http/Admin/Services/Refund.php index 6c21711a..ed8aeed0 100644 --- a/app/Http/Admin/Services/Refund.php +++ b/app/Http/Admin/Services/Refund.php @@ -9,6 +9,7 @@ namespace App\Http\Admin\Services; use App\Builders\RefundList as RefundListBuilder; use App\Library\Paginator\Query as PaginateQuery; +use App\Library\Validators\Common as CommonValidator; use App\Models\Refund as RefundModel; use App\Models\Task as TaskModel; use App\Repos\Account as AccountRepo; @@ -43,6 +44,21 @@ class Refund extends Service $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(); $page = $pageQuery->getPage(); $limit = $pageQuery->getLimit(); diff --git a/app/Http/Admin/Services/Review.php b/app/Http/Admin/Services/Review.php index 14bc5aa7..26922213 100644 --- a/app/Http/Admin/Services/Review.php +++ b/app/Http/Admin/Services/Review.php @@ -9,8 +9,12 @@ namespace App\Http\Admin\Services; use App\Builders\ReviewList as ReviewListBuilder; use App\Library\Paginator\Query as PagerQuery; +use App\Library\Validators\Common as CommonValidator; use App\Models\Course as CourseModel; +use App\Models\Reason as ReasonModel; 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\Review as ReviewRepo; use App\Services\CourseStat as CourseStatService; @@ -25,6 +29,34 @@ class Review extends Service 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() { $pagerQuery = new PagerQuery(); @@ -33,6 +65,21 @@ class Review extends Service $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(); $page = $pagerQuery->getPage(); $limit = $pagerQuery->getLimit(); @@ -91,6 +138,10 @@ class Review extends Service $data['rating3'] = $validator->checkRating($post['rating3']); } + if (isset($post['anonymous'])) { + $data['anonymous'] = $validator->checkAnonymous($post['anonymous']); + } + if (isset($post['published'])) { $data['published'] = $validator->checkPublishStatus($post['published']); $this->recountCourseReviews($course); @@ -99,6 +150,7 @@ class Review extends Service $review->update($data); $this->updateCourseRating($course); + $this->recountCourseReviews($course); $this->eventsManager->fire('Review:afterUpdate', $this, $review); @@ -117,6 +169,12 @@ class Review extends Service $this->recountCourseReviews($course); + $this->updateCourseRating($course); + + $sender = $this->getLoginUser(); + + $this->handleReviewDeletedNotice($review, $sender); + $this->eventsManager->fire('Review:afterReview', $this, $review); } @@ -138,30 +196,102 @@ class Review extends Service public function moderate($id) { $type = $this->request->getPost('type', ['trim', 'string']); + $reason = $this->request->getPost('reason', ['trim', 'string']); $review = $this->findOrFail($id); - if ($type == 'approve') { - $review->published = ReviewModel::PUBLISH_APPROVED; - } elseif ($type == 'reject') { - $review->published = ReviewModel::PUBLISH_REJECTED; - } + $sender = $this->getLoginUser(); - $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); $this->recountCourseReviews($course); - - if ($type == 'approve') { - $this->eventsManager->fire('Review:afterApprove', $this, $review); - } elseif ($type == 'reject') { - $this->eventsManager->fire('Review:afterReject', $this, $review); - } + $this->updateCourseRating($course); 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) { $validator = new ReviewValidator(); @@ -176,6 +306,21 @@ class Review extends Service 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) { $courseRepo = new CourseRepo(); diff --git a/app/Http/Admin/Services/Role.php b/app/Http/Admin/Services/Role.php index e6e50b2e..3899d6cd 100644 --- a/app/Http/Admin/Services/Role.php +++ b/app/Http/Admin/Services/Role.php @@ -140,6 +140,9 @@ class Role extends Service $list[] = str_replace('.edit', '.list', $route); } elseif (strpos($route, '.delete')) { $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')) { $list[] = str_replace('.search', '.list', $route); } diff --git a/app/Http/Admin/Services/Student.php b/app/Http/Admin/Services/Student.php deleted file mode 100644 index 1743e513..00000000 --- a/app/Http/Admin/Services/Student.php +++ /dev/null @@ -1,223 +0,0 @@ - 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; - } - -} diff --git a/app/Http/Admin/Services/Trade.php b/app/Http/Admin/Services/Trade.php index 42616281..3023e9ae 100644 --- a/app/Http/Admin/Services/Trade.php +++ b/app/Http/Admin/Services/Trade.php @@ -9,6 +9,7 @@ namespace App\Http\Admin\Services; use App\Builders\TradeList as TradeListBuilder; use App\Library\Paginator\Query as PaginateQuery; +use App\Library\Validators\Common as CommonValidator; use App\Models\Refund as RefundModel; use App\Models\Trade as TradeModel; use App\Repos\Account as AccountRepo; @@ -46,6 +47,21 @@ class Trade extends Service $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(); $page = $pageQuery->getPage(); $limit = $pageQuery->getLimit(); diff --git a/app/Http/Admin/Services/User.php b/app/Http/Admin/Services/User.php index 7a15e29f..be2f4039 100644 --- a/app/Http/Admin/Services/User.php +++ b/app/Http/Admin/Services/User.php @@ -335,11 +335,12 @@ class User extends Service $items = $pager->items->toArray(); $pipeA = $builder->handleUsers($items); - $pipeB = $builder->handleAdminRoles($pipeA); - $pipeC = $builder->handleEduRoles($pipeB); - $pipeD = $builder->objects($pipeC); + $pipeB = $builder->handleAccounts($pipeA); + $pipeC = $builder->handleAdminRoles($pipeB); + $pipeD = $builder->handleEduRoles($pipeC); + $pipeE = $builder->objects($pipeD); - $pager->items = $pipeD; + $pager->items = $pipeE; } return $pager; diff --git a/app/Http/Admin/Services/Util.php b/app/Http/Admin/Services/Util.php index b9352de6..552f235b 100644 --- a/app/Http/Admin/Services/Util.php +++ b/app/Http/Admin/Services/Util.php @@ -7,8 +7,7 @@ namespace App\Http\Admin\Services; -use App\Caches\IndexSlideList as IndexSlideListCache; -use App\Services\Utils\IndexCourseCache as IndexCourseCacheUtil; +use App\Services\Utils\IndexPageCache as IndexPageCacheUtil; class Util extends Service { @@ -17,29 +16,25 @@ class Util extends Service { $items = $this->request->getPost('items'); - if ($items['slide'] == 1) { - $cache = new IndexSlideListCache(); - $cache->rebuild(); + $sections = [ + 'slide', + 'featured_course', + 'new_course', + 'free_course', + 'vip_course', + ]; + + if (empty($items)) { + $items = $sections; } - $util = new IndexCourseCacheUtil(); + $util = new IndexPageCacheUtil(); - if ($items['featured_course'] == 1) { - $util->rebuild('featured_course'); + foreach ($sections as $section) { + 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'); - } - } } diff --git a/app/Http/Admin/Services/Vip.php b/app/Http/Admin/Services/Vip.php new file mode 100644 index 00000000..a926aba7 --- /dev/null +++ b/app/Http/Admin/Services/Vip.php @@ -0,0 +1,120 @@ +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); + } + +} diff --git a/app/Http/Admin/Views/answer/edit.volt b/app/Http/Admin/Views/answer/edit.volt index 9f5d83a5..3e354819 100644 --- a/app/Http/Admin/Views/answer/edit.volt +++ b/app/Http/Admin/Views/answer/edit.volt @@ -7,16 +7,27 @@
信息 | ++ | 作者信息 | +问答信息 | 评论 | 点赞 | 状态 | @@ -46,10 +55,15 @@ {% set restore_url = url({'for':'admin.answer.restore','id':item.id}) %} {% set moderate_url = url({'for':'admin.answer.moderate','id':item.id}) %}
---|---|---|---|---|---|---|
-
- 回答:{{ substr(item.summary,0,32) }} -作者:{{ item.owner.name }} 创建:{{ date('Y-m-d',item.create_time) }} + +编号:{{ item.owner.id }} + |
+
+ 问题:{{ item.question.title }}({{ item.question.id }}) +回答:{{ item.summary }}({{ item.id }}) +创建:{{ date('Y-m-d',item.create_time) }} |
{{ item.comment_count }} | {{ item.like_count }} | diff --git a/app/Http/Admin/Views/answer/moderate.volt b/app/Http/Admin/Views/answer/moderate.volt index 703cebd4..4dec226a 100644 --- a/app/Http/Admin/Views/answer/moderate.volt +++ b/app/Http/Admin/Views/answer/moderate.volt @@ -37,8 +37,8 @@