完善消息中心功能

This commit is contained in:
lilong@dgg.net 2021-03-26 18:18:23 +08:00
parent eb9d903988
commit 04247fcaf4
13 changed files with 908 additions and 110 deletions

View File

@ -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)

View File

@ -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,

View File

@ -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) {

View File

@ -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();
}

View File

@ -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('帐号已存在');

View File

@ -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

View File

@ -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')

View File

@ -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

View File

@ -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")}}",
})
})

View File

@ -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({

View File

@ -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>

View File

@ -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>