mirror of
https://gitee.com/koogua/course-tencent-cloud.git
synced 2025-06-25 04:07:17 +08:00
增加了群组和用户的全文搜索
This commit is contained in:
parent
3c2cc976b6
commit
fddaa3573e
@ -42,13 +42,13 @@ class HelpList extends Cache
|
||||
'name' => $category->name,
|
||||
];
|
||||
|
||||
$item['list'] = [];
|
||||
$item['helps'] = [];
|
||||
|
||||
$helps = $this->findHelps($category->id);
|
||||
|
||||
if ($helps->count() > 0) {
|
||||
foreach ($helps as $help) {
|
||||
$item['list'][] = [
|
||||
$item['helps'][] = [
|
||||
'id' => $help->id,
|
||||
'title' => $help->title,
|
||||
];
|
||||
|
@ -28,8 +28,6 @@ class IndexFreeCourseList extends Cache
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$result = [];
|
||||
|
||||
$categoryLimit = 5;
|
||||
|
||||
$courseLimit = 10;
|
||||
@ -40,13 +38,19 @@ class IndexFreeCourseList extends Cache
|
||||
return [];
|
||||
}
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($categories as $category) {
|
||||
|
||||
$categoryItem = [
|
||||
$item = [];
|
||||
|
||||
$item['category'] = [
|
||||
'id' => $category->id,
|
||||
'name' => $category->name,
|
||||
];
|
||||
|
||||
$item['courses'] = [];
|
||||
|
||||
$courses = $this->findCategoryCourses($category->id, $courseLimit);
|
||||
|
||||
if ($courses->count() == 0) {
|
||||
@ -69,9 +73,9 @@ class IndexFreeCourseList extends Cache
|
||||
];
|
||||
}
|
||||
|
||||
$categoryItem['courses'] = $categoryCourses;
|
||||
$item['courses'] = $categoryCourses;
|
||||
|
||||
$result[] = $categoryItem;
|
||||
$result[] = $item;
|
||||
}
|
||||
|
||||
return $result;
|
||||
|
@ -28,8 +28,6 @@ class IndexNewCourseList extends Cache
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$result = [];
|
||||
|
||||
$categoryLimit = 5;
|
||||
|
||||
$courseLimit = 10;
|
||||
@ -40,13 +38,19 @@ class IndexNewCourseList extends Cache
|
||||
return [];
|
||||
}
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($categories as $category) {
|
||||
|
||||
$categoryItem = [
|
||||
$item = [];
|
||||
|
||||
$item['category'] = [
|
||||
'id' => $category->id,
|
||||
'name' => $category->name,
|
||||
];
|
||||
|
||||
$item['courses'] = [];
|
||||
|
||||
$courses = $this->findCategoryCourses($category->id, $courseLimit);
|
||||
|
||||
if ($courses->count() == 0) {
|
||||
@ -69,9 +73,9 @@ class IndexNewCourseList extends Cache
|
||||
];
|
||||
}
|
||||
|
||||
$categoryItem['courses'] = $categoryCourses;
|
||||
$item['courses'] = $categoryCourses;
|
||||
|
||||
$result[] = $categoryItem;
|
||||
$result[] = $item;
|
||||
}
|
||||
|
||||
return $result;
|
||||
|
@ -28,8 +28,6 @@ class IndexVipCourseList extends Cache
|
||||
|
||||
public function getContent($id = null)
|
||||
{
|
||||
$result = [];
|
||||
|
||||
$categoryLimit = 5;
|
||||
|
||||
$courseLimit = 10;
|
||||
@ -40,13 +38,19 @@ class IndexVipCourseList extends Cache
|
||||
return [];
|
||||
}
|
||||
|
||||
$result = [];
|
||||
|
||||
foreach ($categories as $category) {
|
||||
|
||||
$categoryItem = [
|
||||
$item = [];
|
||||
|
||||
$item['category'] = [
|
||||
'id' => $category->id,
|
||||
'name' => $category->name,
|
||||
];
|
||||
|
||||
$item['courses'] = [];
|
||||
|
||||
$courses = $this->findCategoryCourses($category->id, $courseLimit);
|
||||
|
||||
if ($courses->count() == 0) {
|
||||
@ -69,9 +73,9 @@ class IndexVipCourseList extends Cache
|
||||
];
|
||||
}
|
||||
|
||||
$categoryItem['courses'] = $categoryCourses;
|
||||
$item['courses'] = $categoryCourses;
|
||||
|
||||
$result[] = $categoryItem;
|
||||
$result[] = $item;
|
||||
}
|
||||
|
||||
return $result;
|
||||
|
128
app/Console/Tasks/GroupIndexTask.php
Normal file
128
app/Console/Tasks/GroupIndexTask.php
Normal file
@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Tasks;
|
||||
|
||||
use App\Models\ImGroup as GroupModel;
|
||||
use App\Services\Search\GroupDocument;
|
||||
use App\Services\Search\GroupSearcher;
|
||||
use Phalcon\Cli\Task;
|
||||
use Phalcon\Mvc\Model\Resultset;
|
||||
use Phalcon\Mvc\Model\ResultsetInterface;
|
||||
|
||||
class GroupIndexTask extends Task
|
||||
{
|
||||
|
||||
/**
|
||||
* 搜索测试
|
||||
*
|
||||
* @command: php console.php group_index search {query}
|
||||
* @param array $params
|
||||
* @throws \XSException
|
||||
*/
|
||||
public function searchAction($params)
|
||||
{
|
||||
$query = $params[0] ?? null;
|
||||
|
||||
if (!$query) {
|
||||
exit("please special a query word" . PHP_EOL);
|
||||
}
|
||||
|
||||
$result = $this->searchGroups($query);
|
||||
|
||||
var_export($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空索引
|
||||
*
|
||||
* @command: php console.php group_index clean
|
||||
*/
|
||||
public function cleanAction()
|
||||
{
|
||||
$this->cleanGroupIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
* 重建索引
|
||||
*
|
||||
* @command: php console.php group_index rebuild
|
||||
*/
|
||||
public function rebuildAction()
|
||||
{
|
||||
$this->rebuildGroupIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空索引
|
||||
*/
|
||||
protected function cleanGroupIndex()
|
||||
{
|
||||
$handler = new GroupSearcher();
|
||||
|
||||
$index = $handler->getXS()->getIndex();
|
||||
|
||||
echo "start clean index" . PHP_EOL;
|
||||
|
||||
$index->clean();
|
||||
|
||||
echo "end clean index" . PHP_EOL;
|
||||
}
|
||||
|
||||
/**
|
||||
* 重建索引
|
||||
*/
|
||||
protected function rebuildGroupIndex()
|
||||
{
|
||||
$groups = $this->findGroups();
|
||||
|
||||
if ($groups->count() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$handler = new GroupSearcher();
|
||||
|
||||
$documenter = new GroupDocument();
|
||||
|
||||
$index = $handler->getXS()->getIndex();
|
||||
|
||||
echo "start rebuild index" . PHP_EOL;
|
||||
|
||||
$index->beginRebuild();
|
||||
|
||||
foreach ($groups as $group) {
|
||||
$document = $documenter->setDocument($group);
|
||||
$index->add($document);
|
||||
}
|
||||
|
||||
$index->endRebuild();
|
||||
|
||||
echo "end rebuild index" . PHP_EOL;
|
||||
}
|
||||
|
||||
/**
|
||||
* 搜索课程
|
||||
*
|
||||
* @param string $query
|
||||
* @return array
|
||||
* @throws \XSException
|
||||
*/
|
||||
protected function searchGroups($query)
|
||||
{
|
||||
$handler = new GroupSearcher();
|
||||
|
||||
return $handler->search($query);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找课程
|
||||
*
|
||||
* @return ResultsetInterface|Resultset|GroupModel[]
|
||||
*/
|
||||
protected function findGroups()
|
||||
{
|
||||
return GroupModel::query()
|
||||
->where('published = 1')
|
||||
->execute();
|
||||
}
|
||||
|
||||
}
|
128
app/Console/Tasks/UserIndexTask.php
Normal file
128
app/Console/Tasks/UserIndexTask.php
Normal file
@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Tasks;
|
||||
|
||||
use App\Models\User as UserModel;
|
||||
use App\Services\Search\UserDocument;
|
||||
use App\Services\Search\UserSearcher;
|
||||
use Phalcon\Cli\Task;
|
||||
use Phalcon\Mvc\Model\Resultset;
|
||||
use Phalcon\Mvc\Model\ResultsetInterface;
|
||||
|
||||
class UserIndexTask extends Task
|
||||
{
|
||||
|
||||
/**
|
||||
* 搜索测试
|
||||
*
|
||||
* @command: php console.php user_index search {query}
|
||||
* @param array $params
|
||||
* @throws \XSException
|
||||
*/
|
||||
public function searchAction($params)
|
||||
{
|
||||
$query = $params[0] ?? null;
|
||||
|
||||
if (!$query) {
|
||||
exit("please special a query word" . PHP_EOL);
|
||||
}
|
||||
|
||||
$result = $this->searchUsers($query);
|
||||
|
||||
var_export($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空索引
|
||||
*
|
||||
* @command: php console.php user_index clean
|
||||
*/
|
||||
public function cleanAction()
|
||||
{
|
||||
$this->cleanUserIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
* 重建索引
|
||||
*
|
||||
* @command: php console.php user_index rebuild
|
||||
*/
|
||||
public function rebuildAction()
|
||||
{
|
||||
$this->rebuildUserIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空索引
|
||||
*/
|
||||
protected function cleanUserIndex()
|
||||
{
|
||||
$handler = new UserSearcher();
|
||||
|
||||
$index = $handler->getXS()->getIndex();
|
||||
|
||||
echo "start clean index" . PHP_EOL;
|
||||
|
||||
$index->clean();
|
||||
|
||||
echo "end clean index" . PHP_EOL;
|
||||
}
|
||||
|
||||
/**
|
||||
* 重建索引
|
||||
*/
|
||||
protected function rebuildUserIndex()
|
||||
{
|
||||
$users = $this->findUsers();
|
||||
|
||||
if ($users->count() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$handler = new UserSearcher();
|
||||
|
||||
$documenter = new UserDocument();
|
||||
|
||||
$index = $handler->getXS()->getIndex();
|
||||
|
||||
echo "start rebuild index" . PHP_EOL;
|
||||
|
||||
$index->beginRebuild();
|
||||
|
||||
foreach ($users as $user) {
|
||||
$document = $documenter->setDocument($user);
|
||||
$index->add($document);
|
||||
}
|
||||
|
||||
$index->endRebuild();
|
||||
|
||||
echo "end rebuild index" . PHP_EOL;
|
||||
}
|
||||
|
||||
/**
|
||||
* 搜索课程
|
||||
*
|
||||
* @param string $query
|
||||
* @return array
|
||||
* @throws \XSException
|
||||
*/
|
||||
protected function searchUsers($query)
|
||||
{
|
||||
$handler = new UserSearcher();
|
||||
|
||||
return $handler->search($query);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找课程
|
||||
*
|
||||
* @return ResultsetInterface|Resultset|UserModel[]
|
||||
*/
|
||||
protected function findUsers()
|
||||
{
|
||||
return UserModel::query()
|
||||
->where('deleted = 0')
|
||||
->execute();
|
||||
}
|
||||
|
||||
}
|
@ -18,11 +18,11 @@ class HelpController extends Controller
|
||||
{
|
||||
$service = new HelpListService();
|
||||
|
||||
$helps = $service->handle();
|
||||
$items = $service->handle();
|
||||
|
||||
$this->seo->prependTitle('帮助');
|
||||
|
||||
$this->view->setVar('helps', $helps);
|
||||
$this->view->setVar('items', $items);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2,9 +2,9 @@
|
||||
|
||||
namespace App\Http\Web\Controllers;
|
||||
|
||||
use App\Services\Frontend\Search\CourseHotQuery as CourseHotQueryService;
|
||||
use App\Services\Frontend\Search\CourseList as CourseListService;
|
||||
use App\Services\Frontend\Search\CourseRelatedQuery as CourseRelatedQueryService;
|
||||
use App\Services\Frontend\Search\Course as CourseSearchService;
|
||||
use App\Services\Frontend\Search\Group as GroupSearchService;
|
||||
use App\Services\Frontend\Search\User as UserSearchService;
|
||||
use App\Traits\Response as ResponseTrait;
|
||||
|
||||
/**
|
||||
@ -20,7 +20,8 @@ class SearchController extends Controller
|
||||
*/
|
||||
public function indexAction()
|
||||
{
|
||||
$query = $this->request->get('query', ['trim']);
|
||||
$query = $this->request->get('query', ['trim', 'string']);
|
||||
$type = $this->request->get('type', ['trim'], 'course');
|
||||
|
||||
if (empty($query)) {
|
||||
return $this->response->redirect(['for' => 'web.course.list']);
|
||||
@ -28,21 +29,38 @@ class SearchController extends Controller
|
||||
|
||||
$this->seo->prependTitle(['搜索', $query]);
|
||||
|
||||
$service = new CourseHotQueryService();
|
||||
$service = $this->getSearchService($type);
|
||||
|
||||
$hotQueries = $service->handle();
|
||||
$hotQueries = $service->hotQuery();
|
||||
|
||||
$service = new CourseRelatedQueryService();
|
||||
$relatedQueries = $service->relatedQuery($query);
|
||||
|
||||
$relatedQueries = $service->handle($query);
|
||||
|
||||
$service = new CourseListService();
|
||||
|
||||
$pager = $service->handle();
|
||||
$pager = $service->search();
|
||||
|
||||
$this->view->setVar('hot_queries', $hotQueries);
|
||||
$this->view->setVar('related_queries', $relatedQueries);
|
||||
$this->view->setVar('pager', $pager);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
* @return CourseSearchService|GroupSearchService|UserSearchService
|
||||
*/
|
||||
protected function getSearchService($type)
|
||||
{
|
||||
switch ($type) {
|
||||
case 'group':
|
||||
$service = new GroupSearchService;
|
||||
break;
|
||||
case 'user':
|
||||
$service = new UserSearchService();
|
||||
break;
|
||||
default:
|
||||
$service = new CourseSearchService();
|
||||
break;
|
||||
}
|
||||
|
||||
return $service;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -13,12 +13,12 @@
|
||||
<div class="layout-content">
|
||||
<div class="wrap">
|
||||
<div class="layui-collapse">
|
||||
{% for item in helps %}
|
||||
{% for item in items %}
|
||||
<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 %}
|
||||
{% for help in item.helps %}
|
||||
<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>
|
||||
|
@ -4,21 +4,21 @@
|
||||
|
||||
{{ partial('macros/course') }}
|
||||
|
||||
{%- macro category_courses(courses) %}
|
||||
{%- macro category_courses(items) %}
|
||||
<div class="layui-tab layui-tab-brief">
|
||||
<ul class="layui-tab-title">
|
||||
{% for category in courses %}
|
||||
{% for item in items %}
|
||||
{% set class = loop.first ? 'layui-this' : 'none' %}
|
||||
<li class="{{ class }}">{{ category.name }}</li>
|
||||
<li class="{{ class }}">{{ item.category.name }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<div class="layui-tab-content">
|
||||
{% for category in courses %}
|
||||
{% for item in items %}
|
||||
{% set class = loop.first ? 'layui-tab-item layui-show' : 'layui-tab-item' %}
|
||||
<div class="{{ class }}">
|
||||
<div class="index-course-list clearfix">
|
||||
<div class="layui-row layui-col-space20">
|
||||
{% for course in category.courses %}
|
||||
{% for course in item.courses %}
|
||||
<div class="layui-col-md3">
|
||||
{{ course_card(course) }}
|
||||
</div>
|
||||
|
@ -17,20 +17,18 @@
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{% set query = request.get('query','striptags','') %}
|
||||
|
||||
<div class="search">
|
||||
<form class="layui-form" action="{{ url({'for':'web.search.index'}) }}">
|
||||
<input class="layui-input" type="text" name="query" maxlength="30" autocomplete="off" placeholder="请输入课程关键字..." value="{{ query }}">
|
||||
</form>
|
||||
</div>
|
||||
{% set query = request.get('query',['trim','striptags'],'') %}
|
||||
{% set type = request.get('type',['trim','string'],'course') %}
|
||||
|
||||
<div class="user layui-layout-right">
|
||||
{% if auth_user.id > 0 %}
|
||||
<ul class="layui-nav">
|
||||
<li class="layui-nav-item">
|
||||
<a href="{{ url({'for':'web.im'}) }}" target="im">微聊<span class="layui-badge-dot"></span></a>
|
||||
</li>
|
||||
<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>
|
||||
</li>
|
||||
<li class="layui-nav-item">
|
||||
<a href="{{ url({'for':'web.im'}) }}" target="im">微聊<span class="layui-badge-dot"></span></a>
|
||||
</li>
|
||||
{% if auth_user.id > 0 %}
|
||||
<li class="layui-nav-item">
|
||||
<a href="javascript:">{{ auth_user.name }}</a>
|
||||
<dl class="layui-nav-child">
|
||||
@ -42,11 +40,9 @@
|
||||
<dd><a href="{{ url({'for':'web.account.logout'}) }}">退出登录</a></dd>
|
||||
</dl>
|
||||
</li>
|
||||
</ul>
|
||||
{% else %}
|
||||
<ul class="layui-nav">
|
||||
{% else %}
|
||||
<li class="layui-nav-item"><a href="{{ url({'for':'web.account.login'}) }}">登录</a></li>
|
||||
<li class="layui-nav-item"><a href="{{ url({'for':'web.account.register'}) }}">注册</a></li>
|
||||
</ul>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
23
app/Http/Web/Views/search/group.volt
Normal file
23
app/Http/Web/Views/search/group.volt
Normal file
@ -0,0 +1,23 @@
|
||||
<div class="search-group-list">
|
||||
{% for item in pager.items %}
|
||||
{% set group_url = url({'for':'web.im_group.show','id':item.id}) %}
|
||||
{% set item.about = item.about ? item.about : '这个家伙真懒,什么也没有留下!' %}
|
||||
<div class="search-group-card clearfix">
|
||||
<div class="avatar">
|
||||
<a href="{{ group_url }}">
|
||||
<img src="{{ item.avatar }}" alt="{{ item.name }}">
|
||||
</a>
|
||||
</div>
|
||||
<div class="info">
|
||||
<div class="name layui-elip">
|
||||
<a href="{{ group_url }}">{{ item.name }}</a>
|
||||
</div>
|
||||
<div class="about layui-elip">{{ item.about }}</div>
|
||||
<div class="meta">
|
||||
<span>组长:{{ item.owner.name }}</span>
|
||||
<span>组员:{{ item.user_count }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
@ -2,11 +2,12 @@
|
||||
|
||||
{% block content %}
|
||||
|
||||
{{ partial('macros/course') }}
|
||||
|
||||
{% set types = {'course':'课程','group':'群组','user':'用户'} %}
|
||||
{% set type = request.get('type','trim','course') %}
|
||||
{% set query = request.get('query','striptags','') %}
|
||||
|
||||
{{ partial('macros/course') }}
|
||||
|
||||
<div class="layui-breadcrumb breadcrumb">
|
||||
<a href="/">首页</a>
|
||||
<a href="#">搜索</a>
|
||||
@ -15,12 +16,21 @@
|
||||
|
||||
<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>
|
||||
{% if pager.total_pages > 0 %}
|
||||
<div class="wrap">
|
||||
{% if type == 'course' %}
|
||||
{{ partial('search/course') }}
|
||||
{% elseif type == 'other' %}
|
||||
{{ partial('search/other') }}
|
||||
{% elseif type == 'group' %}
|
||||
{{ partial('search/group') }}
|
||||
{% elseif type == 'user' %}
|
||||
{{ partial('search/user') }}
|
||||
{% endif %}
|
||||
</div>
|
||||
{{ partial('partials/pager') }}
|
||||
|
33
app/Http/Web/Views/search/user.volt
Normal file
33
app/Http/Web/Views/search/user.volt
Normal file
@ -0,0 +1,33 @@
|
||||
{%- macro gender_info(gender) %}
|
||||
{% if gender == 1 %}
|
||||
男
|
||||
{% elseif gender == 2 %}
|
||||
女
|
||||
{% else %}
|
||||
保密
|
||||
{% endif %}
|
||||
{%- endmacro %}
|
||||
|
||||
<div class="search-user-list">
|
||||
{% for item in pager.items %}
|
||||
{% set user_url = url({'for':'web.user.show','id':item.id}) %}
|
||||
{% set item.about = item.about ? item.about : '这个家伙真懒,什么也没有留下!' %}
|
||||
<div class="search-group-card clearfix">
|
||||
<div class="avatar">
|
||||
<a href="{{ user_url }}">
|
||||
<img src="{{ item.avatar }}" alt="{{ item.name }}">
|
||||
</a>
|
||||
</div>
|
||||
<div class="info">
|
||||
<div class="name layui-elip">
|
||||
<a href="{{ user_url }}">{{ item.name }}</a>
|
||||
</div>
|
||||
<div class="about layui-elip">{{ item.about }}</div>
|
||||
<div class="meta">
|
||||
<span>性别:{{ gender_info(item.gender) }}</span>
|
||||
<span>地区:{{ item.location }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
82
app/Services/Frontend/Search/Course.php
Normal file
82
app/Services/Frontend/Search/Course.php
Normal file
@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Frontend\Search;
|
||||
|
||||
use App\Library\Paginator\Adapter\XunSearch as XunSearchPaginator;
|
||||
use App\Library\Paginator\Query as PagerQuery;
|
||||
use App\Services\Frontend\Service as FrontendService;
|
||||
use App\Services\Search\CourseSearcher as CourseSearcherService;
|
||||
|
||||
class Course extends FrontendService
|
||||
{
|
||||
|
||||
public function search()
|
||||
{
|
||||
$pagerQuery = new PagerQuery();
|
||||
|
||||
$params = $pagerQuery->getParams();
|
||||
$page = $pagerQuery->getPage();
|
||||
$limit = $pagerQuery->getLimit();
|
||||
|
||||
$searcher = new CourseSearcherService();
|
||||
|
||||
$paginator = new XunSearchPaginator([
|
||||
'xs' => $searcher->getXS(),
|
||||
'highlight' => $searcher->getHighlightFields(),
|
||||
'query' => $params['query'],
|
||||
'page' => $page,
|
||||
'limit' => $limit,
|
||||
]);
|
||||
|
||||
$pager = $paginator->getPaginate();
|
||||
|
||||
return $this->handleCourses($pager);
|
||||
}
|
||||
|
||||
public function hotQuery($limit = 10, $type = 'total')
|
||||
{
|
||||
$searcher = new CourseSearcherService();
|
||||
|
||||
return $searcher->getHotQuery($limit, $type);
|
||||
}
|
||||
|
||||
public function relatedQuery($query, $limit = 10)
|
||||
{
|
||||
$searcher = new CourseSearcherService();
|
||||
|
||||
return $searcher->getRelatedQuery($query, $limit);
|
||||
}
|
||||
|
||||
protected function handleCourses($pager)
|
||||
{
|
||||
if ($pager->total_items == 0) {
|
||||
return $pager;
|
||||
}
|
||||
|
||||
$items = [];
|
||||
|
||||
foreach ($pager->items as $item) {
|
||||
$items[] = [
|
||||
'id' => (int)$item['id'],
|
||||
'title' => $item['title'],
|
||||
'cover' => $item['cover'],
|
||||
'summary' => $item['summary'],
|
||||
'model' => $item['model'],
|
||||
'level' => $item['level'],
|
||||
'market_price' => (float)$item['market_price'],
|
||||
'vip_price' => (float)$item['vip_price'],
|
||||
'user_count' => (int)$item['user_count'],
|
||||
'lesson_count' => (int)$item['lesson_count'],
|
||||
'review_count' => (int)$item['review_count'],
|
||||
'favorite_count' => (int)$item['favorite_count'],
|
||||
'teacher' => json_decode($item['teacher'], true),
|
||||
'category' => json_decode($item['category'], true),
|
||||
];
|
||||
}
|
||||
|
||||
$pager->items = $items;
|
||||
|
||||
return $pager;
|
||||
}
|
||||
|
||||
}
|
75
app/Services/Frontend/Search/Group.php
Normal file
75
app/Services/Frontend/Search/Group.php
Normal file
@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Frontend\Search;
|
||||
|
||||
use App\Library\Paginator\Adapter\XunSearch as XunSearchPaginator;
|
||||
use App\Library\Paginator\Query as PagerQuery;
|
||||
use App\Services\Frontend\Service as FrontendService;
|
||||
use App\Services\Search\GroupSearcher as GroupSearcherService;
|
||||
|
||||
class Group extends FrontendService
|
||||
{
|
||||
|
||||
public function search()
|
||||
{
|
||||
$pagerQuery = new PagerQuery();
|
||||
|
||||
$params = $pagerQuery->getParams();
|
||||
$page = $pagerQuery->getPage();
|
||||
$limit = $pagerQuery->getLimit();
|
||||
|
||||
$searcher = new GroupSearcherService();
|
||||
|
||||
$paginator = new XunSearchPaginator([
|
||||
'xs' => $searcher->getXS(),
|
||||
'highlight' => $searcher->getHighlightFields(),
|
||||
'query' => $params['query'],
|
||||
'page' => $page,
|
||||
'limit' => $limit,
|
||||
]);
|
||||
|
||||
$pager = $paginator->getPaginate();
|
||||
|
||||
return $this->handleGroups($pager);
|
||||
}
|
||||
|
||||
public function hotQuery($limit = 10, $type = 'total')
|
||||
{
|
||||
$searcher = new GroupSearcherService();
|
||||
|
||||
return $searcher->getHotQuery($limit, $type);
|
||||
}
|
||||
|
||||
public function relatedQuery($query, $limit = 10)
|
||||
{
|
||||
$searcher = new GroupSearcherService();
|
||||
|
||||
return $searcher->getRelatedQuery($query, $limit);
|
||||
}
|
||||
|
||||
protected function handleGroups($pager)
|
||||
{
|
||||
if ($pager->total_items == 0) {
|
||||
return $pager;
|
||||
}
|
||||
|
||||
$items = [];
|
||||
|
||||
foreach ($pager->items as $item) {
|
||||
$items[] = [
|
||||
'id' => (int)$item['id'],
|
||||
'type' => $item['type'],
|
||||
'name' => $item['name'],
|
||||
'avatar' => $item['avatar'],
|
||||
'about' => $item['about'],
|
||||
'user_count' => (int)$item['user_count'],
|
||||
'owner' => json_decode($item['owner'], true),
|
||||
];
|
||||
}
|
||||
|
||||
$pager->items = $items;
|
||||
|
||||
return $pager;
|
||||
}
|
||||
|
||||
}
|
76
app/Services/Frontend/Search/User.php
Normal file
76
app/Services/Frontend/Search/User.php
Normal file
@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Frontend\Search;
|
||||
|
||||
use App\Library\Paginator\Adapter\XunSearch as XunSearchPaginator;
|
||||
use App\Library\Paginator\Query as PagerQuery;
|
||||
use App\Services\Frontend\Service as FrontendService;
|
||||
use App\Services\Search\UserSearcher as UserSearcherService;
|
||||
|
||||
class User extends FrontendService
|
||||
{
|
||||
|
||||
public function search()
|
||||
{
|
||||
$pagerQuery = new PagerQuery();
|
||||
|
||||
$params = $pagerQuery->getParams();
|
||||
$page = $pagerQuery->getPage();
|
||||
$limit = $pagerQuery->getLimit();
|
||||
|
||||
$searcher = new UserSearcherService();
|
||||
|
||||
$paginator = new XunSearchPaginator([
|
||||
'xs' => $searcher->getXS(),
|
||||
'highlight' => $searcher->getHighlightFields(),
|
||||
'query' => $params['query'],
|
||||
'page' => $page,
|
||||
'limit' => $limit,
|
||||
]);
|
||||
|
||||
$pager = $paginator->getPaginate();
|
||||
|
||||
return $this->handleUsers($pager);
|
||||
}
|
||||
|
||||
public function hotQuery($limit = 10, $type = 'total')
|
||||
{
|
||||
$searcher = new UserSearcherService();
|
||||
|
||||
return $searcher->getHotQuery($limit, $type);
|
||||
}
|
||||
|
||||
public function relatedQuery($query, $limit = 10)
|
||||
{
|
||||
$searcher = new UserSearcherService();
|
||||
|
||||
return $searcher->getRelatedQuery($query, $limit);
|
||||
}
|
||||
|
||||
protected function handleUsers($pager)
|
||||
{
|
||||
if ($pager->total_items == 0) {
|
||||
return $pager;
|
||||
}
|
||||
|
||||
$items = [];
|
||||
|
||||
foreach ($pager->items as $item) {
|
||||
$items[] = [
|
||||
'id' => (int)$item['id'],
|
||||
'name' => $item['name'],
|
||||
'avatar' => $item['avatar'],
|
||||
'title' => $item['title'],
|
||||
'about' => $item['about'],
|
||||
'vip' => (int)$item['vip'],
|
||||
'gender' => (int)$item['gender'],
|
||||
'location' => $item['location'],
|
||||
];
|
||||
}
|
||||
|
||||
$pager->items = $items;
|
||||
|
||||
return $pager;
|
||||
}
|
||||
|
||||
}
|
@ -2,112 +2,24 @@
|
||||
|
||||
namespace App\Services\Search;
|
||||
|
||||
use Phalcon\Mvc\User\Component;
|
||||
|
||||
class CourseSearcher extends Component
|
||||
class CourseSearcher extends Searcher
|
||||
{
|
||||
|
||||
/**
|
||||
* @var \XS
|
||||
*/
|
||||
protected $xs;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$filename = config_path('xs.course.ini');
|
||||
|
||||
$this->xs = new \XS($filename);
|
||||
$this->xs = $this->getXS();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取XS
|
||||
*
|
||||
* @return \XS
|
||||
*/
|
||||
public function getXS()
|
||||
{
|
||||
return $this->xs;
|
||||
$filename = config_path('xs.course.ini');
|
||||
|
||||
return new \XS($filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取高亮字段
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getHighlightFields()
|
||||
{
|
||||
return ['title', 'summary'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 搜索课程
|
||||
*
|
||||
* @param string $query
|
||||
* @param int $limit
|
||||
* @param int $offset
|
||||
* @return array
|
||||
* @throws \XSException
|
||||
*/
|
||||
public function search($query, $limit = 15, $offset = 0)
|
||||
{
|
||||
$search = $this->xs->getSearch();
|
||||
|
||||
$docs = $search->setQuery($query)->setLimit($limit, $offset)->search();
|
||||
|
||||
$total = $search->getLastCount();
|
||||
|
||||
$fields = array_keys($this->xs->getAllFields());
|
||||
|
||||
$items = [];
|
||||
|
||||
foreach ($docs as $doc) {
|
||||
$item = [];
|
||||
foreach ($fields as $field) {
|
||||
if (in_array($field, $this->getHighlightFields())) {
|
||||
$item[$field] = $search->highlight($doc->{$field});
|
||||
} else {
|
||||
$item[$field] = $doc->{$field};
|
||||
}
|
||||
}
|
||||
$items[] = $item;
|
||||
}
|
||||
|
||||
return [
|
||||
'total' => $total,
|
||||
'items' => $items,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取相关搜索
|
||||
*
|
||||
* @param string $query
|
||||
* @param int $limit
|
||||
* @return array
|
||||
* @throws \XSException
|
||||
*/
|
||||
public function getRelatedQuery($query, $limit = 10)
|
||||
{
|
||||
$search = $this->xs->getSearch();
|
||||
|
||||
$search->setQuery($query);
|
||||
|
||||
return $search->getRelatedQuery($query, $limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $limit
|
||||
* @param string $type [total => 总量, lastnum => 上周, currnum => 本周]
|
||||
* @return array
|
||||
* @throws \XSException
|
||||
*/
|
||||
public function getHotQuery($limit = 10, $type = 'total')
|
||||
{
|
||||
$search = $this->xs->getSearch();
|
||||
|
||||
$hotQuery = $search->getHotQuery($limit, $type);
|
||||
|
||||
return array_keys($hotQuery);
|
||||
}
|
||||
|
||||
}
|
||||
|
60
app/Services/Search/GroupDocument.php
Normal file
60
app/Services/Search/GroupDocument.php
Normal file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Search;
|
||||
|
||||
use App\Models\ImGroup as GroupModel;
|
||||
use App\Models\User as UserModel;
|
||||
use Phalcon\Mvc\User\Component;
|
||||
|
||||
class GroupDocument extends Component
|
||||
{
|
||||
|
||||
/**
|
||||
* 设置文档
|
||||
*
|
||||
* @param GroupModel $group
|
||||
* @return \XSDocument
|
||||
*/
|
||||
public function setDocument(GroupModel $group)
|
||||
{
|
||||
$doc = new \XSDocument();
|
||||
|
||||
$data = $this->formatDocument($group);
|
||||
|
||||
$doc->setFields($data);
|
||||
|
||||
return $doc;
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化文档
|
||||
*
|
||||
* @param GroupModel $group
|
||||
* @return array
|
||||
*/
|
||||
public function formatDocument(GroupModel $group)
|
||||
{
|
||||
$owner = '';
|
||||
|
||||
if ($group->owner_id > 0) {
|
||||
|
||||
$record = UserModel::findFirst($group->owner_id);
|
||||
|
||||
$owner = kg_json_encode([
|
||||
'id' => $record->id,
|
||||
'name' => $record->name,
|
||||
]);
|
||||
}
|
||||
|
||||
return [
|
||||
'id' => $group->id,
|
||||
'type' => $group->type,
|
||||
'name' => $group->name,
|
||||
'avatar' => $group->avatar,
|
||||
'about' => $group->about,
|
||||
'user_count' => $group->user_count,
|
||||
'owner' => $owner,
|
||||
];
|
||||
}
|
||||
|
||||
}
|
25
app/Services/Search/GroupSearcher.php
Normal file
25
app/Services/Search/GroupSearcher.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Search;
|
||||
|
||||
class GroupSearcher extends Searcher
|
||||
{
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->xs = $this->getXS();
|
||||
}
|
||||
|
||||
public function getXS()
|
||||
{
|
||||
$filename = config_path('xs.group.ini');
|
||||
|
||||
return new \XS($filename);
|
||||
}
|
||||
|
||||
public function getHighlightFields()
|
||||
{
|
||||
return ['name', 'about'];
|
||||
}
|
||||
|
||||
}
|
100
app/Services/Search/Searcher.php
Normal file
100
app/Services/Search/Searcher.php
Normal file
@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Search;
|
||||
|
||||
use Phalcon\Mvc\User\Component;
|
||||
|
||||
abstract class Searcher extends Component
|
||||
{
|
||||
|
||||
/**
|
||||
* @var \XS
|
||||
*/
|
||||
protected $xs;
|
||||
|
||||
/**
|
||||
* 获取XS
|
||||
*
|
||||
* @return \XS
|
||||
*/
|
||||
abstract public function getXS();
|
||||
|
||||
/**
|
||||
* 获取高亮字段
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
abstract public function getHighlightFields();
|
||||
|
||||
/**
|
||||
* 搜索课程
|
||||
*
|
||||
* @param string $query
|
||||
* @param int $limit
|
||||
* @param int $offset
|
||||
* @return array
|
||||
* @throws \XSException
|
||||
*/
|
||||
public function search($query, $limit = 15, $offset = 0)
|
||||
{
|
||||
$search = $this->xs->getSearch();
|
||||
|
||||
$docs = $search->setQuery($query)->setLimit($limit, $offset)->search();
|
||||
|
||||
$total = $search->getLastCount();
|
||||
|
||||
$fields = array_keys($this->xs->getAllFields());
|
||||
|
||||
$items = [];
|
||||
|
||||
foreach ($docs as $doc) {
|
||||
$item = [];
|
||||
foreach ($fields as $field) {
|
||||
if (in_array($field, $this->getHighlightFields())) {
|
||||
$item[$field] = $search->highlight($doc->{$field});
|
||||
} else {
|
||||
$item[$field] = $doc->{$field};
|
||||
}
|
||||
}
|
||||
$items[] = $item;
|
||||
}
|
||||
|
||||
return [
|
||||
'total' => $total,
|
||||
'items' => $items,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取相关搜索
|
||||
*
|
||||
* @param string $query
|
||||
* @param int $limit
|
||||
* @return array
|
||||
* @throws \XSException
|
||||
*/
|
||||
public function getRelatedQuery($query, $limit = 10)
|
||||
{
|
||||
$search = $this->xs->getSearch();
|
||||
|
||||
$search->setQuery($query);
|
||||
|
||||
return $search->getRelatedQuery($query, $limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $limit
|
||||
* @param string $type [total => 总量, lastnum => 上周, currnum => 本周]
|
||||
* @return array
|
||||
* @throws \XSException
|
||||
*/
|
||||
public function getHotQuery($limit = 10, $type = 'total')
|
||||
{
|
||||
$search = $this->xs->getSearch();
|
||||
|
||||
$hotQuery = $search->getHotQuery($limit, $type);
|
||||
|
||||
return array_keys($hotQuery);
|
||||
}
|
||||
|
||||
}
|
48
app/Services/Search/UserDocument.php
Normal file
48
app/Services/Search/UserDocument.php
Normal file
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Search;
|
||||
|
||||
use App\Models\User as UserModel;
|
||||
use Phalcon\Mvc\User\Component;
|
||||
|
||||
class UserDocument extends Component
|
||||
{
|
||||
|
||||
/**
|
||||
* 设置文档
|
||||
*
|
||||
* @param UserModel $user
|
||||
* @return \XSDocument
|
||||
*/
|
||||
public function setDocument(UserModel $user)
|
||||
{
|
||||
$doc = new \XSDocument();
|
||||
|
||||
$data = $this->formatDocument($user);
|
||||
|
||||
$doc->setFields($data);
|
||||
|
||||
return $doc;
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化文档
|
||||
*
|
||||
* @param UserModel $user
|
||||
* @return array
|
||||
*/
|
||||
public function formatDocument(UserModel $user)
|
||||
{
|
||||
return [
|
||||
'id' => $user->id,
|
||||
'name' => $user->name,
|
||||
'title' => $user->title,
|
||||
'avatar' => $user->avatar,
|
||||
'about' => $user->about,
|
||||
'gender' => $user->gender,
|
||||
'location' => $user->location,
|
||||
'vip' => $user->vip,
|
||||
];
|
||||
}
|
||||
|
||||
}
|
25
app/Services/Search/UserSearcher.php
Normal file
25
app/Services/Search/UserSearcher.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Search;
|
||||
|
||||
class UserSearcher extends Searcher
|
||||
{
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->xs = $this->getXS();
|
||||
}
|
||||
|
||||
public function getXS()
|
||||
{
|
||||
$filename = config_path('xs.user.ini');
|
||||
|
||||
return new \XS($filename);
|
||||
}
|
||||
|
||||
public function getHighlightFields()
|
||||
{
|
||||
return ['name', 'about'];
|
||||
}
|
||||
|
||||
}
|
47
app/Services/Syncer/GroupIndex.php
Normal file
47
app/Services/Syncer/GroupIndex.php
Normal file
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Syncer;
|
||||
|
||||
use App\Library\Cache\Backend\Redis as RedisCache;
|
||||
use App\Services\Service;
|
||||
|
||||
class GroupIndex extends Service
|
||||
{
|
||||
|
||||
/**
|
||||
* @var RedisCache
|
||||
*/
|
||||
protected $cache;
|
||||
|
||||
/**
|
||||
* @var \Redis
|
||||
*/
|
||||
protected $redis;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $lifetime = 86400;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->cache = $this->getDI()->get('cache');
|
||||
|
||||
$this->redis = $this->cache->getRedis();
|
||||
}
|
||||
|
||||
public function addItem($groupId)
|
||||
{
|
||||
$key = $this->getSyncKey();
|
||||
|
||||
$this->redis->sAdd($key, $groupId);
|
||||
|
||||
$this->redis->expire($key, $this->lifetime);
|
||||
}
|
||||
|
||||
public function getSyncKey()
|
||||
{
|
||||
return 'group_index_sync';
|
||||
}
|
||||
|
||||
}
|
47
app/Services/Syncer/UserIndex.php
Normal file
47
app/Services/Syncer/UserIndex.php
Normal file
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services\Syncer;
|
||||
|
||||
use App\Library\Cache\Backend\Redis as RedisCache;
|
||||
use App\Services\Service;
|
||||
|
||||
class UserIndex extends Service
|
||||
{
|
||||
|
||||
/**
|
||||
* @var RedisCache
|
||||
*/
|
||||
protected $cache;
|
||||
|
||||
/**
|
||||
* @var \Redis
|
||||
*/
|
||||
protected $redis;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $lifetime = 86400;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->cache = $this->getDI()->get('cache');
|
||||
|
||||
$this->redis = $this->cache->getRedis();
|
||||
}
|
||||
|
||||
public function addItem($userId)
|
||||
{
|
||||
$key = $this->getSyncKey();
|
||||
|
||||
$this->redis->sAdd($key, $userId);
|
||||
|
||||
$this->redis->expire($key, $this->lifetime);
|
||||
}
|
||||
|
||||
public function getSyncKey()
|
||||
{
|
||||
return 'user_index_sync';
|
||||
}
|
||||
|
||||
}
|
28
config/xs.group.default.ini
Normal file
28
config/xs.group.default.ini
Normal file
@ -0,0 +1,28 @@
|
||||
project.name = group
|
||||
project.default_charset = UTF-8
|
||||
|
||||
server.index = xunsearch:8383
|
||||
server.search = xunsearch:8384
|
||||
|
||||
[id]
|
||||
type = id
|
||||
|
||||
[type]
|
||||
type = string
|
||||
index = self
|
||||
tokenizer = full
|
||||
|
||||
[name]
|
||||
type = title
|
||||
|
||||
[avatar]
|
||||
type = string
|
||||
|
||||
[about]
|
||||
type = body
|
||||
|
||||
[owner]
|
||||
type = string
|
||||
|
||||
[user_count]
|
||||
type = string
|
28
config/xs.group.ini
Normal file
28
config/xs.group.ini
Normal file
@ -0,0 +1,28 @@
|
||||
project.name = group
|
||||
project.default_charset = UTF-8
|
||||
|
||||
server.index = 8383
|
||||
server.search = 8384
|
||||
|
||||
[id]
|
||||
type = id
|
||||
|
||||
[type]
|
||||
type = string
|
||||
index = self
|
||||
tokenizer = full
|
||||
|
||||
[name]
|
||||
type = title
|
||||
|
||||
[avatar]
|
||||
type = string
|
||||
|
||||
[about]
|
||||
type = body
|
||||
|
||||
[owner]
|
||||
type = string
|
||||
|
||||
[user_count]
|
||||
type = string
|
33
config/xs.user.default.ini
Normal file
33
config/xs.user.default.ini
Normal file
@ -0,0 +1,33 @@
|
||||
project.name = user
|
||||
project.default_charset = UTF-8
|
||||
|
||||
server.index = xunsearch:8383
|
||||
server.search = xunsearch:8384
|
||||
|
||||
[id]
|
||||
type = id
|
||||
|
||||
[name]
|
||||
type = title
|
||||
|
||||
[avatar]
|
||||
type = string
|
||||
|
||||
[title]
|
||||
type = string
|
||||
|
||||
[about]
|
||||
type = body
|
||||
|
||||
[location]
|
||||
type = string
|
||||
index = self
|
||||
tokenizer = full
|
||||
|
||||
[gender]
|
||||
type = string
|
||||
index = self
|
||||
tokenizer = full
|
||||
|
||||
[vip]
|
||||
type = string
|
33
config/xs.user.ini
Normal file
33
config/xs.user.ini
Normal file
@ -0,0 +1,33 @@
|
||||
project.name = user
|
||||
project.default_charset = UTF-8
|
||||
|
||||
server.index = 8383
|
||||
server.search = 8384
|
||||
|
||||
[id]
|
||||
type = id
|
||||
|
||||
[name]
|
||||
type = title
|
||||
|
||||
[avatar]
|
||||
type = string
|
||||
|
||||
[title]
|
||||
type = string
|
||||
|
||||
[about]
|
||||
type = body
|
||||
|
||||
[location]
|
||||
type = string
|
||||
index = self
|
||||
tokenizer = full
|
||||
|
||||
[gender]
|
||||
type = string
|
||||
index = self
|
||||
tokenizer = full
|
||||
|
||||
[vip]
|
||||
type = string
|
@ -245,6 +245,15 @@ body {
|
||||
max-height: 270px;
|
||||
}
|
||||
|
||||
.search-tab {
|
||||
padding: 10px 20px;
|
||||
}
|
||||
|
||||
.search-tab a {
|
||||
min-width: 50px;
|
||||
margin-right: 30px;
|
||||
}
|
||||
|
||||
.search-empty {
|
||||
padding: 50px 0;
|
||||
text-align: center;
|
||||
@ -269,13 +278,13 @@ body {
|
||||
padding: 0 5px;
|
||||
}
|
||||
|
||||
.search-course-card {
|
||||
.search-course-card, .search-group-card {
|
||||
padding-bottom: 15px;
|
||||
margin-bottom: 15px;
|
||||
border-bottom: 1px dashed #ccc;
|
||||
}
|
||||
|
||||
.search-course-card:last-child {
|
||||
.search-course-card:last-child, .search-group-card:last-child {
|
||||
padding-bottom: 0;
|
||||
margin-bottom: 0;
|
||||
border: none;
|
||||
@ -288,17 +297,17 @@ body {
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.search-course-card .cover img {
|
||||
.search-course-card .cover img, .search-group-card .avatar img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.search-course-card .info {
|
||||
.search-course-card .info, .search-group-card .info {
|
||||
float: left;
|
||||
width: 500px;
|
||||
}
|
||||
|
||||
.search-course-card .title {
|
||||
.search-course-card .title, .search-group-card .name {
|
||||
margin-bottom: 10px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
@ -313,19 +322,36 @@ body {
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
.search-course-card .meta {
|
||||
.search-course-card .meta, .search-group-card .meta {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.search-course-card .meta span {
|
||||
.search-course-card .meta span, .search-group-card .meta span {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.search-course-card em {
|
||||
.search-course-card em, .search-group-card em {
|
||||
color: red;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.search-group-card .avatar {
|
||||
float: left;
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.search-group-card .avatar img {
|
||||
border-radius: 100%;
|
||||
}
|
||||
|
||||
.search-group-card .about {
|
||||
margin-bottom: 10px;
|
||||
line-height: 1.5em;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.query-badge {
|
||||
padding: 2px 5px;
|
||||
margin-right: 5px;
|
||||
@ -421,7 +447,6 @@ body {
|
||||
|
||||
.course-sort {
|
||||
padding: 10px 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.course-sort a {
|
||||
|
Loading…
x
Reference in New Issue
Block a user