1
0
mirror of https://gitee.com/koogua/course-tencent-cloud.git synced 2025-08-09 16:01:39 +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
{
public function handle()
public function handle($type)
{
$topCategories = $this->findChildCategories(0);
$topCategories = $this->findChildCategories($type, 0);
if ($topCategories->count() == 0) {
return [];
@ -32,7 +32,7 @@ class CategoryTreeList extends Builder
protected function handleChildren(CategoryModel $category)
{
$subCategories = $this->findChildCategories($category->id);
$subCategories = $this->findChildCategories($category->type, $category->id);
if ($subCategories->count() == 0) {
return [];
@ -51,16 +51,27 @@ class CategoryTreeList extends Builder
}
/**
* @param int $categoryId
* @param string $type
* @param int $parentId
* @return ResultsetInterface|Resultset|CategoryModel[]
*/
protected function findChildCategories($categoryId = 0)
protected function findChildCategories($type = 'course', $parentId = 0)
{
return CategoryModel::query()
->where('parent_id = :parent_id:', ['parent_id' => $categoryId])
->andWhere('published = 1')
->orderBy('priority ASC')
->execute();
$query = CategoryModel::query();
$query->where('published = 1');
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;
use App\Caches\CategoryList as CategoryListCache;
use App\Models\Category as CategoryModel;
use App\Repos\User as UserRepo;
class CourseList extends Builder
@ -34,7 +35,7 @@ class CourseList extends Builder
{
$cache = new CategoryListCache();
$items = $cache->get();
$items = $cache->get(CategoryModel::TYPE_COURSE);
if (empty($items)) {
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;
}
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
*/
public function getContent($id = null)
public function getContent($type = null)
{
/**
* @var Resultset $categories
*/
$categories = CategoryModel::query()
->columns(['id', 'parent_id', 'name', 'priority', 'level', 'path'])
->where('published = 1')
->where('type = :type:', ['type' => $type])
->andWhere('published = 1')
->execute();
if ($categories->count() == 0) {

View File

@ -14,16 +14,16 @@ class CategoryTreeList extends Cache
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();
$list = $builder->handle();
$list = $builder->handle($type);
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)
{
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')
->limit($limit)
->execute();

View File

@ -84,7 +84,8 @@ class IndexNewCourseList extends Cache
protected function findCategories($limit = 5)
{
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')
->limit($limit)
->execute();

View File

@ -84,7 +84,8 @@ class IndexVipCourseList extends Cache
protected function findCategories($limit = 5)
{
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')
->limit($limit)
->execute();

View File

@ -16,12 +16,20 @@ class CategoryController extends Controller
public function listAction()
{
$parentId = $this->request->get('parent_id', 'int', 0);
$type = $this->request->get('type', 'string', 'course');
$categoryService = new CategoryService();
$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('categories', $categories);
}
@ -32,12 +40,20 @@ class CategoryController extends Controller
public function addAction()
{
$parentId = $this->request->get('parent_id', 'int', 0);
$type = $this->request->get('type', 'string', 'course');
$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);
}
@ -52,7 +68,7 @@ class CategoryController extends Controller
$location = $this->url->get(
['for' => 'admin.category.list'],
['parent_id' => $category->parent_id]
['type' => $category->type, 'parent_id' => $category->parent_id],
);
$content = [
@ -88,7 +104,7 @@ class CategoryController extends Controller
$location = $this->url->get(
['for' => 'admin.category.list'],
['parent_id' => $category->parent_id]
['type' => $category->type, 'parent_id' => $category->parent_id],
);
$content = [

View File

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

View File

@ -10,6 +10,19 @@ use App\Http\Admin\Services\Course as CourseService;
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")
*/

View File

@ -10,6 +10,19 @@ use App\Http\Admin\Services\Help as HelpService;
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")
*/
@ -27,7 +40,11 @@ class HelpController extends Controller
*/
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;
$categories = $helpService->getCategories();
$help = $helpService->getHelp($id);
$this->view->setVar('categories', $categories);
$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\Live as LiveService;
use App\Services\Mailer\Test as TestMailerService;
use App\Services\MyStorage as StorageService;
use App\Services\Smser\Test as TestSmserService;
use App\Services\Storage as StorageService;
use App\Services\Vod as VodService;
use Phalcon\Mvc\View;
@ -29,16 +29,8 @@ class TestController extends Controller
$result = [];
$result['hello'] = $storageService->uploadTestFile();
$avatarPath = public_path('static/admin/img/default_avatar.png');
$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);
$result['avatar'] = $storageService->uploadDefaultAvatarImage();
$result['cover'] = $storageService->uploadDefaultCoverImage();
if ($result['hello'] && $result['avatar'] && $result['cover']) {
return $this->jsonSuccess(['msg' => '上传文件成功,请到控制台确认']);
@ -176,9 +168,9 @@ class TestController extends Controller
$order = $alipayTestService->createOrder();
$trade = $alipayTestService->createTrade($order);
$qrcodeUrl = $alipayTestService->scan($trade);
$qrcode = $alipayTestService->scan($trade);
if ($order && $trade && $qrcodeUrl) {
if ($order && $trade && $qrcode) {
$this->db->commit();
} else {
$this->db->rollback();
@ -186,7 +178,7 @@ class TestController extends Controller
$this->view->pick('setting/pay_alipay_test');
$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();
$trade = $wxpayTestService->createTrade($order);
$qrcodeUrl = $wxpayTestService->scan($trade);
$qrcode = $wxpayTestService->scan($trade);
if ($order && $trade && $qrcodeUrl) {
if ($order && $trade && $qrcode) {
$this->db->commit();
} else {
$this->db->rollback();
@ -238,7 +230,7 @@ class TestController extends Controller
$this->view->pick('setting/pay_wxpay_test');
$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;
use App\Services\Storage as StorageService;
use App\Services\MyStorage as StorageService;
/**
* @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()
{
@ -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()
{
@ -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()
{

View File

@ -18,7 +18,9 @@ class AuthMenu extends Component
public function __construct()
{
$this->authUser = $this->getAuthInfo();
$this->authNodes = $this->getAuthNodes();
$this->setOwnedLevelIds();
}
@ -46,6 +48,7 @@ class AuthMenu extends Component
foreach ($level['children'] as $key2 => $level2) {
foreach ($level2['children'] as $key3 => $level3) {
$allowed = ($this->authUser['root'] == 1) || in_array($level3['id'], $this->owned3rdLevelIds);
$params = $level3['params'] ?? [];
if ($level3['type'] == 'menu' && $allowed) {
$menus[$key]['id'] = $level['id'];
$menus[$key]['title'] = $level['title'];
@ -54,7 +57,7 @@ class AuthMenu extends Component
$menus[$key]['children'][$key2]['children'][$key3] = [
'id' => $level3['id'],
'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' => '课程管理',
'type' => 'menu',
'children' => [
[
'id' => '1-1-0',
'title' => '课程分类',
'type' => 'menu',
'route' => 'admin.course.category',
],
[
'id' => '1-1-1',
'title' => '课程列表',
@ -71,12 +77,14 @@ class AuthNode extends Service
'title' => '分类列表',
'type' => 'menu',
'route' => 'admin.category.list',
'params' => ['type' => 'course'],
],
[
'id' => '1-2-2',
'title' => '添加分类',
'type' => 'menu',
'route' => 'admin.category.add',
'params' => ['type' => 'course'],
],
[
'id' => '1-2-3',
@ -196,6 +204,12 @@ class AuthNode extends Service
'title' => '帮助管理',
'type' => 'menu',
'children' => [
[
'id' => '1-6-0',
'title' => '帮助分类',
'type' => 'menu',
'route' => 'admin.help.category',
],
[
'id' => '1-6-1',
'title' => '帮助列表',

View File

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

View File

@ -2,23 +2,48 @@
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\Repos\Category as CategoryRepo;
use App\Repos\Help as HelpRepo;
use App\Validators\Help as HelpValidator;
use Phalcon\Mvc\Model\Resultset;
class Help extends Service
{
public function getCategories()
{
$categoryRepo = new CategoryRepo();
return $categoryRepo->findTopCategories(CategoryModel::TYPE_HELP);
}
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();
return $helpRepo->findAll([
'deleted' => $deleted,
]);
$helps = $helpRepo->findAll($params);
$result = [];
if ($helps->count() > 0) {
$result = $this->handleHelps($helps);
}
return $result;
}
public function getHelp($id)
@ -34,16 +59,19 @@ class Help extends Service
$data = [];
$category = $validator->checkCategory($post['category_id']);
$data['title'] = $validator->checkTitle($post['title']);
$data['content'] = $validator->checkContent($post['content']);
$data['priority'] = $validator->checkPriority($post['priority']);
$data['published'] = $validator->checkPublishStatus($post['published']);
$data['category_id'] = $category->id;
$help = new HelpModel();
$help->create($data);
$this->rebuildHelpCache($help);
$this->rebuildHelpListCache();
return $help;
}
@ -58,6 +86,11 @@ class Help extends Service
$data = [];
if (isset($post['category_id'])) {
$category = $validator->checkCategory($post['category_id']);
$data['category_id'] = $category->id;
}
if (isset($post['title'])) {
$data['title'] = $validator->checkTitle($post['title']);
}
@ -76,7 +109,7 @@ class Help extends Service
$help->update($data);
$this->rebuildHelpCache($help);
$this->rebuildHelpListCache();
return $help;
}
@ -89,7 +122,7 @@ class Help extends Service
$help->update();
$this->rebuildHelpCache($help);
$this->rebuildHelpListCache();
return $help;
}
@ -102,16 +135,16 @@ class Help extends Service
$help->update();
$this->rebuildHelpCache($help);
$this->rebuildHelpListCache();
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)
@ -121,4 +154,23 @@ class Help extends Service
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';
}
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);
return array_values($list);

View File

@ -38,6 +38,7 @@
</thead>
<tbody>
{% for item in pager.items %}
{% set show_url = url({'for':'admin.audit.show','id':item.id}) %}
<tr>
<td>{{ item.user_id }}</td>
<td>{{ item.user_name }}</td>
@ -46,7 +47,7 @@
<td>{{ item.req_path }}</td>
<td>{{ date('Y-m-d H:i:s',item.create_time) }}</td>
<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>
</tr>
{% endfor %}

View File

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

View File

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

View File

@ -2,6 +2,9 @@
{% 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-left">
<span class="layui-breadcrumb">
@ -15,9 +18,11 @@
</span>
</div>
<div class="kg-nav-right">
<a class="layui-btn layui-btn-sm" href="{{ url({'for':'admin.category.add'},{'parent_id':parent.id}) }}">
<i class="layui-icon layui-icon-add-1"></i>添加分类
</a>
{% if allow_add_category %}
<a class="layui-btn layui-btn-sm" href="{{ add_category_url }}">
<i class="layui-icon layui-icon-add-1"></i>添加分类
</a>
{% endif %}
</div>
</div>
@ -44,26 +49,32 @@
</thead>
<tbody>
{% 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>
<td>{{ item.id }}</td>
{% if item.level < 2 %}
<td><a href="{{ url({'for':'admin.category.list'}) }}?parent_id={{ item.id }}">{{ item.name }}</a></td>
{% if show_child_url %}
<td><a href="{{ child_url }}">{{ item.name }}</a></td>
{% else %}
<td>{{ item.name }}</td>
{% endif %}
<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><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 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 class="layui-input kg-priority" type="text" name="priority" title="数值越小排序越靠前" value="{{ item.priority }}" data-url="{{ update_url }}"></td>
<td><input type="checkbox" name="published" value="1" lay-skin="switch" lay-text="是|否" lay-filter="published" data-url="{{ update_url }}" {% if item.published == 1 %}checked{% endif %}></td>
<td align="center">
<div class="layui-dropdown">
<button class="layui-btn layui-btn-sm">操作 <span class="layui-icon layui-icon-triangle-d"></span></button>
<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 %}
<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 %}
<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 %}
</ul>
</div>

View File

@ -2,10 +2,14 @@
{% 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-left">
<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> 返回
</a>
<a><cite>{{ course.title }}</cite></a>
@ -14,10 +18,10 @@
</span>
</div>
<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>添加章
</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>添加课
</a>
</div>

View File

@ -44,9 +44,14 @@
</thead>
<tbody>
{% 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>
<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>
{% if item.answer %}
<p>回复:<a href="javascript:" title="{{ item.answer }}">{{ substr(item.answer,0,30) }}</a></p>
@ -57,17 +62,17 @@
<p>编号:{{ item.owner.id }}</p>
</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">
<div class="layui-dropdown">
<button class="layui-btn layui-btn-sm">操作 <span class="layui-icon layui-icon-triangle-d"></span>
</button>
<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 %}
<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 %}
<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 %}
</ul>
</div>

View File

@ -28,13 +28,15 @@
{%- macro category_info(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 %}
{%- endmacro %}
{%- macro teacher_info(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 %}
{%- endmacro %}
@ -75,18 +77,26 @@
</thead>
<tbody>
{% 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>
<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>
</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>
</a>
</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>
</a>
</td>
@ -94,23 +104,23 @@
<p>市场:{{ '¥%0.2f'|format(item.market_price) }}</p>
<p>会员:{{ '¥%0.2f'|format(item.vip_price) }}</p>
</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">
<div class="layui-dropdown">
<button class="layui-btn layui-btn-sm">操作 <span class="layui-icon layui-icon-triangle-d"></span></button>
<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 %}
<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 %}
<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 %}
<hr>
<li><a href="{{ url({'for':'admin.course.chapters','id':item.id}) }}">章节管理</a></li>
<li><a href="{{ url({'for':'admin.student.list'},{'course_id':item.id}) }}">学员管理</a></li>
<li><a href="{{ catalog_url }}">章节管理</a></li>
<li><a href="{{ student_url }}">学员管理</a></li>
<hr>
<li><a href="{{ url({'for':'admin.consult.list'}) }}?course_id={{ item.id }}">咨询管理</a></li>
<li><a href="{{ url({'for':'admin.review.list'}) }}?course_id={{ item.id }}">评价管理</a></li>
<li><a href="{{ consult_url }}">咨询管理</a></li>
<li><a href="{{ review_url }}">评价管理</a></li>
</ul>
</div>
</td>

View File

@ -52,18 +52,21 @@
</thead>
<tbody>
{% 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>
<td>{{ item.id }}</td>
<td>{{ item.name }} {{ type_info(item.type) }}</td>
<td>{{ owner_info(item.owner) }}</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">
<div class="layui-dropdown">
<button class="layui-btn layui-btn-sm">操作 <span class="layui-icon layui-icon-triangle-d"></span></button>
<ul>
<li><a href="{{ url({'for':'admin.group.edit','id':item.id}) }}">编辑</a></li>
<li><a href="javascript:" class="kg-delete" data-url="{{ url({'for':'admin.group.delete','id':item.id}) }}">删除</a></li>
<li><a href="{{ edit_url }}">编辑</a></li>
<li><a href="javascript:" class="kg-delete" data-url="{{ delete_url }}">删除</a></li>
</ul>
</div>
</td>

View File

@ -6,6 +6,17 @@
<fieldset class="layui-elem-field layui-field-title">
<legend>添加帮助</legend>
</fieldset>
<div class="layui-form-item">
<label class="layui-form-label">分类</label>
<div class="layui-input-block">
<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">
<label class="layui-form-label">标题</label>
<div class="layui-input-block">

View File

@ -6,6 +6,17 @@
<fieldset class="layui-elem-field layui-field-title">
<legend>编辑帮助</legend>
</fieldset>
<div class="layui-form-item">
<label class="layui-form-label">分类</label>
<div class="layui-input-block">
<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">
<label class="layui-form-label">标题</label>
<div class="layui-input-block">

View File

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

View File

@ -18,11 +18,14 @@
{% endif %}
{%- 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-left">
<span class="layui-breadcrumb">
{% 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> 返回
</a>
<a><cite>{{ parent.name }}</cite></a>
@ -31,7 +34,7 @@
</span>
</div>
<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>添加导航
</a>
</div>
@ -64,10 +67,15 @@
</thead>
<tbody>
{% 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>
<td>{{ item.id }}</td>
{% 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 %}
<td>{{ item.name }}</td>
{% endif %}
@ -75,17 +83,17 @@
<td><span class="layui-badge layui-bg-gray">{{ item.child_count }}</span></td>
<td>{{ position_info(item.position) }}</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 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 class="layui-input kg-priority" type="text" name="priority" title="数值越小排序越靠前" value="{{ item.priority }}" data-url="{{ update_url }}"></td>
<td><input type="checkbox" name="published" value="1" lay-skin="switch" lay-text="是|否" lay-filter="published" data-url="{{ update_url }}" {% if item.published == 1 %}checked{% endif %}></td>
<td align="center">
<div class="layui-dropdown">
<button class="layui-btn layui-btn-sm">操作 <span class="layui-icon layui-icon-triangle-d"></span></button>
<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 %}
<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 %}
<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 %}
</ul>
</div>

View File

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

View File

@ -2,6 +2,8 @@
{% block content %}
{% set add_pkg_url = url({'for':'admin.package.add'}) %}
<div class="kg-nav">
<div class="kg-nav-left">
<span class="layui-breadcrumb">
@ -9,7 +11,7 @@
</span>
</div>
<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>添加套餐
</a>
</div>
@ -38,19 +40,22 @@
</thead>
<tbody>
{% 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>
<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>{{ '¥%0.2f'|format(item.market_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">
<div class="layui-dropdown">
<button class="layui-btn layui-btn-sm">操作 <span class="layui-icon layui-icon-triangle-d"></span></button>
<ul>
<li><a href="{{ url({'for':'admin.package.edit','id':item.id}) }}">编辑</a></li>
<li><a href="javascript:" class="kg-delete" data-url="{{ url({'for':'admin.package.delete','id':item.id}) }}">删除</a></li>
<li><a href="{{ edit_url }}">编辑</a></li>
<li><a href="javascript:" class="kg-delete" data-url="{{ delete_url }}">删除</a></li>
</ul>
</div>
</td>

View File

@ -2,6 +2,8 @@
{% block content %}
{% set add_page_url = url({'for':'admin.page.add'}) %}
<div class="kg-nav">
<div class="kg-nav-left">
<span class="layui-breadcrumb">
@ -9,7 +11,7 @@
</span>
</div>
<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>添加单页
</a>
</div>
@ -36,19 +38,23 @@
</thead>
<tbody>
{% 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>
<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.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 align="center">
<div class="layui-dropdown">
<button class="layui-btn layui-btn-sm">操作 <span class="layui-icon layui-icon-triangle-d"></span></button>
<ul>
<li><a href="{{ url({'for':'admin.page.edit','id':item.id}) }}">编辑</a></li>
<li><a href="javascript:" class="kg-delete" data-url="{{ url({'for':'admin.page.delete','id':item.id}) }}">删除</a></li>
<li><a href="{{ edit_url }}">编辑</a></li>
<li><a href="javascript:" class="kg-delete" data-url="{{ delete_url }}">删除</a></li>
</ul>
</div>
</td>

View File

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

View File

@ -2,6 +2,8 @@
{% block content %}
{% set search_review_url = url({'for':'admin.review.search'}) %}
<div class="kg-nav">
<div class="kg-nav-left">
<span class="layui-breadcrumb">
@ -13,7 +15,7 @@
</span>
</div>
<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>搜索评价
</a>
</div>
@ -38,9 +40,15 @@
</thead>
<tbody>
{% 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>
<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>时间:{{ date('Y-m-d H:i:s',item.create_time) }}</p>
</td>
@ -50,19 +58,19 @@
<p>逻辑清晰:{{ item.rating3 }}</p>
</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>
</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">
<div class="layui-dropdown">
<button class="layui-btn layui-btn-sm">操作 <span class="layui-icon layui-icon-triangle-d"></span></button>
<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 %}
<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 %}
<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 %}
</ul>
</div>

View File

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

View File

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

View File

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

View File

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

View File

@ -14,6 +14,14 @@ class ImController extends LayerController
use ResponseTrait;
/**
* @Get("/", name="web.im.index")
*/
public function indexAction()
{
}
/**
* @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();
@ -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();
$count = $service->countUnreadSystemMessages();
$count = $service->countUnreadNotices();
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();
$pager = $service->getSystemMessages();
$pager = $service->getNotices();
$pager->items = kg_array_object($pager->items);
$this->view->pick('im/sys_messages');
$this->view->pick('im/sys_msg');
$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->readSystemMessages();
$service->readNotices();
return $this->jsonSuccess();
}
@ -210,21 +218,6 @@ class ImController extends LayerController
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")
*/

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();
$this->view->setVar('carousels', $indexService->getCarousels());
$this->view->setVar('lives', $indexService->getLives());
$this->view->setVar('carousels', $indexService->getCarousels());
$this->view->setVar('new_courses', $indexService->getNewCourses());
$this->view->setVar('free_courses', $indexService->getFreeCourses());
$this->view->setVar('vip_courses', $indexService->getVipCourses());

View File

@ -3,7 +3,7 @@
namespace App\Http\Web\Controllers;
use App\Services\Storage as StorageService;
use App\Services\MyStorage as StorageService;
/**
* @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()
{
@ -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;
use App\Caches\Category as CategoryCache;
use App\Models\Category as CategoryModel;
use App\Models\Course as CourseModel;
use App\Services\Category as CategoryService;
use App\Validators\CourseQuery as CourseQueryValidator;
class CourseQuery extends Service
{
@ -42,7 +44,7 @@ class CourseQuery extends Service
$categoryService = new CategoryService();
$topCategories = $categoryService->getChildCategories(0);
$topCategories = $categoryService->getChildCategories(CategoryModel::TYPE_COURSE, 0);
foreach ($topCategories as $key => $category) {
$params['tc'] = $category['id'];
@ -66,7 +68,7 @@ class CourseQuery extends Service
$categoryService = new CategoryService();
$subCategories = $categoryService->getChildCategories($params['tc']);
$subCategories = $categoryService->getChildCategories(CategoryModel::TYPE_COURSE, $params['tc']);
if (empty($subCategories)) {
return [];
@ -216,7 +218,7 @@ class CourseQuery extends Service
$params = [];
$validator = new \App\Validators\CourseQuery();
$validator = new CourseQueryValidator();
if (isset($query['tc']) && $query['tc'] != 'all') {
$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\ImNewUserList as ImNewUserListCache;
use App\Library\Paginator\Query as PagerQuery;
use App\Models\ImFriendMessage as ImFriendMessageModel;
use App\Models\ImGroupMessage as ImGroupMessageModel;
use App\Models\ImMessage as ImMessageModel;
use App\Models\ImUser as ImUserModel;
use App\Repos\ImFriendMessage as ImFriendMessageRepo;
use App\Repos\ImFriendUser as ImFriendUserRepo;
use App\Repos\ImGroup as ImGroupRepo;
use App\Repos\ImGroupMessage as ImGroupMessageRepo;
use App\Repos\ImSystemMessage as ImSystemMessageRepo;
use App\Repos\ImMessage as ImMessageRepo;
use App\Repos\ImNotice as ImNoticeRepo;
use App\Repos\ImUser as ImUserRepo;
use App\Repos\User as UserRepo;
use App\Validators\ImFriendUser as ImFriendUserValidator;
@ -207,16 +205,16 @@ class Im extends Service
$friendUser->update(['msg_count' => 0]);
}
public function countUnreadSystemMessages()
public function countUnreadNotices()
{
$user = $this->getLoginUser();
$userRepo = new ImUserRepo();
return $userRepo->countUnreadSystemMessages($user->id);
return $userRepo->countUnreadNotices($user->id);
}
public function getSystemMessages()
public function getNotices()
{
$user = $this->getLoginUser();
@ -230,9 +228,9 @@ class Im extends Service
$page = $pagerQuery->getPage();
$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()
@ -251,23 +249,28 @@ class Im extends Service
$page = $pagerQuery->getPage();
$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);
} 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);
}
@ -351,7 +354,7 @@ class Im extends Service
Gateway::$registerAddress = $this->getRegisterAddress();
if ($to['type'] == 'friend') {
if ($to['type'] == ImMessageModel::TYPE_FRIEND) {
$validator = new ImFriendUserValidator();
@ -359,11 +362,12 @@ class Im extends Service
$online = Gateway::isUidOnline($to['id']);
$messageModel = new ImFriendMessageModel();
$messageModel = new ImMessageModel();
$messageModel->create([
'sender_id' => $from['id'],
'receiver_id' => $to['id'],
'chat_type' => $to['type'],
'content' => $from['content'],
'viewed' => $online ? 1 : 0,
]);
@ -374,7 +378,7 @@ class Im extends Service
$this->incrFriendUserMsgCount($relation);
}
} elseif ($to['type'] == 'group') {
} elseif ($to['type'] == ImMessageModel::TYPE_GROUP) {
$validator = new ImGroupValidator();
@ -384,11 +388,12 @@ class Im extends Service
$validator->checkGroupUser($group->id, $user->id);
$messageModel = new ImGroupMessageModel();
$messageModel = new ImMessageModel();
$messageModel->create([
'group_id' => $to['id'],
'sender_id' => $from['id'],
'receiver_id' => $to['id'],
'chat_type' => $to['type'],
'content' => $from['content'],
]);
@ -409,13 +414,13 @@ class Im extends Service
}
}
public function readSystemMessages()
public function readNotices()
{
$user = $this->getLoginUser();
$userRepo = new ImUserRepo();
$messages = $userRepo->findUnreadSystemMessages($user->id);
$messages = $userRepo->findUnreadNotices($user->id);
if ($messages->count() > 0) {
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();
$qrCodeUrl = $this->getQrCodeUrl($trade);
$qrCode = $this->getQrCode($trade);
if ($trade && $qrCodeUrl) {
if ($trade && $qrCode) {
$this->db->commit();
return [
'sn' => $trade->sn,
'channel' => $trade->channel,
'qrcode_url' => $qrCodeUrl,
'qrcode' => $qrCode,
];
} 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) {
$qrcodeUrl = $this->getAlipayQrCodeUrl($trade);
$qrCode = $this->getAlipayQrCode($trade);
} 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();
$text = $service->scan($trade);
if ($text) {
$qrCodeUrl = $this->url->get(
$qrCode = $this->url->get(
['for' => 'web.qrcode'],
['text' => urlencode($text)]
);
}
return $qrCodeUrl;
return $qrCode;
}
protected function getWxpayQrCodeUrl(TradeModel $trade)
protected function getWxpayQrCode(TradeModel $trade)
{
$service = new WxpayService();

View File

@ -9,14 +9,34 @@
</span>
</div>
<div class="page-info wrap">
<div class="layui-collapse">
{% for help in helps %}
<div class="layui-colla-item">
<h2 class="layui-colla-title">{{ help.title }}</h2>
<div class="layui-colla-content layui-show">{{ help.content }}</div>
<div class="layout-main">
<div class="layout-content">
<div class="wrap">
<div class="layui-collapse">
{% for item in helps %}
<div class="layui-colla-item">
<h2 class="layui-colla-title">{{ item.category.name }}</h2>
<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>
{% endfor %}
</div>
{% endfor %}
</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>

View File

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

View File

@ -1,5 +1,6 @@
<?php
use App\Caches\Setting as SettingCache;
use App\Library\Validators\Common as CommonValidator;
use App\Services\Storage as StorageService;
use Koogua\Ip2Region\Searcher as Ip2RegionSearcher;
@ -129,6 +130,24 @@ function kg_site_base_url()
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;
/**
* 别名
*
* @var string
*/
public $alias;
/**
* 类型
*
@ -143,4 +136,12 @@ class Category extends Model
$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;
/**
* 别名
* 分类编号
*
* @var string
* @var int
*/
public $alias;
public $category_id;
/**
* 标题
@ -29,13 +29,6 @@ class Help extends Model
*/
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;
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;
/**
* 接收方类型
*
* @var string
*/
public $receiver_type;
/**
* 内容
*
@ -72,7 +82,7 @@ class ImFriendMessage extends Model
public function getSource(): string
{
return 'kg_im_friend_message';
return 'kg_im_message';
}
public function initialize()
@ -91,7 +101,9 @@ class ImFriendMessage extends Model
{
$this->create_time = time();
$this->chat_id = self::getChatId($this->sender_id, $this->receiver_id);
if ($this->chat_type == self::TYPE_FRIEND) {
$this->chat_id = self::getChatId($this->sender_id, $this->receiver_id);
}
}
public function beforeUpdate()

View File

@ -4,7 +4,7 @@ namespace App\Models;
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 TYPE_FRIEND_REQUEST = 1; // 好友请求
const TYPE_FRIEND_ACCEPTED = 2; // 好友被接受
@ -96,7 +96,7 @@ class ImSystemMessage extends Model
public function getSource(): string
{
return 'kg_im_system_message';
return 'kg_im_notice';
}
public function initialize()

View File

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

View File

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

View File

@ -3,8 +3,6 @@
namespace App\Repos;
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\Resultset;
use Phalcon\Mvc\Model\ResultsetInterface;
@ -26,6 +24,10 @@ class Category extends Repository
$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'])) {
$query->andWhere('level = :level:', ['level' => $where['level']]);
}
@ -66,13 +68,16 @@ class Category extends Repository
}
/**
* @param string $type
* @return ResultsetInterface|Resultset|CategoryModel[]
*/
public function findTopCategories()
public function findTopCategories($type)
{
return CategoryModel::query()
->where('parent_id = 0')
->where('type = :type:', ['type' => $type])
->andWhere('parent_id = 0')
->andWhere('published = 1')
->orderBy('priority ASC')
->execute();
}
@ -85,6 +90,7 @@ class Category extends Repository
return CategoryModel::query()
->where('parent_id = :parent_id:', ['parent_id' => $categoryId])
->andWhere('published = 1')
->orderBy('priority ASC')
->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');
if (!empty($where['category_id'])) {
$query->andWhere('category_id = :category_id:', ['category_id' => $where['category_id']]);
}
if (!empty($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->orderBy('priority ASC');
$query->orderBy('category_id ASC,priority ASC');
return $query->execute();
}

View File

@ -4,8 +4,8 @@ namespace App\Repos;
use App\Library\Paginator\Adapter\QueryBuilder as PagerQueryBuilder;
use App\Models\ImGroup as ImGroupModel;
use App\Models\ImGroupMessage as ImGroupMessageModel;
use App\Models\ImGroupUser as ImGroupUserModel;
use App\Models\ImMessage as ImMessageModel;
use App\Models\ImUser as ImUserModel;
use Phalcon\Mvc\Model;
use Phalcon\Mvc\Model\Resultset;
@ -117,9 +117,9 @@ class ImGroup extends Repository
public function countMessages($groupId)
{
return (int)ImGroupMessageModel::count([
'conditions' => 'group_id = :group_id: AND published = 1',
'bind' => ['group_id' => $groupId],
return (int)ImMessageModel::count([
'conditions' => 'receiver_id = ?1 AND receiver_type = ?2 AND deleted = 0',
'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;
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\Resultset;
use Phalcon\Mvc\Model\ResultsetInterface;
class ImFriendMessage extends Repository
class ImMessage extends Repository
{
public function paginate($where = [], $sort = 'latest', $page = 1, $limit = 15)
{
$builder = $this->modelsManager->createBuilder();
$builder->from(ImFriendMessageModel::class);
$builder->from(ImMessageModel::class);
$builder->where('1 = 1');
@ -31,6 +31,10 @@ class ImFriendMessage extends Repository
$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'])) {
$builder->andWhere('deleted = :deleted:', ['deleted' => $where['deleted']]);
}
@ -57,21 +61,21 @@ class ImFriendMessage extends Repository
/**
* @param int $id
* @return ImFriendMessageModel|Model|bool
* @return ImMessageModel|Model|bool
*/
public function findById($id)
{
return ImFriendMessageModel::findFirst($id);
return ImMessageModel::findFirst($id);
}
/**
* @param array $ids
* @param string|array $columns
* @return ResultsetInterface|Resultset|ImFriendMessageModel[]
* @return ResultsetInterface|Resultset|ImMessageModel[]
*/
public function findByIds($ids, $columns = '*')
{
return ImFriendMessageModel::query()
return ImMessageModel::query()
->columns($columns)
->inWhere('id', $ids)
->execute();

View File

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

View File

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

View File

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

View File

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

View File

@ -2,8 +2,7 @@
namespace App\Services\Frontend\Help;
use App\Models\Help as HelpModel;
use App\Repos\Help as HelpRepo;
use App\Caches\HelpList as HelpListCache;
use App\Services\Frontend\Service as FrontendService;
class HelpList extends FrontendService
@ -11,38 +10,11 @@ class HelpList extends FrontendService
public function handle()
{
$helpRepo = new HelpRepo();
$cache = new HelpListCache();
$params = ['published' => 1];
$result = $cache->get();
$helps = $helpRepo->findAll($params);
$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;
return $result ?: [];
}
}

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;
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 Qcloud\Cos\Client as CosClient;
class Storage extends Service
{
/**
* 文件类型
*/
const TYPE_IMAGE = 'image';
const TYPE_VIDEO = 'video';
const TYPE_AUDIO = 'audio';
const TYPE_FILE = 'file';
/**
* @var array
*/
@ -43,117 +32,6 @@ class Storage extends Service
$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
* @return string|bool
*/
protected function putString($key, $body)
public function putString($key, $body)
{
$bucket = $this->settings['bucket_name'];
@ -189,16 +67,16 @@ class Storage extends Service
* 上传文件
*
* @param string $key
* @param string $fileName
* @param string $filename
* @return mixed string|bool
*/
protected function putFile($key, $fileName)
public function putFile($key, $filename)
{
$bucket = $this->settings['bucket_name'];
try {
$body = fopen($fileName, 'rb');
$body = fopen($filename, 'rb');
$response = $this->client->upload($bucket, $key, $body);
@ -224,7 +102,7 @@ class Storage extends Service
* @param string $key
* @return string|bool
*/
protected function deleteObject($key)
public function deleteObject($key)
{
$bucket = $this->settings['bucket_name'];
@ -316,43 +194,16 @@ class Storage extends Service
/**
* 获取文件扩展名
*
* @param $fileName
* @param $filename
* @return string
*/
protected function getFileExtension($fileName)
protected function getFileExtension($filename)
{
$extension = pathinfo($fileName, PATHINFO_EXTENSION);
$extension = pathinfo($filename, PATHINFO_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
*

View File

@ -68,6 +68,17 @@ class Category extends Validator
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)
{
$value = $this->filter->sanitize($name, ['trim', 'string']);

View File

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

View File

@ -55,6 +55,13 @@ class Help extends Validator
return $help;
}
public function checkCategory($id)
{
$validator = new Category();
return $validator->checkCategory($id);
}
public function checkTitle($title)
{
$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.parent_not_found'] = '父级分类不存在';
$error['category.invalid_type'] = '无效的分类类型';
$error['category.invalid_priority'] = '无效的排序值范围1-255';
$error['category.invalid_publish_status'] = '无效的发布状态';
$error['category.name_too_short'] = '名称太短少于2个字符';

View File

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

View File

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

View File

@ -23,7 +23,7 @@ layui.use(['jquery', 'layim'], function () {
socket.send('pong...');
} else if (data.type === 'bind_user') {
bindUser(data);
refreshMessageBox();
refreshMsgBox();
} else if (data.type === 'new_group_user') {
showNewGroupUserMessage(data);
} else if (data.type === 'show_online_tips') {
@ -32,13 +32,13 @@ layui.use(['jquery', 'layim'], function () {
setChatMessageCount(data);
showChatMessage(data);
} else if (data.type === 'refresh_msg_box') {
refreshMessageBox();
refreshMsgBox();
} else if (data.type === 'friend_accepted') {
friendAccepted(data);
refreshMessageBox();
refreshMsgBox();
} else if (data.type === 'group_accepted') {
groupAccepted(data);
refreshMessageBox();
refreshMsgBox();
}
};
@ -51,10 +51,10 @@ layui.use(['jquery', 'layim'], function () {
url: '/im/group/users'
},
uploadImage: {
url: '/im/img/upload'
url: '/upload/im/image'
},
uploadFile: {
url: '/im/file/upload'
url: '/upload/im/file'
},
maxLength: 1000,
find: '/im/find',
@ -151,7 +151,7 @@ layui.use(['jquery', 'layim'], function () {
if (res.data.type === 'friend' && unreadListMsgCount > 0) {
$.ajax({
type: 'GET',
url: '/im/msg/friend/unread',
url: '/im/friend/msg/unread',
data: {id: res.data.id}
});
}
@ -193,10 +193,10 @@ layui.use(['jquery', 'layim'], function () {
});
}
function refreshMessageBox() {
function refreshMsgBox() {
$.ajax({
type: 'GET',
url: '/im/msg/sys/unread',
url: '/im/sys/msg/unread',
success: function (res) {
if (res.count > 0) {
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 layer = layui.layer;
var layim = layui.layim;
var laypage = layui.laypage;
var $target = $('#LAY_view');
var $page = $('#LAY_page');
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) {
$.get('/im/msg/sys', {page: page}, function (html) {
$.get('/im/sys/msg', {page: page}, function (html) {
target.html(html);
});
}
function readSystemMessages() {
$.post('/im/msg/sys/read');
function readNotices() {
$.post('/im/sys/msg/read');
}
var action = {

View File

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

View File

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