1
0
mirror of https://gitee.com/koogua/course-tencent-cloud.git synced 2025-06-24 20:06:09 +08:00

搜索页面换成tab形式

This commit is contained in:
xiaochong0302 2020-08-16 19:33:38 +08:00
parent fddaa3573e
commit 9f5b48c307
30 changed files with 385 additions and 82 deletions

View File

@ -2,7 +2,7 @@
namespace App\Caches;
use App\Models\ImGroupMessage as ImGroupMessageModel;
use App\Models\ImMessage as ImMessageModel;
use App\Models\User as UserModel;
use App\Repos\User as UserRepo;
use Phalcon\Mvc\Model\Resultset;
@ -58,11 +58,12 @@ class ImGroupActiveUserList extends Cache
$startTime = strtotime("-{$days} days");
$endTime = time();
$rows = ImGroupMessageModel::query()
$rows = ImMessageModel::query()
->columns(['sender_id', 'total_count' => 'count(sender_id)'])
->groupBy('sender_id')
->orderBy('total_count DESC')
->where('group_id = :group_id:', ['group_id' => $groupId])
->where('receiver_id = :group_id:', ['group_id' => $groupId])
->andWhere('receiver_type = :type:', ['type' => ImMessageModel::TYPE_GROUP])
->betweenWhere('create_time', $startTime, $endTime)
->limit($limit)
->execute();

View File

@ -34,7 +34,7 @@ class SyncCourseIndexTask extends Task
{
$key = $this->getSyncKey();
$courseIds = $this->redis->sRandMember($key, 100);
$courseIds = $this->redis->sRandMember($key, 1000);
if (!$courseIds) return;

View File

@ -0,0 +1,80 @@
<?php
namespace App\Console\Tasks;
use App\Library\Cache\Backend\Redis as RedisCache;
use App\Repos\ImGroup as GroupRepo;
use App\Services\Search\GroupDocument;
use App\Services\Search\GroupSearcher;
use App\Services\Syncer\GroupIndex as GroupIndexSyncer;
class SyncGroupIndexTask extends Task
{
/**
* @var RedisCache
*/
protected $cache;
/**
* @var \Redis
*/
protected $redis;
public function mainAction()
{
$this->cache = $this->getDI()->get('cache');
$this->redis = $this->cache->getRedis();
$this->rebuild();
}
protected function rebuild()
{
$key = $this->getSyncKey();
$groupIds = $this->redis->sRandMember($key, 1000);
if (!$groupIds) return;
$groupRepo = new GroupRepo();
$groups = $groupRepo->findByIds($groupIds);
if ($groups->count() == 0) {
return;
}
$document = new GroupDocument();
$handler = new GroupSearcher();
$index = $handler->getXS()->getIndex();
$index->openBuffer();
foreach ($groups as $group) {
$doc = $document->setDocument($group);
if ($group->published == 1) {
$index->update($doc);
} else {
$index->del($group->id);
}
}
$index->closeBuffer();
$this->redis->sRem($key, ...$groupIds);
}
protected function getSyncKey()
{
$syncer = new GroupIndexSyncer();
return $syncer->getSyncKey();
}
}

View File

@ -0,0 +1,80 @@
<?php
namespace App\Console\Tasks;
use App\Library\Cache\Backend\Redis as RedisCache;
use App\Repos\User as UserRepo;
use App\Services\Search\UserDocument;
use App\Services\Search\UserSearcher;
use App\Services\Syncer\UserIndex as UserIndexSyncer;
class SyncUserIndexTask extends Task
{
/**
* @var RedisCache
*/
protected $cache;
/**
* @var \Redis
*/
protected $redis;
public function mainAction()
{
$this->cache = $this->getDI()->get('cache');
$this->redis = $this->cache->getRedis();
$this->rebuild();
}
protected function rebuild()
{
$key = $this->getSyncKey();
$userIds = $this->redis->sRandMember($key, 1000);
if (!$userIds) return;
$userRepo = new UserRepo();
$users = $userRepo->findByIds($userIds);
if ($users->count() == 0) {
return;
}
$document = new UserDocument();
$handler = new UserSearcher();
$index = $handler->getXS()->getIndex();
$index->openBuffer();
foreach ($users as $user) {
$doc = $document->setDocument($user);
if ($user->deleted == 0) {
$index->update($doc);
} else {
$index->del($user->id);
}
}
$index->closeBuffer();
$this->redis->sRem($key, ...$userIds);
}
protected function getSyncKey()
{
$syncer = new UserIndexSyncer();
return $syncer->getSyncKey();
}
}

View File

@ -2,10 +2,27 @@
{% block content %}
{% set closed_tips_display = site.status == 'normal' ? 'style="display:none;"' : '' %}
<form class="layui-form kg-form" method="POST" action="{{ url({'for':'admin.setting.site'}) }}">
<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">
<input type="radio" name="status" value="normal" title="正常" lay-filter="status" {% if site.status == "normal" %}checked{% endif %}>
<input type="radio" name="status" value="closed" title="关闭" lay-filter="status" {% if site.status == "closed" %}checked{% endif %}>
</div>
</div>
<div id="closed-tips-block" {{ closed_tips_display }}>
<div class="layui-form-item">
<label class="layui-form-label">关闭原因</label>
<div class="layui-input-block">
<textarea name="closed_tips" class="layui-textarea">{{ site.closed_tips }}</textarea>
</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">网站名称</label>
<div class="layui-input-block">
@ -79,4 +96,29 @@
</div>
</form>
{% endblock %}
{% block inline_js %}
<script>
layui.use(['jquery', 'form', 'layer'], function () {
var $ = layui.jquery;
var form = layui.form;
form.on('radio(status)', function (data) {
var block = $('#closed-tips-block');
if (data.value === 'closed') {
block.show();
} else {
block.hide();
}
});
});
</script>
{% endblock %}

View File

@ -45,6 +45,10 @@ class Controller extends \Phalcon\Mvc\Controller
public function beforeExecuteRoute(Dispatcher $dispatcher)
{
$this->site = $this->getSiteSettings();
$this->checkSiteStatus();
if ($this->isNotSafeRequest()) {
$this->checkHttpReferer();
$this->checkCsrfToken();
@ -57,16 +61,15 @@ class Controller extends \Phalcon\Mvc\Controller
public function initialize()
{
$this->navs = $this->getNavs();
$this->seo = $this->getSeo();
$this->site = $this->getSiteSettings();
$this->navs = $this->getNavs();
$this->appInfo = $this->getAppInfo();
$this->authUser = $this->getAuthUser();
$this->seo->setTitle($this->site['title']);
$this->view->setVar('seo', $this->seo);
$this->view->setVar('site', $this->site);
$this->view->setVar('seo', $this->seo);
$this->view->setVar('navs', $this->navs);
$this->view->setVar('app_info', $this->appInfo);
$this->view->setVar('auth_user', $this->authUser);
@ -114,4 +117,15 @@ class Controller extends \Phalcon\Mvc\Controller
return $config->websocket->url;
}
protected function checkSiteStatus()
{
if ($this->site['status'] == 'closed') {
$this->dispatcher->forward([
'controller' => 'error',
'action' => 'shutdown',
'params' => ['message' => $this->site['closed_tips']],
]);
}
}
}

View File

@ -67,4 +67,16 @@ class ErrorController extends \Phalcon\Mvc\Controller
$this->response->setStatusCode(503);
}
/**
* @Get("/shutdown", name="web.error.shutdown")
*/
public function shutdownAction()
{
$message = $this->dispatcher->getParam('message');
$this->response->setStatusCode(503);
$this->view->setVar('message', $message);
}
}

View File

@ -14,14 +14,6 @@ class ImController extends LayerController
use ResponseTrait;
/**
* @Get("/", name="web.im.index")
*/
public function indexAction()
{
}
/**
* @Get("/init", name="web.im.init")
*/

View File

@ -32,4 +32,11 @@ class IndexController extends Controller
}
protected function getSocketUrl()
{
$config = $this->getDI()->get('config');
return $config->websocket->url;
}
}

View File

@ -42,6 +42,14 @@ class SearchController extends Controller
$this->view->setVar('pager', $pager);
}
/**
* @Get("/form", name="web.search.form")
*/
public function formAction()
{
}
/**
* @param string $type
* @return CourseSearchService|GroupSearchService|UserSearchService

View File

@ -34,7 +34,7 @@ class Live extends Service
public function getStats($id)
{
$chapter = $this->checkChapterCache($id);
$chapter = $this->checkChapter($id);
Gateway::$registerAddress = $this->getRegisterAddress();
@ -55,7 +55,7 @@ class Live extends Service
{
$clientId = $this->request->getPost('client_id');
$chapter = $this->checkChapterCache($id);
$chapter = $this->checkChapter($id);
$user = $this->getCurrentUser();

View File

@ -1,10 +1,10 @@
{% extends 'templates/error.volt' %}
{% block content %}
<div class="layui-fluid">
<div class="kg-tips">
<i class="layui-icon layui-icon-face-surprised"></i>
<div class="message">{{ flashSession.output() }}</div>
<div class="layui-text">
<h1>
<span class="layui-anim layui-anim-loop">4</span>
@ -14,4 +14,5 @@
</div>
</div>
</div>
{% endblock %}

View File

@ -1,6 +1,7 @@
{% extends 'templates/error.volt' %}
{% block content %}
<div class="layui-fluid">
<div class="kg-tips">
<i class="layui-icon layui-icon-face-surprised"></i>
@ -13,4 +14,5 @@
</div>
</div>
</div>
{% endblock %}

View File

@ -1,6 +1,7 @@
{% extends 'templates/error.volt' %}
{% block content %}
<div class="layui-fluid">
<div class="kg-tips">
<i class="layui-icon layui-icon-face-surprised"></i>
@ -13,4 +14,5 @@
</div>
</div>
</div>
{% endblock %}

View File

@ -1,6 +1,7 @@
{% extends 'templates/error.volt' %}
{% block content %}
<div class="layui-fluid">
<div class="kg-tips">
<i class="layui-icon layui-icon-face-surprised"></i>
@ -13,4 +14,5 @@
</div>
</div>
</div>
{% endblock %}

View File

@ -1,6 +1,7 @@
{% extends 'templates/error.volt' %}
{% block content %}
<div class="layui-fluid">
<div class="kg-tips">
<i class="layui-icon layui-icon-face-surprised"></i>
@ -13,4 +14,5 @@
</div>
</div>
</div>
{% endblock %}

View File

@ -1,6 +1,7 @@
{% extends 'templates/error.volt' %}
{% block content %}
<div class="layui-fluid">
<div class="kg-tips">
<i class="layui-icon layui-icon-face-surprised"></i>
@ -13,4 +14,5 @@
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,17 @@
{% extends 'templates/error.volt' %}
{% block content %}
<div class="layui-fluid">
<div class="kg-tips">
<i class="layui-icon layui-icon-face-surprised"></i>
<div class="message">{{ message }}</div>
<div class="layui-text">
<h1>
<span class="layui-anim layui-anim-loop">5</span>
<span class="layui-anim layui-anim-loop layui-anim-rotate">0</span>
<span class="layui-anim layui-anim-loop">3</span>
</h1>
</div>
</div>
</div>
{% endblock %}

View File

@ -17,16 +17,17 @@
</ul>
</div>
{% set query = request.get('query',['trim','striptags'],'') %}
{% set type = request.get('type',['trim','string'],'course') %}
{% set s_type = request.get('type',['trim','string'],'course') %}
{% set s_query = request.get('query',['trim','striptags'],'') %}
{% set s_url = url({'for':'web.search.index'}) %}
<div class="user layui-layout-right">
<ul class="layui-nav">
<li class="layui-nav-item">
<a href="javascript:" class="kg-search" data-type="{{ type }}" data-query="{{ query }}"><i class="layui-icon layui-icon-search"></i> 搜索</a>
<a href="javascript:" class="kg-search" data-type="{{ s_type }}" data-query="{{ s_query }}" data-url="{{ s_url }}"><i class="layui-icon layui-icon-search"></i> 搜索</a>
</li>
<li class="layui-nav-item">
<a href="{{ url({'for':'web.im'}) }}" target="im">微聊<span class="layui-badge-dot"></span></a>
<a href="{{ url({'for':'web.im.index'}) }}" target="im">微聊<span class="layui-badge-dot"></span></a>
</li>
{% if auth_user.id > 0 %}
<li class="layui-nav-item">

View File

@ -8,7 +8,9 @@
locked: '{{ auth_user.locked }}',
vip: '{{ auth_user.vip }}'
},
socketUrl: '{{ socket_url }}'
im: {
socket_url: '{{ im.socket_url }}'
}
};
</script>

View File

@ -1,10 +1,11 @@
<div class="search-course-list">
{% for item in pager.items %}
{% set course_url = url({'for':'web.course.show','id':item.id}) %}
{% set teacher_url = url({'for':'web.teacher.show','id':item.teacher.id}) %}
<div class="search-course-card clearfix">
<div class="cover">
<a href="{{ course_url }}">
<img src="{{ item.cover }}!cover_270" alt="{{ item.title|e }}">
<img src="{{ item.cover }}!cover_270" alt="{{ item.title }}">
</a>
</div>
<div class="info">
@ -13,8 +14,7 @@
</div>
<div class="summary">{{ item.summary }}</div>
<div class="meta">
<span>分类:{{ item.category.name }}</span>
<span>讲师:{{ item.teacher.name }}</span>
<span>讲师:<a href="{{ teacher_url }}">{{ item.teacher.name }}</a></span>
<span>难度:{{ level_info(item.level) }}</span>
<span>课时:{{ item.lesson_count }}</span>
<span>学员:{{ item.user_count }}</span>

View File

@ -1,6 +1,7 @@
<div class="search-group-list">
{% for item in pager.items %}
{% set group_url = url({'for':'web.im_group.show','id':item.id}) %}
{% set owner_url = url({'for':'web.user.show','id':item.onwer.id}) %}
{% set item.about = item.about ? item.about : '这个家伙真懒,什么也没有留下!' %}
<div class="search-group-card clearfix">
<div class="avatar">
@ -14,8 +15,8 @@
</div>
<div class="about layui-elip">{{ item.about }}</div>
<div class="meta">
<span>组长:{{ item.owner.name }}</span>
<span>员:{{ item.user_count }}</span>
<span>组长:<a href="{{ owner_url }}">{{ item.owner.name }}</a></span>
<span>员:{{ item.user_count }}</span>
</div>
</div>
</div>

View File

@ -14,25 +14,36 @@
<a><cite>{{ query }}</cite></a>
</div>
{% set tab_show = type %}
<div class="layout-main clearfix">
<div class="layout-content">
<div class="search-tab wrap">
{% for key,value in types %}
{% set class = (type == key) ? 'layui-btn layui-btn-xs' : 'none' %}
{% set url = url({'for':'web.search.index'},{'type':key,'query':query}) %}
<a class="{{ class }}" href="{{ url }}">{{ value }}</a>
{% endfor %}
<div class="search-tab-wrap wrap">
<div class="layui-tab layui-tab-brief search-tab">
<ul class="layui-tab-title">
{% for key,value in types %}
{% set class = (type == key) ? 'layui-this' : 'none' %}
{% set url = url({'for':'web.search.index'},{'type':key,'query':query}) %}
<li class="{{ class }}"><a href="{{ url }}">{{ value }}</a></li>
{% endfor %}
</ul>
<div class="layui-tab-content">
{% if type == 'course' %}
<div class="layui-tab-item layui-show">
{{ partial('search/course') }}
</div>
{% elseif type == 'group' %}
<div class="layui-tab-item layui-show">
{{ partial('search/group') }}
</div>
{% elseif type == 'user' %}
<div class="layui-tab-item layui-show">
{{ partial('search/user') }}
</div>
{% endif %}
</div>
</div>
</div>
{% if pager.total_pages > 0 %}
<div class="wrap">
{% if type == 'course' %}
{{ partial('search/course') }}
{% elseif type == 'group' %}
{{ partial('search/group') }}
{% elseif type == 'user' %}
{{ partial('search/user') }}
{% endif %}
</div>
{{ partial('partials/pager') }}
{% else %}
<div class="search-empty wrap">

View File

@ -1,6 +0,0 @@
<div class="search-other-list">
</div>
<div class="pager">
{{ partial('partials/pager') }}
</div>

View File

@ -3,7 +3,8 @@
<div class="layui-card-header">热门搜索</div>
<div class="layui-card-body">
{% for query in hot_queries %}
<a class="layui-badge-rim query-badge" href="{{ url({'for':'web.search.index'},{'query':query}) }}">{{ query }}</a>
{% set url = url({'for':'web.search.index'},{'type':type,'query':query}) %}
<a class="layui-badge-rim query-badge" href="{{ url }}">{{ query }}</a>
{% endfor %}
</div>
</div>
@ -14,7 +15,8 @@
<div class="layui-card-header">相关搜索</div>
<div class="layui-card-body">
{% for query in related_queries %}
<a class="layui-badge-rim query-badge" href="{{ url({'for':'web.search.index'},{'query':query}) }}">{{ query }}</a>
{% set url = url({'for':'web.search.index'},{'type':type,'query':query}) %}
<a class="layui-badge-rim query-badge" href="{{ url }}">{{ query }}</a>
{% endfor %}
</div>
</div>

View File

@ -22,7 +22,6 @@ type = body
[location]
type = string
index = self
tokenizer = full
[gender]
type = string

View File

@ -22,7 +22,6 @@ type = body
[location]
type = string
index = self
tokenizer = full
[gender]
type = string

View File

@ -129,27 +129,14 @@ body {
margin-left: 100px;
}
.top-nav .im {
}
.im .layui-icon-chat {
}
.search {
position: absolute;
top: 15px;
right: 240px;
width: 250px;
}
.search .layui-input {
border: none;
height: 30px;
font-size: 12px;
color: rgba(255, 255, 255, 0.5);
background-color: rgba(255, 255, 255, 0.05);
.layer-search input {
height: 75px;
line-height: 75px;
width: 500px;
padding: 0 15px;
font-size: 18px;
border: none 0;
background: none;
}
#footer span, #footer a {
@ -246,12 +233,15 @@ body {
}
.search-tab {
padding: 10px 20px;
margin: 0;
}
.search-tab a {
min-width: 50px;
margin-right: 30px;
.search-tab .layui-tab-title {
margin-bottom: 10px;
}
.search-tab .layui-tab-content {
padding: 10px 0;
}
.search-empty {
@ -302,7 +292,7 @@ body {
height: 100%;
}
.search-course-card .info, .search-group-card .info {
.search-course-card .info {
float: left;
width: 500px;
}
@ -346,6 +336,11 @@ body {
border-radius: 100%;
}
.search-group-card .info {
float: left;
width: 600px;
}
.search-group-card .about {
margin-bottom: 10px;
line-height: 1.5em;
@ -1248,12 +1243,13 @@ body {
}
.user-tab .layui-tab-title {
margin-bottom: 10px;
text-align: center;
border-bottom: none;
}
.user-tab .layui-tab-content {
padding: 20px 0 0 0;
padding: 10px 0;
}
.user-tab .loading {

View File

@ -1,16 +1,23 @@
html {
background-color: #f2f2f2;
}
.kg-tips {
margin-top: 30px;
width: 500px;
margin: 0 auto;
text-align: center;
}
.kg-tips .layui-icon-face-surprised {
display: inline-block;
margin-top: 20px;
font-size: 200px;
color: #393D49;
}
.kg-tips .message {
margin-top: 30px;
margin-top: 20px;
color: #666;
}
.kg-tips .layui-text {

View File

@ -105,6 +105,33 @@ layui.use(['jquery', 'form', 'element', 'layer', 'helper'], function () {
});
});
$('.kg-search').on('click', function () {
var content = '<form action="' + $(this).data('url') + '">';
content += '<input type="text" name="query" autocomplete="off" placeholder="搜索内容,回车跳转">';
content += '<input type="hidden" name="type" value="' + $(this).data('type') + '">';
content += '</form>';
layer.open({
type: 1,
title: false,
closeBtn: false,
shadeClose: true,
offset: '120px',
maxWidth: 10000,
skin: 'layer-search',
content: content,
success: function (dom) {
var form = dom.find('form');
var query = dom.find('input[name=query]');
query.focus();
$(form).submit(function () {
if (query.val().replace(/\s/g, '') === '') {
return false;
}
});
}
});
});
$('.kg-back').on('click', function () {
window.history.back();
});