添加实时聊天模块
This commit is contained in:
parent
18332736e8
commit
eb9d903988
|
|
@ -63,8 +63,9 @@ class SwooleWebsocket extends Command
|
|||
|
||||
public function request($request, $response)
|
||||
{
|
||||
$data = Arr::get($request->post, 'data');
|
||||
$user_ids = Arr::get($request->post, 'user_ids',[]);
|
||||
$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失败
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
<?php
|
||||
|
||||
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
|
||||
if (!function_exists('uuid_generate')) {
|
||||
/**
|
||||
* 生成唯一不重复的uuid
|
||||
|
|
@ -38,24 +40,38 @@ if (!function_exists('push_message')) {
|
|||
/**
|
||||
* 推送websocket消息
|
||||
* @param $data
|
||||
* @param array $user_ids
|
||||
* @throws \GuzzleHttp\Exception\GuzzleException
|
||||
* @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($data, $accept_user_ids = [], $send_user_id = 0)
|
||||
{
|
||||
try {
|
||||
$users = \App\Models\User::query()->pluck('nickname', 'id')->toArray();
|
||||
foreach ($accept_user_ids as $accept_user_id) {
|
||||
\App\Models\Message::create([
|
||||
'send_user_id' => $send_user_id,
|
||||
'send_user_nickname' => \Illuminate\Support\Arr::get($users, $send_user_id, null),
|
||||
'accept_user_id' => $accept_user_id,
|
||||
'accept_user_nickname' => \Illuminate\Support\Arr::get($users, $accept_user_id, null),
|
||||
'title' => $data['title'] ?? null,
|
||||
'content' => $data['content'] ?? null,
|
||||
]);
|
||||
}
|
||||
$client = new \GuzzleHttp\Client();
|
||||
$client->post('http://127.0.0.1:9502',[
|
||||
'form_params' => [
|
||||
$client->post('http://127.0.0.1:9502', [
|
||||
'json' => [
|
||||
'data' => $data,
|
||||
'user_ids' => $user_ids,
|
||||
'user_ids' => $accept_user_ids,
|
||||
],
|
||||
'timeout' => 5,
|
||||
]);
|
||||
}catch (Exception $exception){
|
||||
\Illuminate\Support\Facades\Log::error('推送消息异常:'.$exception->getMessage());
|
||||
return true;
|
||||
} catch (Exception $exception) {
|
||||
\Illuminate\Support\Facades\Log::error('推送消息异常:' . $exception->getMessage());
|
||||
}
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,88 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Chat;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Message;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\View;
|
||||
|
||||
class MessageController extends Controller
|
||||
{
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
if ($request->ajax()){
|
||||
$type = $request->input('type');
|
||||
$res = Message::query();
|
||||
if ($type==2){ //通知
|
||||
$res = $res->where('send_user_id','=',0)
|
||||
->where('accept_user_id','=',$request->user()->id)
|
||||
->where('read','=',0);
|
||||
}elseif ($type==3){ //私信
|
||||
$res = $res->where('send_user_id','>',0)->where('accept_user_id','=',$request->user()->id);
|
||||
}
|
||||
$res = $res->orderBy('read','asc')->orderByDesc('id')->paginate($request->input('limit',30));
|
||||
return $this->success('ok',$res->items(),$res->total());
|
||||
}
|
||||
return View::make('chat.message.index');
|
||||
}
|
||||
|
||||
|
||||
public function create()
|
||||
{
|
||||
return View::make('chat.message.create');
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
if ($res){
|
||||
return $this->success();
|
||||
}
|
||||
return $this->success();
|
||||
}
|
||||
|
||||
|
||||
public function read(Request $request)
|
||||
{
|
||||
$ids = $request->input('ids');
|
||||
if (empty($ids)){
|
||||
return $this->error('请选择操作项');
|
||||
}
|
||||
try {
|
||||
Message::query()->whereIn('id',$ids)->update(['read'=>1]);
|
||||
return $this->success();
|
||||
}catch (\Exception $exception){
|
||||
Log::error('标记为已读操作异常:'.$exception->getMessage());
|
||||
return $this->error();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function show(Request $request,$id)
|
||||
{
|
||||
$model = Message::query()->where('id',$id)->first();
|
||||
return View::make('chat.message.show',compact('model'));
|
||||
}
|
||||
|
||||
|
||||
public function destroy(Request $request)
|
||||
{
|
||||
$ids = $request->get('ids');
|
||||
if (empty($ids)){
|
||||
return $this->error('请选择删除项');
|
||||
}
|
||||
try{
|
||||
Message::destroy($ids);
|
||||
return $this->success();
|
||||
}catch (\Exception $exception){
|
||||
Log::error('删除消息异常:'.$exception->getMessage());
|
||||
return $this->error();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -174,6 +174,26 @@ class MenuTableSeeder extends Seeder
|
|||
],
|
||||
]
|
||||
],
|
||||
[
|
||||
'name' => '实时聊天',
|
||||
'route' => null,
|
||||
'url' => null,
|
||||
'icon' => 'layui-icon-cellphone-fine',
|
||||
'type' => 2,
|
||||
'sort' => 2,
|
||||
'permission_name' => 'chat',
|
||||
'child' => [
|
||||
[
|
||||
'name' => '消息中心',
|
||||
'route' => 'chat.message',
|
||||
'url' => null,
|
||||
'icon' => 'layui-icon-note',
|
||||
'type' => 1,
|
||||
'permission_name' => 'chat.message',
|
||||
],
|
||||
|
||||
]
|
||||
],
|
||||
];
|
||||
$permissions = \App\Models\Permission::pluck('id','name')->toArray();
|
||||
foreach ($datas as $k1 => $d1){
|
||||
|
|
|
|||
|
|
@ -208,6 +208,23 @@ class UserTableSeeder extends Seeder
|
|||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'chat',
|
||||
'display_name' => '实时聊天',
|
||||
'child' => [
|
||||
[
|
||||
'name' => 'chat.message',
|
||||
'display_name' => '消息中心',
|
||||
'child' => [
|
||||
['name' => 'chat.message.create', 'display_name' => '发送消息'],
|
||||
['name' => 'chat.message.edit', 'display_name' => '详情'],
|
||||
['name' => 'chat.message.read', 'display_name' => '已读'],
|
||||
['name' => 'chat.message.destroy', 'display_name' => '删除'],
|
||||
]
|
||||
],
|
||||
|
||||
],
|
||||
],
|
||||
];
|
||||
foreach ($permissions as $pem1) {
|
||||
//生成一级权限
|
||||
|
|
|
|||
|
|
@ -0,0 +1,124 @@
|
|||
@extends('base')
|
||||
|
||||
@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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@section('script')
|
||||
<script>
|
||||
layui.config({
|
||||
base: '/layuiadmin/modules/'
|
||||
}).extend({
|
||||
treetable: 'treetable-lay/treetable'
|
||||
}).use(['layer', 'table', 'form', 'treetable'], function () {
|
||||
var $ = layui.jquery;
|
||||
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(); //调用此函数可重新渲染表格
|
||||
|
||||
//监听工具条
|
||||
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();
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
$("#addBtn").click(function () {
|
||||
layer.open({
|
||||
type: 2,
|
||||
title: "添加",
|
||||
shadeClose: true,
|
||||
area: ["600px","400px"],
|
||||
content: "{{route("crm.department.create")}}",
|
||||
end: function () {
|
||||
dataTable();
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
</script>
|
||||
@endsection
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
@extends('base')
|
||||
|
||||
@section('content')
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-fluid" id="LAY-app-message-detail">
|
||||
<div class="layui-card layuiAdmin-msg-detail">
|
||||
<script type="text/html" template lay-url="{{ layui.setter.base }}json/message/detail.js?id={{ layui.router().search.id }}">
|
||||
<div class="layui-card-header">
|
||||
<h1>{{ d.data.title }}</h1>
|
||||
<p>
|
||||
<span>{{ layui.util.timeAgo(d.data.time) }}</span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="layui-card-body layui-text">
|
||||
<div class="layadmin-text">
|
||||
{{ d.data.content }}
|
||||
<blockquote class="layui-elem-quote">
|
||||
注:这里读取的是静态的模拟接口,实际应用时,您可以在该页面源代码中,修改成以下任意一种方式
|
||||
<ul>
|
||||
<li>将 <em>lay-url=""</em> 改成你的真实接口,系统会自动识别该动态模板,直接前端渲染。</li>
|
||||
<li>剔除 script 动态模板标签,改成服务端渲染。</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
</div>
|
||||
|
||||
<div style="padding-top: 30px;">
|
||||
<a href="javascript:;" layadmin-event="back" class="layui-btn layui-btn-primary layui-btn-sm">返回上级</a>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@section('script')
|
||||
<script>
|
||||
layui.config({
|
||||
base: '/layuiadmin/modules/'
|
||||
}).extend({
|
||||
treetable: 'treetable-lay/treetable'
|
||||
}).use(['layer', 'table', 'form', 'treetable'], function () {
|
||||
var $ = layui.jquery;
|
||||
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(); //调用此函数可重新渲染表格
|
||||
|
||||
//监听工具条
|
||||
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();
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
$("#addBtn").click(function () {
|
||||
layer.open({
|
||||
type: 2,
|
||||
title: "添加",
|
||||
shadeClose: true,
|
||||
area: ["600px","400px"],
|
||||
content: "{{route("crm.department.create")}}",
|
||||
end: function () {
|
||||
dataTable();
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
</script>
|
||||
@endsection
|
||||
|
|
@ -298,3 +298,27 @@ Route::group(['prefix'=>'crm','namespace'=>'Crm','middleware'=>['auth','permissi
|
|||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| 实时聊天模块
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
Route::group(['prefix'=>'chat','namespace'=>'Chat','middleware'=>['auth','permission:chat']],function (){
|
||||
|
||||
//消息中心
|
||||
Route::group([],function (){
|
||||
Route::get('message','MessageController@index')->name('chat.message')->middleware('permission:chat.message');
|
||||
//添加
|
||||
Route::get('message/create','MessageController@create')->name('chat.message.create')->middleware('permission:chat.message.create');
|
||||
Route::post('message/store','MessageController@store')->name('chat.message.store')->middleware('permission:chat.message.create');
|
||||
//详情
|
||||
Route::get('message/{id}/show','MessageController@show')->name('chat.message.edit')->middleware('permission:chat.message.edit');
|
||||
//已读
|
||||
Route::post('message/read','MessageController@read')->name('chat.message.read')->middleware('permission:chat.message.read');
|
||||
//删除
|
||||
Route::delete('message/destroy','MessageController@destroy')->name('chat.message.destroy')->middleware('permission:chat.message.destroy');
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue