完善消息中心功能
This commit is contained in:
parent
eb9d903988
commit
04247fcaf4
|
|
@ -54,29 +54,38 @@ class SwooleWebsocket extends Command
|
|||
{
|
||||
$user_id = Arr::get($request->get,'user_id');
|
||||
$this->fd[$request->fd] = $user_id;
|
||||
$server->push($request->fd,json_encode(['scene'=>'init','data'=>'websocket已连接'],JSON_UNESCAPED_UNICODE));
|
||||
}
|
||||
|
||||
public function message($server, $request)
|
||||
{
|
||||
$server->push($request->fd,$request->data);
|
||||
$server->push($request->fd,json_encode(['scene'=>'heartbeat','data'=>'keep alive '.date('Y-m-d H:i:s')],JSON_UNESCAPED_UNICODE));
|
||||
}
|
||||
|
||||
public function request($request, $response)
|
||||
{
|
||||
$parms = $request->getContent();
|
||||
$data = Arr::get($parms, 'data');
|
||||
$user_ids = Arr::get($parms, 'user_ids',[]);
|
||||
if ($data != null && !empty($user_ids)) {
|
||||
foreach ($this->fd as $k => $v) {
|
||||
// 需要先判断是否是正确的websocket连接,否则有可能会push失败
|
||||
if ($this->ws->isEstablished($k)) {
|
||||
if (in_array($v,$user_ids)){
|
||||
$this->ws->push($k, $data);
|
||||
$parms = json_decode($request->getContent(),true);
|
||||
if ($parms){
|
||||
$scene = Arr::get($parms, 'scene');
|
||||
$data = Arr::get($parms, 'data');
|
||||
$user_ids = Arr::get($parms, 'user_ids',[]);
|
||||
$payload = json_encode([
|
||||
'scene' => $scene,
|
||||
'data' => $data,
|
||||
]);
|
||||
if ($data != null && !empty($user_ids)) {
|
||||
foreach ($this->fd as $k => $v) {
|
||||
// 需要先判断是否是正确的websocket连接,否则有可能会push失败
|
||||
if ($this->ws->isEstablished($k)) {
|
||||
if (in_array($v,$user_ids)){
|
||||
$this->ws->push($k, $payload);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$response->end("");
|
||||
}
|
||||
$response->end("");
|
||||
|
||||
}
|
||||
|
||||
public function close($server, $fd)
|
||||
|
|
|
|||
|
|
@ -38,14 +38,14 @@ if (!function_exists('recursive')) {
|
|||
|
||||
if (!function_exists('push_message')) {
|
||||
/**
|
||||
* 推送websocket消息
|
||||
* @param $scene
|
||||
* @param $data
|
||||
* @param array $accept_user_ids
|
||||
* @param int $send_user_id
|
||||
* @return bool
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
function push_message($data, $accept_user_ids = [], $send_user_id = 0)
|
||||
function push_message($scene,$data, $accept_user_ids = [], $send_user_id = 0)
|
||||
{
|
||||
try {
|
||||
$users = \App\Models\User::query()->pluck('nickname', 'id')->toArray();
|
||||
|
|
@ -62,7 +62,8 @@ if (!function_exists('push_message')) {
|
|||
$client = new \GuzzleHttp\Client();
|
||||
$client->post('http://127.0.0.1:9502', [
|
||||
'json' => [
|
||||
'data' => $data,
|
||||
'scene' => $scene,
|
||||
'data' => $data['title']??null,
|
||||
'user_ids' => $accept_user_ids,
|
||||
],
|
||||
'timeout' => 5,
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@ class ApiController extends Controller
|
|||
|
||||
public function getRoleByUserId(Request $request)
|
||||
{
|
||||
$data = [];
|
||||
$user_id = $request->input('user_id');
|
||||
$user = null;
|
||||
if ($user_id) {
|
||||
|
|
@ -47,12 +46,11 @@ class ApiController extends Controller
|
|||
foreach ($roles as $role) {
|
||||
$role->selected = $user != null && $user->hasRole($role);
|
||||
}
|
||||
return $this->success('ok', $data);
|
||||
return $this->success('ok', $roles);
|
||||
}
|
||||
|
||||
public function getDepartmentByUserId(Request $request)
|
||||
{
|
||||
$data = [];
|
||||
$user_id = $request->input('user_id');
|
||||
$user = null;
|
||||
if ($user_id) {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ namespace App\Http\Controllers\Chat;
|
|||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Message;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\View;
|
||||
|
|
@ -38,12 +39,23 @@ class MessageController extends Controller
|
|||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$data = $request->all(['title','content','accept_user_ids']);
|
||||
$res = push_message(['title'=>$data['title'],'content'=>$data['content']],$data['accept_user_ids'],$request->user()->id);
|
||||
$data = $request->all(['title','content','user_id']);
|
||||
try {
|
||||
$res = push_message('msg',
|
||||
[
|
||||
'title' => $data['title'],
|
||||
'content' => $data['content'],
|
||||
],
|
||||
[$data['user_id']],
|
||||
$request->user()->id
|
||||
);
|
||||
} catch (GuzzleException $e) {
|
||||
$res = false;
|
||||
}
|
||||
if ($res){
|
||||
return $this->success();
|
||||
}
|
||||
return $this->success();
|
||||
return $this->error();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ class UserController extends Controller
|
|||
{
|
||||
$data = $request->all(['phone','name','password','nickname','role_ids','sip_id','department_id']);
|
||||
$data['role_ids'] = $data['role_ids'] == null ? [] : explode(',',$data['role_ids']);
|
||||
$data['password'] = bcrypt($data['password']);
|
||||
$count = User::query()->where('name','=',$data['name'])->count();
|
||||
if ($count){
|
||||
return $this->error('帐号已存在');
|
||||
|
|
|
|||
|
|
@ -0,0 +1,228 @@
|
|||
.toast-title {
|
||||
font-weight: bold;
|
||||
}
|
||||
.toast-message {
|
||||
-ms-word-wrap: break-word;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
.toast-message a,
|
||||
.toast-message label {
|
||||
color: #FFFFFF;
|
||||
}
|
||||
.toast-message a:hover {
|
||||
color: #CCCCCC;
|
||||
text-decoration: none;
|
||||
}
|
||||
.toast-close-button {
|
||||
position: relative;
|
||||
right: -0.3em;
|
||||
top: -0.3em;
|
||||
float: right;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
color: #FFFFFF;
|
||||
-webkit-text-shadow: 0 1px 0 #ffffff;
|
||||
text-shadow: 0 1px 0 #ffffff;
|
||||
opacity: 0.8;
|
||||
-ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=80);
|
||||
filter: alpha(opacity=80);
|
||||
line-height: 1;
|
||||
}
|
||||
.toast-close-button:hover,
|
||||
.toast-close-button:focus {
|
||||
color: #000000;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
opacity: 0.4;
|
||||
-ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=40);
|
||||
filter: alpha(opacity=40);
|
||||
}
|
||||
.rtl .toast-close-button {
|
||||
left: -0.3em;
|
||||
float: left;
|
||||
right: 0.3em;
|
||||
}
|
||||
/*Additional properties for button version
|
||||
iOS requires the button element instead of an anchor tag.
|
||||
If you want the anchor version, it requires `href="#"`.*/
|
||||
button.toast-close-button {
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
.toast-top-center {
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
}
|
||||
.toast-bottom-center {
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
}
|
||||
.toast-top-full-width {
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
}
|
||||
.toast-bottom-full-width {
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
}
|
||||
.toast-top-left {
|
||||
top: 12px;
|
||||
left: 12px;
|
||||
}
|
||||
.toast-top-right {
|
||||
top: 12px;
|
||||
right: 12px;
|
||||
}
|
||||
.toast-bottom-right {
|
||||
right: 12px;
|
||||
bottom: 12px;
|
||||
}
|
||||
.toast-bottom-left {
|
||||
bottom: 12px;
|
||||
left: 12px;
|
||||
}
|
||||
#toast-container {
|
||||
position: fixed;
|
||||
z-index: 999999;
|
||||
pointer-events: none;
|
||||
/*overrides*/
|
||||
}
|
||||
#toast-container * {
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
#toast-container > div {
|
||||
position: relative;
|
||||
pointer-events: auto;
|
||||
overflow: hidden;
|
||||
margin: 0 0 6px;
|
||||
padding: 15px 15px 15px 50px;
|
||||
width: 300px;
|
||||
-moz-border-radius: 3px 3px 3px 3px;
|
||||
-webkit-border-radius: 3px 3px 3px 3px;
|
||||
border-radius: 3px 3px 3px 3px;
|
||||
background-position: 15px center;
|
||||
background-repeat: no-repeat;
|
||||
-moz-box-shadow: 0 0 12px #999999;
|
||||
-webkit-box-shadow: 0 0 12px #999999;
|
||||
box-shadow: 0 0 12px #999999;
|
||||
color: #FFFFFF;
|
||||
opacity: 0.8;
|
||||
-ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=80);
|
||||
filter: alpha(opacity=80);
|
||||
}
|
||||
#toast-container > div.rtl {
|
||||
direction: rtl;
|
||||
padding: 15px 50px 15px 15px;
|
||||
background-position: right 15px center;
|
||||
}
|
||||
#toast-container > div:hover {
|
||||
-moz-box-shadow: 0 0 12px #000000;
|
||||
-webkit-box-shadow: 0 0 12px #000000;
|
||||
box-shadow: 0 0 12px #000000;
|
||||
opacity: 1;
|
||||
-ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=100);
|
||||
filter: alpha(opacity=100);
|
||||
cursor: pointer;
|
||||
}
|
||||
#toast-container > .toast-info {
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGwSURBVEhLtZa9SgNBEMc9sUxxRcoUKSzSWIhXpFMhhYWFhaBg4yPYiWCXZxBLERsLRS3EQkEfwCKdjWJAwSKCgoKCcudv4O5YLrt7EzgXhiU3/4+b2ckmwVjJSpKkQ6wAi4gwhT+z3wRBcEz0yjSseUTrcRyfsHsXmD0AmbHOC9Ii8VImnuXBPglHpQ5wwSVM7sNnTG7Za4JwDdCjxyAiH3nyA2mtaTJufiDZ5dCaqlItILh1NHatfN5skvjx9Z38m69CgzuXmZgVrPIGE763Jx9qKsRozWYw6xOHdER+nn2KkO+Bb+UV5CBN6WC6QtBgbRVozrahAbmm6HtUsgtPC19tFdxXZYBOfkbmFJ1VaHA1VAHjd0pp70oTZzvR+EVrx2Ygfdsq6eu55BHYR8hlcki+n+kERUFG8BrA0BwjeAv2M8WLQBtcy+SD6fNsmnB3AlBLrgTtVW1c2QN4bVWLATaIS60J2Du5y1TiJgjSBvFVZgTmwCU+dAZFoPxGEEs8nyHC9Bwe2GvEJv2WXZb0vjdyFT4Cxk3e/kIqlOGoVLwwPevpYHT+00T+hWwXDf4AJAOUqWcDhbwAAAAASUVORK5CYII=") !important;
|
||||
}
|
||||
#toast-container > .toast-error {
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAHOSURBVEhLrZa/SgNBEMZzh0WKCClSCKaIYOED+AAKeQQLG8HWztLCImBrYadgIdY+gIKNYkBFSwu7CAoqCgkkoGBI/E28PdbLZmeDLgzZzcx83/zZ2SSXC1j9fr+I1Hq93g2yxH4iwM1vkoBWAdxCmpzTxfkN2RcyZNaHFIkSo10+8kgxkXIURV5HGxTmFuc75B2RfQkpxHG8aAgaAFa0tAHqYFfQ7Iwe2yhODk8+J4C7yAoRTWI3w/4klGRgR4lO7Rpn9+gvMyWp+uxFh8+H+ARlgN1nJuJuQAYvNkEnwGFck18Er4q3egEc/oO+mhLdKgRyhdNFiacC0rlOCbhNVz4H9FnAYgDBvU3QIioZlJFLJtsoHYRDfiZoUyIxqCtRpVlANq0EU4dApjrtgezPFad5S19Wgjkc0hNVnuF4HjVA6C7QrSIbylB+oZe3aHgBsqlNqKYH48jXyJKMuAbiyVJ8KzaB3eRc0pg9VwQ4niFryI68qiOi3AbjwdsfnAtk0bCjTLJKr6mrD9g8iq/S/B81hguOMlQTnVyG40wAcjnmgsCNESDrjme7wfftP4P7SP4N3CJZdvzoNyGq2c/HWOXJGsvVg+RA/k2MC/wN6I2YA2Pt8GkAAAAASUVORK5CYII=") !important;
|
||||
}
|
||||
#toast-container > .toast-success {
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADsSURBVEhLY2AYBfQMgf///3P8+/evAIgvA/FsIF+BavYDDWMBGroaSMMBiE8VC7AZDrIFaMFnii3AZTjUgsUUWUDA8OdAH6iQbQEhw4HyGsPEcKBXBIC4ARhex4G4BsjmweU1soIFaGg/WtoFZRIZdEvIMhxkCCjXIVsATV6gFGACs4Rsw0EGgIIH3QJYJgHSARQZDrWAB+jawzgs+Q2UO49D7jnRSRGoEFRILcdmEMWGI0cm0JJ2QpYA1RDvcmzJEWhABhD/pqrL0S0CWuABKgnRki9lLseS7g2AlqwHWQSKH4oKLrILpRGhEQCw2LiRUIa4lwAAAABJRU5ErkJggg==") !important;
|
||||
}
|
||||
#toast-container > .toast-warning {
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAGYSURBVEhL5ZSvTsNQFMbXZGICMYGYmJhAQIJAICYQPAACiSDB8AiICQQJT4CqQEwgJvYASAQCiZiYmJhAIBATCARJy+9rTsldd8sKu1M0+dLb057v6/lbq/2rK0mS/TRNj9cWNAKPYIJII7gIxCcQ51cvqID+GIEX8ASG4B1bK5gIZFeQfoJdEXOfgX4QAQg7kH2A65yQ87lyxb27sggkAzAuFhbbg1K2kgCkB1bVwyIR9m2L7PRPIhDUIXgGtyKw575yz3lTNs6X4JXnjV+LKM/m3MydnTbtOKIjtz6VhCBq4vSm3ncdrD2lk0VgUXSVKjVDJXJzijW1RQdsU7F77He8u68koNZTz8Oz5yGa6J3H3lZ0xYgXBK2QymlWWA+RWnYhskLBv2vmE+hBMCtbA7KX5drWyRT/2JsqZ2IvfB9Y4bWDNMFbJRFmC9E74SoS0CqulwjkC0+5bpcV1CZ8NMej4pjy0U+doDQsGyo1hzVJttIjhQ7GnBtRFN1UarUlH8F3xict+HY07rEzoUGPlWcjRFRr4/gChZgc3ZL2d8oAAAAASUVORK5CYII=") !important;
|
||||
}
|
||||
#toast-container.toast-top-center > div,
|
||||
#toast-container.toast-bottom-center > div {
|
||||
width: 300px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
#toast-container.toast-top-full-width > div,
|
||||
#toast-container.toast-bottom-full-width > div {
|
||||
width: 96%;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
.toast {
|
||||
background-color: #030303;
|
||||
}
|
||||
.toast-success {
|
||||
background-color: #51A351;
|
||||
}
|
||||
.toast-error {
|
||||
background-color: #BD362F;
|
||||
}
|
||||
.toast-info {
|
||||
background-color: #2F96B4;
|
||||
}
|
||||
.toast-warning {
|
||||
background-color: #F89406;
|
||||
}
|
||||
.toast-progress {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
height: 4px;
|
||||
background-color: #000000;
|
||||
opacity: 0.4;
|
||||
-ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=40);
|
||||
filter: alpha(opacity=40);
|
||||
}
|
||||
/*Responsive Design*/
|
||||
@media all and (max-width: 240px) {
|
||||
#toast-container > div {
|
||||
padding: 8px 8px 8px 50px;
|
||||
width: 11em;
|
||||
}
|
||||
#toast-container > div.rtl {
|
||||
padding: 8px 50px 8px 8px;
|
||||
}
|
||||
#toast-container .toast-close-button {
|
||||
right: -0.2em;
|
||||
top: -0.2em;
|
||||
}
|
||||
#toast-container .rtl .toast-close-button {
|
||||
left: -0.2em;
|
||||
right: 0.2em;
|
||||
}
|
||||
}
|
||||
@media all and (min-width: 241px) and (max-width: 480px) {
|
||||
#toast-container > div {
|
||||
padding: 8px 8px 8px 50px;
|
||||
width: 18em;
|
||||
}
|
||||
#toast-container > div.rtl {
|
||||
padding: 8px 50px 8px 8px;
|
||||
}
|
||||
#toast-container .toast-close-button {
|
||||
right: -0.2em;
|
||||
top: -0.2em;
|
||||
}
|
||||
#toast-container .rtl .toast-close-button {
|
||||
left: -0.2em;
|
||||
right: 0.2em;
|
||||
}
|
||||
}
|
||||
@media all and (min-width: 481px) and (max-width: 768px) {
|
||||
#toast-container > div {
|
||||
padding: 15px 15px 15px 50px;
|
||||
width: 25em;
|
||||
}
|
||||
#toast-container > div.rtl {
|
||||
padding: 15px 50px 15px 15px;
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -22,11 +22,13 @@
|
|||
layui.config({
|
||||
base: '/layuiadmin/' //静态资源所在路径
|
||||
}).extend({
|
||||
index: 'lib/index' //主入口模块
|
||||
index: 'lib/index', //主入口模块
|
||||
}).use(['element', 'form', 'layer', 'table', 'upload', 'laydate', 'jquery'], function () {
|
||||
var $ = layui.jquery;
|
||||
var form = layui.form;
|
||||
var table = layui.table;
|
||||
|
||||
|
||||
$.ajaxSetup({
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
|
||||
|
|
@ -164,6 +166,9 @@
|
|||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
});
|
||||
</script>
|
||||
@yield('script')
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
@extends('base')
|
||||
|
||||
@section('content')
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<form action="{{route('chat.message.store')}}" method="post" class="layui-form">
|
||||
{{csrf_field()}}
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">发送给</label>
|
||||
<div class="layui-input-block">
|
||||
@include('common.get_user')
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">标题</label>
|
||||
<div class="layui-input-block">
|
||||
<input class="layui-input" type="text" name="title" lay-verify="required" placeholder="请输入">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">内容</label>
|
||||
<div class="layui-input-block">
|
||||
<textarea name="content" class="layui-textarea" placeholder="请输入" ></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button type="button" class="layui-btn layui-btn-sm" lay-submit lay-filter="go-close-refresh" >确认</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
|
@ -2,39 +2,27 @@
|
|||
|
||||
@section('content')
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-tab layui-tab-brief">
|
||||
<ul class="layui-tab-title">
|
||||
<li class="layui-this">全部消息</li>
|
||||
<li>通知<span class="layui-badge">6</span></li>
|
||||
<li>私信</li>
|
||||
</ul>
|
||||
<div class="layui-tab-content">
|
||||
<div class="layui-tab-item layui-show">
|
||||
<div class="LAY-app-message-btns" style="margin-bottom: 10px;">
|
||||
<button class="layui-btn layui-btn-primary layui-btn-sm" data-type="all" data-events="del">删除</button>
|
||||
<button class="layui-btn layui-btn-primary layui-btn-sm" data-type="all" data-events="ready">标记已读</button>
|
||||
<button class="layui-btn layui-btn-primary layui-btn-sm" data-type="all" data-events="readyAll">全部已读</button>
|
||||
</div>
|
||||
<table id="LAY-app-message-all" lay-filter="LAY-app-message-all"></table>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<div class="LAY-app-message-btns" style="margin-bottom: 10px;">
|
||||
<button class="layui-btn layui-btn-primary layui-btn-sm" data-type="notice" data-events="del">删除</button>
|
||||
<button class="layui-btn layui-btn-primary layui-btn-sm" data-type="notice" data-events="ready">标记已读</button>
|
||||
<button class="layui-btn layui-btn-primary layui-btn-sm" data-type="notice" data-events="readyAll">全部已读</button>
|
||||
</div>
|
||||
<table id="LAY-app-message-notice" lay-filter="LAY-app-message-notice"></table>
|
||||
</div>
|
||||
<div class="layui-tab-item">
|
||||
<div class="LAY-app-message-btns" style="margin-bottom: 10px;">
|
||||
<button class="layui-btn layui-btn-primary layui-btn-sm" data-type="direct" data-events="del">删除</button>
|
||||
<button class="layui-btn layui-btn-primary layui-btn-sm" data-type="direct" data-events="ready">标记已读</button>
|
||||
<button class="layui-btn layui-btn-primary layui-btn-sm" data-type="direct" data-events="readyAll">全部已读</button>
|
||||
</div>
|
||||
<table id="LAY-app-message-direct" lay-filter="LAY-app-message-direct"></table>
|
||||
</div>
|
||||
<div class="layui-card-header layuiadmin-card-header-auto">
|
||||
<form class="layui-form">
|
||||
<div class="layui-btn-group">
|
||||
@can('chat.message.destroy')
|
||||
<button type="button" class="layui-btn layui-btn-sm layui-btn-danger" id="listDelete" data-url="{{ route('chat.message.destroy') }}">删除</button>
|
||||
@endcan
|
||||
@can('chat.message.create')
|
||||
<a class="layui-btn layui-btn-sm" id="addBtn" >发送消息</a>
|
||||
@endcan
|
||||
@can('chat.message.read')
|
||||
<a class="layui-btn layui-btn-sm" id="addBtn" >标记已读</a>
|
||||
@endcan
|
||||
@can('chat.message.read')
|
||||
<a class="layui-btn layui-btn-sm" id="addBtn" >全部已读</a>
|
||||
@endcan
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<table id="dataTable" lay-filter="dataTable"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -51,71 +39,59 @@
|
|||
var layer = layui.layer;
|
||||
var form = layui.form;
|
||||
var table = layui.table;
|
||||
var treetable = layui.treetable;
|
||||
// 渲染表格
|
||||
var dataTable = function () {
|
||||
treetable.render({
|
||||
treeColIndex: 1, // treetable新增参数
|
||||
treeSpid: 0, // treetable新增参数
|
||||
treeIdName: 'id', // treetable新增参数
|
||||
treePidName: 'parent_id', // treetable新增参数
|
||||
treeDefaultClose: false, // treetable新增参数
|
||||
treeLinkage: false, // treetable新增参数
|
||||
elem: '#dataTable',
|
||||
url: "{{ route('crm.department') }}",
|
||||
cols: [[ //表头
|
||||
{field: 'id', title: 'ID', sort: true, width: 80}
|
||||
, {field: 'name', title: '名称'}
|
||||
, {field: 'business_user_nickname', title: '部门经理'}
|
||||
, {field: 'created_at', title: '创建时间'}
|
||||
, {field: 'updated_at', title: '更新时间'}
|
||||
, {fixed: 'right',title:'操作', width: 260, align: 'center', toolbar: '#options'}
|
||||
]]
|
||||
});
|
||||
}
|
||||
dataTable(); //调用此函数可重新渲染表格
|
||||
//用户表格初始化
|
||||
var dataTable = table.render({
|
||||
elem: '#dataTable'
|
||||
,height: 'full-200'
|
||||
,url: "{{ route('chat.message') }}" //数据接口
|
||||
,page: true //开启分页
|
||||
,cols: [[ //表头
|
||||
{checkbox: true}
|
||||
,{field: 'read', title: '状态',width:80,templet:function (d) {
|
||||
return d.read==0?'<span class="layui-badge layui-bg-black">未读</span>':'<span class="layui-badge layui-bg-gray">已读</span>'
|
||||
}}
|
||||
,{field: 'title', title: '标题',width:200}
|
||||
,{field: 'content', title: '内容',width:700}
|
||||
,{field: 'send_user_nickname', title: '发送人',templet:function (d) {
|
||||
return d.send_user_id == 0 ? '系统' : d.send_user_nickname;
|
||||
}}
|
||||
,{field: 'accept_user_nickname', title: '接收人'}
|
||||
,{field: 'created_at', title: '发送时间'}
|
||||
]]
|
||||
,done: function (res, curr, count) {
|
||||
trNum = count;
|
||||
for(var i = 0;i<res.data.length;i++){
|
||||
var state = res.data[i].checkStatus;
|
||||
if(res.data[i].read == 1){
|
||||
var index = res.data[i]['LAY_TABLE_INDEX'];
|
||||
$(".layui-table tr[data-index="+index+"] input[type='checkbox']").prop('disabled',true);
|
||||
$(".layui-table tr[data-index="+index+"] input[type='checkbox']").next().addClass('layui-btn-disabled');
|
||||
|
||||
|
||||
//$(".layui-table tr[data-index="+index+"] td:first-child").html('');
|
||||
//$(".layui-table tr[data-index="+index+"] input[type='checkbox']").remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
//监听工具条
|
||||
table.on('tool(dataTable)', function(obj){ //注:tool是工具条事件名,dataTable是table原始容器的属性 lay-filter="对应的值"
|
||||
var data = obj.data //获得当前行数据
|
||||
,layEvent = obj.event; //获得 lay-event 对应的值
|
||||
if(layEvent === 'del'){
|
||||
deleteData(obj,"{{ route('crm.department.destroy') }}");
|
||||
} else if(layEvent === 'edit'){
|
||||
layer.open({
|
||||
type: 2,
|
||||
title: "编辑",
|
||||
shadeClose: true,
|
||||
area: ["600px","400px"],
|
||||
content: '/crm/department/'+data.id+'/edit',
|
||||
end: function () {
|
||||
dataTable();
|
||||
}
|
||||
})
|
||||
} else if(layEvent === 'create'){
|
||||
layer.open({
|
||||
type: 2,
|
||||
title: "添加子部门",
|
||||
shadeClose: true,
|
||||
area: ["600px","400px"],
|
||||
content: '/crm/department/create?parent_id=' + data.id,
|
||||
end: function () {
|
||||
dataTable();
|
||||
}
|
||||
})
|
||||
if(layEvent === 'show'){
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
$("#addBtn").click(function () {
|
||||
layer.open({
|
||||
type: 2,
|
||||
title: "添加",
|
||||
title: "发送消息",
|
||||
shadeClose: true,
|
||||
area: ["600px","400px"],
|
||||
content: "{{route("crm.department.create")}}",
|
||||
end: function () {
|
||||
dataTable();
|
||||
}
|
||||
content: "{{route("chat.message.create")}}",
|
||||
})
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
// 一般来说,权限数据是异步传递过来的
|
||||
$.ajax({
|
||||
method: 'post',
|
||||
url: '{{route('api.getRoleByUserId',['user_id'=>$user_id??null])}}',
|
||||
url: '{{route('api.getRoleByUserId',['user_id'=>$user_id??0])}}',
|
||||
dataType: 'json',
|
||||
success: function (res) {
|
||||
var demo1 = xmSelect.render({
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{{csrf_field()}}
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">名称</label>
|
||||
<label for="" class="layui-form-label">部门名称</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="hidden" name="parent_id" value="{{$parent_id??0}}">
|
||||
<input class="layui-input" type="text" name="name" lay-verify="required" value="{{$model->name??''}}" placeholder="请输入名称">
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">人员</label>
|
||||
<label for="" class="layui-form-label">部门经理</label>
|
||||
<div class="layui-input-block">
|
||||
@include('common.get_user',['user_id'=>$model->business_user_id??0])
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -220,10 +220,27 @@
|
|||
layui.config({
|
||||
base: '/layuiadmin/' //静态资源所在路径
|
||||
}).extend({
|
||||
index: 'lib/index' //主入口模块
|
||||
}).use(['index', 'layer', 'jquery'], function () {
|
||||
index: 'lib/index',
|
||||
notice: 'notice/notice',
|
||||
}).use(['index', 'layer', 'jquery','notice'], function () {
|
||||
var layer = layui.layer;
|
||||
var $ = layui.jquery;
|
||||
var notice = layui.notice;
|
||||
// 初始化配置,同一样式只需要配置一次,非必须初始化,有默认配置
|
||||
notice.options = {
|
||||
closeButton:true,//显示关闭按钮
|
||||
debug:false,//启用debug
|
||||
positionClass:"toast-bottom-right",//弹出的位置,
|
||||
showDuration:"300",//显示的时间
|
||||
hideDuration:"1000",//消失的时间
|
||||
timeOut:"5000",//停留的时间
|
||||
extendedTimeOut:"1000",//控制时间
|
||||
showEasing:"swing",//显示时的动画缓冲方式
|
||||
hideEasing:"linear",//消失时的动画缓冲方式
|
||||
iconClass: 'toast-info', // 自定义图标,有内置,如不需要则传空 支持layui内置图标/自定义iconfont类名
|
||||
onclick: null, // 点击关闭回调
|
||||
};
|
||||
|
||||
$(".change-password").on("click", function () {
|
||||
layer.open({
|
||||
type: 2,
|
||||
|
|
@ -322,6 +339,37 @@
|
|||
}
|
||||
})
|
||||
|
||||
|
||||
const ws = new WebSocket("ws://127.0.0.1:9502?user_id={{auth()->user()->id}}")
|
||||
var ticker
|
||||
ws.onopen = function () {
|
||||
ticker = setInterval(function () {
|
||||
ws.send('{"scene":"heartbeat","data":""}')
|
||||
},30000)
|
||||
}
|
||||
ws.onmessage = function (e) {
|
||||
console.log("收到服务端消息:" + e.data)
|
||||
let data = JSON.parse(e.data);
|
||||
if (data.scene != undefined){
|
||||
switch (data.scene) {
|
||||
case 'heartbeat':
|
||||
console.log(data.data)
|
||||
break;
|
||||
case 'msg':
|
||||
notice.info(data.data)
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ws.onclose = function (e) {
|
||||
console.log("websocket已断开")
|
||||
if(ticker){
|
||||
clearInterval(ticker)
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue