1
0
mirror of https://gitee.com/koogua/course-tencent-cloud.git synced 2025-08-10 16:31:38 +08:00

调整category数据结构变化带来的问题

This commit is contained in:
xiaochong0302 2020-08-11 21:50:57 +08:00
parent f8fb1444f3
commit 343c8d49d4
82 changed files with 1138 additions and 775 deletions

View File

@ -9,9 +9,9 @@ use Phalcon\Mvc\Model\ResultsetInterface;
class CategoryTreeList extends Builder class CategoryTreeList extends Builder
{ {
public function handle() public function handle($type)
{ {
$topCategories = $this->findChildCategories(0); $topCategories = $this->findChildCategories($type, 0);
if ($topCategories->count() == 0) { if ($topCategories->count() == 0) {
return []; return [];
@ -32,7 +32,7 @@ class CategoryTreeList extends Builder
protected function handleChildren(CategoryModel $category) protected function handleChildren(CategoryModel $category)
{ {
$subCategories = $this->findChildCategories($category->id); $subCategories = $this->findChildCategories($category->type, $category->id);
if ($subCategories->count() == 0) { if ($subCategories->count() == 0) {
return []; return [];
@ -51,16 +51,27 @@ class CategoryTreeList extends Builder
} }
/** /**
* @param int $categoryId * @param string $type
* @param int $parentId
* @return ResultsetInterface|Resultset|CategoryModel[] * @return ResultsetInterface|Resultset|CategoryModel[]
*/ */
protected function findChildCategories($categoryId = 0) protected function findChildCategories($type = 'course', $parentId = 0)
{ {
return CategoryModel::query() $query = CategoryModel::query();
->where('parent_id = :parent_id:', ['parent_id' => $categoryId])
->andWhere('published = 1') $query->where('published = 1');
->orderBy('priority ASC')
->execute(); if ($type) {
$query->andWhere('type = :type:', ['type' => $type]);
}
if ($parentId) {
$query->andWhere('parent_id = :parent_id:', ['parent_id' => $parentId]);
}
$query->orderBy('priority ASC');
return $query->execute();
} }
} }

View File

@ -3,6 +3,7 @@
namespace App\Builders; namespace App\Builders;
use App\Caches\CategoryList as CategoryListCache; use App\Caches\CategoryList as CategoryListCache;
use App\Models\Category as CategoryModel;
use App\Repos\User as UserRepo; use App\Repos\User as UserRepo;
class CourseList extends Builder class CourseList extends Builder
@ -34,7 +35,7 @@ class CourseList extends Builder
{ {
$cache = new CategoryListCache(); $cache = new CategoryListCache();
$items = $cache->get(); $items = $cache->get(CategoryModel::TYPE_COURSE);
if (empty($items)) { if (empty($items)) {
return []; return [];

42
app/Builders/HelpList.php Normal file
View File

@ -0,0 +1,42 @@
<?php
namespace App\Builders;
use App\Caches\CategoryList as CategoryListCache;
use App\Models\Category as CategoryModel;
class HelpList extends Builder
{
public function handleCategories(array $helps)
{
$categories = $this->getCategories();
foreach ($helps as $key => $help) {
$helps[$key]['category'] = $categories[$help['category_id']] ?? new \stdClass();
}
return $helps;
}
public function getCategories()
{
$cache = new CategoryListCache();
$items = $cache->get(CategoryModel::TYPE_HELP);
if (!$items) return [];
$result = [];
foreach ($items as $item) {
$result[$item['id']] = [
'id' => $item['id'],
'name' => $item['name'],
];
}
return $result;
}
}

View File

@ -15,23 +15,24 @@ class CategoryList extends Cache
return $this->lifetime; return $this->lifetime;
} }
public function getKey($id = null) public function getKey($type = null)
{ {
return 'category_list'; return "category_list:{$type}";
} }
/** /**
* @param null $id * @param null $type
* @return array * @return array
*/ */
public function getContent($id = null) public function getContent($type = null)
{ {
/** /**
* @var Resultset $categories * @var Resultset $categories
*/ */
$categories = CategoryModel::query() $categories = CategoryModel::query()
->columns(['id', 'parent_id', 'name', 'priority', 'level', 'path']) ->columns(['id', 'parent_id', 'name', 'priority', 'level', 'path'])
->where('published = 1') ->where('type = :type:', ['type' => $type])
->andWhere('published = 1')
->execute(); ->execute();
if ($categories->count() == 0) { if ($categories->count() == 0) {

View File

@ -14,16 +14,16 @@ class CategoryTreeList extends Cache
return $this->lifetime; return $this->lifetime;
} }
public function getKey($id = null) public function getKey($type = null)
{ {
return 'category_tree_list'; return "category_tree_list:{$type}";
} }
public function getContent($id = null) public function getContent($type = null)
{ {
$builder = new CategoryTreeListBuilder(); $builder = new CategoryTreeListBuilder();
$list = $builder->handle(); $list = $builder->handle($type);
return $list ?: []; return $list ?: [];
} }

89
app/Caches/HelpList.php Normal file
View File

@ -0,0 +1,89 @@
<?php
namespace App\Caches;
use App\Models\Category as CategoryModel;
use App\Models\Help as HelpModel;
use Phalcon\Mvc\Model\Resultset;
use Phalcon\Mvc\Model\ResultsetInterface;
class HelpList extends Cache
{
protected $lifetime = 365 * 86400;
public function getLifetime()
{
return $this->lifetime;
}
public function getKey($id = null)
{
return 'help_list';
}
public function getContent($id = null)
{
$categories = $this->findCategories();
if ($categories->count() == 0) {
return [];
}
$result = [];
foreach ($categories as $category) {
$item = [];
$item['category'] = [
'id' => $category->id,
'name' => $category->name,
];
$item['list'] = [];
$helps = $this->findHelps($category->id);
if ($helps->count() > 0) {
foreach ($helps as $help) {
$item['list'][] = [
'id' => $help->id,
'title' => $help->title,
];
}
}
$result[] = $item;
}
return $result;
}
/**
* @return ResultsetInterface|Resultset|CategoryModel[]
*/
protected function findCategories()
{
return CategoryModel::query()
->where('type = :type:', ['type' => CategoryModel::TYPE_HELP])
->andWhere('level = 1 AND published = 1')
->orderBy('priority ASC')
->execute();
}
/**
* @param int $categoryId
* @return ResultsetInterface|Resultset|CategoryModel[]
*/
protected function findHelps($categoryId)
{
return HelpModel::query()
->where('category_id = :category_id:', ['category_id' => $categoryId])
->andWhere('published = 1')
->orderBy('priority ASC')
->execute();
}
}

View File

@ -84,7 +84,8 @@ class IndexFreeCourseList extends Cache
protected function findCategories($limit = 5) protected function findCategories($limit = 5)
{ {
return CategoryModel::query() return CategoryModel::query()
->where('level = 1 AND published = 1') ->where('type = :type:', ['type' => CategoryModel::TYPE_COURSE])
->andWhere('level = 1 AND published = 1')
->orderBy('priority ASC') ->orderBy('priority ASC')
->limit($limit) ->limit($limit)
->execute(); ->execute();

View File

@ -84,7 +84,8 @@ class IndexNewCourseList extends Cache
protected function findCategories($limit = 5) protected function findCategories($limit = 5)
{ {
return CategoryModel::query() return CategoryModel::query()
->where('level = 1 AND published = 1') ->where('type = :type:', ['type' => CategoryModel::TYPE_COURSE])
->andWhere('level = 1 AND published = 1')
->orderBy('priority ASC') ->orderBy('priority ASC')
->limit($limit) ->limit($limit)
->execute(); ->execute();

View File

@ -84,7 +84,8 @@ class IndexVipCourseList extends Cache
protected function findCategories($limit = 5) protected function findCategories($limit = 5)
{ {
return CategoryModel::query() return CategoryModel::query()
->where('level = 1 AND published = 1') ->where('type = :type:', ['type' => CategoryModel::TYPE_COURSE])
->andWhere('level = 1 AND published = 1')
->orderBy('priority ASC') ->orderBy('priority ASC')
->limit($limit) ->limit($limit)
->execute(); ->execute();

View File

@ -16,12 +16,20 @@ class CategoryController extends Controller
public function listAction() public function listAction()
{ {
$parentId = $this->request->get('parent_id', 'int', 0); $parentId = $this->request->get('parent_id', 'int', 0);
$type = $this->request->get('type', 'string', 'course');
$categoryService = new CategoryService(); $categoryService = new CategoryService();
$parent = $categoryService->getParentCategory($parentId); $parent = $categoryService->getParentCategory($parentId);
$categories = $categoryService->getChildCategories($parentId);
if ($parent->id > 0) {
$type = $parent->type;
$categories = $categoryService->getChildCategories($parentId);
} else {
$categories = $categoryService->getTopCategories($type);
}
$this->view->setVar('type', $type);
$this->view->setVar('parent', $parent); $this->view->setVar('parent', $parent);
$this->view->setVar('categories', $categories); $this->view->setVar('categories', $categories);
} }
@ -32,12 +40,20 @@ class CategoryController extends Controller
public function addAction() public function addAction()
{ {
$parentId = $this->request->get('parent_id', 'int', 0); $parentId = $this->request->get('parent_id', 'int', 0);
$type = $this->request->get('type', 'string', 'course');
$categoryService = new CategoryService(); $categoryService = new CategoryService();
$topCategories = $categoryService->getTopCategories(); $parent = $categoryService->getParentCategory($parentId);
$this->view->setVar('parent_id', $parentId); if ($parent->id > 0) {
$type = $parent->type;
}
$topCategories = $categoryService->getTopCategories($type);
$this->view->setVar('type', $type);
$this->view->setVar('parent', $parent);
$this->view->setVar('top_categories', $topCategories); $this->view->setVar('top_categories', $topCategories);
} }
@ -52,7 +68,7 @@ class CategoryController extends Controller
$location = $this->url->get( $location = $this->url->get(
['for' => 'admin.category.list'], ['for' => 'admin.category.list'],
['parent_id' => $category->parent_id] ['type' => $category->type, 'parent_id' => $category->parent_id],
); );
$content = [ $content = [
@ -88,7 +104,7 @@ class CategoryController extends Controller
$location = $this->url->get( $location = $this->url->get(
['for' => 'admin.category.list'], ['for' => 'admin.category.list'],
['parent_id' => $category->parent_id] ['type' => $category->type, 'parent_id' => $category->parent_id],
); );
$content = [ $content = [

View File

@ -53,7 +53,7 @@ class Controller extends \Phalcon\Mvc\Controller
* 特例白名单 * 特例白名单
*/ */
$whitelist = [ $whitelist = [
'controllers' => ['public', 'index', 'storage', 'vod', 'test', 'xm_course'], 'controllers' => ['public', 'index', 'vod', 'test', 'xm_course'],
'routes' => ['admin.package.guiding'], 'routes' => ['admin.package.guiding'],
]; ];

View File

@ -10,6 +10,19 @@ use App\Http\Admin\Services\Course as CourseService;
class CourseController extends Controller class CourseController extends Controller
{ {
/**
* @Get("/category", name="admin.course.category")
*/
public function categoryAction()
{
$location = $this->url->get(
['for' => 'admin.category.list'],
['type' => 'course'],
);
return $this->response->redirect($location);
}
/** /**
* @Get("/search", name="admin.course.search") * @Get("/search", name="admin.course.search")
*/ */

View File

@ -10,6 +10,19 @@ use App\Http\Admin\Services\Help as HelpService;
class HelpController extends Controller class HelpController extends Controller
{ {
/**
* @Get("/category", name="admin.help.category")
*/
public function categoryAction()
{
$location = $this->url->get(
['for' => 'admin.category.list'],
['type' => 'help'],
);
return $this->response->redirect($location);
}
/** /**
* @Get("/list", name="admin.help.list") * @Get("/list", name="admin.help.list")
*/ */
@ -27,7 +40,11 @@ class HelpController extends Controller
*/ */
public function addAction() public function addAction()
{ {
$helpService = new HelpService();
$categories = $helpService->getCategories();
$this->view->setVar('categories', $categories);
} }
/** /**
@ -56,8 +73,11 @@ class HelpController extends Controller
{ {
$helpService = new HelpService; $helpService = new HelpService;
$categories = $helpService->getCategories();
$help = $helpService->getHelp($id); $help = $helpService->getHelp($id);
$this->view->setVar('categories', $categories);
$this->view->setVar('help', $help); $this->view->setVar('help', $help);
} }

View File

@ -8,8 +8,8 @@ use App\Http\Admin\Services\WxpayTest as WxpayTestService;
use App\Services\Captcha as CaptchaService; use App\Services\Captcha as CaptchaService;
use App\Services\Live as LiveService; use App\Services\Live as LiveService;
use App\Services\Mailer\Test as TestMailerService; use App\Services\Mailer\Test as TestMailerService;
use App\Services\MyStorage as StorageService;
use App\Services\Smser\Test as TestSmserService; use App\Services\Smser\Test as TestSmserService;
use App\Services\Storage as StorageService;
use App\Services\Vod as VodService; use App\Services\Vod as VodService;
use Phalcon\Mvc\View; use Phalcon\Mvc\View;
@ -29,16 +29,8 @@ class TestController extends Controller
$result = []; $result = [];
$result['hello'] = $storageService->uploadTestFile(); $result['hello'] = $storageService->uploadTestFile();
$result['avatar'] = $storageService->uploadDefaultAvatarImage();
$avatarPath = public_path('static/admin/img/default_avatar.png'); $result['cover'] = $storageService->uploadDefaultCoverImage();
$avatarKey = '/img/avatar/default.png';
$result['avatar'] = $storageService->putFile($avatarKey, $avatarPath);
$coverPath = public_path('static/admin/img/default_cover.png');
$coverKey = '/img/cover/default.png';
$result['cover'] = $storageService->putFile($coverKey, $coverPath);
if ($result['hello'] && $result['avatar'] && $result['cover']) { if ($result['hello'] && $result['avatar'] && $result['cover']) {
return $this->jsonSuccess(['msg' => '上传文件成功,请到控制台确认']); return $this->jsonSuccess(['msg' => '上传文件成功,请到控制台确认']);
@ -176,9 +168,9 @@ class TestController extends Controller
$order = $alipayTestService->createOrder(); $order = $alipayTestService->createOrder();
$trade = $alipayTestService->createTrade($order); $trade = $alipayTestService->createTrade($order);
$qrcodeUrl = $alipayTestService->scan($trade); $qrcode = $alipayTestService->scan($trade);
if ($order && $trade && $qrcodeUrl) { if ($order && $trade && $qrcode) {
$this->db->commit(); $this->db->commit();
} else { } else {
$this->db->rollback(); $this->db->rollback();
@ -186,7 +178,7 @@ class TestController extends Controller
$this->view->pick('setting/pay_alipay_test'); $this->view->pick('setting/pay_alipay_test');
$this->view->setVar('sn', $trade->sn); $this->view->setVar('sn', $trade->sn);
$this->view->setVar('qrcode_url', $qrcodeUrl); $this->view->setVar('qrcode', $qrcode);
} }
/** /**
@ -228,9 +220,9 @@ class TestController extends Controller
$order = $wxpayTestService->createOrder(); $order = $wxpayTestService->createOrder();
$trade = $wxpayTestService->createTrade($order); $trade = $wxpayTestService->createTrade($order);
$qrcodeUrl = $wxpayTestService->scan($trade); $qrcode = $wxpayTestService->scan($trade);
if ($order && $trade && $qrcodeUrl) { if ($order && $trade && $qrcode) {
$this->db->commit(); $this->db->commit();
} else { } else {
$this->db->rollback(); $this->db->rollback();
@ -238,7 +230,7 @@ class TestController extends Controller
$this->view->pick('setting/pay_wxpay_test'); $this->view->pick('setting/pay_wxpay_test');
$this->view->setVar('sn', $trade->sn); $this->view->setVar('sn', $trade->sn);
$this->view->setVar('qrcode_url', $qrcodeUrl); $this->view->setVar('qrcode', $qrcode);
} }
/** /**

View File

@ -2,7 +2,7 @@
namespace App\Http\Admin\Controllers; namespace App\Http\Admin\Controllers;
use App\Services\Storage as StorageService; use App\Services\MyStorage as StorageService;
/** /**
* @RoutePrefix("/admin/upload") * @RoutePrefix("/admin/upload")
@ -11,7 +11,7 @@ class UploadController extends Controller
{ {
/** /**
* @Post("/img/cover", name="admin.upload.cover_img") * @Post("/cover/img", name="admin.upload.cover_img")
*/ */
public function uploadCoverImageAction() public function uploadCoverImageAction()
{ {
@ -32,7 +32,7 @@ class UploadController extends Controller
} }
/** /**
* @Post("/img/avatar", name="admin.upload.avatar_img") * @Post("/avatar/img", name="admin.upload.avatar_img")
*/ */
public function uploadAvatarImageAction() public function uploadAvatarImageAction()
{ {
@ -53,7 +53,7 @@ class UploadController extends Controller
} }
/** /**
* @Post("/img/editor", name="admin.upload.editor_img") * @Post("/editor/img", name="admin.upload.editor_img")
*/ */
public function uploadEditorImageAction() public function uploadEditorImageAction()
{ {

View File

@ -18,7 +18,9 @@ class AuthMenu extends Component
public function __construct() public function __construct()
{ {
$this->authUser = $this->getAuthInfo(); $this->authUser = $this->getAuthInfo();
$this->authNodes = $this->getAuthNodes(); $this->authNodes = $this->getAuthNodes();
$this->setOwnedLevelIds(); $this->setOwnedLevelIds();
} }
@ -46,6 +48,7 @@ class AuthMenu extends Component
foreach ($level['children'] as $key2 => $level2) { foreach ($level['children'] as $key2 => $level2) {
foreach ($level2['children'] as $key3 => $level3) { foreach ($level2['children'] as $key3 => $level3) {
$allowed = ($this->authUser['root'] == 1) || in_array($level3['id'], $this->owned3rdLevelIds); $allowed = ($this->authUser['root'] == 1) || in_array($level3['id'], $this->owned3rdLevelIds);
$params = $level3['params'] ?? [];
if ($level3['type'] == 'menu' && $allowed) { if ($level3['type'] == 'menu' && $allowed) {
$menus[$key]['id'] = $level['id']; $menus[$key]['id'] = $level['id'];
$menus[$key]['title'] = $level['title']; $menus[$key]['title'] = $level['title'];
@ -54,7 +57,7 @@ class AuthMenu extends Component
$menus[$key]['children'][$key2]['children'][$key3] = [ $menus[$key]['children'][$key2]['children'][$key3] = [
'id' => $level3['id'], 'id' => $level3['id'],
'title' => $level3['title'], 'title' => $level3['title'],
'url' => $this->url->get(['for' => $level3['route']]), 'url' => $this->url->get(['for' => $level3['route']], $params),
]; ];
} }
} }

View File

@ -29,6 +29,12 @@ class AuthNode extends Service
'title' => '课程管理', 'title' => '课程管理',
'type' => 'menu', 'type' => 'menu',
'children' => [ 'children' => [
[
'id' => '1-1-0',
'title' => '课程分类',
'type' => 'menu',
'route' => 'admin.course.category',
],
[ [
'id' => '1-1-1', 'id' => '1-1-1',
'title' => '课程列表', 'title' => '课程列表',
@ -71,12 +77,14 @@ class AuthNode extends Service
'title' => '分类列表', 'title' => '分类列表',
'type' => 'menu', 'type' => 'menu',
'route' => 'admin.category.list', 'route' => 'admin.category.list',
'params' => ['type' => 'course'],
], ],
[ [
'id' => '1-2-2', 'id' => '1-2-2',
'title' => '添加分类', 'title' => '添加分类',
'type' => 'menu', 'type' => 'menu',
'route' => 'admin.category.add', 'route' => 'admin.category.add',
'params' => ['type' => 'course'],
], ],
[ [
'id' => '1-2-3', 'id' => '1-2-3',
@ -196,6 +204,12 @@ class AuthNode extends Service
'title' => '帮助管理', 'title' => '帮助管理',
'type' => 'menu', 'type' => 'menu',
'children' => [ 'children' => [
[
'id' => '1-6-0',
'title' => '帮助分类',
'type' => 'menu',
'route' => 'admin.help.category',
],
[ [
'id' => '1-6-1', 'id' => '1-6-1',
'title' => '帮助列表', 'title' => '帮助列表',

View File

@ -30,19 +30,20 @@ class Category extends Service
return $parent; return $parent;
} }
public function getTopCategories() public function getTopCategories($type)
{ {
$categoryRepo = new CategoryRepo(); $categoryRepo = new CategoryRepo();
return $categoryRepo->findAll([ return $categoryRepo->findAll([
'parent_id' => 0, 'parent_id' => 0,
'published' => 1, 'deleted' => 0,
'type' => $type,
]); ]);
} }
public function getChildCategories($parentId) public function getChildCategories($parentId)
{ {
$deleted = $this->request->getQuery('deleted', 'int', 0); $deleted = $this->request->getQuery('deleted', ['int'], 0);
$categoryRepo = new CategoryRepo(); $categoryRepo = new CategoryRepo();
@ -70,6 +71,7 @@ class Category extends Service
$data['parent_id'] = $parent->id; $data['parent_id'] = $parent->id;
} }
$data['type'] = $validator->checkType($post['type']);
$data['name'] = $validator->checkName($post['name']); $data['name'] = $validator->checkName($post['name']);
$data['priority'] = $validator->checkPriority($post['priority']); $data['priority'] = $validator->checkPriority($post['priority']);
$data['published'] = $validator->checkPublishStatus($post['published']); $data['published'] = $validator->checkPublishStatus($post['published']);
@ -190,11 +192,11 @@ class Category extends Service
$cache = new CategoryListCache(); $cache = new CategoryListCache();
$cache->rebuild(); $cache->rebuild($category->type);
$cache = new CategoryTreeListCache(); $cache = new CategoryTreeListCache();
$cache->rebuild(); $cache->rebuild($category->type);
} }
protected function enableChildCategories($parentId) protected function enableChildCategories($parentId)

View File

@ -2,23 +2,48 @@
namespace App\Http\Admin\Services; namespace App\Http\Admin\Services;
use App\Caches\Help as HelpCache; use App\Builders\HelpList as HelpListBuilder;
use App\Caches\HelpList as HelpListCache;
use App\Models\Category as CategoryModel;
use App\Models\Help as HelpModel; use App\Models\Help as HelpModel;
use App\Repos\Category as CategoryRepo;
use App\Repos\Help as HelpRepo; use App\Repos\Help as HelpRepo;
use App\Validators\Help as HelpValidator; use App\Validators\Help as HelpValidator;
use Phalcon\Mvc\Model\Resultset;
class Help extends Service class Help extends Service
{ {
public function getCategories()
{
$categoryRepo = new CategoryRepo();
return $categoryRepo->findTopCategories(CategoryModel::TYPE_HELP);
}
public function getHelps() public function getHelps()
{ {
$deleted = $this->request->getQuery('deleted', 'int', 0); $query = $this->request->getQuery();
$params = [];
$params['deleted'] = $query['deleted'] ?? 0;
if (isset($query['category_id'])) {
$params['category_id'] = $query['category_id'];
}
$helpRepo = new HelpRepo(); $helpRepo = new HelpRepo();
return $helpRepo->findAll([ $helps = $helpRepo->findAll($params);
'deleted' => $deleted,
]); $result = [];
if ($helps->count() > 0) {
$result = $this->handleHelps($helps);
}
return $result;
} }
public function getHelp($id) public function getHelp($id)
@ -34,16 +59,19 @@ class Help extends Service
$data = []; $data = [];
$category = $validator->checkCategory($post['category_id']);
$data['title'] = $validator->checkTitle($post['title']); $data['title'] = $validator->checkTitle($post['title']);
$data['content'] = $validator->checkContent($post['content']); $data['content'] = $validator->checkContent($post['content']);
$data['priority'] = $validator->checkPriority($post['priority']); $data['priority'] = $validator->checkPriority($post['priority']);
$data['published'] = $validator->checkPublishStatus($post['published']); $data['published'] = $validator->checkPublishStatus($post['published']);
$data['category_id'] = $category->id;
$help = new HelpModel(); $help = new HelpModel();
$help->create($data); $help->create($data);
$this->rebuildHelpCache($help); $this->rebuildHelpListCache();
return $help; return $help;
} }
@ -58,6 +86,11 @@ class Help extends Service
$data = []; $data = [];
if (isset($post['category_id'])) {
$category = $validator->checkCategory($post['category_id']);
$data['category_id'] = $category->id;
}
if (isset($post['title'])) { if (isset($post['title'])) {
$data['title'] = $validator->checkTitle($post['title']); $data['title'] = $validator->checkTitle($post['title']);
} }
@ -76,7 +109,7 @@ class Help extends Service
$help->update($data); $help->update($data);
$this->rebuildHelpCache($help); $this->rebuildHelpListCache();
return $help; return $help;
} }
@ -89,7 +122,7 @@ class Help extends Service
$help->update(); $help->update();
$this->rebuildHelpCache($help); $this->rebuildHelpListCache();
return $help; return $help;
} }
@ -102,16 +135,16 @@ class Help extends Service
$help->update(); $help->update();
$this->rebuildHelpCache($help); $this->rebuildHelpListCache();
return $help; return $help;
} }
protected function rebuildHelpCache(HelpModel $help) protected function rebuildHelpListCache()
{ {
$cache = new HelpCache(); $cache = new HelpListCache();
$cache->rebuild($help->id); $cache->rebuild();
} }
protected function findOrFail($id) protected function findOrFail($id)
@ -121,4 +154,23 @@ class Help extends Service
return $validator->checkHelp($id); return $validator->checkHelp($id);
} }
/**
* @param Resultset $helps
* @return array|object
*/
protected function handleHelps($helps)
{
if ($helps->count() == 0) {
return [];
}
$builder = new HelpListBuilder();
$items = $helps->toArray();
$items = $builder->handleCategories($items);
return $builder->objects($items);
}
} }

View File

@ -151,6 +151,19 @@ class Role extends Service
$list[] = 'admin.chapter.restore'; $list[] = 'admin.chapter.restore';
} }
if (in_array('admin.category.list', $routes)) {
$list[] = 'admin.course.category';
$list[] = 'admin.help.category';
}
if (in_array('admin.course.category', $routes)) {
$list[] = 'admin.category.list';
}
if (in_array('admin.help.category', $routes)) {
$list[] = 'admin.category.list';
}
$list = array_unique($list); $list = array_unique($list);
return array_values($list); return array_values($list);

View File

@ -38,6 +38,7 @@
</thead> </thead>
<tbody> <tbody>
{% for item in pager.items %} {% for item in pager.items %}
{% set show_url = url({'for':'admin.audit.show','id':item.id}) %}
<tr> <tr>
<td>{{ item.user_id }}</td> <td>{{ item.user_id }}</td>
<td>{{ item.user_name }}</td> <td>{{ item.user_name }}</td>
@ -46,7 +47,7 @@
<td>{{ item.req_path }}</td> <td>{{ item.req_path }}</td>
<td>{{ date('Y-m-d H:i:s',item.create_time) }}</td> <td>{{ date('Y-m-d H:i:s',item.create_time) }}</td>
<td align="center"> <td align="center">
<button class="kg-view layui-btn layui-btn-sm" data-url="{{ url({'for':'admin.audit.show','id':item.id}) }}">浏览</button> <button class="kg-view layui-btn layui-btn-sm" data-url="{{ show_url }}">浏览</button>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}

View File

@ -46,18 +46,21 @@
</thead> </thead>
<tbody> <tbody>
{% for item in pager.items %} {% for item in pager.items %}
{% set edit_url = url({'for':'admin.carousel.edit','id':item.id}) %}
{% set update_url = url({'for':'admin.carousel.update','id':item.id}) %}
{% set delete_url = url({'for':'admin.carousel.delete','id':item.id}) %}
<tr> <tr>
<td>{{ item.id }}</td> <td>{{ item.id }}</td>
<td>{{ item.title }}</td> <td>{{ item.title }}</td>
<td>{{ target_info(item.target) }}</td> <td>{{ target_info(item.target) }}</td>
<td><input class="layui-input kg-priority" type="text" name="priority" title="数值越小排序越靠前" value="{{ item.priority }}" data-url="{{ url({'for':'admin.carousel.update','id':item.id}) }}"></td> <td><input class="layui-input kg-priority" type="text" name="priority" title="数值越小排序越靠前" value="{{ item.priority }}" data-url="{{ update_url }}"></td>
<td><input type="checkbox" name="published" value="1" lay-filter="published" lay-skin="switch" lay-text="是|否" data-url="{{ url({'for':'admin.carousel.update','id':item.id}) }}" {% if item.published == 1 %}checked{% endif %}></td> <td><input type="checkbox" name="published" value="1" lay-filter="published" lay-skin="switch" lay-text="是|否" data-url="{{ update_url }}" {% if item.published == 1 %}checked{% endif %}></td>
<td align="center"> <td align="center">
<div class="layui-dropdown"> <div class="layui-dropdown">
<button class="layui-btn layui-btn-sm">操作 <span class="layui-icon layui-icon-triangle-d"></span></button> <button class="layui-btn layui-btn-sm">操作 <span class="layui-icon layui-icon-triangle-d"></span></button>
<ul> <ul>
<li><a href="{{ url({'for':'admin.carousel.edit','id':item.id}) }}">编辑</a></li> <li><a href="{{ edit_url }}">编辑</a></li>
<li><a href="javascript:" class="kg-delete" data-url="{{ url({'for':'admin.carousel.delete','id':item.id}) }}">删除</a></li> <li><a href="javascript:" class="kg-delete" data-url="{{ delete_url }}">删除</a></li>
</ul> </ul>
</div> </div>
</td> </td>

View File

@ -6,14 +6,14 @@
<fieldset class="layui-elem-field layui-field-title"> <fieldset class="layui-elem-field layui-field-title">
<legend>添加分类</legend> <legend>添加分类</legend>
</fieldset> </fieldset>
{% if parent_id > 0 %} {% if parent.id > 0 %}
<div class="layui-form-item"> <div class="layui-form-item">
<label class="layui-form-label">父级</label> <label class="layui-form-label">父级</label>
<div class="layui-input-block"> <div class="layui-input-block">
<select name="parent_id" lay-verify="required"> <select name="parent_id" lay-verify="required">
<option value="">选择父类</option> <option value="">选择父类</option>
{% for category in top_categories %} {% for category in top_categories %}
<option value="{{ category.id }}" {% if category.id == parent_id %}selected{% endif %}>{{ category.name }}</option> <option value="{{ category.id }}" {% if category.id == parent.id %}selected{% endif %}>{{ category.name }}</option>
{% endfor %} {% endfor %}
</select> </select>
</div> </div>
@ -43,7 +43,8 @@
<div class="layui-input-block"> <div class="layui-input-block">
<button class="layui-btn" lay-submit="true" lay-filter="go">提交</button> <button class="layui-btn" lay-submit="true" lay-filter="go">提交</button>
<button type="button" class="kg-back layui-btn layui-btn-primary">返回</button> <button type="button" class="kg-back layui-btn layui-btn-primary">返回</button>
<input type="hidden" name="parent_id" value="{{ parent_id }}"> <input type="hidden" name="parent_id" value="{{ parent.id }}">
<input type="hidden" name="type" value="{{ type }}">
</div> </div>
</div> </div>
</form> </form>

View File

@ -2,6 +2,9 @@
{% block content %} {% block content %}
{% set add_category_url = url({'for':'admin.category.add'},{'type':type,'parent_id':parent.id}) %}
{% set allow_add_category = (type == 'course' and parent.level < 2) or (type == 'help' and parent.level < 1) %}
<div class="kg-nav"> <div class="kg-nav">
<div class="kg-nav-left"> <div class="kg-nav-left">
<span class="layui-breadcrumb"> <span class="layui-breadcrumb">
@ -15,9 +18,11 @@
</span> </span>
</div> </div>
<div class="kg-nav-right"> <div class="kg-nav-right">
<a class="layui-btn layui-btn-sm" href="{{ url({'for':'admin.category.add'},{'parent_id':parent.id}) }}"> {% if allow_add_category %}
<a class="layui-btn layui-btn-sm" href="{{ add_category_url }}">
<i class="layui-icon layui-icon-add-1"></i>添加分类 <i class="layui-icon layui-icon-add-1"></i>添加分类
</a> </a>
{% endif %}
</div> </div>
</div> </div>
@ -44,26 +49,32 @@
</thead> </thead>
<tbody> <tbody>
{% for item in categories %} {% for item in categories %}
{% set show_child_url = item.type == 'course' and item.level < 2 %}
{% set child_url = url({'for':'admin.category.list'},{'type':item.type,'parent_id':item.id}) %}
{% set edit_url = url({'for':'admin.category.edit','id':item.id}) %}
{% set update_url = url({'for':'admin.category.update','id':item.id}) %}
{% set delete_url = url({'for':'admin.category.delete','id':item.id}) %}
{% set restore_url = url({'for':'admin.category.restore','id':item.id}) %}
<tr> <tr>
<td>{{ item.id }}</td> <td>{{ item.id }}</td>
{% if item.level < 2 %} {% if show_child_url %}
<td><a href="{{ url({'for':'admin.category.list'}) }}?parent_id={{ item.id }}">{{ item.name }}</a></td> <td><a href="{{ child_url }}">{{ item.name }}</a></td>
{% else %} {% else %}
<td>{{ item.name }}</td> <td>{{ item.name }}</td>
{% endif %} {% endif %}
<td><span class="layui-badge layui-bg-gray">{{ item.level }}</span></td> <td><span class="layui-badge layui-bg-gray">{{ item.level }}</span></td>
<td><span class="layui-badge layui-bg-gray">{{ item.child_count }}</span></td> <td><span class="layui-badge layui-bg-gray">{{ item.child_count }}</span></td>
<td><input class="layui-input kg-priority" type="text" name="priority" title="数值越小排序越靠前" value="{{ item.priority }}" data-url="{{ url({'for':'admin.category.update','id':item.id}) }}"></td> <td><input class="layui-input kg-priority" type="text" name="priority" title="数值越小排序越靠前" value="{{ item.priority }}" data-url="{{ update_url }}"></td>
<td><input type="checkbox" name="published" value="1" lay-skin="switch" lay-text="是|否" lay-filter="published" data-url="{{ url({'for':'admin.category.update','id':item.id}) }}" {% if item.published == 1 %}checked{% endif %}></td> <td><input type="checkbox" name="published" value="1" lay-skin="switch" lay-text="是|否" lay-filter="published" data-url="{{ update_url }}" {% if item.published == 1 %}checked{% endif %}></td>
<td align="center"> <td align="center">
<div class="layui-dropdown"> <div class="layui-dropdown">
<button class="layui-btn layui-btn-sm">操作 <span class="layui-icon layui-icon-triangle-d"></span></button> <button class="layui-btn layui-btn-sm">操作 <span class="layui-icon layui-icon-triangle-d"></span></button>
<ul> <ul>
<li><a href="{{ url({'for':'admin.category.edit','id':item.id}) }}">编辑</a></li> <li><a href="{{ edit_url }}">编辑</a></li>
{% if item.deleted == 0 %} {% if item.deleted == 0 %}
<li><a href="javascript:" class="kg-delete" data-url="{{ url({'for':'admin.category.delete','id':item.id}) }}">删除</a></li> <li><a href="javascript:" class="kg-delete" data-url="{{ delete_url }}">删除</a></li>
{% else %} {% else %}
<li><a href="javascript:" class="kg-restore" data-url="{{ url({'for':'admin.category.restore','id':item.id}) }}">还原</a></li> <li><a href="javascript:" class="kg-restore" data-url="{{ restore_url }}">还原</a></li>
{% endif %} {% endif %}
</ul> </ul>
</div> </div>

View File

@ -2,10 +2,14 @@
{% block content %} {% block content %}
{% set back_url = url({'for':'admin.course.chapters','id':course.id}) %}
{% set add_chapter_url = url({'for':'admin.chapter.add'},{'type':'chapter','course_id':course.id}) %}
{% set add_lesson_url = url({'for':'admin.chapter.add'},{'type':'lesson','course_id':course.id,'parent_id':chapter.id}) %}
<div class="kg-nav"> <div class="kg-nav">
<div class="kg-nav-left"> <div class="kg-nav-left">
<span class="layui-breadcrumb"> <span class="layui-breadcrumb">
<a class="kg-back" href="{{ url({'for':'admin.course.chapters','id':course.id}) }}"> <a class="kg-back" href="{{ back_url }}">
<i class="layui-icon layui-icon-return"></i> 返回 <i class="layui-icon layui-icon-return"></i> 返回
</a> </a>
<a><cite>{{ course.title }}</cite></a> <a><cite>{{ course.title }}</cite></a>
@ -14,10 +18,10 @@
</span> </span>
</div> </div>
<div class="kg-nav-right"> <div class="kg-nav-right">
<a class="layui-btn layui-btn-sm" href="{{ url({'for':'admin.chapter.add'},{'course_id':course.id,'type':'chapter'}) }}"> <a class="layui-btn layui-btn-sm" href="{{ add_chapter_url }}">
<i class="layui-icon layui-icon-add-1"></i>添加章 <i class="layui-icon layui-icon-add-1"></i>添加章
</a> </a>
<a class="layui-btn layui-btn-sm" href="{{ url({'for':'admin.chapter.add'},{'course_id':course.id,'parent_id':chapter.id,'type':'lesson'}) }}"> <a class="layui-btn layui-btn-sm" href="{{ add_lesson_url }}">
<i class="layui-icon layui-icon-add-1"></i>添加课 <i class="layui-icon layui-icon-add-1"></i>添加课
</a> </a>
</div> </div>

View File

@ -44,9 +44,14 @@
</thead> </thead>
<tbody> <tbody>
{% for item in pager.items %} {% for item in pager.items %}
{% set list_url = url({'for':'admin.consult.list'},{'course_id':item.course.id}) %}
{% set edit_url = url({'for':'admin.consult.edit','id':item.id}) %}
{% set update_url = url({'for':'admin.consult.update','id':item.id}) %}
{% set delete_url = url({'for':'admin.consult.delete','id':item.id}) %}
{% set restore_url = url({'for':'admin.consult.restore','id':item.id}) %}
<tr> <tr>
<td> <td>
<p>课程:<a href="{{ url({'for':'admin.consult.list'},{'course_id':item.course.id}) }}">{{ item.course.title }}</a>{{ private_info(item.private) }}</p> <p>课程:<a href="{{ list_url }}">{{ item.course.title }}</a>{{ private_info(item.private) }}</p>
<p>提问:<a href="javascript:" title="{{ item.question }}">{{ substr(item.question,0,30) }}</a></p> <p>提问:<a href="javascript:" title="{{ item.question }}">{{ substr(item.question,0,30) }}</a></p>
{% if item.answer %} {% if item.answer %}
<p>回复:<a href="javascript:" title="{{ item.answer }}">{{ substr(item.answer,0,30) }}</a></p> <p>回复:<a href="javascript:" title="{{ item.answer }}">{{ substr(item.answer,0,30) }}</a></p>
@ -57,17 +62,17 @@
<p>编号:{{ item.owner.id }}</p> <p>编号:{{ item.owner.id }}</p>
</td> </td>
<td>{{ date('Y-m-d H:i:s',item.create_time) }}</td> <td>{{ date('Y-m-d H:i:s',item.create_time) }}</td>
<td><input type="checkbox" name="published" value="1" lay-skin="switch" lay-text="是|否" lay-filter="published" data-url="{{ url({'for':'admin.consult.update','id':item.id}) }}" {% if item.published == 1 %}checked{% endif %}></td> <td><input type="checkbox" name="published" value="1" lay-skin="switch" lay-text="是|否" lay-filter="published" data-url="{{ update_url }}" {% if item.published == 1 %}checked{% endif %}></td>
<td align="center"> <td align="center">
<div class="layui-dropdown"> <div class="layui-dropdown">
<button class="layui-btn layui-btn-sm">操作 <span class="layui-icon layui-icon-triangle-d"></span> <button class="layui-btn layui-btn-sm">操作 <span class="layui-icon layui-icon-triangle-d"></span>
</button> </button>
<ul> <ul>
<li><a href="{{ url({'for':'admin.consult.edit','id':item.id}) }}">编辑</a></li> <li><a href="{{ edit_url }}">编辑</a></li>
{% if item.deleted == 0 %} {% if item.deleted == 0 %}
<li><a href="javascript:" class="kg-delete" data-url="{{ url({'for':'admin.consult.delete','id':item.id}) }}">删除</a></li> <li><a href="javascript:" class="kg-delete" data-url="{{ delete_url }}">删除</a></li>
{% else %} {% else %}
<li><a href="javascript:" class="kg-restore" data-url="{{ url({'for':'admin.consult.restore','id':item.id}) }}">还原</a></li> <li><a href="javascript:" class="kg-restore" data-url="{{ restore_url }}">还原</a></li>
{% endif %} {% endif %}
</ul> </ul>
</div> </div>

View File

@ -28,13 +28,15 @@
{%- macro category_info(category) %} {%- macro category_info(category) %}
{% if category %} {% if category %}
分类:<a class="layui-badge layui-bg-gray" href="{{ url({'for':'admin.course.list'},{'category_id':category.id}) }}">{{ category.name }}</a> {% set url = url({'for':'admin.course.list'},{'category_id':category.id}) %}
分类:<a class="layui-badge layui-bg-gray" href="{{ url }}">{{ category.name }}</a>
{% endif %} {% endif %}
{%- endmacro %} {%- endmacro %}
{%- macro teacher_info(teacher) %} {%- macro teacher_info(teacher) %}
{% if teacher %} {% if teacher %}
讲师:<a class="layui-badge layui-bg-gray" href="{{ url({'for':'admin.course.list'},{'teacher_id':teacher.id}) }}">{{ teacher.name }}</a> {% set url = url({'for':'admin.course.list'},{'teacher_id':teacher.id}) %}
讲师:<a class="layui-badge layui-bg-gray" href="{{ url }}">{{ teacher.name }}</a>
{% endif %} {% endif %}
{%- endmacro %} {%- endmacro %}
@ -75,18 +77,26 @@
</thead> </thead>
<tbody> <tbody>
{% for item in pager.items %} {% for item in pager.items %}
{% set edit_url = url({'for':'admin.course.edit','id':item.id}) %}
{% set update_url = url({'for':'admin.course.update','id':item.id}) %}
{% set delete_url = url({'for':'admin.course.delete','id':item.id}) %}
{% set restore_url = url({'for':'admin.course.restore','id':item.id}) %}
{% set catalog_url = url({'for':'admin.course.chapters','id':item.id}) %}
{% set student_url = url({'for':'admin.student.list'},{'course_id':item.id}) %}
{% set review_url = url({'for':'admin.review.list'},{'course_id':item.id}) %}
{% set consult_url = url({'for':'admin.consult.list'},{'course_id':item.id}) %}
<tr> <tr>
<td> <td>
<p>标题:<a href="{{ url({'for':'admin.course.chapters','id':item.id}) }}">{{ item.title }}</a> {{ model_info(item.model) }}</p> <p>标题:<a href="{{ catalog_url }}">{{ item.title }}</a> {{ model_info(item.model) }}</p>
<p>{{ category_info(item.category) }}&nbsp;&nbsp;{{ teacher_info(item.teacher) }}&nbsp;&nbsp;{{ level_info(item.level) }}</p> <p>{{ category_info(item.category) }}&nbsp;&nbsp;{{ teacher_info(item.teacher) }}&nbsp;&nbsp;{{ level_info(item.level) }}</p>
</td> </td>
<td> <td>
<a href="{{ url({'for':'admin.course.chapters','id':item.id}) }}"> <a href="{{ catalog_url }}">
<span class="layui-badge layui-bg-green">{{ item.lesson_count }}</span> <span class="layui-badge layui-bg-green">{{ item.lesson_count }}</span>
</a> </a>
</td> </td>
<td> <td>
<a href="{{ url({'for':'admin.student.list'},{'course_id':item.id}) }}"> <a href="{{ student_url }}">
<span class="layui-badge layui-bg-green">{{ item.user_count }}</span> <span class="layui-badge layui-bg-green">{{ item.user_count }}</span>
</a> </a>
</td> </td>
@ -94,23 +104,23 @@
<p>市场:{{ '¥%0.2f'|format(item.market_price) }}</p> <p>市场:{{ '¥%0.2f'|format(item.market_price) }}</p>
<p>会员:{{ '¥%0.2f'|format(item.vip_price) }}</p> <p>会员:{{ '¥%0.2f'|format(item.vip_price) }}</p>
</td> </td>
<td><input type="checkbox" name="published" value="1" lay-skin="switch" lay-text="是|否" lay-filter="published" data-url="{{ url({'for':'admin.course.update','id':item.id}) }}" {% if item.published == 1 %}checked{% endif %}></td> <td><input type="checkbox" name="published" value="1" lay-skin="switch" lay-text="是|否" lay-filter="published" data-url="{{ update_url }}" {% if item.published == 1 %}checked{% endif %}></td>
<td align="center"> <td align="center">
<div class="layui-dropdown"> <div class="layui-dropdown">
<button class="layui-btn layui-btn-sm">操作 <span class="layui-icon layui-icon-triangle-d"></span></button> <button class="layui-btn layui-btn-sm">操作 <span class="layui-icon layui-icon-triangle-d"></span></button>
<ul> <ul>
<li><a href="{{ url({'for':'admin.course.edit','id':item.id}) }}">编辑课程</a></li> <li><a href="{{ edit_url }}">编辑课程</a></li>
{% if item.deleted == 0 %} {% if item.deleted == 0 %}
<li><a href="javascript:" class="kg-delete" data-url="{{ url({'for':'admin.course.delete','id':item.id}) }}">删除课程</a></li> <li><a href="javascript:" class="kg-delete" data-url="{{ delete_url }}">删除课程</a></li>
{% else %} {% else %}
<li><a href="javascript:" class="kg-restore" data-url="{{ url({'for':'admin.course.restore','id':item.id}) }}">还原课程</a></li> <li><a href="javascript:" class="kg-restore" data-url="{{ restore_url }}">还原课程</a></li>
{% endif %} {% endif %}
<hr> <hr>
<li><a href="{{ url({'for':'admin.course.chapters','id':item.id}) }}">章节管理</a></li> <li><a href="{{ catalog_url }}">章节管理</a></li>
<li><a href="{{ url({'for':'admin.student.list'},{'course_id':item.id}) }}">学员管理</a></li> <li><a href="{{ student_url }}">学员管理</a></li>
<hr> <hr>
<li><a href="{{ url({'for':'admin.consult.list'}) }}?course_id={{ item.id }}">咨询管理</a></li> <li><a href="{{ consult_url }}">咨询管理</a></li>
<li><a href="{{ url({'for':'admin.review.list'}) }}?course_id={{ item.id }}">评价管理</a></li> <li><a href="{{ review_url }}">评价管理</a></li>
</ul> </ul>
</div> </div>
</td> </td>

View File

@ -52,18 +52,21 @@
</thead> </thead>
<tbody> <tbody>
{% for item in pager.items %} {% for item in pager.items %}
{% set edit_url = url({'for':'admin.group.edit','id':item.id}) %}
{% set update_url = url({'for':'admin.group.update','id':item.id}) %}
{% set delete_url = url({'for':'admin.group.delete','id':item.id}) %}
<tr> <tr>
<td>{{ item.id }}</td> <td>{{ item.id }}</td>
<td>{{ item.name }} {{ type_info(item.type) }}</td> <td>{{ item.name }} {{ type_info(item.type) }}</td>
<td>{{ owner_info(item.owner) }}</td> <td>{{ owner_info(item.owner) }}</td>
<td><span class="layui-badge layui-bg-gray">{{ item.user_count }}</span></td> <td><span class="layui-badge layui-bg-gray">{{ item.user_count }}</span></td>
<td><input type="checkbox" name="published" value="1" lay-filter="published" lay-skin="switch" lay-text="是|否" data-url="{{ url({'for':'admin.group.update','id':item.id}) }}" {% if item.published == 1 %}checked{% endif %}></td> <td><input type="checkbox" name="published" value="1" lay-filter="published" lay-skin="switch" lay-text="是|否" data-url="{{ update_url }}" {% if item.published == 1 %}checked{% endif %}></td>
<td align="center"> <td align="center">
<div class="layui-dropdown"> <div class="layui-dropdown">
<button class="layui-btn layui-btn-sm">操作 <span class="layui-icon layui-icon-triangle-d"></span></button> <button class="layui-btn layui-btn-sm">操作 <span class="layui-icon layui-icon-triangle-d"></span></button>
<ul> <ul>
<li><a href="{{ url({'for':'admin.group.edit','id':item.id}) }}">编辑</a></li> <li><a href="{{ edit_url }}">编辑</a></li>
<li><a href="javascript:" class="kg-delete" data-url="{{ url({'for':'admin.group.delete','id':item.id}) }}">删除</a></li> <li><a href="javascript:" class="kg-delete" data-url="{{ delete_url }}">删除</a></li>
</ul> </ul>
</div> </div>
</td> </td>

View File

@ -6,6 +6,17 @@
<fieldset class="layui-elem-field layui-field-title"> <fieldset class="layui-elem-field layui-field-title">
<legend>添加帮助</legend> <legend>添加帮助</legend>
</fieldset> </fieldset>
<div class="layui-form-item">
<label class="layui-form-label">分类</label>
<div class="layui-input-block">
<select name="category_id" lay-verify="required">
<option value="">选择分类</option>
{% for category in categories %}
<option value="{{ category.id }}">{{ category.name }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="layui-form-item"> <div class="layui-form-item">
<label class="layui-form-label">标题</label> <label class="layui-form-label">标题</label>
<div class="layui-input-block"> <div class="layui-input-block">

View File

@ -6,6 +6,17 @@
<fieldset class="layui-elem-field layui-field-title"> <fieldset class="layui-elem-field layui-field-title">
<legend>编辑帮助</legend> <legend>编辑帮助</legend>
</fieldset> </fieldset>
<div class="layui-form-item">
<label class="layui-form-label">分类</label>
<div class="layui-input-block">
<select name="category_id" lay-verify="required">
<option value="">选择分类</option>
{% for category in categories %}
<option value="{{ category.id }}" {% if category.id == help.category_id %}selected{% endif %}>{{ category.name }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="layui-form-item"> <div class="layui-form-item">
<label class="layui-form-label">标题</label> <label class="layui-form-label">标题</label>
<div class="layui-input-block"> <div class="layui-input-block">

View File

@ -20,17 +20,15 @@
<col> <col>
<col> <col>
<col> <col>
<col> <col width="10%">
<col> <col width="10%">
<col>
<col width="12%"> <col width="12%">
</colgroup> </colgroup>
<thead> <thead>
<tr> <tr>
<th>编号</th> <th>编号</th>
<th>标题</th> <th>标题</th>
<th>创建时间</th> <th>分类</th>
<th>更新时间</th>
<th>排序</th> <th>排序</th>
<th>发布</th> <th>发布</th>
<th>操作</th> <th>操作</th>
@ -38,20 +36,23 @@
</thead> </thead>
<tbody> <tbody>
{% for item in helps %} {% for item in helps %}
{% set list_url = url({'for':'admin.help.list'},{'category_id':item.category.id}) %}
{% set edit_url = url({'for':'admin.help.edit','id':item.id}) %}
{% set update_url = url({'for':'admin.help.update','id':item.id}) %}
{% set delete_url = url({'for':'admin.help.delete','id':item.id}) %}
{% set restore_url = url({'for':'admin.help.restore','id':item.id}) %}
<tr> <tr>
<td>{{ item.id }}</td> <td>{{ item.id }}</td>
<td>{{ item.title }}</td> <td>{{ item.title }}</td>
<td>{{ date('Y-m-d H:i',item.create_time) }}</td> <td><a href="{{ list_url }}">{{ item.category.name }}</a></td>
<td>{{ date('Y-m-d H:i',item.update_time) }}</td> <td align="center"><input class="layui-input kg-priority" type="text" name="priority" title="数值越小排序越靠前" value="{{ item.priority }}" data-url="{{ update_url }}"></td>
<td><input class="layui-input kg-priority" type="text" name="priority" title="数值越小排序越靠前" value="{{ item.priority }}" data-url="{{ url({'for':'admin.help.update','id':item.id}) }}"></td> <td align="center"><input type="checkbox" name="published" value="1" lay-skin="switch" lay-text="是|否" lay-filter="published" data-url="{{ update_url }}" {% if item.published == 1 %}checked{% endif %}></td>
<td><input type="checkbox" name="published" value="1" lay-skin="switch" lay-text="是|否" lay-filter="published" data-url="{{ url({'for':'admin.help.update','id':item.id}) }}" {% if item.published == 1 %}checked{% endif %}>
</td>
<td align="center"> <td align="center">
<div class="layui-dropdown"> <div class="layui-dropdown">
<button class="layui-btn layui-btn-sm">操作 <span class="layui-icon layui-icon-triangle-d"></span></button> <button class="layui-btn layui-btn-sm">操作 <span class="layui-icon layui-icon-triangle-d"></span></button>
<ul> <ul>
<li><a href="{{ url({'for':'admin.help.edit','id':item.id}) }}">编辑</a></li> <li><a href="{{ edit_url }}">编辑</a></li>
<li><a href="javascript:" class="kg-delete" data-url="{{ url({'for':'admin.help.delete','id':item.id}) }}">删除</a></li> <li><a href="javascript:" class="kg-delete" data-url="{{ delete_url }}">删除</a></li>
</ul> </ul>
</div> </div>
</td> </td>

View File

@ -18,11 +18,14 @@
{% endif %} {% endif %}
{%- endmacro %} {%- endmacro %}
{% set back_url = url({'for':'admin.nav.list'}) %}
{% set add_nav_url = url({'for':'admin.nav.add'},{'parent_id':parent.id}) %}
<div class="kg-nav"> <div class="kg-nav">
<div class="kg-nav-left"> <div class="kg-nav-left">
<span class="layui-breadcrumb"> <span class="layui-breadcrumb">
{% if parent.id > 0 %} {% if parent.id > 0 %}
<a class="kg-back" href="{{ url({'for':'admin.nav.list'}) }}"> <a class="kg-back" href="{{ back_url }}">
<i class="layui-icon layui-icon-return"></i> 返回 <i class="layui-icon layui-icon-return"></i> 返回
</a> </a>
<a><cite>{{ parent.name }}</cite></a> <a><cite>{{ parent.name }}</cite></a>
@ -31,7 +34,7 @@
</span> </span>
</div> </div>
<div class="kg-nav-right"> <div class="kg-nav-right">
<a class="layui-btn layui-btn-sm" href="{{ url({'for':'admin.nav.add'},{'parent_id':parent.id}) }}"> <a class="layui-btn layui-btn-sm" href="{{ add_nav_url }}">
<i class="layui-icon layui-icon-add-1"></i>添加导航 <i class="layui-icon layui-icon-add-1"></i>添加导航
</a> </a>
</div> </div>
@ -64,10 +67,15 @@
</thead> </thead>
<tbody> <tbody>
{% for item in navs %} {% for item in navs %}
{% set child_url = url({'for':'admin.nav.list'},{'parent_id':item.id}) %}
{% set edit_url = url({'for':'admin.nav.edit','id':item.id}) %}
{% set update_url = url({'for':'admin.nav.update','id':item.id}) %}
{% set delete_url = url({'for':'admin.nav.delete','id':item.id}) %}
{% set restore_url = url({'for':'admin.nav.restore','id':item.id}) %}
<tr> <tr>
<td>{{ item.id }}</td> <td>{{ item.id }}</td>
{% if item.position == 'top' and item.level < 2 %} {% if item.position == 'top' and item.level < 2 %}
<td><a href="{{ url({'for':'admin.nav.list'},{'parent_id':item.id}) }}">{{ item.name }}</a></td> <td><a href="{{ child_url }}">{{ item.name }}</a></td>
{% else %} {% else %}
<td>{{ item.name }}</td> <td>{{ item.name }}</td>
{% endif %} {% endif %}
@ -75,17 +83,17 @@
<td><span class="layui-badge layui-bg-gray">{{ item.child_count }}</span></td> <td><span class="layui-badge layui-bg-gray">{{ item.child_count }}</span></td>
<td>{{ position_info(item.position) }}</td> <td>{{ position_info(item.position) }}</td>
<td>{{ target_info(item.target) }}</td> <td>{{ target_info(item.target) }}</td>
<td><input class="layui-input kg-priority" type="text" name="priority" title="数值越小排序越靠前" value="{{ item.priority }}" data-url="{{ url({'for':'admin.nav.update','id':item.id}) }}"></td> <td><input class="layui-input kg-priority" type="text" name="priority" title="数值越小排序越靠前" value="{{ item.priority }}" data-url="{{ update_url }}"></td>
<td><input type="checkbox" name="published" value="1" lay-skin="switch" lay-text="是|否" lay-filter="published" data-url="{{ url({'for':'admin.nav.update','id':item.id}) }}" {% if item.published == 1 %}checked{% endif %}></td> <td><input type="checkbox" name="published" value="1" lay-skin="switch" lay-text="是|否" lay-filter="published" data-url="{{ update_url }}" {% if item.published == 1 %}checked{% endif %}></td>
<td align="center"> <td align="center">
<div class="layui-dropdown"> <div class="layui-dropdown">
<button class="layui-btn layui-btn-sm">操作 <span class="layui-icon layui-icon-triangle-d"></span></button> <button class="layui-btn layui-btn-sm">操作 <span class="layui-icon layui-icon-triangle-d"></span></button>
<ul> <ul>
<li><a href="{{ url({'for':'admin.nav.edit','id':item.id}) }}">编辑</a></li> <li><a href="{{ edit_url }}">编辑</a></li>
{% if item.deleted == 0 %} {% if item.deleted == 0 %}
<li><a href="javascript:" class="kg-delete" data-url="{{ url({'for':'admin.nav.delete','id':item.id}) }}">删除</a></li> <li><a href="javascript:" class="kg-delete" data-url="{{ delete_url }}">删除</a></li>
{% else %} {% else %}
<li><a href="javascript:" class="kg-restore" data-url="{{ url({'for':'admin.nav.restore','id':item.id}) }}">还原</a></li> <li><a href="javascript:" class="kg-restore" data-url="{{ restore_url }}">还原</a></li>
{% endif %} {% endif %}
</ul> </ul>
</div> </div>

View File

@ -4,6 +4,8 @@
{{ partial('order/macro') }} {{ partial('order/macro') }}
{% set search_url = url({'for':'admin.order.search'}) %}
<div class="kg-nav"> <div class="kg-nav">
<div class="kg-nav-left"> <div class="kg-nav-left">
<span class="layui-breadcrumb"> <span class="layui-breadcrumb">
@ -11,7 +13,7 @@
</span> </span>
</div> </div>
<div class="kg-nav-right"> <div class="kg-nav-right">
<a class="layui-btn layui-btn-sm" href="{{ url({'for':'admin.order.search'}) }}"> <a class="layui-btn layui-btn-sm" href="{{ search_url }}">
<i class="layui-icon layui-icon-search"></i>搜索订单 <i class="layui-icon layui-icon-search"></i>搜索订单
</a> </a>
</div> </div>
@ -38,6 +40,7 @@
</thead> </thead>
<tbody> <tbody>
{% for item in pager.items %} {% for item in pager.items %}
{% set show_url = url({'for':'admin.order.show','id':item.id}) %}
<tr> <tr>
<td> <td>
<p>商品:{{ item.subject }} {{ item_type(item.item_type) }}</p> <p>商品:{{ item.subject }} {{ item_type(item.item_type) }}</p>
@ -51,7 +54,7 @@
<td>{{ order_status(item.status) }}</td> <td>{{ order_status(item.status) }}</td>
<td>{{ date('Y-m-d H:i:s',item.create_time) }}</td> <td>{{ date('Y-m-d H:i:s',item.create_time) }}</td>
<td align="center"> <td align="center">
<a class="layui-btn layui-btn-sm layui-bg-green" href="{{ url({'for':'admin.order.show','id':item.id}) }}">详情</a> <a class="layui-btn layui-btn-sm layui-bg-green" href="{{ show_url }}">详情</a>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}

View File

@ -2,6 +2,8 @@
{% block content %} {% block content %}
{% set add_pkg_url = url({'for':'admin.package.add'}) %}
<div class="kg-nav"> <div class="kg-nav">
<div class="kg-nav-left"> <div class="kg-nav-left">
<span class="layui-breadcrumb"> <span class="layui-breadcrumb">
@ -9,7 +11,7 @@
</span> </span>
</div> </div>
<div class="kg-nav-right"> <div class="kg-nav-right">
<a class="layui-btn layui-btn-sm" href="{{ url({'for':'admin.package.add'}) }}"> <a class="layui-btn layui-btn-sm" href="{{ add_pkg_url }}">
<i class="layui-icon layui-icon-add-1"></i>添加套餐 <i class="layui-icon layui-icon-add-1"></i>添加套餐
</a> </a>
</div> </div>
@ -38,19 +40,22 @@
</thead> </thead>
<tbody> <tbody>
{% for item in pager.items %} {% for item in pager.items %}
{% set edit_url = url({'for':'admin.package.edit','id':item.id}) %}
{% set update_url = url({'for':'admin.package.update','id':item.id}) %}
{% set delete_url = url({'for':'admin.package.delete','id':item.id}) %}
<tr> <tr>
<td>{{ item.id }}</td> <td>{{ item.id }}</td>
<td><a href="{{ url({'for':'admin.package.edit','id':item.id}) }}">{{ item.title }}</a></td> <td><a href="{{ edit_url }}">{{ item.title }}</a></td>
<td><span class="layui-badge layui-bg-gray">{{ item.course_count }}</span></td> <td><span class="layui-badge layui-bg-gray">{{ item.course_count }}</span></td>
<td>{{ '¥%0.2f'|format(item.market_price) }}</td> <td>{{ '¥%0.2f'|format(item.market_price) }}</td>
<td>{{ '¥%0.2f'|format(item.vip_price) }}</td> <td>{{ '¥%0.2f'|format(item.vip_price) }}</td>
<td><input type="checkbox" name="published" value="1" lay-skin="switch" lay-text="是|否" lay-filter="published" data-url="{{ url({'for':'admin.package.update','id':item.id}) }}" {% if item.published == 1 %}checked{% endif %}></td> <td><input type="checkbox" name="published" value="1" lay-skin="switch" lay-text="是|否" lay-filter="published" data-url="{{ update_url }}" {% if item.published == 1 %}checked{% endif %}></td>
<td align="center"> <td align="center">
<div class="layui-dropdown"> <div class="layui-dropdown">
<button class="layui-btn layui-btn-sm">操作 <span class="layui-icon layui-icon-triangle-d"></span></button> <button class="layui-btn layui-btn-sm">操作 <span class="layui-icon layui-icon-triangle-d"></span></button>
<ul> <ul>
<li><a href="{{ url({'for':'admin.package.edit','id':item.id}) }}">编辑</a></li> <li><a href="{{ edit_url }}">编辑</a></li>
<li><a href="javascript:" class="kg-delete" data-url="{{ url({'for':'admin.package.delete','id':item.id}) }}">删除</a></li> <li><a href="javascript:" class="kg-delete" data-url="{{ delete_url }}">删除</a></li>
</ul> </ul>
</div> </div>
</td> </td>

View File

@ -2,6 +2,8 @@
{% block content %} {% block content %}
{% set add_page_url = url({'for':'admin.page.add'}) %}
<div class="kg-nav"> <div class="kg-nav">
<div class="kg-nav-left"> <div class="kg-nav-left">
<span class="layui-breadcrumb"> <span class="layui-breadcrumb">
@ -9,7 +11,7 @@
</span> </span>
</div> </div>
<div class="kg-nav-right"> <div class="kg-nav-right">
<a class="layui-btn layui-btn-sm" href="{{ url({'for':'admin.page.add'}) }}"> <a class="layui-btn layui-btn-sm" href="{{ add_page_url }}">
<i class="layui-icon layui-icon-add-1"></i>添加单页 <i class="layui-icon layui-icon-add-1"></i>添加单页
</a> </a>
</div> </div>
@ -36,19 +38,23 @@
</thead> </thead>
<tbody> <tbody>
{% for item in pager.items %} {% for item in pager.items %}
{% set show_url = url({'for':'web.page.show','id':item.id}) %}
{% set edit_url = url({'for':'admin.page.edit','id':item.id}) %}
{% set update_url = url({'for':'admin.page.update','id':item.id}) %}
{% set delete_url = url({'for':'admin.page.delete','id':item.id}) %}
<tr> <tr>
<td>{{ item.id }}</td> <td>{{ item.id }}</td>
<td>{{ item.title }}</td> <td><a href="{{ show_url }}" target="_blank">{{ item.title }}</a></td>
<td>{{ date('Y-m-d H:i',item.create_time) }}</td> <td>{{ date('Y-m-d H:i',item.create_time) }}</td>
<td>{{ date('Y-m-d H:i',item.update_time) }}</td> <td>{{ date('Y-m-d H:i',item.update_time) }}</td>
<td><input type="checkbox" name="published" value="1" lay-skin="switch" lay-text="是|否" lay-filter="published" data-url="{{ url({'for':'admin.page.update','id':item.id}) }}" {% if item.published == 1 %}checked{% endif %}> <td><input type="checkbox" name="published" value="1" lay-skin="switch" lay-text="是|否" lay-filter="published" data-url="{{ update_url }}" {% if item.published == 1 %}checked{% endif %}>
</td> </td>
<td align="center"> <td align="center">
<div class="layui-dropdown"> <div class="layui-dropdown">
<button class="layui-btn layui-btn-sm">操作 <span class="layui-icon layui-icon-triangle-d"></span></button> <button class="layui-btn layui-btn-sm">操作 <span class="layui-icon layui-icon-triangle-d"></span></button>
<ul> <ul>
<li><a href="{{ url({'for':'admin.page.edit','id':item.id}) }}">编辑</a></li> <li><a href="{{ edit_url }}">编辑</a></li>
<li><a href="javascript:" class="kg-delete" data-url="{{ url({'for':'admin.page.delete','id':item.id}) }}">删除</a></li> <li><a href="javascript:" class="kg-delete" data-url="{{ delete_url }}">删除</a></li>
</ul> </ul>
</div> </div>
</td> </td>

View File

@ -4,6 +4,8 @@
{{ partial('refund/macro') }} {{ partial('refund/macro') }}
{% set search_refund_url = url({'for':'admin.refund.search'}) %}
<div class="kg-nav"> <div class="kg-nav">
<div class="kg-nav-left"> <div class="kg-nav-left">
<span class="layui-breadcrumb"> <span class="layui-breadcrumb">
@ -11,7 +13,7 @@
</span> </span>
</div> </div>
<div class="kg-nav-right"> <div class="kg-nav-right">
<a class="layui-btn layui-btn-sm" href="{{ url({'for':'admin.refund.search'}) }}"> <a class="layui-btn layui-btn-sm" href="{{ search_refund_url }}">
<i class="layui-icon layui-icon-search"></i>搜索退款 <i class="layui-icon layui-icon-search"></i>搜索退款
</a> </a>
</div> </div>
@ -38,6 +40,7 @@
</thead> </thead>
<tbody> <tbody>
{% for item in pager.items %} {% for item in pager.items %}
{% set show_url = url({'for':'admin.refund.show','id':item.id}) %}
<tr> <tr>
<td> <td>
<p>商品:{{ item.order.subject }}</p> <p>商品:{{ item.order.subject }}</p>
@ -51,7 +54,7 @@
<td>{{ refund_status(item.status) }}</td> <td>{{ refund_status(item.status) }}</td>
<td>{{ date('Y-m-d H:i:s',item.create_time) }}</td> <td>{{ date('Y-m-d H:i:s',item.create_time) }}</td>
<td align="center"> <td align="center">
<a class="layui-btn layui-btn-sm layui-bg-green" href="{{ url({'for':'admin.refund.show','id':item.id}) }}">详情</a> <a class="layui-btn layui-btn-sm layui-bg-green" href="{{ show_url }}">详情</a>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}

View File

@ -2,6 +2,8 @@
{% block content %} {% block content %}
{% set search_review_url = url({'for':'admin.review.search'}) %}
<div class="kg-nav"> <div class="kg-nav">
<div class="kg-nav-left"> <div class="kg-nav-left">
<span class="layui-breadcrumb"> <span class="layui-breadcrumb">
@ -13,7 +15,7 @@
</span> </span>
</div> </div>
<div class="kg-nav-right"> <div class="kg-nav-right">
<a class="layui-btn layui-btn-sm" href="{{ url({'for':'admin.review.search'}) }}"> <a class="layui-btn layui-btn-sm" href="{{ search_review_url }}">
<i class="layui-icon layui-icon-search"></i>搜索评价 <i class="layui-icon layui-icon-search"></i>搜索评价
</a> </a>
</div> </div>
@ -38,9 +40,15 @@
</thead> </thead>
<tbody> <tbody>
{% for item in pager.items %} {% for item in pager.items %}
{% set list_by_course_url = url({'for':'admin.review.list'},{'course_id':item.course.id}) %}
{% set list_by_owner_url = url({'for':'admin.review.list'},{'owner_id':item.owner.id}) %}
{% set edit_url = url({'for':'admin.review.edit','id':item.id}) %}
{% set update_url = url({'for':'admin.review.update','id':item.id}) %}
{% set delete_url = url({'for':'admin.review.delete','id':item.id}) %}
{% set restore_url = url({'for':'admin.review.restore','id':item.id}) %}
<tr> <tr>
<td> <td>
<p>课程:<a href="{{ url({'for':'admin.review.list'},{'course_id':item.course.id}) }}">{{ item.course.title }}</a></p> <p>课程:<a href="{{ list_by_course_url }}">{{ item.course.title }}</a></p>
<p>评价:<a href="javascript:" title="{{ item.content }}">{{ substr(item.content,0,30) }}</a></p> <p>评价:<a href="javascript:" title="{{ item.content }}">{{ substr(item.content,0,30) }}</a></p>
<p>时间:{{ date('Y-m-d H:i:s',item.create_time) }}</p> <p>时间:{{ date('Y-m-d H:i:s',item.create_time) }}</p>
</td> </td>
@ -50,19 +58,19 @@
<p>逻辑清晰:{{ item.rating3 }}</p> <p>逻辑清晰:{{ item.rating3 }}</p>
</td> </td>
<td> <td>
<p>昵称:<a href="{{ url({'for':'admin.review.list'},{'owner_id':item.owner.id}) }}">{{ item.owner.name }}</a></p> <p>昵称:<a href="{{ list_by_owner_url }}">{{ item.owner.name }}</a></p>
<p>编号:{{ item.owner.id }}</p> <p>编号:{{ item.owner.id }}</p>
</td> </td>
<td><input type="checkbox" name="published" value="1" lay-skin="switch" lay-text="是|否" lay-filter="published" data-url="{{ url({'for':'admin.review.update','id':item.id}) }}" {% if item.published == 1 %}checked{% endif %}></td> <td><input type="checkbox" name="published" value="1" lay-skin="switch" lay-text="是|否" lay-filter="published" data-url="{{ update_url }}" {% if item.published == 1 %}checked{% endif %}></td>
<td align="center"> <td align="center">
<div class="layui-dropdown"> <div class="layui-dropdown">
<button class="layui-btn layui-btn-sm">操作 <span class="layui-icon layui-icon-triangle-d"></span></button> <button class="layui-btn layui-btn-sm">操作 <span class="layui-icon layui-icon-triangle-d"></span></button>
<ul> <ul>
<li><a href="{{ url({'for':'admin.review.edit','id':item.id}) }}">编辑</a></li> <li><a href="{{ edit_url }}">编辑</a></li>
{% if item.deleted == 0 %} {% if item.deleted == 0 %}
<li><a href="javascript:" class="kg-delete" data-url="{{ url({'for':'admin.review.delete','id':item.id}) }}">删除</a></li> <li><a href="javascript:" class="kg-delete" data-url="{{ delete_url }}">删除</a></li>
{% else %} {% else %}
<li><a href="javascript:" class="kg-restore" data-url="{{ url({'for':'admin.review.restore','id':item.id}) }}">还原</a></li> <li><a href="javascript:" class="kg-restore" data-url="{{ restore_url }}">还原</a></li>
{% endif %} {% endif %}
</ul> </ul>
</div> </div>

View File

@ -10,6 +10,8 @@
{% endif %} {% endif %}
{%- endmacro %} {%- endmacro %}
{% set add_role_url = url({'for':'admin.role.add'}) %}
<div class="kg-nav"> <div class="kg-nav">
<div class="kg-nav-left"> <div class="kg-nav-left">
<span class="layui-breadcrumb"> <span class="layui-breadcrumb">
@ -17,7 +19,7 @@
</span> </span>
</div> </div>
<div class="kg-nav-right"> <div class="kg-nav-right">
<a class="layui-btn layui-btn-sm" href="{{ url({'for':'admin.role.add'}) }}"> <a class="layui-btn layui-btn-sm" href="{{ add_role_url }}">
<i class="layui-icon layui-icon-add-1"></i>添加角色 <i class="layui-icon layui-icon-add-1"></i>添加角色
</a> </a>
</div> </div>
@ -42,12 +44,15 @@
</thead> </thead>
<tbody> <tbody>
{% for item in roles %} {% for item in roles %}
{% set user_list_url = url({'for':'admin.user.list'},{'admin_role':item.id}) %}
{% set edit_url = url({'for':'admin.role.edit','id':item.id}) %}
{% set delete_url = url({'for':'admin.role.delete','id':item.id}) %}
<tr> <tr>
<td>{{ item.id }}</td> <td>{{ item.id }}</td>
<td><a href="javascript:" title="{{ item.summary }}">{{ item.name }}</a></td> <td><a href="javascript:" title="{{ item.summary }}">{{ item.name }}</a></td>
<td>{{ type_info(item.type) }}</td> <td>{{ type_info(item.type) }}</td>
<td> <td>
<a href="{{ url({'for':'admin.user.list'},{'admin_role':item.id}) }}"> <a href="{{ user_list_url }}">
<span class="layui-badge layui-bg-green">{{ item.user_count }}</span> <span class="layui-badge layui-bg-green">{{ item.user_count }}</span>
</a> </a>
</td> </td>
@ -55,8 +60,8 @@
<div class="layui-dropdown"> <div class="layui-dropdown">
<button class="layui-btn layui-btn-sm">操作 <span class="layui-icon layui-icon-triangle-d"></span></button> <button class="layui-btn layui-btn-sm">操作 <span class="layui-icon layui-icon-triangle-d"></span></button>
<ul> <ul>
<li><a href="{{ url({'for':'admin.role.edit','id':item.id}) }}">编辑</a></li> <li><a href="{{ edit_url }}">编辑</a></li>
<li><a href="javascript:" class="kg-delete" data-url="{{ url({'for':'admin.role.delete','id':item.id}) }}">删除</a></li> <li><a href="javascript:" class="kg-delete" data-url="{{ delete_url }}">删除</a></li>
</ul> </ul>
</div> </div>
</td> </td>

View File

@ -4,9 +4,9 @@
<div class="kg-qrcode-block"> <div class="kg-qrcode-block">
{% if qrcode_url %} {% if qrcode %}
<div id="qrcode"> <div id="qrcode">
<img class="kg-qrcode" src="{{ qrcode_url }}" alt="二维码图片"> <img class="kg-qrcode" src="{{ qrcode }}" alt="二维码图片">
</div> </div>
<input type="hidden" name="sn" value="{{ sn }}"> <input type="hidden" name="sn" value="{{ sn }}">
<div id="success-tips" class="kg-success-tips layui-hide"> <div id="success-tips" class="kg-success-tips layui-hide">
@ -27,7 +27,7 @@
{% block inline_js %} {% block inline_js %}
{% if qrcode_url %} {% if Code %}
<script> <script>
layui.use(['jquery'], function () { layui.use(['jquery'], function () {

View File

@ -3,9 +3,9 @@
{% block contnet %} {% block contnet %}
<div class="kg-qrcode-block"> <div class="kg-qrcode-block">
{% if qrcode_url %} {% if qrcode %}
<div id="qrcode"> <div id="qrcode">
<img class="kg-qrcode" src="{{ qrcode_url }}" alt="二维码图片"> <img class="kg-qrcode" src="{{ qrcode }}" alt="二维码图片">
</div> </div>
<input type="hidden" name="sn" value="{{ sn }}"> <input type="hidden" name="sn" value="{{ sn }}">
<div id="success-tips" class="kg-success-tips layui-hide"> <div id="success-tips" class="kg-success-tips layui-hide">
@ -25,7 +25,7 @@
{% block inline_js %} {% block inline_js %}
{% if qrcode_url %} {% if Code %}
<script> <script>
layui.use(['jquery'], function () { layui.use(['jquery'], function () {

View File

@ -2,9 +2,9 @@
namespace App\Http\Web\Controllers; namespace App\Http\Web\Controllers;
use App\Caches\NavTreeList as NavTreeListCache; use App\Caches\NavTreeList as NavCache;
use App\Caches\Setting as SettingCache; use App\Caches\Setting as SettingCache;
use App\Library\Seo as Seo; use App\Library\Seo as SiteSeo;
use App\Models\User as UserModel; use App\Models\User as UserModel;
use App\Services\Auth\Web as WebAuth; use App\Services\Auth\Web as WebAuth;
use App\Traits\Response as ResponseTrait; use App\Traits\Response as ResponseTrait;
@ -15,19 +15,19 @@ class Controller extends \Phalcon\Mvc\Controller
{ {
/** /**
* @var Seo * @var SiteSeo
*/ */
protected $seo; protected $seo;
/** /**
* @var array * @var array
*/ */
protected $settings; protected $navs;
/** /**
* @var array * @var array
*/ */
protected $navs; protected $settings;
/** /**
* @var UserModel * @var UserModel
@ -75,16 +75,16 @@ class Controller extends \Phalcon\Mvc\Controller
return $auth->getCurrentUser(); return $auth->getCurrentUser();
} }
protected function getNavs()
{
$cache = new NavTreeListCache();
return $cache->get() ?: [];
}
protected function getSeo() protected function getSeo()
{ {
return new Seo(); return new SiteSeo();
}
protected function getNavs()
{
$cache = new NavCache();
return $cache->get() ?: [];
} }
protected function getSettings() protected function getSettings()

View File

@ -14,6 +14,14 @@ class ImController extends LayerController
use ResponseTrait; use ResponseTrait;
/**
* @Get("/", name="web.im.index")
*/
public function indexAction()
{
}
/** /**
* @Get("/init", name="web.im.init") * @Get("/init", name="web.im.init")
*/ */
@ -66,9 +74,9 @@ class ImController extends LayerController
} }
/** /**
* @Get("/msg/friend/unread", name="web.im.unread_friend_msg") * @Get("/friend/msg/unread", name="web.im.unread_friend_msg")
*/ */
public function unreadFriendMessagesAction() public function unreadFriendMsgAction()
{ {
$service = new ImService(); $service = new ImService();
@ -78,40 +86,40 @@ class ImController extends LayerController
} }
/** /**
* @Get("/msg/sys/unread", name="web.im.unread_sys_msg") * @Get("/sys/msg/unread", name="web.im.unread_sys_msg")
*/ */
public function unreadSystemMessagesAction() public function unreadSysMsgAction()
{ {
$service = new ImService(); $service = new ImService();
$count = $service->countUnreadSystemMessages(); $count = $service->countUnreadNotices();
return $this->jsonSuccess(['count' => $count]); return $this->jsonSuccess(['count' => $count]);
} }
/** /**
* @Get("/msg/sys", name="web.im.sys_msg") * @Get("/sys/msg", name="web.im.sys_msg")
*/ */
public function systemMessagesAction() public function sysMsgAction()
{ {
$service = new ImService(); $service = new ImService();
$pager = $service->getSystemMessages(); $pager = $service->getNotices();
$pager->items = kg_array_object($pager->items); $pager->items = kg_array_object($pager->items);
$this->view->pick('im/sys_messages'); $this->view->pick('im/sys_msg');
$this->view->setVar('pager', $pager); $this->view->setVar('pager', $pager);
} }
/** /**
* @Post("/msg/sys/read", name="web.im.read_sys_msg") * @Post("/sys/msg/read", name="web.im.read_sys_msg")
*/ */
public function readSystemMessagesAction() public function readSysMsgAction()
{ {
$service = new ImService(); $service = new ImService();
$service->readSystemMessages(); $service->readNotices();
return $this->jsonSuccess(); return $this->jsonSuccess();
} }
@ -210,21 +218,6 @@ class ImController extends LayerController
return $this->jsonSuccess(); return $this->jsonSuccess();
} }
/**
* @Post("/img/upload", name="web.im.upload_img")
*/
public function uploadImageAction()
{
}
/**
* @Post("/file/upload", name="web.im.upload_file")
*/
public function uploadFileAction()
{
}
/** /**
* @Post("/status/update", name="web.im.update_status") * @Post("/status/update", name="web.im.update_status")
*/ */

View File

@ -0,0 +1,54 @@
<?php
namespace App\Http\Web\Controllers;
use App\Http\Web\Services\ImGroup as ImGroupService;
use Phalcon\Mvc\View;
/**
* @RoutePrefix("/im")
*/
class ImSummaryController extends Controller
{
/**
* @Get("/active/groups", name="web.im.active_groups")
*/
public function activeGroupsAction()
{
$this->seo->prependTitle('群组');
}
/**
* @Get("/active/users", name="web.im.active_users")
*/
public function activeUsersAction()
{
$this->seo->prependTitle('群组');
}
/**
* @Get("/online/users", name="web.im.online_users")
*/
public function onlineUsersAction()
{
$this->seo->prependTitle('群组');
}
/**
* @Get("/pager", name="web.im_group.pager")
*/
public function pagerAction()
{
$service = new ImGroupService();
$pager = $service->getGroups();
$pager->items = kg_array_object($pager->items);
$pager->target = 'group-list';
$this->view->setRenderLevel(View::LEVEL_ACTION_VIEW);
$this->view->pick('im_group/pager');
$this->view->setVar('pager', $pager);
}
}

View File

@ -17,8 +17,8 @@ class IndexController extends Controller
$indexService = new IndexService(); $indexService = new IndexService();
$this->view->setVar('carousels', $indexService->getCarousels());
$this->view->setVar('lives', $indexService->getLives()); $this->view->setVar('lives', $indexService->getLives());
$this->view->setVar('carousels', $indexService->getCarousels());
$this->view->setVar('new_courses', $indexService->getNewCourses()); $this->view->setVar('new_courses', $indexService->getNewCourses());
$this->view->setVar('free_courses', $indexService->getFreeCourses()); $this->view->setVar('free_courses', $indexService->getFreeCourses());
$this->view->setVar('vip_courses', $indexService->getVipCourses()); $this->view->setVar('vip_courses', $indexService->getVipCourses());

View File

@ -3,7 +3,7 @@
namespace App\Http\Web\Controllers; namespace App\Http\Web\Controllers;
use App\Services\Storage as StorageService; use App\Services\MyStorage as StorageService;
/** /**
* @RoutePrefix("/upload") * @RoutePrefix("/upload")
@ -12,7 +12,7 @@ class UploadController extends Controller
{ {
/** /**
* @Post("/img/avatar", name="web.upload.avatar_img") * @Post("/avatar/img", name="web.upload.avatar_img")
*/ */
public function uploadAvatarImageAction() public function uploadAvatarImageAction()
{ {
@ -29,4 +29,19 @@ class UploadController extends Controller
} }
} }
/**
* @Post("/im/img", name="web.upload.im_img")
*/
public function uploadImImageAction()
{
}
/**
* @Post("/im/file", name="web.upload.im_file")
*/
public function uploadImFileAction()
{
}
} }

View File

@ -3,8 +3,10 @@
namespace App\Http\Web\Services; namespace App\Http\Web\Services;
use App\Caches\Category as CategoryCache; use App\Caches\Category as CategoryCache;
use App\Models\Category as CategoryModel;
use App\Models\Course as CourseModel; use App\Models\Course as CourseModel;
use App\Services\Category as CategoryService; use App\Services\Category as CategoryService;
use App\Validators\CourseQuery as CourseQueryValidator;
class CourseQuery extends Service class CourseQuery extends Service
{ {
@ -42,7 +44,7 @@ class CourseQuery extends Service
$categoryService = new CategoryService(); $categoryService = new CategoryService();
$topCategories = $categoryService->getChildCategories(0); $topCategories = $categoryService->getChildCategories(CategoryModel::TYPE_COURSE, 0);
foreach ($topCategories as $key => $category) { foreach ($topCategories as $key => $category) {
$params['tc'] = $category['id']; $params['tc'] = $category['id'];
@ -66,7 +68,7 @@ class CourseQuery extends Service
$categoryService = new CategoryService(); $categoryService = new CategoryService();
$subCategories = $categoryService->getChildCategories($params['tc']); $subCategories = $categoryService->getChildCategories(CategoryModel::TYPE_COURSE, $params['tc']);
if (empty($subCategories)) { if (empty($subCategories)) {
return []; return [];
@ -216,7 +218,7 @@ class CourseQuery extends Service
$params = []; $params = [];
$validator = new \App\Validators\CourseQuery(); $validator = new CourseQueryValidator();
if (isset($query['tc']) && $query['tc'] != 'all') { if (isset($query['tc']) && $query['tc'] != 'all') {
$validator->checkTopCategory($query['tc']); $validator->checkTopCategory($query['tc']);

View File

@ -6,14 +6,12 @@ use App\Builders\ImMessageList as ImMessageListBuilder;
use App\Caches\ImNewGroupList as ImNewGroupListCache; use App\Caches\ImNewGroupList as ImNewGroupListCache;
use App\Caches\ImNewUserList as ImNewUserListCache; use App\Caches\ImNewUserList as ImNewUserListCache;
use App\Library\Paginator\Query as PagerQuery; use App\Library\Paginator\Query as PagerQuery;
use App\Models\ImFriendMessage as ImFriendMessageModel; use App\Models\ImMessage as ImMessageModel;
use App\Models\ImGroupMessage as ImGroupMessageModel;
use App\Models\ImUser as ImUserModel; use App\Models\ImUser as ImUserModel;
use App\Repos\ImFriendMessage as ImFriendMessageRepo;
use App\Repos\ImFriendUser as ImFriendUserRepo; use App\Repos\ImFriendUser as ImFriendUserRepo;
use App\Repos\ImGroup as ImGroupRepo; use App\Repos\ImGroup as ImGroupRepo;
use App\Repos\ImGroupMessage as ImGroupMessageRepo; use App\Repos\ImMessage as ImMessageRepo;
use App\Repos\ImSystemMessage as ImSystemMessageRepo; use App\Repos\ImNotice as ImNoticeRepo;
use App\Repos\ImUser as ImUserRepo; use App\Repos\ImUser as ImUserRepo;
use App\Repos\User as UserRepo; use App\Repos\User as UserRepo;
use App\Validators\ImFriendUser as ImFriendUserValidator; use App\Validators\ImFriendUser as ImFriendUserValidator;
@ -207,16 +205,16 @@ class Im extends Service
$friendUser->update(['msg_count' => 0]); $friendUser->update(['msg_count' => 0]);
} }
public function countUnreadSystemMessages() public function countUnreadNotices()
{ {
$user = $this->getLoginUser(); $user = $this->getLoginUser();
$userRepo = new ImUserRepo(); $userRepo = new ImUserRepo();
return $userRepo->countUnreadSystemMessages($user->id); return $userRepo->countUnreadNotices($user->id);
} }
public function getSystemMessages() public function getNotices()
{ {
$user = $this->getLoginUser(); $user = $this->getLoginUser();
@ -230,9 +228,9 @@ class Im extends Service
$page = $pagerQuery->getPage(); $page = $pagerQuery->getPage();
$limit = $pagerQuery->getLimit(); $limit = $pagerQuery->getLimit();
$messageRepo = new ImSystemMessageRepo(); $noticeRepo = new ImNoticeRepo();
return $messageRepo->paginate($params, $sort, $page, $limit); return $noticeRepo->paginate($params, $sort, $page, $limit);
} }
public function getChatMessages() public function getChatMessages()
@ -251,23 +249,28 @@ class Im extends Service
$page = $pagerQuery->getPage(); $page = $pagerQuery->getPage();
$limit = $pagerQuery->getLimit(); $limit = $pagerQuery->getLimit();
if ($params['type'] == 'friend') { if ($params['type'] == ImMessageModel::TYPE_FRIEND) {
$params['chat_id'] = ImFriendMessageModel::getChatId($user->id, $params['id']); $chatId = ImMessageModel::getChatId($user->id, $params['id']);
$messageRepo = new ImFriendMessageRepo(); $where = ['chat_id' => $chatId];
$pager = $messageRepo->paginate($params, $sort, $page, $limit); $messageRepo = new ImMessageRepo();
$pager = $messageRepo->paginate($where, $sort, $page, $limit);
return $this->handleChatMessagePager($pager); return $this->handleChatMessagePager($pager);
} elseif ($params['type'] == 'group') { } elseif ($params['type'] == ImMessageModel::TYPE_GROUP) {
$params['group_id'] = $params['id']; $where = [
'receiver_type' => $params['type'],
'receiver_id' => $params['id'],
];
$messageRepo = new ImGroupMessageRepo(); $messageRepo = new ImMessageRepo();
$pager = $messageRepo->paginate($params, $sort, $page, $limit); $pager = $messageRepo->paginate($where, $sort, $page, $limit);
return $this->handleChatMessagePager($pager); return $this->handleChatMessagePager($pager);
} }
@ -351,7 +354,7 @@ class Im extends Service
Gateway::$registerAddress = $this->getRegisterAddress(); Gateway::$registerAddress = $this->getRegisterAddress();
if ($to['type'] == 'friend') { if ($to['type'] == ImMessageModel::TYPE_FRIEND) {
$validator = new ImFriendUserValidator(); $validator = new ImFriendUserValidator();
@ -359,11 +362,12 @@ class Im extends Service
$online = Gateway::isUidOnline($to['id']); $online = Gateway::isUidOnline($to['id']);
$messageModel = new ImFriendMessageModel(); $messageModel = new ImMessageModel();
$messageModel->create([ $messageModel->create([
'sender_id' => $from['id'], 'sender_id' => $from['id'],
'receiver_id' => $to['id'], 'receiver_id' => $to['id'],
'chat_type' => $to['type'],
'content' => $from['content'], 'content' => $from['content'],
'viewed' => $online ? 1 : 0, 'viewed' => $online ? 1 : 0,
]); ]);
@ -374,7 +378,7 @@ class Im extends Service
$this->incrFriendUserMsgCount($relation); $this->incrFriendUserMsgCount($relation);
} }
} elseif ($to['type'] == 'group') { } elseif ($to['type'] == ImMessageModel::TYPE_GROUP) {
$validator = new ImGroupValidator(); $validator = new ImGroupValidator();
@ -384,11 +388,12 @@ class Im extends Service
$validator->checkGroupUser($group->id, $user->id); $validator->checkGroupUser($group->id, $user->id);
$messageModel = new ImGroupMessageModel(); $messageModel = new ImMessageModel();
$messageModel->create([ $messageModel->create([
'group_id' => $to['id'],
'sender_id' => $from['id'], 'sender_id' => $from['id'],
'receiver_id' => $to['id'],
'chat_type' => $to['type'],
'content' => $from['content'], 'content' => $from['content'],
]); ]);
@ -409,13 +414,13 @@ class Im extends Service
} }
} }
public function readSystemMessages() public function readNotices()
{ {
$user = $this->getLoginUser(); $user = $this->getLoginUser();
$userRepo = new ImUserRepo(); $userRepo = new ImUserRepo();
$messages = $userRepo->findUnreadSystemMessages($user->id); $messages = $userRepo->findUnreadNotices($user->id);
if ($messages->count() > 0) { if ($messages->count() > 0) {
foreach ($messages as $message) { foreach ($messages as $message) {

View File

@ -0,0 +1,77 @@
<?php
namespace App\Http\Web\Services;
use App\Builders\ImGroupList as ImGroupListBuilder;
use App\Library\Paginator\Query as PagerQuery;
use App\Repos\ImGroup as ImGroupRepo;
class ImSummary extends Service
{
public function getActiveGroups()
{
$pagerQuery = new PagerQuery();
$params = $pagerQuery->getParams();
$params['published'] = 1;
$sort = $pagerQuery->getSort();
$page = $pagerQuery->getPage();
$limit = $pagerQuery->getLimit();
$groupRepo = new ImGroupRepo();
$pager = $groupRepo->paginate($params, $sort, $page, $limit);
return $this->handleGroups($pager);
}
public function getActiveUsers()
{
}
public function getOnlineUsers()
{
}
protected function handleGroups($pager)
{
if ($pager->total_items == 0) {
return $pager;
}
$builder = new ImGroupListBuilder();
$groups = $pager->items->toArray();
$users = $builder->getUsers($groups);
$baseUrl = kg_ci_base_url();
$items = [];
foreach ($groups as $group) {
$group['avatar'] = $baseUrl . $group['avatar'];
$group['owner'] = $users[$group['owner_id']] ?? new \stdClass();
$items[] = [
'id' => $group['id'],
'type' => $group['type'],
'name' => $group['name'],
'avatar' => $group['avatar'],
'about' => $group['about'],
'user_count' => $group['user_count'],
'msg_count' => $group['msg_count'],
'owner' => $group['owner'],
];
}
$pager->items = $items;
return $pager;
}
}

View File

@ -19,16 +19,16 @@ class Trade extends Service
$trade = $service->handle(); $trade = $service->handle();
$qrCodeUrl = $this->getQrCodeUrl($trade); $qrCode = $this->getQrCode($trade);
if ($trade && $qrCodeUrl) { if ($trade && $qrCode) {
$this->db->commit(); $this->db->commit();
return [ return [
'sn' => $trade->sn, 'sn' => $trade->sn,
'channel' => $trade->channel, 'channel' => $trade->channel,
'qrcode_url' => $qrCodeUrl, 'qrcode' => $qrCode,
]; ];
} else { } else {
@ -39,38 +39,38 @@ class Trade extends Service
} }
} }
protected function getQrCodeUrl(TradeModel $trade) protected function getQrCode(TradeModel $trade)
{ {
$qrcodeUrl = null; $qrCode = null;
if ($trade->channel == TradeModel::CHANNEL_ALIPAY) { if ($trade->channel == TradeModel::CHANNEL_ALIPAY) {
$qrcodeUrl = $this->getAlipayQrCodeUrl($trade); $qrCode = $this->getAlipayQrCode($trade);
} elseif ($trade->channel == TradeModel::CHANNEL_WXPAY) { } elseif ($trade->channel == TradeModel::CHANNEL_WXPAY) {
$qrcodeUrl = $this->getWxpayQrCodeUrl($trade); $qrCode = $this->getWxpayQrCode($trade);
} }
return $qrcodeUrl; return $qrCode;
} }
protected function getAlipayQrCodeUrl(TradeModel $trade) protected function getAlipayQrCode(TradeModel $trade)
{ {
$qrCodeUrl = null; $qrCode = null;
$service = new AlipayService(); $service = new AlipayService();
$text = $service->scan($trade); $text = $service->scan($trade);
if ($text) { if ($text) {
$qrCodeUrl = $this->url->get( $qrCode = $this->url->get(
['for' => 'web.qrcode'], ['for' => 'web.qrcode'],
['text' => urlencode($text)] ['text' => urlencode($text)]
); );
} }
return $qrCodeUrl; return $qrCode;
} }
protected function getWxpayQrCodeUrl(TradeModel $trade) protected function getWxpayQrCode(TradeModel $trade)
{ {
$service = new WxpayService(); $service = new WxpayService();

View File

@ -9,15 +9,35 @@
</span> </span>
</div> </div>
<div class="page-info wrap"> <div class="layout-main">
<div class="layout-content">
<div class="wrap">
<div class="layui-collapse"> <div class="layui-collapse">
{% for help in helps %} {% for item in helps %}
<div class="layui-colla-item"> <div class="layui-colla-item">
<h2 class="layui-colla-title">{{ help.title }}</h2> <h2 class="layui-colla-title">{{ item.category.name }}</h2>
<div class="layui-colla-content layui-show">{{ help.content }}</div> <div class="layui-colla-content layui-show">
<ul class="help-list">
{% for help in item.list %}
<li><a href="{{ url({'for':'web.help.show','id':help.id}) }}"><i class="layui-icon layui-icon-right"></i>{{ help.title }}</a></li>
{% endfor %}
</ul>
</div>
</div> </div>
{% endfor %} {% endfor %}
</div> </div>
</div> </div>
</div>
<div class="layout-sidebar">
<div class="layui-card">
<div class="layui-card-header">意见反馈</div>
<div class="layui-card-body">
<form class="layui-form">
<textarea name="content" class="layui-textarea" lay-verify="required"></textarea>
</form>
</div>
</div>
</div>
</div>
{% endblock %} {% endblock %}

View File

@ -1,4 +1,4 @@
{%- macro message_info(item) %} {%- macro notice_info(item) %}
{% set item_type = item.item_type %} {% set item_type = item.item_type %}
{% set item_info = item.item_info %} {% set item_info = item.item_info %}
@ -84,7 +84,7 @@
{% if pager.items %} {% if pager.items %}
<ul class="layim-msgbox"> <ul class="layim-msgbox">
{% for item in pager.items %} {% for item in pager.items %}
{{ message_info(item) }} {{ notice_info(item) }}
{% endfor %} {% endfor %}
</ul> </ul>
{% endif %} {% endif %}

View File

@ -1,5 +1,6 @@
<?php <?php
use App\Caches\Setting as SettingCache;
use App\Library\Validators\Common as CommonValidator; use App\Library\Validators\Common as CommonValidator;
use App\Services\Storage as StorageService; use App\Services\Storage as StorageService;
use Koogua\Ip2Region\Searcher as Ip2RegionSearcher; use Koogua\Ip2Region\Searcher as Ip2RegionSearcher;
@ -129,6 +130,24 @@ function kg_site_base_url()
return "{$scheme}://{$host}" . rtrim(dirname($path), '/'); return "{$scheme}://{$host}" . rtrim(dirname($path), '/');
} }
/**
* 获取站点设置
*
* @param string $section
* @param string $key
* @return mixed
*/
function kg_site_setting($section, $key = null)
{
$cache = new SettingCache();
$settings = $cache->get($section);
if (!$key) return $settings;
return $settings[$key] ?? null;
}
/** /**
* 获取默认头像路径 * 获取默认头像路径
* *

View File

@ -28,13 +28,6 @@ class Category extends Model
*/ */
public $parent_id; public $parent_id;
/**
* 别名
*
* @var string
*/
public $alias;
/** /**
* 类型 * 类型
* *
@ -143,4 +136,12 @@ class Category extends Model
$cache->rebuild(); $cache->rebuild();
} }
public static function types()
{
return [
self::TYPE_COURSE => '课程',
self::TYPE_HELP => '帮助',
];
}
} }

View File

@ -16,11 +16,11 @@ class Help extends Model
public $id; public $id;
/** /**
* 别名 * 分类编号
* *
* @var string * @var int
*/ */
public $alias; public $category_id;
/** /**
* 标题 * 标题
@ -29,13 +29,6 @@ class Help extends Model
*/ */
public $title; public $title;
/**
* 关键字
*
* @var string
*/
public $keywords;
/** /**
* 内容 * 内容
* *

View File

@ -1,46 +0,0 @@
<?php
namespace App\Models;
class HelpCategory extends Model
{
/**
* 主键编号
*
* @var int
*/
public $id;
/**
* 帮助编号
*
* @var int
*/
public $help_id;
/**
* 分类编号
*
* @var int
*/
public $category_id;
/**
* 创建时间
*
* @var int
*/
public $create_time;
public function getSource(): string
{
return 'kg_help_category';
}
public function beforeCreate()
{
$this->create_time = time();
}
}

View File

@ -1,86 +0,0 @@
<?php
namespace App\Models;
use Phalcon\Mvc\Model\Behavior\SoftDelete;
class ImGroupMessage extends Model
{
/**
* 主键编号
*
* @var int
*/
public $id;
/**
* 群组编号
*
* @var int
*/
public $group_id;
/**
* 发送方编号
*
* @var int
*/
public $sender_id;
/**
* 内容
*
* @var string
*/
public $content;
/**
* 删除标识
*
* @var int
*/
public $deleted;
/**
* 创建时间
*
* @var int
*/
public $create_time;
/**
* 更新时间
*
* @var int
*/
public $update_time;
public function getSource(): string
{
return 'kg_im_group_message';
}
public function initialize()
{
parent::initialize();
$this->addBehavior(
new SoftDelete([
'field' => 'deleted',
'value' => 1,
])
);
}
public function beforeCreate()
{
$this->create_time = time();
}
public function beforeUpdate()
{
$this->update_time = time();
}
}

View File

@ -4,9 +4,12 @@ namespace App\Models;
use Phalcon\Mvc\Model\Behavior\SoftDelete; use Phalcon\Mvc\Model\Behavior\SoftDelete;
class ImFriendMessage extends Model class ImMessage extends Model
{ {
const TYPE_FRIEND = 'friend';
const TYPE_GROUP = 'group';
/** /**
* 主键编号 * 主键编号
* *
@ -35,6 +38,13 @@ class ImFriendMessage extends Model
*/ */
public $receiver_id; public $receiver_id;
/**
* 接收方类型
*
* @var string
*/
public $receiver_type;
/** /**
* 内容 * 内容
* *
@ -72,7 +82,7 @@ class ImFriendMessage extends Model
public function getSource(): string public function getSource(): string
{ {
return 'kg_im_friend_message'; return 'kg_im_message';
} }
public function initialize() public function initialize()
@ -91,8 +101,10 @@ class ImFriendMessage extends Model
{ {
$this->create_time = time(); $this->create_time = time();
if ($this->chat_type == self::TYPE_FRIEND) {
$this->chat_id = self::getChatId($this->sender_id, $this->receiver_id); $this->chat_id = self::getChatId($this->sender_id, $this->receiver_id);
} }
}
public function beforeUpdate() public function beforeUpdate()
{ {

View File

@ -4,7 +4,7 @@ namespace App\Models;
use Phalcon\Mvc\Model\Behavior\SoftDelete; use Phalcon\Mvc\Model\Behavior\SoftDelete;
class ImSystemMessage extends Model class ImNotice extends Model
{ {
/** /**
@ -15,7 +15,7 @@ class ImSystemMessage extends Model
const REQUEST_REFUSED = 'refused'; // 已拒绝 const REQUEST_REFUSED = 'refused'; // 已拒绝
/** /**
* 消息类型 * 通知类型
*/ */
const TYPE_FRIEND_REQUEST = 1; // 好友请求 const TYPE_FRIEND_REQUEST = 1; // 好友请求
const TYPE_FRIEND_ACCEPTED = 2; // 好友被接受 const TYPE_FRIEND_ACCEPTED = 2; // 好友被接受
@ -96,7 +96,7 @@ class ImSystemMessage extends Model
public function getSource(): string public function getSource(): string
{ {
return 'kg_im_system_message'; return 'kg_im_notice';
} }
public function initialize() public function initialize()

View File

@ -15,13 +15,6 @@ class Page extends Model
*/ */
public $id; public $id;
/**
* 别名
*
* @var string
*/
public $alias;
/** /**
* 标题 * 标题
* *
@ -29,13 +22,6 @@ class Page extends Model
*/ */
public $title; public $title;
/**
* 关键字
*
* @var string
*/
public $keywords;
/** /**
* 内容 * 内容
* *

View File

@ -22,6 +22,10 @@ class Volt extends Provider
$compiler = $volt->getCompiler(); $compiler = $volt->getCompiler();
$compiler->addFunction('site_setting', function ($resolvedArgs) {
return 'kg_site_setting(' . $resolvedArgs . ')';
});
$compiler->addFunction('full_url', function ($resolvedArgs) { $compiler->addFunction('full_url', function ($resolvedArgs) {
return 'kg_full_url(' . $resolvedArgs . ')'; return 'kg_full_url(' . $resolvedArgs . ')';
}); });

View File

@ -3,8 +3,6 @@
namespace App\Repos; namespace App\Repos;
use App\Models\Category as CategoryModel; use App\Models\Category as CategoryModel;
use App\Models\Course as CourseModel;
use App\Models\CourseCategory as CourseCategoryModel;
use Phalcon\Mvc\Model; use Phalcon\Mvc\Model;
use Phalcon\Mvc\Model\Resultset; use Phalcon\Mvc\Model\Resultset;
use Phalcon\Mvc\Model\ResultsetInterface; use Phalcon\Mvc\Model\ResultsetInterface;
@ -26,6 +24,10 @@ class Category extends Repository
$query->andWhere('parent_id = :parent_id:', ['parent_id' => $where['parent_id']]); $query->andWhere('parent_id = :parent_id:', ['parent_id' => $where['parent_id']]);
} }
if (isset($where['type'])) {
$query->andWhere('type = :type:', ['type' => $where['type']]);
}
if (isset($where['level'])) { if (isset($where['level'])) {
$query->andWhere('level = :level:', ['level' => $where['level']]); $query->andWhere('level = :level:', ['level' => $where['level']]);
} }
@ -66,13 +68,16 @@ class Category extends Repository
} }
/** /**
* @param string $type
* @return ResultsetInterface|Resultset|CategoryModel[] * @return ResultsetInterface|Resultset|CategoryModel[]
*/ */
public function findTopCategories() public function findTopCategories($type)
{ {
return CategoryModel::query() return CategoryModel::query()
->where('parent_id = 0') ->where('type = :type:', ['type' => $type])
->andWhere('parent_id = 0')
->andWhere('published = 1') ->andWhere('published = 1')
->orderBy('priority ASC')
->execute(); ->execute();
} }
@ -85,6 +90,7 @@ class Category extends Repository
return CategoryModel::query() return CategoryModel::query()
->where('parent_id = :parent_id:', ['parent_id' => $categoryId]) ->where('parent_id = :parent_id:', ['parent_id' => $categoryId])
->andWhere('published = 1') ->andWhere('published = 1')
->orderBy('priority ASC')
->execute(); ->execute();
} }
@ -96,17 +102,4 @@ class Category extends Repository
]); ]);
} }
public function countCourses($categoryId)
{
$phql = 'SELECT COUNT(*) AS total FROM %s cc JOIN %s c ON cc.course_id = c.id WHERE cc.category_id = :category_id: AND c.published = 1';
$phql = sprintf($phql, CourseCategoryModel::class, CourseModel::class);
$bind = ['category_id' => $categoryId];
$record = $this->modelsManager->executeQuery($phql, $bind)->getFirst();
return (int)$record['total'];
}
} }

View File

@ -42,6 +42,10 @@ class Help extends Repository
$query->where('1 = 1'); $query->where('1 = 1');
if (!empty($where['category_id'])) {
$query->andWhere('category_id = :category_id:', ['category_id' => $where['category_id']]);
}
if (!empty($where['title'])) { if (!empty($where['title'])) {
$query->andWhere('title LIKE :title:', ['title' => "%{$where['title']}%"]); $query->andWhere('title LIKE :title:', ['title' => "%{$where['title']}%"]);
} }
@ -54,7 +58,7 @@ class Help extends Repository
$query->andWhere('deleted = :deleted:', ['deleted' => $where['deleted']]); $query->andWhere('deleted = :deleted:', ['deleted' => $where['deleted']]);
} }
$query->orderBy('priority ASC'); $query->orderBy('category_id ASC,priority ASC');
return $query->execute(); return $query->execute();
} }

View File

@ -4,8 +4,8 @@ namespace App\Repos;
use App\Library\Paginator\Adapter\QueryBuilder as PagerQueryBuilder; use App\Library\Paginator\Adapter\QueryBuilder as PagerQueryBuilder;
use App\Models\ImGroup as ImGroupModel; use App\Models\ImGroup as ImGroupModel;
use App\Models\ImGroupMessage as ImGroupMessageModel;
use App\Models\ImGroupUser as ImGroupUserModel; use App\Models\ImGroupUser as ImGroupUserModel;
use App\Models\ImMessage as ImMessageModel;
use App\Models\ImUser as ImUserModel; use App\Models\ImUser as ImUserModel;
use Phalcon\Mvc\Model; use Phalcon\Mvc\Model;
use Phalcon\Mvc\Model\Resultset; use Phalcon\Mvc\Model\Resultset;
@ -117,9 +117,9 @@ class ImGroup extends Repository
public function countMessages($groupId) public function countMessages($groupId)
{ {
return (int)ImGroupMessageModel::count([ return (int)ImMessageModel::count([
'conditions' => 'group_id = :group_id: AND published = 1', 'conditions' => 'receiver_id = ?1 AND receiver_type = ?2 AND deleted = 0',
'bind' => ['group_id' => $groupId], 'bind' => [1 => $groupId, 2 => ImMessageModel::TYPE_GROUP],
]); ]);
} }

View File

@ -1,76 +0,0 @@
<?php
namespace App\Repos;
use App\Library\Paginator\Adapter\QueryBuilder as PagerQueryBuilder;
use App\Models\ImGroupMessage as ImGroupMessageModel;
use Phalcon\Mvc\Model;
use Phalcon\Mvc\Model\Resultset;
use Phalcon\Mvc\Model\ResultsetInterface;
class ImGroupMessage extends Repository
{
public function paginate($where = [], $sort = 'latest', $page = 1, $limit = 15)
{
$builder = $this->modelsManager->createBuilder();
$builder->from(ImGroupMessageModel::class);
$builder->where('1 = 1');
if (!empty($where['group_id'])) {
$builder->andWhere('group_id = :group_id:', ['group_id' => $where['group_id']]);
}
if (!empty($where['sender_id'])) {
$builder->andWhere('sender_id = :sender_id:', ['sender_id' => $where['sender_id']]);
}
if (isset($where['deleted'])) {
$builder->andWhere('deleted = :deleted:', ['deleted' => $where['deleted']]);
}
switch ($sort) {
case 'oldest':
$orderBy = 'id ASC';
break;
default:
$orderBy = 'id DESC';
break;
}
$builder->orderBy($orderBy);
$pager = new PagerQueryBuilder([
'builder' => $builder,
'page' => $page,
'limit' => $limit,
]);
return $pager->paginate();
}
/**
* @param int $id
* @return ImGroupMessageModel|Model|bool
*/
public function findById($id)
{
return ImGroupMessageModel::findFirst($id);
}
/**
* @param array $ids
* @param string|array $columns
* @return ResultsetInterface|Resultset|ImGroupMessageModel[]
*/
public function findByIds($ids, $columns = '*')
{
return ImGroupMessageModel::query()
->columns($columns)
->inWhere('id', $ids)
->execute();
}
}

View File

@ -3,19 +3,19 @@
namespace App\Repos; namespace App\Repos;
use App\Library\Paginator\Adapter\QueryBuilder as PagerQueryBuilder; use App\Library\Paginator\Adapter\QueryBuilder as PagerQueryBuilder;
use App\Models\ImFriendMessage as ImFriendMessageModel; use App\Models\ImMessage as ImMessageModel;
use Phalcon\Mvc\Model; use Phalcon\Mvc\Model;
use Phalcon\Mvc\Model\Resultset; use Phalcon\Mvc\Model\Resultset;
use Phalcon\Mvc\Model\ResultsetInterface; use Phalcon\Mvc\Model\ResultsetInterface;
class ImFriendMessage extends Repository class ImMessage extends Repository
{ {
public function paginate($where = [], $sort = 'latest', $page = 1, $limit = 15) public function paginate($where = [], $sort = 'latest', $page = 1, $limit = 15)
{ {
$builder = $this->modelsManager->createBuilder(); $builder = $this->modelsManager->createBuilder();
$builder->from(ImFriendMessageModel::class); $builder->from(ImMessageModel::class);
$builder->where('1 = 1'); $builder->where('1 = 1');
@ -31,6 +31,10 @@ class ImFriendMessage extends Repository
$builder->andWhere('receiver_id = :receiver_id:', ['receiver_id' => $where['receiver_id']]); $builder->andWhere('receiver_id = :receiver_id:', ['receiver_id' => $where['receiver_id']]);
} }
if (!empty($where['receiver_type'])) {
$builder->andWhere('receiver_type = :receiver_type:', ['receiver_type' => $where['receiver_type']]);
}
if (isset($where['deleted'])) { if (isset($where['deleted'])) {
$builder->andWhere('deleted = :deleted:', ['deleted' => $where['deleted']]); $builder->andWhere('deleted = :deleted:', ['deleted' => $where['deleted']]);
} }
@ -57,21 +61,21 @@ class ImFriendMessage extends Repository
/** /**
* @param int $id * @param int $id
* @return ImFriendMessageModel|Model|bool * @return ImMessageModel|Model|bool
*/ */
public function findById($id) public function findById($id)
{ {
return ImFriendMessageModel::findFirst($id); return ImMessageModel::findFirst($id);
} }
/** /**
* @param array $ids * @param array $ids
* @param string|array $columns * @param string|array $columns
* @return ResultsetInterface|Resultset|ImFriendMessageModel[] * @return ResultsetInterface|Resultset|ImMessageModel[]
*/ */
public function findByIds($ids, $columns = '*') public function findByIds($ids, $columns = '*')
{ {
return ImFriendMessageModel::query() return ImMessageModel::query()
->columns($columns) ->columns($columns)
->inWhere('id', $ids) ->inWhere('id', $ids)
->execute(); ->execute();

View File

@ -3,19 +3,19 @@
namespace App\Repos; namespace App\Repos;
use App\Library\Paginator\Adapter\QueryBuilder as PagerQueryBuilder; use App\Library\Paginator\Adapter\QueryBuilder as PagerQueryBuilder;
use App\Models\ImSystemMessage as ImSystemMessageModel; use App\Models\ImNotice as ImNoticeModel;
use Phalcon\Mvc\Model; use Phalcon\Mvc\Model;
use Phalcon\Mvc\Model\Resultset; use Phalcon\Mvc\Model\Resultset;
use Phalcon\Mvc\Model\ResultsetInterface; use Phalcon\Mvc\Model\ResultsetInterface;
class ImSystemMessage extends Repository class ImNotice extends Repository
{ {
public function paginate($where = [], $sort = 'latest', $page = 1, $limit = 15) public function paginate($where = [], $sort = 'latest', $page = 1, $limit = 15)
{ {
$builder = $this->modelsManager->createBuilder(); $builder = $this->modelsManager->createBuilder();
$builder->from(ImSystemMessageModel::class); $builder->from(ImNoticeModel::class);
$builder->where('1 = 1'); $builder->where('1 = 1');
@ -53,21 +53,21 @@ class ImSystemMessage extends Repository
/** /**
* @param int $id * @param int $id
* @return ImSystemMessageModel|Model|bool * @return ImNoticeModel|Model|bool
*/ */
public function findById($id) public function findById($id)
{ {
return ImSystemMessageModel::findFirst($id); return ImNoticeModel::findFirst($id);
} }
/** /**
* @param array $ids * @param array $ids
* @param string|array $columns * @param string|array $columns
* @return ResultsetInterface|Resultset|ImSystemMessageModel[] * @return ResultsetInterface|Resultset|ImNoticeModel[]
*/ */
public function findByIds($ids, $columns = '*') public function findByIds($ids, $columns = '*')
{ {
return ImSystemMessageModel::query() return ImNoticeModel::query()
->columns($columns) ->columns($columns)
->inWhere('id', $ids) ->inWhere('id', $ids)
->execute(); ->execute();

View File

@ -4,11 +4,11 @@ namespace App\Repos;
use App\Library\Paginator\Adapter\QueryBuilder as PagerQueryBuilder; use App\Library\Paginator\Adapter\QueryBuilder as PagerQueryBuilder;
use App\Models\ImFriendGroup as ImFriendGroupModel; use App\Models\ImFriendGroup as ImFriendGroupModel;
use App\Models\ImFriendMessage as ImFriendMessageModel;
use App\Models\ImFriendUser as ImFriendUserModel; use App\Models\ImFriendUser as ImFriendUserModel;
use App\Models\ImGroup as ImGroupModel; use App\Models\ImGroup as ImGroupModel;
use App\Models\ImGroupUser as ImGroupUserModel; use App\Models\ImGroupUser as ImGroupUserModel;
use App\Models\ImSystemMessage as ImSystemMessageModel; use App\Models\ImMessage as ImMessageModel;
use App\Models\ImNotice as ImNoticeModel;
use App\Models\ImUser as ImUserModel; use App\Models\ImUser as ImUserModel;
use Phalcon\Mvc\Model; use Phalcon\Mvc\Model;
use Phalcon\Mvc\Model\Resultset; use Phalcon\Mvc\Model\Resultset;
@ -111,31 +111,30 @@ class ImUser extends Repository
->addFrom(ImGroupModel::class, 'g') ->addFrom(ImGroupModel::class, 'g')
->join(ImGroupUserModel::class, 'g.id = gu.group_id', 'gu') ->join(ImGroupUserModel::class, 'g.id = gu.group_id', 'gu')
->where('gu.user_id = :user_id:', ['user_id' => $userId]) ->where('gu.user_id = :user_id:', ['user_id' => $userId])
->andWhere('g.published = 1')
->getQuery()->execute(); ->getQuery()->execute();
} }
/** /**
* @param int $friendId * @param int $friendId
* @param int $userId * @param int $userId
* @return ResultsetInterface|Resultset|ImFriendMessageModel[] * @return ResultsetInterface|Resultset|ImMessageModel[]
*/ */
public function findUnreadFriendMessages($friendId, $userId) public function findUnreadFriendMessages($friendId, $userId)
{ {
return ImFriendMessageModel::find([ return ImMessageModel::find([
'conditions' => 'sender_id = ?1 AND receiver_id = ?2 AND viewed = ?3', 'conditions' => 'sender_id = ?1 AND receiver_id = ?2 AND viewed = 0',
'bind' => [1 => $friendId, 2 => $userId, 3 => 0], 'bind' => [1 => $friendId, 2 => $userId],
]); ]);
} }
/** /**
* @param int $userId * @param int $userId
* @param int $itemType * @param int $itemType
* @return ImSystemMessageModel|Model|bool * @return ImNoticeModel|Model|bool
*/ */
public function findSystemMessage($userId, $itemType) public function findNotice($userId, $itemType)
{ {
return ImSystemMessageModel::findFirst([ return ImNoticeModel::findFirst([
'conditions' => 'receiver_id = ?1 AND item_type = ?2', 'conditions' => 'receiver_id = ?1 AND item_type = ?2',
'bind' => [1 => $userId, 2 => $itemType], 'bind' => [1 => $userId, 2 => $itemType],
'order' => 'id DESC', 'order' => 'id DESC',
@ -144,21 +143,21 @@ class ImUser extends Repository
/** /**
* @param int $userId * @param int $userId
* @return ResultsetInterface|Resultset|ImFriendMessageModel[] * @return ResultsetInterface|Resultset|ImNoticeModel[]
*/ */
public function findUnreadSystemMessages($userId) public function findUnreadNotices($userId)
{ {
return ImSystemMessageModel::find([ return ImNoticeModel::find([
'conditions' => 'receiver_id = ?1 AND viewed = ?2', 'conditions' => 'receiver_id = :receiver_id: AND viewed = 0',
'bind' => [1 => $userId, 2 => 0], 'bind' => ['receiver_id' => $userId],
]); ]);
} }
public function countUnreadSystemMessages($userId) public function countUnreadNotices($userId)
{ {
return (int)ImSystemMessageModel::count([ return (int)ImNoticeModel::count([
'conditions' => 'receiver_id = ?1 AND viewed = ?2', 'conditions' => 'receiver_id = :receiver_id: AND viewed = 0',
'bind' => [1 => $userId, 2 => 0], 'bind' => ['receiver_id' => $userId],
]); ]);
} }

View File

@ -4,6 +4,7 @@ namespace App\Services;
use App\Caches\Category as CategoryCache; use App\Caches\Category as CategoryCache;
use App\Caches\CategoryList as CategoryListCache; use App\Caches\CategoryList as CategoryListCache;
use App\Models\Category as CategoryModel;
class Category extends Service class Category extends Service
{ {
@ -50,14 +51,15 @@ class Category extends Service
/** /**
* 获取子节点 * 获取子节点
* *
* @param string $type
* @param int $id * @param int $id
* @return array * @return array
*/ */
public function getChildCategories($id = 0) public function getChildCategories($type, $id)
{ {
$categoryListCache = new CategoryListCache(); $categoryListCache = new CategoryListCache();
$categories = $categoryListCache->get(); $categories = $categoryListCache->get($type);
$result = []; $result = [];
@ -80,6 +82,9 @@ class Category extends Service
{ {
$categoryCache = new CategoryCache(); $categoryCache = new CategoryCache();
/**
* @var CategoryModel $category
*/
$category = $categoryCache->get($id); $category = $categoryCache->get($id);
if (!$category) { if (!$category) {
@ -92,7 +97,7 @@ class Category extends Service
$categoryListCache = new CategoryListCache(); $categoryListCache = new CategoryListCache();
$categories = $categoryListCache->get(); $categories = $categoryListCache->get($category->type);
$result = []; $result = [];

View File

@ -13,7 +13,7 @@ class HelpInfo extends FrontendService
public function handle($id) public function handle($id)
{ {
$help = $this->checkHelpCache($id); $help = $this->checkHelp($id);
return $this->handleHelp($help); return $this->handleHelp($help);
} }

View File

@ -2,8 +2,7 @@
namespace App\Services\Frontend\Help; namespace App\Services\Frontend\Help;
use App\Models\Help as HelpModel; use App\Caches\HelpList as HelpListCache;
use App\Repos\Help as HelpRepo;
use App\Services\Frontend\Service as FrontendService; use App\Services\Frontend\Service as FrontendService;
class HelpList extends FrontendService class HelpList extends FrontendService
@ -11,38 +10,11 @@ class HelpList extends FrontendService
public function handle() public function handle()
{ {
$helpRepo = new HelpRepo(); $cache = new HelpListCache();
$params = ['published' => 1]; $result = $cache->get();
$helps = $helpRepo->findAll($params); return $result ?: [];
$result = [];
if ($helps->count() > 0) {
$result = $this->handleHelps($helps);
}
return $result;
}
/**
* @param HelpModel[] $helps
* @return array
*/
protected function handleHelps($helps)
{
$items = [];
foreach ($helps as $help) {
$items[] = [
'id' => $help->id,
'title' => $help->title,
'content' => $help->content,
];
}
return $items;
} }
} }

171
app/Services/MyStorage.php Normal file
View File

@ -0,0 +1,171 @@
<?php
namespace App\Services;
use App\Library\Utils\FileInfo;
use App\Models\UploadFile as UploadFileModel;
use App\Repos\UploadFile as UploadFileRepo;
class MyStorage extends Storage
{
/**
* 文件类型
*/
const TYPE_IMAGE = 'image';
const TYPE_VIDEO = 'video';
const TYPE_AUDIO = 'audio';
const TYPE_FILE = 'file';
public function uploadTestFile()
{
$key = 'hello_world.txt';
$value = 'hello world';
return $this->putString($key, $value);
}
public function uploadDefaultAvatarImage()
{
$filename = public_path('static/admin/img/default_avatar.png');
$key = '/img/avatar/default.png';
return $this->putFile($key, $filename);
}
public function uploadDefaultCoverImage()
{
$filename = public_path('static/admin/img/default_cover.png');
$key = '/img/cover/default.png';
return $this->putFile($key, $filename);
}
/**
* 上传封面图片
*
* @return UploadFileModel|bool
*/
public function uploadCoverImage()
{
return $this->upload('/img/cover/', self::TYPE_IMAGE);
}
/**
* 上传编辑器图片
*
* @return UploadFileModel|bool
*/
public function uploadEditorImage()
{
return $this->upload('/img/editor/', self::TYPE_IMAGE);
}
/**
* 上传头像图片
*
* @return UploadFileModel|bool
*/
public function uploadAvatarImage()
{
return $this->upload('/img/avatar/', self::TYPE_IMAGE);
}
/**
* 上传im图片
*
* @return UploadFileModel|bool
*/
public function uploadImImage()
{
return $this->upload('/im/img/', self::TYPE_IMAGE);
}
/**
* 上传im文件
*/
public function uploadImFile()
{
return $this->upload('/im/file/', self::TYPE_FILE);
}
/**
* 上传文件
*
* @param string $prefix
* @param string $type
* @return UploadFileModel|bool
*/
protected function upload($prefix = '', $type = self::TYPE_IMAGE)
{
$list = [];
if ($this->request->hasFiles(true)) {
$files = $this->request->getUploadedFiles(true);
$uploadFileRepo = new UploadFileRepo();
foreach ($files as $file) {
if ($this->checkFile($file->getRealType(), $type) == false) {
continue;
}
$md5 = md5_file($file->getTempName());
$uploadFile = $uploadFileRepo->findByMd5($md5);
if ($uploadFile == false) {
$extension = $this->getFileExtension($file->getName());
$keyName = $this->generateFileName($extension, $prefix);
$path = $this->putFile($keyName, $file->getTempName());
$uploadFile = new UploadFileModel();
$uploadFile->mime = $file->getRealType();
$uploadFile->size = $file->getSize();
$uploadFile->path = $path;
$uploadFile->md5 = $md5;
$uploadFile->create();
}
$list[] = $uploadFile;
}
}
return $list[0] ?: false;
}
/**
* 检查上传文件
*
* @param string $mime
* @param string $type
* @return bool
*/
protected function checkFile($mime, $type)
{
switch ($type) {
case self::TYPE_IMAGE:
$result = FileInfo::isImage($mime);
break;
case self::TYPE_VIDEO:
$result = FileInfo::isVideo($mime);
break;
case self::TYPE_AUDIO:
$result = FileInfo::isAudio($mime);
break;
default:
$result = FileInfo::isSecure($mime);
break;
}
return $result;
}
}

View File

@ -2,23 +2,12 @@
namespace App\Services; namespace App\Services;
use App\Library\Utils\FileInfo;
use App\Models\UploadFile as UploadFileModel;
use App\Repos\UploadFile as UploadFileRepo;
use Phalcon\Logger\Adapter\File as FileLogger; use Phalcon\Logger\Adapter\File as FileLogger;
use Qcloud\Cos\Client as CosClient; use Qcloud\Cos\Client as CosClient;
class Storage extends Service class Storage extends Service
{ {
/**
* 文件类型
*/
const TYPE_IMAGE = 'image';
const TYPE_VIDEO = 'video';
const TYPE_AUDIO = 'audio';
const TYPE_FILE = 'file';
/** /**
* @var array * @var array
*/ */
@ -43,117 +32,6 @@ class Storage extends Service
$this->client = $this->getCosClient(); $this->client = $this->getCosClient();
} }
/**
* 上传测试文件
*
* @return bool
*/
public function uploadTestFile()
{
$key = 'hello_world.txt';
$value = 'hello world';
return $this->putString($key, $value);
}
/**
* 上传封面图片
*
* @return UploadFileModel|bool
*/
public function uploadCoverImage()
{
return $this->upload('/img/cover/', self::TYPE_IMAGE);
}
/**
* 上传编辑器图片
*
* @return UploadFileModel|bool
*/
public function uploadEditorImage()
{
return $this->upload('/img/editor/', self::TYPE_IMAGE);
}
/**
* 上传头像图片
*
* @return UploadFileModel|bool
*/
public function uploadAvatarImage()
{
return $this->upload('/img/avatar/', self::TYPE_IMAGE);
}
/**
* 上传im图片
*
* @return UploadFileModel|bool
*/
public function uploadImImage()
{
return $this->upload('/im/img/', self::TYPE_IMAGE);
}
/**
* 上传im文件
*/
public function uploadImFile()
{
return $this->upload('/im/file/', self::TYPE_FILE);
}
/**
* 上传文件
*
* @param string $prefix
* @param string $type
* @return UploadFileModel|bool
*/
protected function upload($prefix = '', $type = self::TYPE_IMAGE)
{
$list = [];
if ($this->request->hasFiles(true)) {
$files = $this->request->getUploadedFiles(true);
$uploadFileRepo = new UploadFileRepo();
foreach ($files as $file) {
if ($this->checkUploadFile($file->getRealType(), $type) == false) {
continue;
}
$md5 = md5_file($file->getTempName());
$uploadFile = $uploadFileRepo->findByMd5($md5);
if ($uploadFile == false) {
$extension = $this->getFileExtension($file->getName());
$keyName = $this->generateFileName($extension, $prefix);
$path = $this->putFile($keyName, $file->getTempName());
$uploadFile = new UploadFileModel();
$uploadFile->mime = $file->getRealType();
$uploadFile->size = $file->getSize();
$uploadFile->path = $path;
$uploadFile->md5 = $md5;
$uploadFile->create();
}
$list[] = $uploadFile;
}
}
return $list[0] ?: false;
}
/** /**
* 上传字符内容 * 上传字符内容
* *
@ -161,7 +39,7 @@ class Storage extends Service
* @param string $body * @param string $body
* @return string|bool * @return string|bool
*/ */
protected function putString($key, $body) public function putString($key, $body)
{ {
$bucket = $this->settings['bucket_name']; $bucket = $this->settings['bucket_name'];
@ -189,16 +67,16 @@ class Storage extends Service
* 上传文件 * 上传文件
* *
* @param string $key * @param string $key
* @param string $fileName * @param string $filename
* @return mixed string|bool * @return mixed string|bool
*/ */
protected function putFile($key, $fileName) public function putFile($key, $filename)
{ {
$bucket = $this->settings['bucket_name']; $bucket = $this->settings['bucket_name'];
try { try {
$body = fopen($fileName, 'rb'); $body = fopen($filename, 'rb');
$response = $this->client->upload($bucket, $key, $body); $response = $this->client->upload($bucket, $key, $body);
@ -224,7 +102,7 @@ class Storage extends Service
* @param string $key * @param string $key
* @return string|bool * @return string|bool
*/ */
protected function deleteObject($key) public function deleteObject($key)
{ {
$bucket = $this->settings['bucket_name']; $bucket = $this->settings['bucket_name'];
@ -316,43 +194,16 @@ class Storage extends Service
/** /**
* 获取文件扩展名 * 获取文件扩展名
* *
* @param $fileName * @param $filename
* @return string * @return string
*/ */
protected function getFileExtension($fileName) protected function getFileExtension($filename)
{ {
$extension = pathinfo($fileName, PATHINFO_EXTENSION); $extension = pathinfo($filename, PATHINFO_EXTENSION);
return strtolower($extension); return strtolower($extension);
} }
/**
* 检查上传文件
*
* @param string $mime
* @param string $type
* @return bool
*/
protected function checkUploadFile($mime, $type)
{
switch ($type) {
case self::TYPE_IMAGE:
$result = FileInfo::isImage($mime);
break;
case self::TYPE_VIDEO:
$result = FileInfo::isVideo($mime);
break;
case self::TYPE_AUDIO:
$result = FileInfo::isAudio($mime);
break;
default:
$result = FileInfo::isSecure($mime);
break;
}
return $result;
}
/** /**
* 获取CosClient * 获取CosClient
* *

View File

@ -68,6 +68,17 @@ class Category extends Validator
return $category; return $category;
} }
public function checkType($type)
{
$list = CategoryModel::types();
if (!isset($list[$type])) {
throw new BadRequestException('category.invalid_type');
}
return $type;
}
public function checkName($name) public function checkName($name)
{ {
$value = $this->filter->sanitize($name, ['trim', 'string']); $value = $this->filter->sanitize($name, ['trim', 'string']);

View File

@ -147,10 +147,10 @@ class Course extends Validator
$list = []; $list = [];
foreach ($keywords as $keywords) { foreach ($keywords as $keyword) {
$keywords = trim($keywords); $keyword = trim($keyword);
if (kg_strlen($keywords) > 1) { if (kg_strlen($keyword) > 1) {
$list[] = $keywords; $list[] = $keyword;
} }
} }

View File

@ -55,6 +55,13 @@ class Help extends Validator
return $help; return $help;
} }
public function checkCategory($id)
{
$validator = new Category();
return $validator->checkCategory($id);
}
public function checkTitle($title) public function checkTitle($title)
{ {
$value = $this->filter->sanitize($title, ['trim', 'string']); $value = $this->filter->sanitize($title, ['trim', 'string']);

View File

@ -75,6 +75,7 @@ $error['user.invalid_lock_expiry_time'] = '无效的锁定期限';
*/ */
$error['category.not_found'] = '分类不存在'; $error['category.not_found'] = '分类不存在';
$error['category.parent_not_found'] = '父级分类不存在'; $error['category.parent_not_found'] = '父级分类不存在';
$error['category.invalid_type'] = '无效的分类类型';
$error['category.invalid_priority'] = '无效的排序值范围1-255'; $error['category.invalid_priority'] = '无效的排序值范围1-255';
$error['category.invalid_publish_status'] = '无效的发布状态'; $error['category.invalid_publish_status'] = '无效的发布状态';
$error['category.name_too_short'] = '名称太短少于2个字符'; $error['category.name_too_short'] = '名称太短少于2个字符';

View File

@ -6,7 +6,7 @@ layui.use(['jquery', 'layer', 'upload'], function () {
upload.render({ upload.render({
elem: '#change-avatar', elem: '#change-avatar',
url: '/admin/upload/img/avatar', url: '/admin/upload/avatar/img',
accept: 'images', accept: 'images',
acceptMime: 'image/*', acceptMime: 'image/*',
size: 512, size: 512,

View File

@ -6,7 +6,7 @@ layui.use(['jquery', 'layer', 'upload'], function () {
upload.render({ upload.render({
elem: '#change-cover', elem: '#change-cover',
url: '/admin/upload/img/cover', url: '/admin/upload/cover/img',
accept: 'images', accept: 'images',
acceptMime: 'image/*', acceptMime: 'image/*',
before: function () { before: function () {

View File

@ -23,7 +23,7 @@ layui.use(['jquery', 'layim'], function () {
socket.send('pong...'); socket.send('pong...');
} else if (data.type === 'bind_user') { } else if (data.type === 'bind_user') {
bindUser(data); bindUser(data);
refreshMessageBox(); refreshMsgBox();
} else if (data.type === 'new_group_user') { } else if (data.type === 'new_group_user') {
showNewGroupUserMessage(data); showNewGroupUserMessage(data);
} else if (data.type === 'show_online_tips') { } else if (data.type === 'show_online_tips') {
@ -32,13 +32,13 @@ layui.use(['jquery', 'layim'], function () {
setChatMessageCount(data); setChatMessageCount(data);
showChatMessage(data); showChatMessage(data);
} else if (data.type === 'refresh_msg_box') { } else if (data.type === 'refresh_msg_box') {
refreshMessageBox(); refreshMsgBox();
} else if (data.type === 'friend_accepted') { } else if (data.type === 'friend_accepted') {
friendAccepted(data); friendAccepted(data);
refreshMessageBox(); refreshMsgBox();
} else if (data.type === 'group_accepted') { } else if (data.type === 'group_accepted') {
groupAccepted(data); groupAccepted(data);
refreshMessageBox(); refreshMsgBox();
} }
}; };
@ -51,10 +51,10 @@ layui.use(['jquery', 'layim'], function () {
url: '/im/group/users' url: '/im/group/users'
}, },
uploadImage: { uploadImage: {
url: '/im/img/upload' url: '/upload/im/image'
}, },
uploadFile: { uploadFile: {
url: '/im/file/upload' url: '/upload/im/file'
}, },
maxLength: 1000, maxLength: 1000,
find: '/im/find', find: '/im/find',
@ -151,7 +151,7 @@ layui.use(['jquery', 'layim'], function () {
if (res.data.type === 'friend' && unreadListMsgCount > 0) { if (res.data.type === 'friend' && unreadListMsgCount > 0) {
$.ajax({ $.ajax({
type: 'GET', type: 'GET',
url: '/im/msg/friend/unread', url: '/im/friend/msg/unread',
data: {id: res.data.id} data: {id: res.data.id}
}); });
} }
@ -193,10 +193,10 @@ layui.use(['jquery', 'layim'], function () {
}); });
} }
function refreshMessageBox() { function refreshMsgBox() {
$.ajax({ $.ajax({
type: 'GET', type: 'GET',
url: '/im/msg/sys/unread', url: '/im/sys/msg/unread',
success: function (res) { success: function (res) {
if (res.count > 0) { if (res.count > 0) {
layim.msgbox(res.count); layim.msgbox(res.count);

View File

@ -1,19 +1,18 @@
layui.use(['jquery', 'layer', 'layim', 'laypage'], function () { layui.use(['jquery', 'layer', 'laypage'], function () {
var $ = layui.jquery; var $ = layui.jquery;
var layer = layui.layer; var layer = layui.layer;
var layim = layui.layim;
var laypage = layui.laypage; var laypage = layui.laypage;
var $target = $('#LAY_view'); var $target = $('#LAY_view');
var $page = $('#LAY_page'); var $page = $('#LAY_page');
var count = $page.data('count'); var count = $page.data('count');
var limit = 15; var limit = 12;
/** /**
* 标记信息为已读 * 标记通知为已读
*/ */
readSystemMessages(); readNotices();
/** /**
* 加载第一页数据 * 加载第一页数据
@ -37,13 +36,13 @@ layui.use(['jquery', 'layer', 'layim', 'laypage'], function () {
} }
function loadPageHtml(target, page) { function loadPageHtml(target, page) {
$.get('/im/msg/sys', {page: page}, function (html) { $.get('/im/sys/msg', {page: page}, function (html) {
target.html(html); target.html(html);
}); });
} }
function readSystemMessages() { function readNotices() {
$.post('/im/msg/sys/read'); $.post('/im/sys/msg/read');
} }
var action = { var action = {

View File

@ -4,22 +4,24 @@ layui.use(['jquery', 'layer'], function () {
var layer = layui.layer; var layer = layui.layer;
$('.btn-pay').on('click', function () { $('.btn-pay').on('click', function () {
var channel = $(this).data('channel'); var channel = $(this).data('channel');
var createUrl = $('input[name=trade_create_url]').val(); var createUrl = $('input[name=trade_create_url]').val();
var statusUrl = $('input[name=trade_status_url]').val(); var statusUrl = $('input[name=trade_status_url]').val();
var forwardUrl = $('input[name=forward_url]').val(); var forwardUrl = $('input[name=forward_url]').val();
var orderSn = $('input[name=order_sn]').val(); var orderSn = $('input[name=order_sn]').val();
var $qrBlock = $('#' + channel + '-qrcode'); var $qrBlock = $('#' + channel + '-qrcode');
var $snInput = $('input[name=' + channel + '_trade_sn]'); var $tradeSn = $('input[name=' + channel + '_trade_sn]');
var qrTitle = channel === 'alipay' ? '支付宝扫码支付' : '微信扫码支付'; var qrTitle = channel === 'alipay' ? '支付宝扫码支付' : '微信扫码支付';
var qrHtml = $qrBlock.html(); var qrHtml = $qrBlock.html();
if (qrHtml.length === 0) { if (qrHtml.length === 0) {
var postData = {order_sn: orderSn, channel: channel}; var postData = {order_sn: orderSn, channel: channel};
$.post(createUrl, postData, function (res) { $.post(createUrl, postData, function (res) {
qrHtml = '<div class="qrcode"><img src="' + res.qrcode_url + '" alt="支付二维码"></div>'; qrHtml = '<div class="qrcode"><img src="' + res.qrcode + '" alt="支付二维码"></div>';
showQrLayer(qrTitle, qrHtml); showQrLayer(qrTitle, qrHtml);
$qrBlock.html(qrHtml); $qrBlock.html(qrHtml);
$snInput.html(res.sn); $tradeSn.val(res.sn);
var interval = setInterval(function () { var interval = setInterval(function () {
var queryData = {sn: res.sn}; var queryData = {sn: res.sn};
$.get(statusUrl, queryData, function (res) { $.get(statusUrl, queryData, function (res) {
@ -31,7 +33,7 @@ layui.use(['jquery', 'layer'], function () {
}, 5000); }, 5000);
} }
}); });
}, 3000) }, 5000);
}); });
} else { } else {
showQrLayer(qrTitle, qrHtml); showQrLayer(qrTitle, qrHtml);

View File

@ -6,7 +6,7 @@ layui.use(['jquery', 'layer', 'upload'], function () {
upload.render({ upload.render({
elem: '#change-avatar', elem: '#change-avatar',
url: '/upload/img/avatar', url: '/upload/avatar/img',
accept: 'images', accept: 'images',
acceptMime: 'image/*', acceptMime: 'image/*',
size: 512, size: 512,