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

优化IM,修改后台登录页

This commit is contained in:
xiaochong0302 2020-08-20 19:52:13 +08:00
parent 1de760ba56
commit 33b24e65e7
28 changed files with 447 additions and 251 deletions

View File

@ -60,10 +60,10 @@ class IndexLiveList extends Cache
$chapters = $chapterRepo->findByIds($chapterIds);
$chapterMappings = [];
$chapterMapping = [];
foreach ($chapters as $chapter) {
$chapterMappings[$chapter->id] = $chapter;
$chapterMapping[$chapter->id] = $chapter;
}
$courseIds = kg_array_column($lives->toArray(), 'course_id');
@ -72,10 +72,10 @@ class IndexLiveList extends Cache
$courses = $courseRepo->findByIds($courseIds);
$courseMappings = [];
$courseMapping = [];
foreach ($courses as $course) {
$courseMappings[$course->id] = $course;
$courseMapping[$course->id] = $course;
}
foreach ($lives as $live) {
@ -90,8 +90,8 @@ class IndexLiveList extends Cache
continue;
}
$chapter = $chapterMappings[$live->chapter_id];
$course = $courseMappings[$chapter->course_id];
$chapter = $chapterMapping[$live->chapter_id];
$course = $courseMapping[$chapter->course_id];
$chapterInfo = [
'id' => $chapter->id,

View File

@ -4,6 +4,7 @@ namespace App\Http\Admin\Controllers;
use App\Http\Admin\Services\Session as SessionService;
use App\Http\Admin\Services\Setting as SettingService;
use App\Library\AppInfo as AppInfo;
use App\Traits\Auth as AuthTrait;
use App\Traits\Response as ResponseTrait;
use App\Traits\Security as SecurityTrait;
@ -23,9 +24,9 @@ class SessionController extends \Phalcon\Mvc\Controller
*/
public function loginAction()
{
$currentUser = $this->getCurrentUser();
$user = $this->getCurrentUser();
if ($currentUser->id > 0) {
if ($user->id > 0) {
$this->response->redirect(['for' => 'admin.index']);
}
@ -43,11 +44,14 @@ class SessionController extends \Phalcon\Mvc\Controller
return $this->jsonSuccess(['location' => $location]);
}
$appInfo = new AppInfo();
$settingService = new SettingService();
$captcha = $settingService->getSectionSettings('captcha');
$this->view->pick('public/login');
$this->view->setVar('app_info', $appInfo);
$this->view->setVar('captcha', $captcha);
}
@ -56,9 +60,9 @@ class SessionController extends \Phalcon\Mvc\Controller
*/
public function logoutAction()
{
$service = new SessionService();
$sessionService = new SessionService();
$service->logout();
$sessionService->logout();
$this->response->redirect(['for' => 'admin.login']);
}

View File

@ -2,33 +2,54 @@
{% block content %}
<form class="kg-login-form layui-form" method="POST" action="{{ url({'for':'admin.login'}) }}">
<div class="layui-form-item">
<div class="layui-input-block">
<input class="layui-input" type="text" name="account" autocomplete="off" placeholder="手机 / 邮箱" lay-verify="required">
<div class="kg-login-wrap">
<div class="layui-card">
<div class="layui-card-header">管理登录</div>
<div class="layui-card-body">
<form class="layui-form kg-login-form" method="POST" action="{{ url({'for':'admin.login'}) }}">
<div class="layui-form-item">
<div class="layui-input-block">
<input class="layui-input" type="text" name="account" autocomplete="off" placeholder="手机 / 邮箱" lay-verify="required">
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<input class="layui-input" type="password" name="password" autocomplete="off" placeholder="密码" lay-verify="required">
</div>
</div>
{% if captcha.enabled == 1 %}
<div id="captcha-block" class="layui-form-item">
<div class="layui-input-block">
<button id="captcha-btn" class="layui-btn layui-btn-fluid" type="button" data-app-id="{{ captcha.app_id }}">点击完成验证</button>
</div>
</div>
{% endif %}
<div class="layui-form-item">
<div class="layui-input-block">
{% set disabled = captcha.enabled ? 'disabled' : '' %}
<button id="submit-btn" class="layui-btn layui-btn-fluid layui-btn-disabled" {{ disabled }} lay-submit="true" lay-filter="go">立即登录</button>
<input type="hidden" name="ticket">
<input type="hidden" name="rand">
</div>
</div>
</form>
</div>
</div>
<div class="layui-form-item">
<div class="layui-input-block">
<input class="layui-input" type="password" name="password" autocomplete="off" placeholder="密码" lay-verify="required">
</div>
</div>
{% if captcha.enabled == 1 %}
<div id="captcha-block" class="layui-form-item">
<div class="layui-input-block">
<button id="captcha-btn" class="layui-btn layui-btn-fluid" type="button" data-app-id="{{ captcha.app_id }}">点击完成验证</button>
</div>
</div>
{% endif %}
<div class="layui-form-item">
<div class="layui-input-block">
{% set disabled = captcha.enabled ? 'disabled' : '' %}
<button id="submit-btn" class="layui-btn layui-btn-fluid layui-btn-disabled" {{ disabled }} lay-submit="true" lay-filter="go">立即登录</button>
<input type="hidden" name="ticket">
<input type="hidden" name="rand">
</div>
</div>
</form>
</div>
<div class="kg-login-copyright">
Powered by <a href="{{ app_info.link }}" title="{{ app_info.name }}">{{ app_info.alias }} {{ app_info.version }}</a>
</div>
{% endblock %}
{% block inline_css %}
<style>
body {
background: #f2f2f2;
}
</style>
{% endblock %}

View File

@ -2,6 +2,8 @@
{% block content %}
{% set expiry_editable = relation.source_type in [1,3] %}
<form class="layui-form kg-form" method="POST" action="{{ url({'for':'admin.student.update'}) }}">
<fieldset class="layui-elem-field layui-field-title">
<legend>编辑学员</legend>
@ -18,12 +20,21 @@
<div class="layui-form-mid layui-word-aux">{{ student.name }}</div>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">过期时间</label>
<div class="layui-input-block">
<input class="layui-input" type="text" name="expiry_time" autocomplete="off" value="{{ date('Y-m-d H:i:s',relation.expiry_time) }}" lay-verify="required">
{% if expiry_editable %}
<div class="layui-form-item">
<label class="layui-form-label">过期时间</label>
<div class="layui-input-block">
<input class="layui-input" type="text" name="expiry_time" autocomplete="off" value="{{ date('Y-m-d H:i:s',relation.expiry_time) }}" lay-verify="required">
</div>
</div>
</div>
{% else %}
<div class="layui-form-item">
<label class="layui-form-label">过期时间</label>
<div class="layui-input-block">
<div class="layui-form-mid layui-word-aux">{{ date('Y-m-d H:i:s',relation.expiry_time) }}</div>
</div>
</div>
{% endif %}
<div class="layui-form-item">
<label class="layui-form-label"></label>
<div class="layui-input-block">

View File

@ -42,23 +42,6 @@
</div>
</div>
{% endif %}
<div class="layui-form-item">
<label class="layui-form-label">会员服务</label>
<div class="layui-input-block">
<input type="radio" name="vip" value="1" title="是" lay-filter="vip" {% if user.vip == 1 %}checked="checked"{% endif %}>
<input type="radio" name="vip" value="0" title="否" lay-filter="vip" {% if user.vip == 0 %}checked="checked"{% endif %}>
</div>
</div>
<div class="layui-form-item" id="vip-expiry-block" {% if user.vip == 0 %}style="display:none;"{% endif %}>
<label class="layui-form-label">会员期限</label>
<div class="layui-input-block">
{% if user.vip_expiry_time > 0 %}
<input class="layui-input" type="text" name="vip_expiry_time" autocomplete="off" value="{{ date('Y-m-d H:i:s',user.vip_expiry_time) }}">
{% else %}
<input class="layui-input" type="text" name="vip_expiry_time" autocomplete="off">
{% endif %}
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">锁定帐号</label>
<div class="layui-input-block">
@ -132,25 +115,11 @@
var form = layui.form;
var laydate = layui.laydate;
laydate.render({
elem: 'input[name=vip_expiry_time]',
type: 'datetime'
});
laydate.render({
elem: 'input[name=lock_expiry_time]',
type: 'datetime'
});
form.on('radio(vip)', function (data) {
var block = $('#vip-expiry-block');
if (data.value === '1') {
block.show();
} else {
block.hide();
}
});
form.on('radio(locked)', function (data) {
var block = $('#lock-expiry-block');
if (data.value === '1') {

View File

@ -4,9 +4,9 @@
{%- macro gender_info(value) %}
{% if value == 1 %}
<span class="layui-badge layui-bg-red">男</span>
<span class="layui-badge layui-bg-gray">男</span>
{% elseif value == 2 %}
<span class="layui-badge layui-bg-green">女</span>
<span class="layui-badge layui-bg-gray">女</span>
{% elseif value == 3 %}
<span class="layui-badge layui-bg-gray">密</span>
{% endif %}

View File

@ -29,6 +29,18 @@ class ImController extends Controller
public function indexAction()
{
$this->seo->prependTitle('微聊');
$service = new ImService();
$activeGroups = $service->getActiveGroups();
$activeUsers = $service->getActiveUsers();
$newGroups = $service->getNewGroups();
$newUsers = $service->getNewUsers();
$this->view->setVar('active_users', $activeUsers);
$this->view->setVar('active_groups', $activeGroups);
$this->view->setVar('new_groups', $newGroups);
$this->view->setVar('new_users', $newUsers);
}
/**
@ -74,7 +86,7 @@ class ImController extends Controller
{
$service = new ImService();
$pager = $service->getSystemMessages();
$pager = $service->getNotices();
$this->view->pick('im/msgbox');
$this->view->setVar('pager', $pager);

View File

@ -46,6 +46,8 @@ class ImGroupController extends Controller
$group = $service->getGroup($id);
$this->seo->prependTitle([$group['name'], '群组']);
$this->view->pick('im/group/show');
$this->view->setVar('group', $group);
}

View File

@ -2,7 +2,6 @@
namespace App\Http\Web\Services;
use App\Caches\Setting as SettingCache;
use App\Models\ImUser as ImUserModel;
use App\Repos\ImGroup as ImGroupRepo;
use App\Repos\ImUser as ImUserRepo;
@ -13,55 +12,13 @@ use GatewayClient\Gateway;
class Im extends Service
{
use ImCsTrait;
use ImFriendTrait;
use ImGroupTrait;
use ImMessageTrait;
use ImNoticeTrait;
use ImStatTrait;
public function getCsUser()
{
$csUserIds = [];
$onlineUserIds = [];
$cache = new SettingCache();
$imInfo = $cache->get('im');
Gateway::$registerAddress = $this->getRegisterAddress();
if (!empty($imInfo['cs_user1_id'])) {
$csUserIds[] = $imInfo['cs_user1_id'];
if (Gateway::isUidOnline($imInfo['cs_user1_id'])) {
$onlineUserIds[] = $imInfo['cs_user1_id'];
}
}
if (!empty($imInfo['cs_user2_id'])) {
$csUserIds[] = $imInfo['cs_user2_id'];
if (Gateway::isUidOnline($imInfo['cs_user2_id'])) {
$onlineUserIds[] = $imInfo['cs_user2_id'];
}
}
if (!empty($imInfo['cs_user3_id'])) {
$csUserIds[] = $imInfo['cs_user3_id'];
if (Gateway::isUidOnline($imInfo['cs_user3_id'])) {
$onlineUserIds[] = $imInfo['cs_user3_id'];
}
}
if (count($onlineUserIds) > 0) {
$key = array_rand($onlineUserIds);
$userId = $onlineUserIds[$key];
} else {
$key = array_rand($csUserIds);
$userId = $csUserIds[$key];
}
return $this->getImUser($userId);
}
public function getInitInfo()
{
$loginUser = $this->getLoginUser();
@ -295,26 +252,29 @@ class Im extends Service
$users = $userRepo->findByIds($ids);
$mappings = [];
$baseUrl = kg_ci_base_url();
$mapping = [];
/**
* 用户可以设置状态为 ['online', 'hide']
* 列表在线状态识别为 ['online', 'offline']
*/
foreach ($users as $user) {
$status = in_array($user->status, ['online', 'offline']) ? $user->status : 'offline';
$mappings[$user->id] = [
'id' => $user->id,
'username' => $user->name,
'avatar' => $user->avatar,
'sign' => $user->sign,
foreach ($users->toArray() as $user) {
$status = in_array($user['status'], ['online', 'offline']) ? $user['status'] : 'offline';
$user['avatar'] = $baseUrl . $user['avatar'];
$mapping[$user['id']] = [
'id' => $user['id'],
'username' => $user['name'],
'avatar' => $user['avatar'],
'sign' => $user['sign'],
'status' => $status,
];
}
foreach ($items as $key => $item) {
foreach ($friendUsers as $friendUser) {
$friend = $mappings[$friendUser->friend_id];
$friend = $mapping[$friendUser->friend_id];
if ($item['id'] == $friendUser->group_id) {
$friend['msg_count'] = $friendUser->msg_count;
$items[$key]['list'][] = $friend;
@ -331,23 +291,34 @@ class Im extends Service
{
$userRepo = new ImUserRepo();
$groups = $userRepo->findGroups($user->id);
$groupUsers = $userRepo->findGroupUsers($user->id);
if ($groups->count() == 0) {
if ($groupUsers->count() == 0) {
return [];
}
$groupRepo = new ImGroupRepo();
$ids = kg_array_column($groupUsers->toArray(), 'group_id');
$groups = $groupRepo->findByIds($ids);
$baseUrl = kg_ci_base_url();
$mapping = [];
foreach ($groups->toArray() as $group) {
$mapping[$group['id']] = [
'id' => $group['id'],
'groupname' => $group['name'],
'avatar' => $baseUrl . $group['avatar'],
];
}
$result = [];
foreach ($groups->toArray() as $group) {
$group['avatar'] = $baseUrl . $group['avatar'];
$result[] = [
'id' => $group['id'],
'groupname' => $group['name'],
'avatar' => $group['avatar'],
];
foreach ($groupUsers as $groupUser) {
$result[] = $mapping[$groupUser->group_id];
}
return $result;

View File

@ -0,0 +1,54 @@
<?php
namespace App\Http\Web\Services;
use App\Caches\Setting as SettingCache;
use GatewayClient\Gateway;
trait ImCsTrait
{
public function getCsUser()
{
$csUserIds = [];
$onlineUserIds = [];
$cache = new SettingCache();
$imInfo = $cache->get('im');
Gateway::$registerAddress = $this->getRegisterAddress();
if (!empty($imInfo['cs_user1_id'])) {
$csUserIds[] = $imInfo['cs_user1_id'];
if (Gateway::isUidOnline($imInfo['cs_user1_id'])) {
$onlineUserIds[] = $imInfo['cs_user1_id'];
}
}
if (!empty($imInfo['cs_user2_id'])) {
$csUserIds[] = $imInfo['cs_user2_id'];
if (Gateway::isUidOnline($imInfo['cs_user2_id'])) {
$onlineUserIds[] = $imInfo['cs_user2_id'];
}
}
if (!empty($imInfo['cs_user3_id'])) {
$csUserIds[] = $imInfo['cs_user3_id'];
if (Gateway::isUidOnline($imInfo['cs_user3_id'])) {
$onlineUserIds[] = $imInfo['cs_user3_id'];
}
}
if (count($onlineUserIds) > 0) {
$key = array_rand($onlineUserIds);
$userId = $onlineUserIds[$key];
} else {
$key = array_rand($csUserIds);
$userId = $csUserIds[$key];
}
return $this->getImUser($userId);
}
}

View File

@ -6,6 +6,7 @@ use App\Builders\ImMessageList as ImMessageListBuilder;
use App\Library\Paginator\Query as PagerQuery;
use App\Models\ImFriendUser as ImFriendUserModel;
use App\Models\ImGroup as ImGroupModel;
use App\Models\ImGroupUser as ImGroupUserModel;
use App\Models\ImMessage as ImMessageModel;
use App\Repos\ImFriendUser as ImFriendUserRepo;
use App\Repos\ImMessage as ImMessageRepo;
@ -24,52 +25,6 @@ use GatewayClient\Gateway;
Trait ImMessageTrait
{
public function pullUnreadFriendMessages($id)
{
$user = $this->getLoginUser();
$validator = new ImUserValidator();
$friend = $validator->checkUser($id);
$userRepo = new ImUserRepo();
$messages = $userRepo->findUnreadFriendMessages($friend->id, $user->id);
if ($messages->count() == 0) {
return;
}
Gateway::$registerAddress = $this->getRegisterAddress();
foreach ($messages as $message) {
$message->update(['viewed' => 1]);
$content = kg_json_encode([
'type' => 'show_chat_msg',
'message' => [
'username' => $friend->name,
'avatar' => $friend->avatar,
'id' => $friend->id,
'fromid' => $friend->id,
'content' => $message->content,
'timestamp' => 1000 * $message->create_time,
'type' => 'friend',
'mine' => false,
],
]);
Gateway::sendToUid($user->id, $content);
}
$repo = new ImFriendUserRepo();
$friendUser = $repo->findFriendUser($user->id, $friend->id);
$friendUser->update(['msg_count' => 0]);
}
public function getChatMessages()
{
$user = $this->getLoginUser();
@ -86,7 +41,7 @@ Trait ImMessageTrait
$page = $pagerQuery->getPage();
$limit = $pagerQuery->getLimit();
if ($params['type'] == ImMessageModel::TYPE_FRIEND) {
if ($params['type'] == 'friend') {
$chatId = ImMessageModel::getChatId($user->id, $params['id']);
@ -98,7 +53,7 @@ Trait ImMessageTrait
return $this->handleChatMessagePager($pager);
} elseif ($params['type'] == ImMessageModel::TYPE_GROUP) {
} elseif ($params['type'] == 'group') {
$where = [
'receiver_type' => $params['type'],
@ -161,6 +116,8 @@ Trait ImMessageTrait
'viewed' => $online ? 1 : 0,
]);
$this->updateFriendUserChatTime($relation);
if ($online) {
Gateway::sendToUid($to['id'], $content);
} else {
@ -177,7 +134,7 @@ Trait ImMessageTrait
$validator = new ImGroupUserValidator();
$validator->checkGroupUser($group->id, $user->id);
$relation = $validator->checkGroupUser($group->id, $user->id);
$messageModel = new ImMessageModel();
@ -188,6 +145,8 @@ Trait ImMessageTrait
'content' => $from['content'],
]);
$this->updateGroupUserChatTime($relation);
$this->incrGroupMsgCount($group);
$excludeClientId = null;
@ -254,6 +213,52 @@ Trait ImMessageTrait
$this->sendChatMessage($from, $to);
}
public function pullUnreadFriendMessages($id)
{
$user = $this->getLoginUser();
$validator = new ImUserValidator();
$friend = $validator->checkUser($id);
$userRepo = new ImUserRepo();
$messages = $userRepo->findUnreadFriendMessages($friend->id, $user->id);
if ($messages->count() == 0) {
return;
}
Gateway::$registerAddress = $this->getRegisterAddress();
foreach ($messages as $message) {
$message->update(['viewed' => 1]);
$content = kg_json_encode([
'type' => 'show_chat_msg',
'message' => [
'username' => $friend->name,
'avatar' => $friend->avatar,
'id' => $friend->id,
'fromid' => $friend->id,
'content' => $message->content,
'timestamp' => 1000 * $message->create_time,
'type' => 'friend',
'mine' => false,
],
]);
Gateway::sendToUid($user->id, $content);
}
$repo = new ImFriendUserRepo();
$friendUser = $repo->findFriendUser($user->id, $friend->id);
$friendUser->update(['msg_count' => 0]);
}
protected function handleChatMessagePager($pager)
{
if ($pager->total_items == 0) {
@ -283,6 +288,34 @@ Trait ImMessageTrait
return $pager;
}
protected function updateFriendUserChatTime(ImFriendUserModel $hisFriendUser)
{
/**
* 用于联系人排序,近期有联系的排上面
*/
if (time() - $hisFriendUser->update_time > 15 * 60) {
$hisFriendUser->update(['update_time' => time()]);
$repo = new ImFriendUserRepo();
$myFriendUser = $repo->findFriendUser($hisFriendUser->friend_id, $hisFriendUser->user_id);
$myFriendUser->update(['update_time' => time()]);
}
}
protected function updateGroupUserChatTime(ImGroupUserModel $groupUser)
{
/**
* 用于联系人排序,近期有联系的排上面
*/
if (time() - $groupUser->update_time > 15 * 60) {
$groupUser->update_time = time();
$groupUser->update();
}
}
protected function incrFriendUserMsgCount(ImFriendUserModel $friendUser)
{
$friendUser->msg_count += 1;

View File

@ -2,27 +2,40 @@
namespace App\Http\Web\Services;
use App\Caches\ImActiveGroupList;
use App\Caches\ImActiveUserList;
use App\Caches\ImNewGroupList;
use App\Caches\ImNewUserList;
trait ImStatTrait
{
public function getActiveGroups()
{
$cache = new ImActiveGroupList();
return $cache->get();
}
public function getActiveUsers()
{
$cache = new ImActiveUserList();
return $cache->get();
}
public function getNewGroups()
{
$cache = new ImNewGroupList();
return $cache->get();
}
public function getNewUsers()
{
$cache = new ImNewUserList();
return $cache->get();
}
}

View File

@ -37,4 +37,14 @@
{{ js_include('web/js/captcha.login.js') }}
{{ js_include('web/js/captcha.verify.js') }}
{% endblock %}
{% block inline_js %}
<script>
if (window !== top) {
top.location.href = window.location.href;
}
</script>
{% endblock %}

View File

@ -16,5 +16,6 @@
{% block include_js %}
{{ js_include('web/js/im.group.list.js') }}
{{ js_include('web/js/im.apply.js') }}
{% endblock %}

View File

@ -1,40 +1,33 @@
{%- macro type_info(value) %}
{% if value == 'course' %}
<span class="layui-badge layui-bg-green type">课</span>
{% elseif value == 'chat' %}
<span class="layui-badge layui-bg-blue type">聊</span>
{% elseif value == 'staff' %}
<span class="layui-badge layui-bg-red type">工</span>
{% endif %}
{%- endmacro %}
{{ partial('macros/group') }}
<div class="group-list clearfix">
<div class="layui-row layui-col-space20">
{% for item in pager.items %}
{% set group_url = url({'for':'web.group.show','id':item.id}) %}
{% set owner_url = url({'for':'web.user.show','id':item.owner.id}) %}
{% set item.about = item.about ? item.about : '这家伙真懒,什么都没留下!' %}
<div class="layui-col-md3">
<div class="user-card">
{{ type_info(item.type) }}
<div class="avatar">
<a href="{{ group_url }}" title="{{ item.about }}">
<img src="{{ item.avatar }}" alt="{{ item.name }}">
</a>
</div>
<div class="name layui-elip">
<a href="{{ group_url }}" title="{{ item.name }}">{{ item.name }}</a>
</div>
<div class="owner">
<span>组长:<a href="{{ owner_url }}">{{ item.owner.name }}</a></span>
</div>
<div class="meta layui-elip">
<span>成员:{{ item.user_count }}</span>
<span>讨论:{{ item.msg_count }}</span>
{% if pager.total_pages > 0 %}
<div class="group-list clearfix">
<div class="layui-row layui-col-space20">
{% for item in pager.items %}
{% set group_url = url({'for':'web.group.show','id':item.id}) %}
{% set item.about = item.about ? item.about : '这家伙真懒,什么都没留下!' %}
<div class="layui-col-md3">
<div class="user-card">
{{ type_info(item.type) }}
<div class="avatar">
<a href="{{ group_url }}" title="{{ item.about }}">
<img src="{{ item.avatar }}" alt="{{ item.name }}">
</a>
</div>
<div class="name layui-elip">
<a href="{{ group_url }}" title="{{ item.name }}">{{ item.name }}</a>
</div>
<div class="meta layui-elip">
<span>成员:{{ item.user_count }}</span>
<span>讨论:{{ item.msg_count }}</span>
</div>
<div class="action">
<span class="layui-btn apply-group" data-id="{{ item.id }}" data-name="{{ item.name }}" data-avatar="{{ item.avatar }}">加入群组</span>
</div>
</div>
</div>
</div>
{% endfor %}
{% endfor %}
</div>
</div>
</div>
{{ partial('partials/pager_ajax') }}
{{ partial('partials/pager_ajax') }}
{% endif %}

View File

@ -2,19 +2,30 @@
{% block content %}
{{ partial('macros/group') }}
{{ partial('macros/user') }}
<div class="tab-wrap">
<div class="layui-tab layui-tab-brief user-tab">
<ul class="layui-tab-title">
<li class="layui-this">活跃群组</li>
<li>活跃用户</li>
<li>新进群组</li>
<li class="layui-this">新进群组</li>
<li>新进用户</li>
<li>活跃群组</li>
<li>活跃用户</li>
</ul>
<div class="layui-tab-content">
<div class="layui-tab-item layui-show"></div>
<div class="layui-tab-item"></div>
<div class="layui-tab-item"></div>
<div class="layui-tab-item"></div>
<div class="layui-tab-item layui-show">
{{ partial('im/index_groups',{'groups':new_groups}) }}
</div>
<div class="layui-tab-item">
{{ partial('im/index_users',{'users':new_users}) }}
</div>
<div class="layui-tab-item">
{{ partial('im/index_groups',{'groups':active_groups}) }}
</div>
<div class="layui-tab-item">
{{ partial('im/index_users',{'users':active_users}) }}
</div>
</div>
</div>
</div>
@ -24,5 +35,6 @@
{% block include_js %}
{{ js_include('web/js/im.js') }}
{{ js_include('web/js/im.apply.js') }}
{% endblock %}

View File

@ -0,0 +1,28 @@
<div class="user-list clearfix">
<div class="layui-row layui-col-space20">
{% for group in groups %}
{% set group_url = url({'for':'web.group.show','id':group.id}) %}
{% set group.about = group.about ? group.about : '这家伙真懒,什么都没留下!' %}
<div class="layui-col-md3">
<div class="user-card">
{{ type_info(group.type) }}
<div class="avatar">
<a href="{{ group_url }}" title="{{ group.about }}" target="group">
<img src="{{ group.avatar }}" alt="{{ group.name }}">
</a>
</div>
<div class="name layui-elip">
<a href="{{ group_url }}" title="{{ group.name }}" target="group">{{ group.name }}</a>
</div>
<div class="meta layui-elip">
<span>成员:{{ group.user_count }}</span>
<span>讨论:{{ group.msg_count }}</span>
</div>
<div class="action">
<span class="layui-btn apply-group" data-id="{{ group.id }}" data-name="{{ group.name }}" data-avatar="{{ group.avatar }}">加入群组</span>
</div>
</div>
</div>
{% endfor %}
</div>
</div>

View File

@ -0,0 +1,26 @@
<div class="user-list clearfix">
<div class="layui-row layui-col-space20">
{% for user in users %}
{% set user.title = user.title ? user.title : '暂露头角' %}
{% set user.about = user.about ? user.about : '这个人很懒,什么都没留下' %}
{% set user_url = url({'for':'web.user.show','id':user.id}) %}
<div class="layui-col-md2">
<div class="user-card">
{{ vip_info(user.vip) }}
<div class="avatar">
<a href="{{ user_url }}" title="{{ user.about }}" target="user">
<img src="{{ user.avatar }}" alt="{{ user.name }}">
</a>
</div>
<div class="name layui-elip">
<a href="{{ user_url }}" title="{{ user.about }}" target="user">{{ user.name }}</a>
</div>
<div class="title layui-elip">{{ user.title }}</div>
<div class="action">
<span class="layui-btn apply-friend" data-id="{{ user.id }}" data-name="{{ user.name }}" data-avatar="{{ user.avatar }}">添加好友</span>
</div>
</div>
</div>
{% endfor %}
</div>
</div>

View File

@ -0,0 +1,9 @@
{%- macro type_info(value) %}
{% if value == 'course' %}
<span class="layui-badge layui-bg-green type" title="课程交流">课</span>
{% elseif value == 'chat' %}
<span class="layui-badge layui-bg-blue type" title="课外畅聊">聊</span>
{% elseif value == 'staff' %}
<span class="layui-badge layui-bg-cyan type" title="职工交流">职</span>
{% endif %}
{%- endmacro %}

View File

@ -0,0 +1,5 @@
{%- macro vip_info(value) %}
{% if value == 1 %}
<span class="layui-badge layui-bg-orange vip">宾</span>
{% endif %}
{%- endmacro %}

View File

@ -1,3 +1,5 @@
{{ partial('macros/user') }}
{% if pager.total_pages > 0 %}
<div class="user-list clearfix">
<div class="layui-row layui-col-space20">
@ -7,9 +9,7 @@
{% set user_url = url({'for':'web.user.show','id':item.id}) %}
<div class="layui-col-md2">
<div class="user-card">
{% if item.vip == 1 %}
<span class="vip">VIP</span>
{% endif %}
{{ vip_info(item.vip) }}
<div class="avatar">
<a href="{{ user_url }}" title="{{ item.about }}">
<img src="{{ item.avatar }}" alt="{{ item.name }}">

View File

@ -1,3 +1,5 @@
{{ partial('macros/group') }}
{% if pager.total_pages > 0 %}
<div class="user-list clearfix">
<div class="layui-row layui-col-space20">
@ -6,11 +8,7 @@
{% set item.about = item.about ? item.about : '这家伙真懒,什么都没留下!' %}
<div class="layui-col-md3">
<div class="user-card">
{% if item.type == 'course' %}
<span class="layui-badge layui-bg-green type">课</span>
{% elseif item.type == 'chat' %}
<span class="layui-badge layui-bg-blue type">聊</span>
{% endif %}
{{ type_info(item.type) }}
<div class="avatar">
<a href="{{ group_url }}" title="{{ item.about }}">
<img src="{{ item.avatar }}" alt="{{ item.name }}">

View File

@ -1,3 +1,5 @@
{{ partial('macros/user') }}
{% if pager.total_pages > 0 %}
<div class="user-list vip-user-list clearfix">
<div class="layui-row layui-col-space20">
@ -7,9 +9,7 @@
{% set item.about = item.about ? item.about : '这个人很懒,什么都没留下' %}
<div class="layui-col-md2">
<div class="user-card">
{% if item.vip == 1 %}
<span class="layui-badge layui-bg-orange vip">VIP</span>
{% endif %}
{{ vip_info(item.vip) }}
<div class="avatar">
<a href="{{ user_url }}" title="{{ item.about }}">
<img src="{{ item.avatar }}" alt="{{ item.name }}">

View File

@ -76,6 +76,18 @@ class ImUser extends Repository
->execute();
}
/**
* @param int $userId
* @return ResultsetInterface|Resultset|ImGroupUserModel[]
*/
public function findGroupUsers($userId)
{
return ImGroupUserModel::query()
->where('user_id = :user_id:', ['user_id' => $userId])
->orderBy('update_time DESC')
->execute();
}
/**
* @param int $userId
* @return ResultsetInterface|Resultset|ImFriendUserModel[]

View File

@ -36,13 +36,13 @@ class ChapterList extends FrontendService
}
if ($user->id > 0 && $this->courseUser) {
$mappings = $this->getLearningMappings($course->id, $user->id, $this->courseUser->plan_id);
$mapping = $this->getLearningMapping($course->id, $user->id, $this->courseUser->plan_id);
foreach ($chapters as &$chapter) {
foreach ($chapter['children'] as &$lesson) {
$lesson['me'] = [
'owned' => $this->ownedCourse || $lesson['free'] ? 1 : 0,
'progress' => $mappings[$lesson['id']]['progress'] ?? 0,
'duration' => $mappings[$lesson['id']]['duration'] ?? 0,
'progress' => $mapping[$lesson['id']]['progress'] ?? 0,
'duration' => $mapping[$lesson['id']]['duration'] ?? 0,
];
}
}
@ -61,7 +61,7 @@ class ChapterList extends FrontendService
return $chapters;
}
protected function getLearningMappings($courseId, $userId, $planId)
protected function getLearningMapping($courseId, $userId, $planId)
{
$courseRepo = new CourseRepo();
@ -71,17 +71,17 @@ class ChapterList extends FrontendService
return [];
}
$mappings = [];
$mapping = [];
foreach ($userLearnings as $learning) {
$mappings[$learning->chapter_id] = [
$mapping[$learning->chapter_id] = [
'progress' => $learning->progress,
'duration' => $learning->duration,
'consumed' => $learning->consumed,
];
}
return $mappings;
return $mapping;
}
}

View File

@ -25,10 +25,10 @@ class LiveList extends FrontendService
return [];
}
$courseMappings = [];
$courseMapping = [];
foreach ($courses as $course) {
$courseMappings[$course->id] = [
$courseMapping[$course->id] = [
'id' => $course->id,
'title' => $course->title,
];
@ -51,7 +51,7 @@ class LiveList extends FrontendService
foreach ($pager->items as $item) {
$items[] = [
'course' => $courseMappings[$item->course_id],
'course' => $courseMapping[$item->course_id],
'chapter' => [
'id' => $item->id,
'title' => $item->title,

View File

@ -27,15 +27,26 @@
text-align: center;
}
.kg-login-form {
.kg-login-wrap {
width: 400px;
margin: 100px auto;
}
.kg-login-form {
padding: 15px 10px 5px 10px;
}
.kg-login-form .layui-input-block {
margin-left: 0;
}
.kg-login-copyright {
margin-top: -80px;
color: #999;
font-size: 12px;
text-align: center;
}
.kg-input-inline {
float: left;
width: 250px;

View File

@ -1345,6 +1345,7 @@ body {
height: 16px;
line-height: 16px;
padding: 0 3px;
font-size: 10px;
}
.user-card .type {
@ -1379,7 +1380,7 @@ body {
}
.group-list .user-card {
height: 250px;
height: 240px;
}
.group-about {