完成群呼队列管理功能

This commit is contained in:
lilong@dgg.net 2021-04-13 10:55:50 +08:00
parent 38ce9407cd
commit e89372b761
15 changed files with 443 additions and 3 deletions

View File

@ -14,6 +14,7 @@ use App\Models\Role;
use App\Models\Sip;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Facades\Storage;
@ -263,7 +264,6 @@ class ApiController extends Controller
}
public function payList(Request $request)
{
$id = $request->input('id');
@ -271,4 +271,19 @@ class ApiController extends Controller
return $this->success('ok',['list'=>$res->items(),'lastPage'=>$res->lastPage()]);
}
public function getSipsByQueueId(Request $request)
{
$queueId = $request->input('queue_id');
$lists = Sip::with('user')->get();
$values = [];
if ($queueId){
$values = DB::table('queue_sip')->where('queue_id',$queueId)->pluck('sip_id')->toArray();
}
foreach ($lists as $item){
$item->checked = in_array($item->id,$values) ? true : false;
}
return $this->success('ok',['lists'=>$lists,'values'=>$values]);
}
}

View File

@ -0,0 +1,127 @@
<?php
namespace App\Http\Controllers\Callcenter;
use App\Http\Controllers\Controller;
use GuzzleHttp\Client;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\View;
use App\Models\Queue;
class QueueController extends Controller
{
public function index(Request $request)
{
if ($request->ajax()){
$res = Queue::withCount('sips')->orderByDesc('id')->paginate($request->input('limit',30));
return $this->success('ok',$res->items(),$res->total());
}
return View::make('callcenter.queue.index');
}
public function create()
{
return View::make('callcenter.queue.create');
}
public function store(Request $request)
{
$data = $request->all([
'name',
'strategy',
'max_wait_time',
'sips',
]);
$data['sips'] = $data['sips'] ? explode(',',$data['sips']) : [];
DB::beginTransaction();
try {
$queueId = DB::table('queue')->insertGetId([
'name' => $data['name'],
'strategy' => $data['strategy'],
'max_wait_time' => $data['max_wait_time'],
]);
foreach ($data['sips'] as $sipId){
DB::table('queue_sip')->insert([
'queue_id' => $queueId,
'sip_id' => $sipId,
]);
}
DB::commit();
return $this->success();
}catch (\Exception $exception){
DB::rollBack();
Log::error('添加队列异常:'.$exception->getMessage());
return $this->error();
}
}
public function edit($id)
{
$model = Queue::query()->where('id',$id)->first();
return View::make('callcenter.queue.edit',compact('model'));
}
public function update(Request $request,$id)
{
$model = Queue::query()->where('id',$id)->first();
$data = $request->all([
'name',
'strategy',
'max_wait_time',
]);
$sipids = $request->input('sips') ? explode(',',$request->input('sips')) : [];
DB::beginTransaction();
try {
$model->update($data);
$model->sips()->sync($sipids);
DB::commit();
return $this->success();
}catch (\Exception $exception){
DB::rollBack();
Log::error('更新队列异常:'.$exception->getMessage());
return $this->error();
}
}
public function destroy(Request $request)
{
$ids = $request->get('ids');
if (empty($ids)){
return $this->error('请选择删除项');
}
DB::beginTransaction();
try{
DB::table('queue_sip')->whereIn('queue_id',$ids)->delete();
DB::table('queue')->whereIn('id',$ids)->delete();
DB::commit();
return $this->success();
}catch (\Exception $exception){
DB::rollBack();
Log::error('删除队列异常:'.$exception->getMessage());
return $this->error();
}
}
public function updateXml()
{
$queues = Queue::with('sips')->get()->toArray();
try{
$client = new Client();
$client->post(config('freeswitch.swoole_http_url.callcenter'),
[
'json' => $queues,
'timeout' => 30
]
);
return $this->success();
}catch (\Exception $exception){
Log::error('更新群呼配置异常:' . $exception->getMessage());
return $this->error('更新失败');
}
}
}

View File

@ -0,0 +1,11 @@
<?php
namespace App\Http\Controllers\Callcenter;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
class Task extends Controller
{
//
}

24
app/Models/Queue.php Normal file
View File

@ -0,0 +1,24 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Arr;
class Queue extends Model
{
protected $table = 'queue';
protected $guarded = ['id'];
protected $appends = ['strategy_name'];
public function sips()
{
return $this->belongsToMany(Sip::class,'queue_sip');
}
public function getStrategyNameAttribute()
{
return $this->attributes['strategy_name'] = Arr::get(config('freeswitch.strategy'),$this->strategy);
}
}

View File

@ -34,7 +34,7 @@ class Sip extends Model
*/
public function user()
{
return $this->hasOne('App\Models\User','sip_id','id')->withDefault(['nickname'=>'-']);
return $this->hasOne('App\Models\User','sip_id','id')->withDefault(['nickname'=>'未分配']);
}
}

View File

@ -6,5 +6,6 @@ use Illuminate\Database\Eloquent\Model;
class Task extends Model
{
//
protected $table = 'task';
protected $guarded = ['id'];
}

View File

@ -99,6 +99,25 @@ class MenuTableSeeder extends Seeder
],
]
],
[
'name' => '群呼管理',
'route' => null,
'url' => null,
'icon' => 'layui-icon-group',
'type' => 2,
'sort' => 2,
'permission_name' => 'callcenter',
'child' => [
[
'name' => '队列管理',
'route' => 'callcenter.queue',
'url' => null,
'icon' => 'layui-icon-user',
'type' => 1,
'permission_name' => 'callcenter.queue',
],
]
],
[
'name' => '实时聊天',
'route' => null,

View File

@ -123,6 +123,22 @@ class UserTableSeeder extends Seeder
],
],
],
[
'name' => 'callcenter',
'display_name' => '群呼管理',
'child' => [
[
'name' => 'callcenter.queue',
'display_name' => '队列管理',
'child' => [
['name' => 'callcenter.queue.create', 'display_name' => '添加'],
['name' => 'callcenter.queue.edit', 'display_name' => '编辑'],
['name' => 'callcenter.queue.destroy', 'display_name' => '删除'],
['name' => 'callcenter.queue.updateXml', 'display_name' => '更新配置'],
]
],
],
],
[
'name' => 'crm',
'display_name' => 'CRM管理',

View File

@ -0,0 +1,35 @@
{{csrf_field()}}
<div class="layui-form-item">
<label for="" class="layui-form-label">队列名称</label>
<div class="layui-input-block">
<input class="layui-input" type="text" name="name" lay-verify="required" value="{{$model->name??old('name')}}" placeholder="如:队列一">
</div>
</div>
<div class="layui-form-item">
<label for="" class="layui-form-label">振铃策略</label>
<div class="layui-input-block">
<select name="strategy" >
@foreach(config('freeswitch.strategy') as $k => $v)
<option value="{{$k}}">{{$v}}</option>
@endforeach
</select>
</div>
</div>
<div class="layui-form-item">
<label for="" class="layui-form-label">超时时间</label>
<div class="layui-input-inline">
<input class="layui-input" type="text" maxlength="4" name="max_wait_time" lay-verify="required|number" value="{{$model->max_wait_time??0}}" placeholder="">
</div>
<div class="layui-form-mid layui-word-aux">最大等待时间0为一直等待</div>
</div>
<div class="layui-form-item">
<label for="" class="layui-form-label">分配坐席</label>
<div class="layui-input-block">
@include('common.get_sips_by_queue_id',['queue_id'=>$model->id??0])
</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>

View File

@ -0,0 +1,12 @@
@extends('base')
@section('content')
<div class="layui-card">
<div class="layui-card-body">
<form action="{{route('callcenter.queue.store')}}" method="post" class="layui-form">
@include('callcenter.queue._form')
</form>
</div>
</div>
@endsection

View File

@ -0,0 +1,12 @@
@extends('base')
@section('content')
<div class="layui-card">
<div class="layui-card-body">
<form action="{{route('callcenter.queue.update',['id'=>$model->id])}}" method="post" class="layui-form">
{{method_field('put')}}
@include('callcenter.queue._form')
</form>
</div>
</div>
@endsection

View File

@ -0,0 +1,98 @@
@extends('base')
@section('content')
<div class="layui-card">
<div class="layui-card-header layuiadmin-card-header-auto">
<form class="layui-form">
<div class="layui-btn-group">
@can('callcenter.queue.destroy')
<button class="layui-btn layui-btn-sm layui-btn-danger" type="button" id="listDelete" data-url="{{route('callcenter.queue.destroy')}}">删除</button>
@endcan
@can('callcenter.queue.create')
<button type="button" class="layui-btn layui-btn-sm" id="addBtn">添加</button>
@endcan
@can('callcenter.queue.updateXml')
<button class="layui-btn layui-btn-sm" type="button" id="updateXml">更新配置</button>
@endcan
</div>
</form>
</div>
<div class="layui-card-body">
<table id="dataTable" lay-filter="dataTable"></table>
<script type="text/html" id="options">
<div class="layui-btn-group">
@can('callcenter.queue.edit')
<a class="layui-btn layui-btn-sm" lay-event="edit">编辑</a>
@endcan
</div>
</script>
</div>
</div>
@endsection
@section('script')
<script>
layui.use(['layer','table','form','jquery'],function () {
var $ = layui.jquery;
var layer = layui.layer;
var form = layui.form;
var table = layui.table;
//用户表格初始化
var dataTable = table.render({
elem: '#dataTable'
,height: 'full-200'
,url: "{{ route('callcenter.queue') }}" //数据接口
,page: true //开启分页
,cols: [[ //表头
{checkbox: true}
,{field: 'id', title: 'ID', sort: true,width:80}
,{field: 'name', title: '队列名称'}
,{field: 'strategy_name', title: '振铃策略'}
,{field: 'sips_count', title: '坐席数量'}
,{field: 'max_wait_time', title: '超时时间(秒)'}
,{field: 'created_at', title: '添加时间'}
,{ width: 220, align:'center', toolbar: '#options', title:'操作'}
]]
});
//监听工具条
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('callcenter.queue.destroy') }}");
} else if(layEvent === 'edit'){
layer.open({
type: 2,
title: "编辑",
shadeClose: true,
area: ["800px","600px"],
content: '/callcenter/queue/'+data.id+'/edit',
})
}
});
$("#addBtn").click(function () {
layer.open({
type: 2,
title: "添加",
shadeClose: true,
area: ["800px","600px"],
content: '/callcenter/queue/create',
})
})
//更新配置
$("#updateXml").click(function () {
layer.confirm('确认更新配置吗?', function (index) {
layer.close(index);
var load = layer.load();
$.post("{{ route('callcenter.queue.updateXml') }}", {}, function (res) {
layer.close(load);
layer.msg(res.msg, {icon: res.code === 0 ? 1 : 2})
});
})
})
})
</script>
@endsection

View File

@ -0,0 +1,45 @@
<div id="transfer-sips"></div>
<input type="hidden" name="sips" id="sips">
<script>
layui.use(['jquery','form', 'layer','transfer'], function () {
var $ = layui.jquery;
var form = layui.form;
var layer = layui.layer;
var transfer = layui.transfer;
// 一般来说,权限数据是异步传递过来的
$.ajax({
method: 'post',
url: '/api/get_sips_by_queue_id?queue_id={{$queue_id}}',
dataType: 'json',
success: function (res) {
transfer.render({
elem: '#transfer-sips'
,id:'transfer-sips'
,title: ['所有坐席', '已选坐席']
,parseData: function(item){
return {
"value": item.id //数据值
,"title": item.username + "" + item.user.nickname + "" //数据标题
//,"disabled": res.disabled //是否禁用
,"checked": res.checked //是否选中
}
}
,data: res.data.lists
,height: 300
,value: res.data.values
,onchange: function(data, index){
var ids = []
getData = transfer.getData('transfer-sips');
for (var v of getData){
ids.push(v.value)
}
$("#sips").val(ids.join(','))
}
})
$("#sips").val(res.data.values.join(','))
},
});
});
</script>

View File

@ -19,6 +19,7 @@ Route::middleware('auth:api')->get('/user', function (Request $request) {
Route::post('get_permission_by_role_id','ApiController@getPermissionByRoleId')->name('api.getPermissionByRoleId');
Route::post('get_role_by_user_id','ApiController@getRoleByUserId')->name('api.getRoleByUserId');
Route::post('get_sips_by_queue_id','ApiController@getSipsByQueueId')->name('api.getSipsByQueueId');
Route::post('get_department_by_user_id','ApiController@getDepartmentByUserId')->name('api.getDepartmentByUserId');
Route::post('get_user','ApiController@getUser')->name('api.getUser');
Route::post('get_node','ApiController@getNode')->name('api.getNode');

View File

@ -189,6 +189,30 @@ Route::group(['prefix'=>'call','namespace'=> 'Call','middleware'=>['auth','permi
});
/*
|--------------------------------------------------------------------------
| 群呼模块
|--------------------------------------------------------------------------
*/
Route::group(['prefix'=>'callcenter','namespace'=>'Callcenter','middleware'=>['auth','permission:callcenter']],function () {
//队列管理
Route::group([],function (){
Route::get('queue','QueueController@index')->name('callcenter.queue')->middleware('permission:callcenter.queue');
//添加
Route::get('queue/create','QueueController@create')->name('callcenter.queue.create')->middleware('permission:callcenter.queue.create');
Route::post('queue/store','QueueController@store')->name('callcenter.queue.store')->middleware('permission:callcenter.queue.create');
//编辑
Route::get('queue/{id}/edit','QueueController@edit')->name('callcenter.queue.edit')->middleware('permission:callcenter.queue.edit');
Route::put('queue/{id}/update','QueueController@update')->name('callcenter.queue.update')->middleware('permission:callcenter.queue.edit');
//删除
Route::delete('queue/destroy','QueueController@destroy')->name('callcenter.queue.destroy')->middleware('permission:callcenter.queue.destroy');
//更新配置
Route::post('queue/updateXml','QueueController@updateXml')->name('callcenter.queue.updateXml')->middleware('permission:callcenter.queue.updateXml');
});
});
/*
|--------------------------------------------------------------------------