完成呼叫中心任务模块
This commit is contained in:
parent
3b4c108813
commit
d0370cd58f
|
|
@ -0,0 +1,136 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Requests\AgentRequest;
|
||||
use App\Models\Agent;
|
||||
use App\Models\Sip;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class AgentController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return view('admin.agent.index');
|
||||
}
|
||||
|
||||
public function data(Request $request)
|
||||
{
|
||||
$res = Agent::orderByDesc('id')->paginate($request->get('limit', 30));
|
||||
$data = [
|
||||
'code' => 0,
|
||||
'msg' => '正在请求中...',
|
||||
'count' => $res->total(),
|
||||
'data' => $res->items(),
|
||||
];
|
||||
return response()->json($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$sips = Sip::orderByDesc('id')->get();
|
||||
return view('admin.agent.create',compact('sips'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(AgentRequest $request)
|
||||
{
|
||||
$data = $request->all();
|
||||
$data['contact'] = 'user/'.$data['contact'];
|
||||
if (Agent::create($data)){
|
||||
return redirect(route('admin.agent'))->with(['success'=>'添加成功']);
|
||||
}
|
||||
return back()->withErrors(['error'=>'添加失败']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function show($id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
$model = Agent::findOrFail($id);
|
||||
$sips = Sip::orderByDesc('id')->get();
|
||||
return view('admin.agent.edit',compact('model','sips'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(AgentRequest $request, $id)
|
||||
{
|
||||
$model = Agent::findOrFail($id);
|
||||
$data = $request->except(['_method','_token']);
|
||||
$data['contact'] = 'user/'.$data['contact'];
|
||||
DB::beginTransaction();
|
||||
try{
|
||||
DB::table('tiers')->where('agent',$model->name)->update(['agent'=>$data['name']]);
|
||||
DB::table('agents')->where('id',$model->id)->update($data);
|
||||
DB::commit();
|
||||
return redirect(route('admin.agent'))->with(['success'=>'更新成功']);
|
||||
}catch (\Exception $exception){
|
||||
DB::rollback();
|
||||
return back()->withErrors(['error'=>'更新失败']);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(Request $request)
|
||||
{
|
||||
$ids = $request->get('ids');
|
||||
if (empty($ids)){
|
||||
return response()->json(['code'=>1,'msg'=>'请选择删除项']);
|
||||
}
|
||||
$names = Agent::whereIn('id',$ids)->pluck('name');
|
||||
DB::beginTransaction();
|
||||
try{
|
||||
DB::table('tiers')->whereIn('agent',$names)->delete();
|
||||
DB::table('agents')->whereIn('id',$ids)->delete();
|
||||
DB::commit();
|
||||
return response()->json(['code'=>0,'msg'=>'删除成功']);
|
||||
}catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
return response()->json(['code'=>1,'msg'=>'删除失败','data'=>$e->getMessage()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -49,7 +49,7 @@ class GatewayController extends Controller
|
|||
*/
|
||||
public function store(GatewayRequest $request)
|
||||
{
|
||||
$data = $request->all(['name','realm','username','password']);
|
||||
$data = $request->except(['_method','_token']);
|
||||
if (Gateway::create($data)){
|
||||
return redirect(route('admin.gateway'))->with(['success'=>'添加成功']);
|
||||
}
|
||||
|
|
@ -89,7 +89,7 @@ class GatewayController extends Controller
|
|||
public function update(Request $request, $id)
|
||||
{
|
||||
$model = Gateway::findOrFail($id);
|
||||
$data = $request->all(['name','realm','username','password']);
|
||||
$data = $request->except(['_method','_token']);
|
||||
if ($model->update($data)){
|
||||
return redirect(route('admin.gateway'))->with(['success'=>'更新成功']);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Requests\QueueRequest;
|
||||
use App\Models\Agent;
|
||||
use App\Models\Queue;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
|
@ -22,7 +23,7 @@ class QueueController extends Controller
|
|||
|
||||
public function data(Request $request)
|
||||
{
|
||||
$res = Queue::orderByDesc('id')->paginate($request->get('limit', 30));
|
||||
$res = Queue::withCount('agents')->orderByDesc('id')->paginate($request->get('limit', 30));
|
||||
$data = [
|
||||
'code' => 0,
|
||||
'msg' => '正在请求中...',
|
||||
|
|
@ -52,7 +53,7 @@ class QueueController extends Controller
|
|||
{
|
||||
$data = $request->all();
|
||||
if (Queue::create($data)){
|
||||
return redirect(route('admin.queue'))->with(['success'=>'添加成功']);
|
||||
return redirect(route('admin.queue'))->with(['success'=>'添加成功,请更新配置']);
|
||||
}
|
||||
return back()->withErrors(['error'=>'添加失败']);
|
||||
}
|
||||
|
|
@ -90,11 +91,18 @@ class QueueController extends Controller
|
|||
public function update(QueueRequest $request, $id)
|
||||
{
|
||||
$model = Queue::findOrFail($id);
|
||||
$data = $request->all();
|
||||
if ($model->update($data)){
|
||||
return redirect(route('admin.queue'))->with(['success'=>'更新成功']);
|
||||
$data = $request->except(['_method','_token']);
|
||||
DB::beginTransaction();
|
||||
try{
|
||||
DB::table('queue')->where('id',$model->id)->update($data);
|
||||
DB::table('tiers')->where('queue',$model->name)->update(['queue'=>$data['name']]);
|
||||
DB::commit();
|
||||
return redirect(route('admin.queue'))->with(['success'=>'更新成功,请更新配置']);
|
||||
}catch (\Exception $exception){
|
||||
DB::rollback();
|
||||
return back()->withErrors(['error'=>'更新失败']);
|
||||
}
|
||||
return back()->withErrors(['error'=>'更新失败']);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -112,8 +120,8 @@ class QueueController extends Controller
|
|||
$queues = Queue::whereIn('id',$ids)->pluck('name');
|
||||
DB::beginTransaction();
|
||||
try{
|
||||
DB::table('tiers')->where('queue','in',$queues)->delete();
|
||||
DB::table('queue')->where('id','in',$ids)->delete();
|
||||
DB::table('tiers')->whereIn('queue',$queues)->delete();
|
||||
DB::table('queue')->whereIn('id',$ids)->delete();
|
||||
DB::commit();
|
||||
return response()->json(['code'=>0,'msg'=>'删除成功,请更新配置']);
|
||||
}catch (\Exception $e) {
|
||||
|
|
@ -124,17 +132,68 @@ class QueueController extends Controller
|
|||
|
||||
public function updateXml()
|
||||
{
|
||||
|
||||
$queues = Queue::get();
|
||||
if ($queues->isEmpty()){
|
||||
return response()->json(['code'=>1,'msg'=>'无数据需要更新']);
|
||||
}
|
||||
try{
|
||||
$xml = "<configuration name=\"callcenter.conf\" description=\"CallCenter\">\n";
|
||||
$xml .= " <settings>\n";
|
||||
$xml .= " <param name=\"odbc-dsn\" value=\"freeswitch:root:pwd\"/>\n";
|
||||
$xml .= " <!--<param name=\"dbname\" value=\"/dev/shm/callcenter.db\"/>-->\n";
|
||||
$xml .= " <!--<param name=\"cc-instance-id\" value=\"single_box\"/>-->\n";
|
||||
$xml .= " </settings>\n";
|
||||
$xml .= " <queues>\n";
|
||||
foreach ($queues->toArray() as $q){
|
||||
$xml .= " <queue name=\"".$q['name']."\">\n";
|
||||
$xml .= " <param name=\"strategy\" value=\"".$q['strategy']."\"/>\n";
|
||||
$xml .= " <param name=\"moh-sound\" value=\"".$q['moh-sound']."\"/>\n";
|
||||
$xml .= " <!--<param name=\"record-template\" value=\"".$q['record-template']."\"/>-->\n";
|
||||
$xml .= " <param name=\"time-base-score\" value=\"".$q['time-base-score']."\"/>\n";
|
||||
$xml .= " <param name=\"max-wait-time\" value=\"".$q['max-wait-time']."\"/>\n";
|
||||
$xml .= " <param name=\"max-wait-time-with-no-agent\" value=\"".$q['max-wait-time-with-no-agent']."\"/>\n";
|
||||
$xml .= " <param name=\"max-wait-time-with-no-agent-time-reached\" value=\"".$q['max-wait-time-with-no-agent-time-reached']."\"/>\n";
|
||||
$xml .= " <param name=\"tier-rules-apply\" value=\"".$q['tier-rules-apply']."\"/>\n";
|
||||
$xml .= " <param name=\"tier-rule-wait-second\" value=\"".$q['tier-rule-wait-second']."\"/>\n";
|
||||
$xml .= " <param name=\"tier-rule-wait-multiply-level\" value=\"".$q['tier-rule-wait-multiply-level']."\"/>\n";
|
||||
$xml .= " <param name=\"tier-rule-no-agent-no-wait\" value=\"".$q['tier-rule-no-agent-no-wait']."\"/>\n";
|
||||
$xml .= " <param name=\"discard-abandoned-after\" value=\"".$q['discard-abandoned-after']."\"/>\n";
|
||||
$xml .= " <param name=\"abandoned-resume-allowed\" value=\"".$q['abandoned-resume-allowed']."\"/>\n";
|
||||
$xml .= " </queue>\n";
|
||||
}
|
||||
$xml .= " </queues>\n";
|
||||
$xml .= " <agents>\n";
|
||||
$xml .= " </agents>\n";
|
||||
$xml .= " <tier>\n";
|
||||
$xml .= " </tier>\n";
|
||||
$xml .= "</configuration>\n";
|
||||
file_put_contents(config('freeswitch.callcenter_dir'),$xml);
|
||||
//生产环境,并且debug关闭的情况下自动更新网关注册信息
|
||||
if (config('app.env')=='production' && config('app.debug')==false){
|
||||
$freeswitch = new \Freeswitchesl();
|
||||
$freeswitch->bgapi("reload callcenter");
|
||||
}
|
||||
return response()->json(['code'=>0,'msg'=>'更新成功']);
|
||||
}catch (\Exception $exception){
|
||||
return response()->json(['code'=>1,'msg'=>'更新失败','data'=>$exception->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
public function agent()
|
||||
public function agent($id)
|
||||
{
|
||||
|
||||
$queue = Queue::with('agents')->findOrFail($id);
|
||||
$agents = Agent::orderByDesc('id')->get();
|
||||
return view('admin.queue.agent',compact('queue','agents'));
|
||||
}
|
||||
|
||||
public function assignAgent()
|
||||
public function assignAgent(Request $request,$id)
|
||||
{
|
||||
|
||||
$queue = Queue::with('agents')->findOrFail($id);
|
||||
$names = $request->get('agents',[]);
|
||||
if ($queue->agents()->sync($names)){
|
||||
return redirect(route('admin.queue'))->with(['success'=>'更新成功']);
|
||||
}
|
||||
return back()->withErrors(['error'=>'更新失败']);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,240 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Requests\TaskRequest;
|
||||
use App\Models\Agent;
|
||||
use App\Models\Gateway;
|
||||
use App\Models\Queue;
|
||||
use App\Models\Task;
|
||||
use Carbon\Carbon;
|
||||
use Faker\Provider\Uuid;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use DB;
|
||||
use zgldh\QiniuStorage\QiniuStorage;
|
||||
|
||||
class TaskController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return view('admin.task.index');
|
||||
}
|
||||
|
||||
public function data(Request $request)
|
||||
{
|
||||
$res = Task::orderByDesc('id')->paginate($request->get('limit', 30));
|
||||
$data = [
|
||||
'code' => 0,
|
||||
'msg' => '正在请求中...',
|
||||
'count' => $res->total(),
|
||||
'data' => $res->items(),
|
||||
];
|
||||
return response()->json($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$queues = Queue::orderByDesc('id')->get();
|
||||
$gateways = Gateway::orderByDesc('id')->get();
|
||||
return view('admin.task.create',compact('queues','gateways'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(TaskRequest $request)
|
||||
{
|
||||
$data = $request->except(['_method','_token']);
|
||||
if (Task::create($data)){
|
||||
return redirect(route('admin.task'))->with(['success'=>'添加成功']);
|
||||
}
|
||||
return back()->withErrors(['error'=>'添加失败']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function show(Request $request, $id)
|
||||
{
|
||||
$task = Task::withCount(['calls','hasCalls','missCalls','successCalls','failCalls'])->findOrFail($id);
|
||||
$percent = $task->calls_count>0?100*round(($task->has_calls_count)/($task->calls_count),4):'0.00%';
|
||||
if ($request->isMethod('post')){
|
||||
$tiers = DB::table('tiers')->where('queue',$task->queue_name)->pluck('agent');
|
||||
$agents = Agent::whereIn('name',$tiers)->get();
|
||||
return response()->json(['code'=>0, 'msg'=>'请求成功', 'data'=>$agents]);
|
||||
}
|
||||
return view('admin.task.show',compact('task','percent'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
$model = Task::findOrFail($id);
|
||||
$queues = Queue::orderByDesc('id')->get();
|
||||
$gateways = Gateway::orderByDesc('id')->get();
|
||||
return view('admin.task.edit',compact('model', 'queues', 'gateways'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(TaskRequest $request, $id)
|
||||
{
|
||||
$data = $request->except(['_method','_token']);
|
||||
$model = Task::findOrFail($id);
|
||||
if ($model->update($data)){
|
||||
return redirect(route('admin.task'))->with(['success'=>'更新成功']);
|
||||
}
|
||||
return back()->withErrors(['error'=>'更新失败']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(Request $request)
|
||||
{
|
||||
$ids = $request->get('ids');
|
||||
if (empty($ids)){
|
||||
return response()->json(['code'=>1,'msg'=>'请选择删除项']);
|
||||
}
|
||||
if (Task::destroy($ids)){
|
||||
return response()->json(['code'=>0,'msg'=>'删除成功']);
|
||||
}
|
||||
return response()->json(['code'=>1,'msg'=>'删除失败']);
|
||||
}
|
||||
|
||||
public function setStatus(Request $request)
|
||||
{
|
||||
$ids = $request->get('ids',[]);
|
||||
if (count($ids)!=1){
|
||||
return response()->json(['code'=>1,'msg'=>'请选择一条记录']);
|
||||
}
|
||||
$task = Task::withCount('calls')->find($ids[0]);
|
||||
if ($task==null){
|
||||
return response()->json(['code'=>1,'msg'=>'任务不存在']);
|
||||
}
|
||||
if ($task->status==3){
|
||||
return response()->json(['code'=>1,'msg'=>'任务已完成,禁止操作']);
|
||||
}
|
||||
$status = $request->get('status',1);
|
||||
|
||||
if ($status==2&&$task->calls_count==0){
|
||||
return response()->json(['code'=>1,'msg'=>'任务未导入号码,禁止操作']);
|
||||
}
|
||||
if ($status==1&&$task->status!=2){
|
||||
return response()->json(['code'=>1,'msg'=>'任务未启动,禁止操作']);
|
||||
}
|
||||
|
||||
if ($task->update(['status'=>$status])){
|
||||
return response()->json(['code'=>0,'msg'=>'更新成功']);
|
||||
}
|
||||
return response()->json(['code'=>1,'msg'=>'更新失败']);
|
||||
}
|
||||
|
||||
public function importCall(Request $request, $id)
|
||||
{
|
||||
set_time_limit(0);
|
||||
$task = Task::find($id);
|
||||
if ($task==null){
|
||||
return response()->json(['code'=>1,'msg'=>'任务不存在']);
|
||||
}
|
||||
|
||||
$file = $request->file('file');
|
||||
if ($file->isValid()){
|
||||
$allowed_extensions = ['csv'];
|
||||
//上传文件最大大小,单位M 500Kb大约4万条数据
|
||||
$maxSize = 1;
|
||||
//检测类型
|
||||
$ext = $file->getClientOriginalExtension();
|
||||
if (!in_array(strtolower($ext),$allowed_extensions)){
|
||||
return response()->json(['code'=>1,'msg'=>"请上传".implode(",",$allowed_extensions)."格式"]);
|
||||
}
|
||||
//检测大小
|
||||
if ($file->getClientSize() > $maxSize*1024*1024){
|
||||
return response()->json(['code'=>1,'msg'=>"图片大小限制".$maxSize."M"]);
|
||||
}
|
||||
//上传到七牛云
|
||||
$newFile = Uuid::uuid().".".$file->getClientOriginalExtension();
|
||||
try{
|
||||
$disk = QiniuStorage::disk('qiniu');
|
||||
$disk->put($newFile,file_get_contents($file->getRealPath()));
|
||||
$url = $disk->downloadUrl($newFile);
|
||||
}catch (\Exception $exception){
|
||||
return response()->json(['code'=>1,'msg'=>'文件上传失败','data'=>$exception->getMessage()]);
|
||||
}
|
||||
//文件内容读取
|
||||
$data = [];
|
||||
try{
|
||||
$fp = fopen($url,"r");
|
||||
while(!feof($fp))
|
||||
{
|
||||
$line = fgetcsv($fp);
|
||||
if ($line){
|
||||
foreach ($line as $phone){
|
||||
array_push($data,$phone);
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose($fp);
|
||||
//去重,去空
|
||||
$data = array_filter(array_unique($data));
|
||||
}catch (\Exception $exception){
|
||||
return response()->json(['code'=>1,'msg'=>'读取文件内容错误','data'=>$exception->getMessage()]);
|
||||
}
|
||||
|
||||
//写入数据库
|
||||
if (!empty($data)){
|
||||
DB::beginTransaction();
|
||||
try{
|
||||
foreach ($data as $d){
|
||||
DB::table('call')->insert([
|
||||
'task_id' => $task->id,
|
||||
'phone' => $d,
|
||||
'created_at'=> Carbon::now(),
|
||||
'updated_at'=> Carbon::now(),
|
||||
]);
|
||||
}
|
||||
DB::commit();
|
||||
return response()->json(['code'=>0,'msg'=>'导入完成']);
|
||||
}catch (\Exception $exception){
|
||||
DB::rollBack();
|
||||
return response()->json(['code'=>1,'msg'=>'导入失败','data'=>$exception->getMessage()]);
|
||||
}
|
||||
}
|
||||
return response()->json(['code'=>1,'msg'=>'导入数据为空']);
|
||||
}
|
||||
return response()->json(['code'=>1,'msg'=>'上传失败','data'=>$file->getErrorMessage()]);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
<?php
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Traits\Msg;
|
||||
use Illuminate\Http\Request;
|
||||
use zgldh\QiniuStorage\QiniuStorage;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class AgentRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'name' => 'required|string|min:2|unique:agents,name,'.$this->id.',id',
|
||||
'contact' => 'required',
|
||||
'status' => 'required|string|in:Logged Out,Available,Available (On Demand),On Break',
|
||||
'state' => 'required|string|in:Idle,Waiting,In a queue call',
|
||||
'max_no_answer' => 'required|numeric|min:0',
|
||||
'wrap_up_time' => 'required|numeric|min:0',
|
||||
'reject_delay_time' => 'required|numeric|min:0',
|
||||
'busy_delay_time' => 'required|numeric|min:0',
|
||||
'no_answer_delay_time' => 'required|numeric|min:0',
|
||||
];
|
||||
}
|
||||
|
||||
public function attributes()
|
||||
{
|
||||
return [
|
||||
'name' => '坐席名称',
|
||||
'contact' => '分机号',
|
||||
'status' => '坐席状态',
|
||||
'state' => '呼叫状态',
|
||||
'max_no_answer' => '最大无应答次数',
|
||||
'wrap_up_time' => '通话间隔',
|
||||
'reject_delay_time' => '拒接间隔时间',
|
||||
'busy_delay_time' => '忙重试间隔时间',
|
||||
'no_answer_delay_time' => '无应答重试间隔',
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -13,7 +13,7 @@ class QueueRequest extends FormRequest
|
|||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class TaskRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'name' => 'required',
|
||||
'datetime_start' => 'required|date_format:Y-m-d H\:i\:s|before:datetime_end',
|
||||
'datetime_end' => 'required|date_format:Y-m-d H\:i\:s|after:datetime_start',
|
||||
'gateway_id' => 'required|exists:gateway,id',
|
||||
'queue_id' => 'required|exists:queue,id',
|
||||
'max_channel' => 'required|numeric|min:0',
|
||||
];
|
||||
}
|
||||
|
||||
public function attributes()
|
||||
{
|
||||
return [
|
||||
'name' => '名称',
|
||||
'datetime_start' => '开始时间',
|
||||
'datetime_end' => '结束时间',
|
||||
'gateway_id' => '网关',
|
||||
'queue_id' => '队列',
|
||||
'max_channel' => '最大并发',
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Agent extends Model
|
||||
{
|
||||
protected $table = 'agents';
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'contact',
|
||||
'status',
|
||||
'state',
|
||||
'max_no_answer',
|
||||
'wrap_up_time',
|
||||
'reject_delay_time',
|
||||
'busy_delay_time',
|
||||
'no_answer_delay_time'
|
||||
];
|
||||
protected $appends = ['contact_name','status_name','state_name'];
|
||||
|
||||
public function getContactNameAttribute()
|
||||
{
|
||||
return $this->attributes['contact_name'] = str_after($this->contact,'user/');
|
||||
}
|
||||
|
||||
public function getStatusNameAttribute()
|
||||
{
|
||||
return $this->attributes['status_name'] = array_get(config('freeswitch.agent_status'),$this->status);
|
||||
}
|
||||
|
||||
public function getStateNameAttribute()
|
||||
{
|
||||
return $this->attributes['state_name'] = array_get(config('freeswitch.agent_state'),$this->state);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Call extends Model
|
||||
{
|
||||
protected $table = 'call';
|
||||
}
|
||||
|
|
@ -7,6 +7,6 @@ use Illuminate\Database\Eloquent\Model;
|
|||
class Gateway extends Model
|
||||
{
|
||||
protected $table = 'gateway';
|
||||
protected $fillable = ['name','realm','username','password'];
|
||||
protected $fillable = ['name','realm','username','password','prefix','outbound_caller_id'];
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,4 +18,16 @@ class Queue extends Model
|
|||
'max-wait-time-with-no-agent',
|
||||
'max-wait-time-with-no-agent-time-reached',
|
||||
];
|
||||
protected $appends = ['strategy_name'];
|
||||
|
||||
public function agents()
|
||||
{
|
||||
return $this->belongsToMany('App\Models\Agent','tiers','queue','agent','name','name');
|
||||
}
|
||||
|
||||
public function getStrategyNameAttribute()
|
||||
{
|
||||
return $this->attributes['strategy_name'] = array_get(config('freeswitch.strategy'),$this->strategy);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Task extends Model
|
||||
{
|
||||
protected $table = 'task';
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'datetime_start',
|
||||
'datetime_end',
|
||||
'gateway_id',
|
||||
'queue_id',
|
||||
'max_channel',
|
||||
'status',
|
||||
];
|
||||
protected $appends = ['gateway_name','queue_name'];
|
||||
|
||||
public function gateway()
|
||||
{
|
||||
return $this->hasOne('App\Models\Gateway','id','gateway_id');
|
||||
}
|
||||
|
||||
public function queue()
|
||||
{
|
||||
return $this->hasOne('App\Models\Queue','id','queue_id');
|
||||
}
|
||||
|
||||
public function getGatewayNameAttribute()
|
||||
{
|
||||
return $this->attributes['gateway_name'] = $this->gateway->name;
|
||||
}
|
||||
|
||||
public function getQueueNameAttribute()
|
||||
{
|
||||
return $this->attributes['queue_name'] = $this->queue->display_name;
|
||||
}
|
||||
|
||||
//总呼叫数
|
||||
public function calls()
|
||||
{
|
||||
return $this->hasMany('App\Models\Call','task_id','id');
|
||||
}
|
||||
|
||||
//已呼叫数 status !=1
|
||||
public function hasCalls()
|
||||
{
|
||||
return $this->hasMany('App\Models\Call','task_id','id')->where('status','!=',1);
|
||||
}
|
||||
|
||||
//漏接数 status=3
|
||||
public function missCalls()
|
||||
{
|
||||
return $this->hasMany('App\Models\Call','task_id','id')->where('status',3);
|
||||
}
|
||||
|
||||
//呼叫成功数 status=4
|
||||
public function successCalls()
|
||||
{
|
||||
return $this->hasMany('App\Models\Call','task_id','id')->where('status',4);
|
||||
}
|
||||
|
||||
//呼叫失败数 status=5
|
||||
public function failCalls()
|
||||
{
|
||||
return $this->hasMany('App\Models\Call','task_id','id')->where('status',5);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -66,13 +66,13 @@ return [
|
|||
'qiniu' => [
|
||||
'driver' => 'qiniu',
|
||||
'domains' => [
|
||||
'default' => 'o95vn3gtk.bkt.clouddn.com', //你的七牛域名
|
||||
'default' => 'static.nicaicai.top', //你的七牛域名
|
||||
'https' => '', //你的HTTPS域名
|
||||
'custom' => '', //Useless 没啥用,请直接使用上面的 default 项
|
||||
],
|
||||
'access_key'=> '1JdLd1hJq8j99yKGwgPgE_p0s8PAQ3UNZIKtLXaV', //AccessKey
|
||||
'secret_key'=> 'e-mpwUbtfF8cv0aCUOvqimlIdexaavYtV_yjyhQG', //SecretKey
|
||||
'bucket' => 'muzilong', //Bucket名字
|
||||
'bucket' => 'company', //Bucket名字
|
||||
'notify_url'=> '', //持久化处理回调地址
|
||||
'access' => 'public' //空间访问控制 public 或 private
|
||||
],
|
||||
|
|
|
|||
|
|
@ -4,6 +4,9 @@ return [
|
|||
//网关目录
|
||||
'gateway_dir' => '/usr/local/freeswitch/etc/freeswitch/sip_profiles/external/',
|
||||
|
||||
//callcenter_conf_dir
|
||||
'callcenter_dir' => '/usr/local/freeswitch/etc/freeswitch/autoload_configs/callcenter.conf.xml',
|
||||
|
||||
//application
|
||||
'application' => [
|
||||
'set' => '设置变量',
|
||||
|
|
@ -17,10 +20,11 @@ return [
|
|||
'park' => '停泊',
|
||||
'transfer' => '呼叫转移',
|
||||
'info' => '显示信息',
|
||||
|
||||
'lua' => 'lua脚本',
|
||||
'detect_speech'=> 'detect_speech',
|
||||
],
|
||||
|
||||
//
|
||||
//队列响铃模式
|
||||
'strategy' => [
|
||||
'ring-all' => '所有振铃',
|
||||
'longest-idle-agent' => '空闲时长最长振铃',
|
||||
|
|
@ -31,6 +35,18 @@ return [
|
|||
'sequentially-by-agent-order' => '优先级振铃',
|
||||
'random' => '随机振铃',
|
||||
],
|
||||
|
||||
//坐席状态
|
||||
'agent_status' => [
|
||||
'Logged Out' => '签出',
|
||||
'Available' => '示闲',
|
||||
'Available (On Demand)' => '示闲(通话完成后自动示忙)',
|
||||
'On Break' => '示忙',
|
||||
],
|
||||
//坐席呼叫状态
|
||||
'agent_state' => [
|
||||
'Idle' => '空闲中(不会分配话务)',
|
||||
'Waiting' => '空闲中(等待分配话务)',
|
||||
'In a queue call' => '通话中'
|
||||
],
|
||||
|
||||
];
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ class CreateGatewayTable extends Migration
|
|||
$table->string('realm')->comment('网关IP,如果端口不是5060,默认格式为:xxx.xxx.xxx.xxx:port');
|
||||
$table->string('username')->comment('帐号');
|
||||
$table->string('password')->comment('密码');
|
||||
$table->string('prefix')->nullable()->comment('前缀');
|
||||
$table->string('outbound_caller_id')->nullable()->comment('出局号码');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,11 +44,11 @@ class CreateCallcenterTable extends Migration
|
|||
Schema::create('agents', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('name')->nullable()->comment('坐席号码');
|
||||
$table->string('system')->nullable()->comment('single_box');
|
||||
$table->string('system')->default('single_box')->comment('single_box');
|
||||
$table->string('uuid')->nullable()->comment('uuid');
|
||||
$table->string('type')->default('callback')->comment('callback 或者 uuid-standby');
|
||||
$table->string('contact')->nullable()->comment('呼叫字符串');
|
||||
$table->string('status')->default('Available')->comment('坐席状态Logged Out签出,Available示闲,Available (On Demand),On Break休息/示忙');
|
||||
$table->string('status')->default('Available')->comment('坐席状态Logged Out签出,Available示闲,Available (On Demand)接通电话完成后示忙,On Break休息/示忙');
|
||||
$table->string('state')->default('Waiting')->comment('坐席呼叫状态 Idle坐席空闲中,但是不会分配话务,Waiting坐席空闲中,正在等待分配话务,In a queue call正在通话');
|
||||
$table->integer('max_no_answer')->default(0)->comment('最大无应答次数,超过次数status变为On Break状态');
|
||||
$table->integer('wrap_up_time')->default(0)->comment('通话完成间隔时间,成功处理一个通话后,多久才会有电话进入的等待时长');
|
||||
|
|
@ -64,6 +64,7 @@ class CreateCallcenterTable extends Migration
|
|||
$table->integer('talk_time')->default(0);
|
||||
$table->integer('ready_time')->default(0);
|
||||
$table->integer('external_calls_count')->default(0);
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('tiers', function (Blueprint $table) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateTask extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('task', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('name')->comment('任务名称');
|
||||
$table->timestamp('datetime_start')->nullable()->comment('任务开始时间');
|
||||
$table->timestamp('datetime_end')->nullable()->comment('任务结束时间');
|
||||
$table->integer('gateway_id')->comment('出局网关ID');
|
||||
$table->integer('queue_id')->nullable()->comment('转接队列ID');
|
||||
$table->integer('max_channel')->default(0)->comment('最大并发');
|
||||
$table->tinyInteger('status')->default(1)->comment('状态,1-停止,2-启动,3-完成');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('task');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateCall extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('call', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->unsignedInteger('task_id')->comment('对应任务ID');
|
||||
$table->string('phone')->comment('待呼叫号码');
|
||||
$table->tinyInteger('status')->default(1)->comment('1-待呼叫,2-呼叫中,3-队列中,4-接通成功,5-接通失败');
|
||||
$table->string('uuid')->nullable()->comment('通话UUID');
|
||||
$table->timestamp('datetime_originate')->nullable()->comment('呼叫时间');
|
||||
$table->timestamp('datetime_answer')->nullable()->comment('应答时间');
|
||||
$table->timestamp('datetime_entry_queue')->nullable()->comment('转接到队列时间');
|
||||
$table->timestamp('datetime_transfer_agent')->nullable()->comment('队列转接到坐席接听时间');
|
||||
$table->string('agent')->nullable()->comment('接听坐席');
|
||||
$table->timestamp('datetime_hangup')->nullable()->comment('挂断时间');
|
||||
$table->integer('duration')->default(0)->comment('通话时长');
|
||||
$table->string('fail_cause')->nullable()->comment('失败原因');
|
||||
$table->timestamps();
|
||||
$table->foreign('task_id')->references('id')->on('task')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('call');
|
||||
}
|
||||
}
|
||||
|
|
@ -155,7 +155,6 @@ class UserTableSeeder extends Seeder
|
|||
'route' => 'admin.queue',
|
||||
'icon_id' => '12',
|
||||
'child' => [
|
||||
['name' => 'pbx.queue.show', 'display_name' => '详情','route'=>'admin.queue.show'],
|
||||
['name' => 'pbx.queue.create', 'display_name' => '添加','route'=>'admin.queue.create'],
|
||||
['name' => 'pbx.queue.edit', 'display_name' => '编辑','route'=>'admin.queue.edit'],
|
||||
['name' => 'pbx.queue.destroy', 'display_name' => '删除','route'=>'admin.queue.destroy'],
|
||||
|
|
@ -163,6 +162,17 @@ class UserTableSeeder extends Seeder
|
|||
['name' => 'pbx.queue.agent', 'display_name' => '分配分机','route'=>'admin.queue.agent'],
|
||||
]
|
||||
],
|
||||
[
|
||||
'name' => 'pbx.agent',
|
||||
'display_name' => '坐席管理',
|
||||
'route' => 'admin.agent',
|
||||
'icon_id' => '12',
|
||||
'child' => [
|
||||
['name' => 'pbx.agent.create', 'display_name' => '添加','route'=>'admin.agent.create'],
|
||||
['name' => 'pbx.agent.edit', 'display_name' => '编辑','route'=>'admin.agent.edit'],
|
||||
['name' => 'pbx.agent.destroy', 'display_name' => '删除','route'=>'admin.agent.destroy'],
|
||||
]
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
|
|
@ -184,6 +194,28 @@ class UserTableSeeder extends Seeder
|
|||
],
|
||||
]
|
||||
],
|
||||
[
|
||||
'name' => 'ai.manage',
|
||||
'display_name' => '批量外呼',
|
||||
'route' => '',
|
||||
'icon_id' => '103',
|
||||
'child' => [
|
||||
[
|
||||
'name' => 'ai.task',
|
||||
'display_name' => '任务管理',
|
||||
'route' => 'admin.task',
|
||||
'icon_id' => '12',
|
||||
'child' => [
|
||||
['name' => 'ai.task.create', 'display_name' => '添加','route'=>'admin.task.create'],
|
||||
['name' => 'ai.task.edit', 'display_name' => '编辑','route'=>'admin.task.edit'],
|
||||
['name' => 'ai.task.destroy', 'display_name' => '删除','route'=>'admin.task.destroy'],
|
||||
['name' => 'ai.task.show', 'display_name' => '呼叫详情','route'=>'admin.task.show'],
|
||||
['name' => 'ai.task.setStatus', 'display_name' => '更新状态','route'=>'admin.task.setStatus'],
|
||||
['name' => 'ai.task.importCall', 'display_name' => '导入号码','route'=>'admin.task.importCall'],
|
||||
]
|
||||
],
|
||||
]
|
||||
],
|
||||
];
|
||||
|
||||
foreach ($permissions as $pem1) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
18908221080
|
||||
13512293513
|
||||
13512293514
|
||||
13512293515
|
||||
13512293516
|
||||
13512293517
|
||||
13512293517
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
{{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="contact" lay-verify="required">
|
||||
<option value="">请选择</option>
|
||||
@foreach($sips as $sip)
|
||||
<option value="{{$sip->username}}" @if(isset($model->contact)&&'user/'.$sip->username==$model->contact) selected @endif >{{$sip->username}}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">坐席状态</label>
|
||||
<div class="layui-input-block">
|
||||
@foreach(config('freeswitch.agent_status') as $k=>$v)
|
||||
<input type="radio" name="status" value="{{$k}}" title="{{$v}}" @if((isset($model->status)&&$model->status==$k) || (!isset($model->status)&&$k=='Available') ) checked @endif >
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">呼叫状态</label>
|
||||
<div class="layui-input-block">
|
||||
@foreach(config('freeswitch.agent_state') as $k=>$v)
|
||||
<input type="radio" name="state" value="{{$k}}" title="{{$v}}" @if((isset($model->state)&&$model->state==$k) || (!isset($model->state)&&$k=='Waiting')) checked @endif >
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">最大无应答次数</label>
|
||||
<div class="layui-input-block">
|
||||
<input class="layui-input" type="number" name="max_no_answer" lay-verify="required|number" value="{{$model->max_no_answer??0}}" >
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">通话间隔</label>
|
||||
<div class="layui-input-block">
|
||||
<input class="layui-input" type="number" name="wrap_up_time" lay-verify="required|number" value="{{$model->wrap_up_time??0}}" >
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">拒接间隔时间</label>
|
||||
<div class="layui-input-block">
|
||||
<input class="layui-input" type="number" name="reject_delay_time" lay-verify="required|number" value="{{$model->reject_delay_time??0}}" >
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">忙重试间隔时间</label>
|
||||
<div class="layui-input-block">
|
||||
<input class="layui-input" type="number" name="busy_delay_time" lay-verify="required|number" value="{{$model->busy_delay_time??0}}" >
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">无应答重试间隔</label>
|
||||
<div class="layui-input-block">
|
||||
<input class="layui-input" type="number" name="no_answer_delay_time" lay-verify="required|number" value="{{$model->no_answer_delay_time??0}}" >
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button type="submit" class="layui-btn" lay-submit lay-filter="*" >确 认</button>
|
||||
<a href="{{route('admin.agent')}}" class="layui-btn" >返 回</a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
@extends('admin.base')
|
||||
|
||||
@section('content')
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header layuiadmin-card-header-auto">
|
||||
<h2>添加坐席</h2>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<form action="{{route('admin.agent.store')}}" method="post" class="layui-form">
|
||||
@include('admin.agent._form')
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
@extends('admin.base')
|
||||
|
||||
@section('content')
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header layuiadmin-card-header-auto">
|
||||
<h2>更新坐席</h2>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<form action="{{route('admin.agent.update',['id'=>$model->id])}}" method="post" class="layui-form">
|
||||
{{method_field('put')}}
|
||||
@include('admin.agent._form')
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
@extends('admin.base')
|
||||
|
||||
@section('content')
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header layuiadmin-card-header-auto">
|
||||
<div class="layui-btn-group">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-danger" id="listDelete">删 除</button>
|
||||
<a class="layui-btn layui-btn-sm" href="{{ route('admin.agent.create') }}">添 加</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<table id="dataTable" lay-filter="dataTable"></table>
|
||||
<script type="text/html" id="options">
|
||||
<div class="layui-btn-group">
|
||||
<a class="layui-btn layui-btn-sm" lay-event="edit">编辑</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-sm " lay-event="del">删除</a>
|
||||
</div>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@section('script')
|
||||
<script>
|
||||
layui.use(['layer','table','form'],function () {
|
||||
var layer = layui.layer;
|
||||
var form = layui.form;
|
||||
var table = layui.table;
|
||||
//用户表格初始化
|
||||
var dataTable = table.render({
|
||||
elem: '#dataTable'
|
||||
,height: 500
|
||||
,url: "{{ route('admin.agent.data') }}" //数据接口
|
||||
,page: true //开启分页
|
||||
,cols: [[ //表头
|
||||
{checkbox: true,fixed: true}
|
||||
//,{field: 'id', title: 'ID', sort: true,width:80}
|
||||
,{field: 'name', title: '坐席名称',width: 100}
|
||||
,{field: 'contact_name', title: '分机号',width: 100}
|
||||
,{field: 'status_name', title: '坐席状态'}
|
||||
,{field: 'state_name', title: '呼叫状态'}
|
||||
,{field: 'max_no_answer', title: '最大无应答次数'}
|
||||
,{field: 'wrap_up_time', title: '通话间隔(秒)'}
|
||||
,{field: 'reject_delay_time', title: '拒接间隔时间(秒)'}
|
||||
,{field: 'busy_delay_time', title: '忙重试间隔时间(秒)'}
|
||||
,{field: 'no_answer_delay_time', title: '无应答重试间隔(秒)'}
|
||||
,{fixed: 'right', width: 150, 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'){
|
||||
layer.confirm('确认删除吗?', function(index){
|
||||
$.post("{{ route('admin.agent.destroy') }}",{_method:'delete',ids:[data.id]},function (result) {
|
||||
if (result.code==0){
|
||||
obj.del(); //删除对应行(tr)的DOM结构
|
||||
}
|
||||
layer.close(index);
|
||||
var icon = result.code==0?6:5;
|
||||
layer.msg(result.msg,{icon:icon})
|
||||
});
|
||||
});
|
||||
} else if(layEvent === 'edit'){
|
||||
location.href = '/admin/agent/'+data.id+'/edit';
|
||||
}
|
||||
});
|
||||
|
||||
//按钮批量删除
|
||||
$("#listDelete").click(function () {
|
||||
var ids = []
|
||||
var hasCheck = table.checkStatus('dataTable')
|
||||
var hasCheckData = hasCheck.data
|
||||
if (hasCheckData.length>0){
|
||||
$.each(hasCheckData,function (index,element) {
|
||||
ids.push(element.id)
|
||||
})
|
||||
}
|
||||
if (ids.length>0){
|
||||
layer.confirm('确认删除吗?', function(index){
|
||||
$.post("{{ route('admin.agent.destroy') }}",{_method:'delete',ids:ids},function (result) {
|
||||
if (result.code==0){
|
||||
dataTable.reload()
|
||||
}
|
||||
layer.close(index);
|
||||
var icon = result.code==0?6:5;
|
||||
layer.msg(result.msg,{icon:icon})
|
||||
});
|
||||
})
|
||||
}else {
|
||||
layer.msg('请选择删除项',{icon:5})
|
||||
}
|
||||
})
|
||||
|
||||
})
|
||||
</script>
|
||||
@endsection
|
||||
|
|
@ -23,6 +23,18 @@
|
|||
<input class="layui-input" type="text" name="password" lay-verify="required" value="{{$model->password??old('password')}}" placeholder="如:123456">
|
||||
</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="prefix" value="{{$model->prefix??old('prefix')}}" placeholder="非必填">
|
||||
</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="outbound_caller_id" value="{{$model->outbound_caller_id??old('outbound_caller_id')}}" placeholder="非必填">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button type="submit" class="layui-btn" lay-submit lay-filter="*" >确 认</button>
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@
|
|||
,{field: 'realm', title: '地址'}
|
||||
,{field: 'username', title: '帐号'}
|
||||
,{field: 'password', title: '密码'}
|
||||
,{field: 'prefix', title: '前缀'}
|
||||
,{field: 'outbound_caller_id', title: '出局号码'}
|
||||
,{field: 'created_at', title: '添加时间'}
|
||||
,{fixed: 'right', width: 220, align:'center', toolbar: '#options', title:'操作'}
|
||||
]]
|
||||
|
|
|
|||
|
|
@ -8,11 +8,7 @@
|
|||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">标识</label>
|
||||
<div class="layui-input-block">
|
||||
@if(isset($model))
|
||||
<input class="layui-input" type="text" value="{{$model->name??old('name')}}" disabled >
|
||||
@else
|
||||
<input class="layui-input" type="text" name="name" lay-verify="required" value="{{$model->name??old('name')}}" placeholder="如:66666">
|
||||
@endif
|
||||
<input class="layui-input" type="text" name="name" lay-verify="required" value="{{$model->name??old('name')}}" placeholder="如:66666">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
@extends('admin.base')
|
||||
|
||||
@section('content')
|
||||
<style>
|
||||
.layui-form-checkbox span{width: 800px;}
|
||||
</style>
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header layuiadmin-card-header-auto">
|
||||
<h2>队列【{{$queue->display_name}}】分配坐席</h2>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<form class="layui-form" action="{{route('admin.queue.assignAgent',['id'=>$queue->id])}}" method="post">
|
||||
{{csrf_field()}}
|
||||
{{method_field('put')}}
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">选择坐席</label>
|
||||
<div class="layui-input-block">
|
||||
@forelse($agents as $agent)
|
||||
<input type="checkbox" name="agents[]" value="{{$agent->name}}" title="名称:{{$agent->name}},分机:{{str_after($agent->contact,'user/')}}, 坐席状态:{{$agent->status_name}}, 呼叫状态:{{$agent->state_name}}, 最大无应答次数:{{$agent->max_no_answer}}" {{ $queue->agents->isNotEmpty()&&$queue->agents->contains($agent) ? 'checked' : '' }} >
|
||||
@empty
|
||||
<div class="layui-form-mid layui-word-aux">还没有坐席</div>
|
||||
@endforelse
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button type="submit" class="layui-btn" lay-submit="" lay-filter="formDemo">确 认</button>
|
||||
<a class="layui-btn" href="{{route('admin.queue')}}" >返 回</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
|
||||
|
|
@ -15,6 +15,7 @@
|
|||
<script type="text/html" id="options">
|
||||
<div class="layui-btn-group">
|
||||
<a class="layui-btn layui-btn-sm" lay-event="edit">编辑</a>
|
||||
<a class="layui-btn layui-btn-sm" lay-event="agent">分配坐席</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-sm " lay-event="del">删除</a>
|
||||
</div>
|
||||
</script>
|
||||
|
|
@ -39,7 +40,8 @@
|
|||
,{field: 'id', title: 'ID', sort: true,width:80}
|
||||
,{field: 'display_name', title: '名称'}
|
||||
,{field: 'name', title: '标识'}
|
||||
,{field: 'strategy', title: '振铃策略'}
|
||||
,{field: 'strategy_name', title: '振铃策略'}
|
||||
,{field: 'agents_count', title: '坐席数'}
|
||||
,{field: 'created_at', title: '添加时间'}
|
||||
,{fixed: 'right', width: 220, align:'center', toolbar: '#options', title:'操作'}
|
||||
]]
|
||||
|
|
@ -51,7 +53,7 @@
|
|||
,layEvent = obj.event; //获得 lay-event 对应的值
|
||||
if(layEvent === 'del'){
|
||||
layer.confirm('确认删除吗?', function(index){
|
||||
$.post("{{ route('admin.gateway.destroy') }}",{_method:'delete',ids:[data.id]},function (result) {
|
||||
$.post("{{ route('admin.queue.destroy') }}",{_method:'delete',ids:[data.id]},function (result) {
|
||||
if (result.code==0){
|
||||
obj.del(); //删除对应行(tr)的DOM结构
|
||||
}
|
||||
|
|
@ -61,7 +63,9 @@
|
|||
});
|
||||
});
|
||||
} else if(layEvent === 'edit'){
|
||||
location.href = '/admin/gateway/'+data.id+'/edit';
|
||||
location.href = '/admin/queue/'+data.id+'/edit';
|
||||
} else if(layEvent === 'agent'){
|
||||
location.href = '/admin/queue/'+data.id+'/agent';
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -77,7 +81,7 @@
|
|||
}
|
||||
if (ids.length>0){
|
||||
layer.confirm('确认删除吗?', function(index){
|
||||
$.post("{{ route('admin.gateway.destroy') }}",{_method:'delete',ids:ids},function (result) {
|
||||
$.post("{{ route('admin.queue.destroy') }}",{_method:'delete',ids:ids},function (result) {
|
||||
if (result.code==0){
|
||||
dataTable.reload()
|
||||
}
|
||||
|
|
@ -93,8 +97,8 @@
|
|||
|
||||
//更新配置
|
||||
$("#updateXml").click(function () {
|
||||
layer.confirm('该操作将重新注册所有网关,确认操作吗?', function(index){
|
||||
$.post("{{ route('admin.gateway.updateXml') }}",{_method:'post',_token:'{{csrf_token()}}'},function (result) {
|
||||
layer.confirm('该操作将更新所有队列信息,确认操作吗?', function(index){
|
||||
$.post("{{ route('admin.queue.updateXml') }}",{_method:'post',_token:'{{csrf_token()}}'},function (result) {
|
||||
var icon = result.code==0?6:5;
|
||||
layer.msg(result.msg,{icon:icon})
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,53 @@
|
|||
{{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">
|
||||
<input class="layui-input" type="text" name="datetime_start" id="datetime_start" lay-verify="required" value="{{$model->datetime_start??old('datetime_start')}}" readonly placeholder="点击选择时间">
|
||||
</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="datetime_end" id="datetime_end" lay-verify="required" value="{{$model->datetime_end??old('datetime_end')}}" readonly placeholder="点击选择时间">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">网关</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="gateway_id" lay-verify="required">
|
||||
<option value="">请选择</option>
|
||||
@foreach($gateways as $gw)
|
||||
<option value="{{$gw->id}}" @if((isset($model->gateway_id)&&$model->gateway_id==$gw->id) || (old('gateway_id')==$gw->id)) selected @endif >{{$gw->name}}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">队列</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="queue_id" lay-verify="required">
|
||||
<option value="">请选择</option>
|
||||
@foreach($queues as $queue)
|
||||
<option value="{{$queue->id}}" @if((isset($model->queue_id)&&$model->queue_id==$queue->id) || (old('queue_id')==$queue->id)) selected @endif>{{$queue->display_name}}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">最大并发</label>
|
||||
<div class="layui-input-block">
|
||||
<input class="layui-input" type="number" name="max_channel" lay-verify="required|number" value="{{$model->max_channel??0}}" placeholder="最大并发,默认:0">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button type="submit" class="layui-btn" lay-submit lay-filter="*" >确 认</button>
|
||||
<a href="{{route('admin.task')}}" class="layui-btn" >返 回</a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<script>
|
||||
layui.use(['layer','table','form','laydate'],function () {
|
||||
var layer = layui.layer;
|
||||
var form = layui.form;
|
||||
var table = layui.table;
|
||||
var laydate = layui.laydate;
|
||||
|
||||
laydate.render({elem:'#datetime_start',type:'datetime'})
|
||||
laydate.render({elem:'#datetime_end',type:'datetime'})
|
||||
|
||||
})
|
||||
</script>
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
@extends('admin.base')
|
||||
|
||||
@section('content')
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header layuiadmin-card-header-auto">
|
||||
<h2>添加任务</h2>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<form action="{{route('admin.task.store')}}" method="post" class="layui-form">
|
||||
@include('admin.task._form')
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@section('script')
|
||||
@include('admin.task._js')
|
||||
@endsection
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
@extends('admin.base')
|
||||
|
||||
@section('content')
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header layuiadmin-card-header-auto">
|
||||
<h2>更新任务</h2>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<form action="{{route('admin.task.update',['id'=>$model->id])}}" method="post" class="layui-form">
|
||||
{{method_field('put')}}
|
||||
@include('admin.task._form')
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@section('script')
|
||||
@include('admin.task._js')
|
||||
@endsection
|
||||
|
|
@ -0,0 +1,199 @@
|
|||
@extends('admin.base')
|
||||
|
||||
@section('content')
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header layuiadmin-card-header-auto">
|
||||
<div class="layui-btn-group">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-danger" id="listDelete">删 除</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-danger" id="setStatus1">停 止</button>
|
||||
<button class="layui-btn layui-btn-sm" id="setStatus2">启 动</button>
|
||||
<a class="layui-btn layui-btn-sm" href="{{ route('admin.task.create') }}">添 加</a>
|
||||
<a class="layui-btn layui-btn-sm" href="/static/outgoing.csv">模板下载</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<table id="dataTable" lay-filter="dataTable"></table>
|
||||
<script type="text/html" id="options">
|
||||
<div class="layui-btn-group">
|
||||
<a class="layui-btn layui-btn-sm" lay-event="import">导入号码</a>
|
||||
<a class="layui-btn layui-btn-sm" lay-event="show">详情</a>
|
||||
<a class="layui-btn layui-btn-sm" lay-event="edit">编辑</a>
|
||||
<a class="layui-btn layui-btn-danger layui-btn-sm " lay-event="del">删除</a>
|
||||
</div>
|
||||
</script>
|
||||
<script type="text/html" id="status">
|
||||
@{{# if(d.status==1){ }}
|
||||
<span class="layui-badge-dot" style="background-color: red;"></span> 停止
|
||||
@{{# } else if(d.status==2){ }}
|
||||
<span class="layui-badge-dot" style="background-color: green;"></span> 启动
|
||||
@{{# } else if(d.status==3){ }}
|
||||
<span class="layui-badge-dot layui-bg-black"></span> 已完成
|
||||
@{{# } }}
|
||||
</script>
|
||||
<script type="text/html" id="import-html">
|
||||
<div style="padding:20px">
|
||||
<div class="layui-form">
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">文件</label>
|
||||
<div class="layui-input-block">
|
||||
<button type="button" class="layui-btn layui-btn-normal" id="uploadBtn">
|
||||
<i class="layui-icon"></i>点击选择
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-input-block">
|
||||
<button class="layui-btn" id="importBtn">确认导入</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@section('script')
|
||||
<script>
|
||||
layui.use(['layer','table','form','upload'],function () {
|
||||
var layer = layui.layer;
|
||||
var form = layui.form;
|
||||
var table = layui.table;
|
||||
var upload = layui.upload;
|
||||
//用户表格初始化
|
||||
var dataTable = table.render({
|
||||
elem: '#dataTable'
|
||||
,height: 500
|
||||
,url: "{{ route('admin.task.data') }}" //数据接口
|
||||
,page: true //开启分页
|
||||
,cols: [[ //表头
|
||||
{checkbox: true,fixed: true}
|
||||
,{field: 'id', title: 'ID', sort: true,width:80}
|
||||
,{field: 'name', title: '名称'}
|
||||
,{field: 'datetime_start', title: '开始时间',width: 160}
|
||||
,{field: 'datetime_end', title: '结束时间',width: 160}
|
||||
,{field: 'gateway_name', title: '网关'}
|
||||
,{field: 'queue_name', title: '队列'}
|
||||
,{field: 'max_channel', title: '并发'}
|
||||
,{field: 'status', title: '状态', toolbar: '#status'}
|
||||
,{field: 'created_at', title: '添加时间',width: 160}
|
||||
,{fixed: 'right', width: 240, 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'){
|
||||
layer.confirm('确认删除吗?', function(index){
|
||||
$.post("{{ route('admin.task.destroy') }}",{_method:'delete',ids:[data.id]},function (result) {
|
||||
if (result.code==0){
|
||||
obj.del(); //删除对应行(tr)的DOM结构
|
||||
}
|
||||
layer.close(index);
|
||||
var icon = result.code==0?6:5;
|
||||
layer.msg(result.msg,{icon:icon})
|
||||
});
|
||||
});
|
||||
} else if(layEvent === 'edit'){
|
||||
location.href = '/admin/task/'+data.id+'/edit';
|
||||
} else if(layEvent === 'import'){
|
||||
layer.open({
|
||||
type : 1,
|
||||
title : '导入号码',
|
||||
shadeClose : true,
|
||||
area : ['500px','auto'],
|
||||
content : $("#import-html").html()
|
||||
});
|
||||
upload.render({
|
||||
elem: '#uploadBtn'
|
||||
,url: '/admin/task/'+data.id+'/importCall'
|
||||
,auto: false
|
||||
,multiple: false
|
||||
,accept: 'file'
|
||||
,exts: 'csv'
|
||||
,bindAction: '#importBtn'
|
||||
,before: function(obj){
|
||||
layer.load();
|
||||
}
|
||||
,done: function(res){
|
||||
layer.closeAll('loading');
|
||||
layer.msg(res.msg,{},function() {
|
||||
if (res.code==0){
|
||||
layer.closeAll();
|
||||
dataTable.reload()
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
} else if(layEvent === 'show'){
|
||||
location.href = '/admin/task/'+data.id+'/show';
|
||||
}
|
||||
});
|
||||
|
||||
//按钮批量删除
|
||||
$("#listDelete").click(function () {
|
||||
var ids = []
|
||||
var hasCheck = table.checkStatus('dataTable')
|
||||
var hasCheckData = hasCheck.data
|
||||
if (hasCheckData.length>0){
|
||||
$.each(hasCheckData,function (index,element) {
|
||||
ids.push(element.id)
|
||||
})
|
||||
}
|
||||
if (ids.length>0){
|
||||
layer.confirm('确认删除吗?', function(index){
|
||||
$.post("{{ route('admin.task.destroy') }}",{_method:'delete',ids:ids},function (result) {
|
||||
if (result.code==0){
|
||||
dataTable.reload()
|
||||
}
|
||||
layer.close(index);
|
||||
var icon = result.code==0?6:5;
|
||||
layer.msg(result.msg,{icon:icon})
|
||||
});
|
||||
})
|
||||
}else {
|
||||
layer.msg('请选择删除项',{icon:5})
|
||||
}
|
||||
})
|
||||
|
||||
function setStatus(msg,status) {
|
||||
var ids = []
|
||||
var hasCheck = table.checkStatus('dataTable')
|
||||
var hasCheckData = hasCheck.data
|
||||
if (hasCheckData.length>0){
|
||||
$.each(hasCheckData,function (index,element) {
|
||||
ids.push(element.id)
|
||||
})
|
||||
}
|
||||
if (ids.length>0){
|
||||
layer.confirm(msg, function(index){
|
||||
$.post("{{ route('admin.task.setStatus') }}",{ids:ids,status:status},function (result) {
|
||||
if (result.code==0){
|
||||
dataTable.reload()
|
||||
}
|
||||
layer.close(index);
|
||||
var icon = result.code==0?6:5;
|
||||
layer.msg(result.msg,{icon:icon})
|
||||
});
|
||||
})
|
||||
}else {
|
||||
layer.msg('请选择操作项',{icon:5})
|
||||
}
|
||||
}
|
||||
|
||||
//停止
|
||||
$("#setStatus1").click(function () {
|
||||
setStatus('确认停止吗?',1);
|
||||
});
|
||||
//启动
|
||||
$("#setStatus2").click(function () {
|
||||
setStatus('确认启动吗?',2);
|
||||
});
|
||||
|
||||
|
||||
|
||||
})
|
||||
</script>
|
||||
@endsection
|
||||
|
|
@ -0,0 +1,172 @@
|
|||
@extends('admin.base')
|
||||
|
||||
@section('content')
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">
|
||||
<b>任务信息</b>
|
||||
<a class="layui-btn layui-btn-sm layui-btn-primary" href="{{route('admin.task')}}" ><i class="layui-icon layui-icon-left"></i>返回</a>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-form">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-xs4">
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">任务名称:</label>
|
||||
<div class="layui-form-mid layui-word-aux">{{$task->name}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-xs4">
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">开始时间:</label>
|
||||
<div class="layui-form-mid layui-word-aux">{{$task->datetime_start}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-xs4">
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">结束时间:</label>
|
||||
<div class="layui-form-mid layui-word-aux">{{$task->datetime_end}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-xs4">
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">网关:</label>
|
||||
<div class="layui-form-mid layui-word-aux">{{$task->gateway_name}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-xs4">
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">队列:</label>
|
||||
<div class="layui-form-mid layui-word-aux">{{$task->queue_name}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-xs4">
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">并发:</label>
|
||||
<div class="layui-form-mid layui-word-aux">{{$task->max_channel}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-xs4">
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">呼叫总数:</label>
|
||||
<div class="layui-form-mid layui-word-aux">{{$task->calls_count}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-xs4">
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">已呼叫:</label>
|
||||
<div class="layui-form-mid layui-word-aux"><span style="color: green">{{$task->has_calls_count}}</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-col-xs4">
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">进度:</label>
|
||||
<div class="layui-input-inline" style="padding-top:10px">
|
||||
<div class="layui-progress layui-progress-big" lay-showPercent="true">
|
||||
<div class="layui-progress-bar layui-bg-black" lay-percent="{{$percent}}"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header"><b>呼叫图表</b></div>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-row layui-col-space10">
|
||||
<div class="layui-col-xs6">
|
||||
<div id="result_pie" style="width: 100%;height: 400px"></div>
|
||||
</div>
|
||||
<div class="layui-col-xs6">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header"><b>呼叫结果</b></div>
|
||||
<div class="layui-card-body">
|
||||
<table class="layui-table" lay-skin="line" lay-size="sm">
|
||||
<thead>
|
||||
<tr><th>状态</th><th>数量</th><th>占比</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td>成功</td><td>{{$task->success_calls_count}}</td><td>{{$task->has_calls_count>0?100*round($task->success_calls_count/$task->has_calls_count,4).'%':'0.00%'}}</td></tr>
|
||||
<tr><td>失败</td><td>{{$task->fail_calls_count}}</td><td>{{$task->has_calls_count>0?100*round($task->fail_calls_count/$task->has_calls_count,4).'%':'0.00%'}}</td></tr>
|
||||
<tr><td>漏接</td><td>{{$task->miss_calls_count}}</td><td>{{$task->has_calls_count>0?100*round($task->miss_calls_count/$task->has_calls_count,4).'%':'0.00%'}}</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header"><b>坐席监控</b></div>
|
||||
<div class="layui-card-body">
|
||||
<table class="layui-table" lay-skin="line" lay-size="sm">
|
||||
<thead>
|
||||
<tr><th>坐席</th><th>分机</th><th>坐席状态</th><th>呼叫状态</th></tr>
|
||||
</thead>
|
||||
<tbody id="agentStatus">
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@endsection
|
||||
|
||||
@section('script')
|
||||
<script>
|
||||
layui.config({
|
||||
version: '1535898708509' //为了更新 js 缓存,可忽略
|
||||
}).extend({
|
||||
echarts: 'lib/extend/echarts' ,
|
||||
echartsTheme: 'lib/extend/echartsTheme' ,
|
||||
}).use(['layer','table','form','echarts','echartsTheme'],function () {
|
||||
var layer = layui.layer;
|
||||
var form = layui.form;
|
||||
var table = layui.table;
|
||||
var echarts = layui.echarts;
|
||||
var echartsTheme = layui.echartsTheme;
|
||||
|
||||
//呼叫结果
|
||||
var result_pie = echarts.init(document.getElementById('result_pie'),echartsTheme)
|
||||
result_pie.setOption({
|
||||
title: {text: "任务呼出情况", x: "center", textStyle: {fontSize: 14}},
|
||||
tooltip: {trigger: "item", formatter: "{a} <br/>{b} : {c} ({d}%)"},
|
||||
legend: {orient: "vertical", x: "left", data: ["成功", "失败", "漏接"]},
|
||||
series: [{
|
||||
name: "呼出",
|
||||
type: "pie",
|
||||
radius: "55%",
|
||||
center: ["50%", "50%"],
|
||||
data: [
|
||||
{value:{{$task->success_calls_count}},name:'成功'},
|
||||
{value:{{$task->fail_calls_count}},name:'失败'},
|
||||
{value:{{$task->miss_calls_count}},name:'漏接'}
|
||||
]
|
||||
}]
|
||||
});
|
||||
window.onresize = result_pie.resize
|
||||
|
||||
function agentStatus() {
|
||||
$.post("{{route('admin.task.show',['id'=>$task->id])}}",{_token:"{{csrf_token()}}"},function (res) {
|
||||
if (res.code==0){
|
||||
var _html = '';
|
||||
$.each(res.data,function (index,item) {
|
||||
_html += '<tr>';
|
||||
_html += '<td>'+item.name+'</td>';
|
||||
_html += '<td>'+item.contact_name+'</td>';
|
||||
_html += '<td>'+item.status_name+'</td>';
|
||||
_html += '<td>'+item.state_name+'</td>';
|
||||
_html += '</tr>';
|
||||
})
|
||||
$("#agentStatus").html(_html);
|
||||
setTimeout(agentStatus,5000)
|
||||
}
|
||||
})
|
||||
}
|
||||
agentStatus();
|
||||
})
|
||||
</script>
|
||||
@endsection
|
||||
|
|
@ -213,11 +213,49 @@ Route::group(['namespace'=>'Admin','prefix'=>'admin','middleware'=>['auth','perm
|
|||
//分配坐席
|
||||
Route::get('queue/{id}/agent','QueueController@agent')->name('admin.queue.agent')->middleware('permission:pbx.queue.agent');
|
||||
Route::put('queue/{id}/assignAgent','QueueController@assignAgent')->name('admin.queue.assignAgent')->middleware('permission:pbx.queue.agent');
|
||||
});
|
||||
//坐席管理
|
||||
Route::group(['middleware'=>'permission:pbx.agent'],function (){
|
||||
Route::get('agent','AgentController@index')->name('admin.agent');
|
||||
Route::get('agent/data','AgentController@data')->name('admin.agent.data');
|
||||
//添加
|
||||
Route::get('agent/create','AgentController@create')->name('admin.agent.create')->middleware('permission:pbx.agent.create');
|
||||
Route::post('agent/store','AgentController@store')->name('admin.agent.store')->middleware('permission:pbx.agent.create');
|
||||
//编辑
|
||||
Route::get('agent/{id}/edit','AgentController@edit')->name('admin.agent.edit')->middleware('permission:pbx.agent.edit');
|
||||
Route::put('agent/{id}/update','AgentController@update')->name('admin.agent.update')->middleware('permission:pbx.agent.edit');
|
||||
//删除
|
||||
Route::delete('agent/destroy','AgentController@destroy')->name('admin.agent.destroy')->middleware('permission:pbx.agent.destroy');
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
//批量外呼
|
||||
Route::group(['namespace'=>'Admin','prefix'=>'admin','middleware'=>['auth','permission:ai.manage']],function (){
|
||||
|
||||
//任务管理
|
||||
Route::group(['middleware'=>'permission:ai.task'],function (){
|
||||
Route::get('task','TaskController@index')->name('admin.task');
|
||||
Route::get('task/data','TaskController@data')->name('admin.task.data');
|
||||
//详情
|
||||
Route::match(['get','post'],'task/{id}/show','TaskController@show')->name('admin.task.show');
|
||||
//添加
|
||||
Route::get('task/create','TaskController@create')->name('admin.task.create')->middleware('permission:ai.task.create');
|
||||
Route::post('task/store','TaskController@store')->name('admin.task.store')->middleware('permission:ai.task.create');
|
||||
//编辑
|
||||
Route::get('task/{id}/edit','TaskController@edit')->name('admin.task.edit')->middleware('permission:ai.task.edit');
|
||||
Route::put('task/{id}/update','TaskController@update')->name('admin.task.update')->middleware('permission:ai.task.edit');
|
||||
//删除
|
||||
Route::delete('task/destroy','TaskController@destroy')->name('admin.task.destroy')->middleware('permission:ai.task.destroy');
|
||||
//设置状态
|
||||
Route::post('task/setStatus','TaskController@setStatus')->name('admin.task.setStatus')->middleware('permission:ai.task.setStatus');
|
||||
//导入号码
|
||||
Route::post('task/{id}/importCall','TaskController@importCall')->name('admin.task.importCall')->middleware('permission:ai.task.importCall');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
//录音管理
|
||||
Route::group(['namespace'=>'Admin','prefix'=>'admin','middleware'=>['auth','permission:record.manage']],function (){
|
||||
|
||||
|
|
@ -233,3 +271,5 @@ Route::group(['namespace'=>'Admin','prefix'=>'admin','middleware'=>['auth','perm
|
|||
Route::get('cdr/{id}/show','CdrController@show')->name('admin.cdr.show');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue