diff --git a/app/Console/Commands/SwooleCallcenterRun.php b/app/Console/Commands/SwooleCallcenterRun.php new file mode 100644 index 00000000..91dfe544 --- /dev/null +++ b/app/Console/Commands/SwooleCallcenterRun.php @@ -0,0 +1,156 @@ +where(['status'=>2])->select(['id'])->get(); + if ($res->isNotEmpty()) { + foreach ($res as $key => $task) { + Redis::rPush($redis_key,$task->id); + } + } + \Swoole\Coroutine\run(function () use ($redis_key) { + //启动服务 + while (true) { + $task_id = Redis::lPop($redis_key); + if ($task_id == null) { + sleep(10); + continue; + } + \Swoole\Coroutine::create(function () use ($task_id){ + while (true){ + $task = Task::with(['queue.sips','gateway']) + ->where('status',2) + ->where('id',$task_id) + ->first(); + //检测是否有启动的任务 + if ($task == null ){ + break; + } + + //检测执行日期 + $now_date = strtotime(date('Y-m-d')); + if ( $now_date < strtotime($task->date_start) || $now_date > strtotime($task->date_end) ) { + //延迟10秒 + sleep(10); + Log::info("任务ID:".$task->id."运行日期不满足"); + continue; + } + + //检测执行时间 + $now_time = strtotime(date('H:i:s')); + if ( $now_time < strtotime($task->time_start) || $now_time > strtotime($task->time_end) ) { + //延迟10秒 + sleep(10); + Log::info("任务ID:".$task->id."运行时间不满足"); + continue; + } + + //检测网关信息 + if ($task->gateway==null){ + Log::info("任务ID:".$task->id." 的网关不存在,任务停止"); + $task->update(['status'=>1]); + break; + } + + //检测队列 + if ($task->queue==null){ + Log::info("任务ID:".$task->id." 的队列不存在,任务停止"); + $task->update(['status'=>1]); + break; + } + //检测队列是否有坐席 + if ($task->queue->sips->isEmpty()){ + Log::info("任务ID:".$task->id." 的队列无坐席存在,任务停止"); + $task->update(['status'=>1]); + break; + } + //并发数调节 + $channel = 0; + $members = 0; + foreach ($task->queue->sips as $sip){ + if ($sip->status==1 && $sip->state=='down'){ + $members++; + } + } + if ($members === 0){ + Log::info("任务ID:".$task->name." 无空闲坐席,sleep:1秒"); + sleep(1); + continue; + }else{ + if ($task->max_channel==0){ + $channel = $members; + }else{ + $channel = $task->max_channel > $members ? $members : $task->max_channel; + } + } + + //如果通道数还是0,则不需要呼叫 + if ($channel == 0) { + Log::info("任务ID:".$task->name." 的并发不需要呼叫"); + sleep(10); + continue; + } + + //进行呼叫 + $calls = Call::where('task_id',$task->id)->where('status',1)->orderBy('id','asc')->take($channel)->get(); + if ($calls->isEmpty()){ + Log::info("任务:".$task->name."已完成"); + $task->update(['status'=>3]); + break; + } + foreach ($calls as $call){ + go(function () use ($call,$task){ + (new Callcenter($call,$task))->run(); + }); + sleep(2); + } + sleep(6); + } + }); + } + }); + } +} diff --git a/app/Console/Commands/SwooleHttp.php b/app/Console/Commands/SwooleHttp.php index c87d81f7..964bc29c 100644 --- a/app/Console/Commands/SwooleHttp.php +++ b/app/Console/Commands/SwooleHttp.php @@ -50,6 +50,7 @@ class SwooleHttp extends Command 'directory' => '/usr/local/freeswitch/conf/directory/default/', //拨号计划下面默认分为default(呼出)和public(呼入) 'dialplan' => '/usr/local/freeswitch/conf/dialplan/', + 'callcenter' => '/usr/local/freeswitch/conf/autoload_configs/callcenter.conf.xml' ]; $http->on('request', function ($request, $response) use ($conf) { if($request->server['request_method'] == 'POST'){ @@ -137,7 +138,60 @@ class SwooleHttp extends Command exec($command."\""."reloadxml"."\""); $return = ['code'=>0,'msg'=>'拨号计划更新成功']; break; + case '/callcenter': + $xml = "\n"; + $xml .= "\t\n"; + $xml .= "\t\t\n"; + $xml .= "\t\t\n"; + $xml .= "\t\t\n"; + $xml .= "\t\t\n"; + $xml .= "\t\t\n"; + $xml .= "\t\n"; + //---------------------------------- 写入队列信息 ------------------------------------ + $xml .= "\t\n"; + foreach ($data['queues'] as $queue){ + $xml .= "\t\t\n"; + $xml .= "\t\t\t\n"; + $xml .= "\t\t\t\n"; + //$xml .= "\t\t\t\n"; + $xml .= "\t\t\t\n"; + $xml .= "\t\t\t\n"; + $xml .= "\t\t\t\n"; + $xml .= "\t\t\t\n"; + $xml .= "\t\t\t\n"; + $xml .= "\t\t\t\n"; + $xml .= "\t\t\t\n"; + $xml .= "\t\t\t\n"; + $xml .= "\t\t\t\n"; + $xml .= "\t\t\t\n"; + $xml .= "\t\t\n"; + } + $xml .= "\t\n"; + //---------------------------------- 写入坐席信息 ------------------------------------ + $xml .= "\t\n"; + foreach ($data['agents'] as $agent){ + $contact = "[leg_timeout=10]user/".$agent['username']; + $xml .= "\t\t\n"; + } + $xml .= "\t\n"; + + //---------------------------------- 写入队列-坐席信息 ------------------------------------ + $xml .= "\t\n"; + foreach ($data['queues'] as $queue){ + if (isset($queue['agents'])&&!empty($queue['agents'])) { + foreach ($queue['agents'] as $agent){ + $xml .= "\t\t\n"; + } + } + } + $xml .= "\t\n"; + $xml .= "\n"; + //生成配置文件 + file_put_contents($conf['callcenter'],$xml); + exec($command."\""."reload mod_callcenter"."\""); + $return = ['code'=>0,'msg'=>'分机更新成功']; + break; case '/favicon.ico': $response->status(404); $response->end(); diff --git a/app/Http/Controllers/Callcenter/QueueController.php b/app/Http/Controllers/Callcenter/QueueController.php index ab1cc662..c4aad17b 100644 --- a/app/Http/Controllers/Callcenter/QueueController.php +++ b/app/Http/Controllers/Callcenter/QueueController.php @@ -3,6 +3,7 @@ namespace App\Http\Controllers\Callcenter; use App\Http\Controllers\Controller; +use App\Models\Sip; use GuzzleHttp\Client; use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; @@ -42,6 +43,7 @@ class QueueController extends Controller 'name' => $data['name'], 'strategy' => $data['strategy'], 'max_wait_time' => $data['max_wait_time'], + 'created_at' => date('Y-m-d H:i:s'), ]); foreach ($data['sips'] as $sipId){ DB::table('queue_sip')->insert([ @@ -108,11 +110,16 @@ class QueueController extends Controller public function updateXml() { $queues = Queue::with('sips')->get()->toArray(); + $sipIds = DB::table('queue_sip')->pluck('sip_id')->toArray(); + $agents = Sip::query()->whereIn('id',$sipIds)->get()->toArray(); try{ $client = new Client(); $client->post(config('freeswitch.swoole_http_url.callcenter'), [ - 'json' => $queues, + 'json' => [ + 'queues' => $queues, + 'agents' => $agents, + ], 'timeout' => 30 ] ); diff --git a/app/Http/Controllers/Callcenter/Task.php b/app/Http/Controllers/Callcenter/Task.php deleted file mode 100644 index 987adf9c..00000000 --- a/app/Http/Controllers/Callcenter/Task.php +++ /dev/null @@ -1,11 +0,0 @@ -ajax()){ + $res = Task::query()->withCount('calls')->orderByDesc('id')->paginate($request->get('limit', 30)); + return $this->success('ok',$res->items(),$res->total()); + } + return View::make('callcenter.task.index'); + } + + public function create() + { + $queues = Queue::query()->orderByDesc('id')->get(); + $gateways = Gateway::query()->orderByDesc('id')->get(); + return View::make('callcenter.task.create',compact('queues','gateways')); + } + + public function store(Request $request) + { + $data = $request->all([ + 'name', + 'date_start', + 'date_end', + 'time_start', + 'time_end', + 'gateway_id', + 'queue_id', + 'max_channel', + ]); + try { + Task::create($data); + return $this->success(); + }catch (\Exception $exception){ + Log::error('添加任务异常:'.$exception->getMessage()); + return $this->error(); + } + } + + public function edit($id) + { + $model = Task::query()->findOrFail($id); + $queues = Queue::query()->orderByDesc('id')->get(); + $gateways = Gateway::query()->orderByDesc('id')->get(); + return View::make('callcenter.task.edit',compact('model', 'queues', 'gateways')); + } + + public function update(Request $request,$id) + { + $data = $request->all([ + 'name', + 'date_start', + 'date_end', + 'time_start', + 'time_end', + 'gateway_id', + 'queue_id', + 'max_channel', + ]); + $model = Task::query()->findOrFail($id); + try { + $model->update($data); + return $this->success(); + }catch (\Exception $exception){ + 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 { + Task::destroy($ids); + + DB::commit(); + return $this->success(); + }catch (\Exception $exception){ + DB::rollBack(); + Log::error('删除群呼任务异常:'.$exception->getMessage()); + return $this->error(); + } + } + + public function show(Request $request,$id) + { + $task = Task::query()->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('queue_agent')->where('queue_id',$task->queue_id)->pluck('agent_id'); + return response()->json(['code'=>0, 'msg'=>'请求成功']); + } + return view('callcenter.task.show',compact('task','percent')); + } + + public function setStatus(Request $request) + { + $ids = $request->get('ids',[]); + if (count($ids)!=1){ + return $this->error('请选择一条记录'); + } + $task = Task::query()->withCount('calls')->find($ids[0]); + if ($task==null){ + return $this->error('任务不存在'); + } + if ($task->status==3){ + return $this->error('任务已完成,禁止操作'); + } + $status = $request->get('status',1); + + if ($status==2&&$task->calls_count==0){ + return $this->error('任务未导入号码,禁止操作'); + } + if ($status==1&&$task->status!=2){ + return $this->error('任务未启动,禁止操作'); + } + try { + $task->update(['status'=>$status]); + $key = config('freeswitch.redis_key.callcenter_task'); + Redis::rPush($key,$task->id); + return $this->success(); + }catch (\Exception $exception){ + Log::error('设置任务状态异常:'.$exception->getMessage()); + return $this->error(); + } + } + + public function importCall(Request $request, $id) + { + $model = Task::query()->findOrFail($id); + if ($request->ajax()){ + $file = $request->input('file'); + if ($file == null){ + return $this->error('请先上传文件'); + } + $xlsFile = public_path().$file; + try{ + Excel::import(new CallImport($id), $xlsFile); + return $this->success('导入成功'); + }catch (\Exception $exception){ + Log::error('导入失败:'.$exception->getMessage()); + return $this->error('导入失败'); + } + } + return View::make('callcenter.task.import',compact('model')); + } + + public function calls(Request $request) + { + $data = $request->all(['task_id','phone']); + $res = Call::query() + ->when($data['phone'],function ($q) use($data){ + return $q->where('phone','like','%'.$data['phone'].'%'); + }) + ->where('task_id',$data['task_id']) + ->orderBy('id','asc') + ->paginate($request->get('limit', 30)); + foreach ($res->items() as $item){ + $item->status_name = Arr::get(config('freeswitch.callcenter_call_status'),$item->status,'-'); + } + return $this->success('ok',$res->items(),$res->total()); + } + +} diff --git a/app/Imports/CallImport.php b/app/Imports/CallImport.php new file mode 100644 index 00000000..f07dc578 --- /dev/null +++ b/app/Imports/CallImport.php @@ -0,0 +1,30 @@ +task_id = $task_id; + } + + public function model(array $row) + { + if (!isset($row[0]) || !preg_match('/\d{7,11}/',$row[0]) ) { + return null; + } + return new Call([ + 'task_id' => $this->task_id, + 'phone' => $row[0], + ]); + } +} diff --git a/app/Models/Call.php b/app/Models/Call.php new file mode 100644 index 00000000..a01e2c57 --- /dev/null +++ b/app/Models/Call.php @@ -0,0 +1,22 @@ +hasOne('App\Models\Sip','id','sip_id'); + } + + public function user() + { + return $this->hasOne('App\Models\User','id','user_id'); + } + +} diff --git a/app/Models/Task.php b/app/Models/Task.php index 58531793..0629f09f 100644 --- a/app/Models/Task.php +++ b/app/Models/Task.php @@ -8,4 +8,67 @@ class Task extends Model { protected $table = 'task'; protected $guarded = ['id']; + + protected $appends = ['gateway_name','queue_name','date','time']; + + 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->name; + } + + public function getDateAttribute() + { + return $this->attributes['date'] = $this->date_start . ' / '. $this->date_end; + } + + public function getTimeAttribute() + { + return $this->attributes['time'] = $this->time_start . ' - '. $this->time_end; + } + + //总呼叫数 + 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=2 + public function failCalls() + { + return $this->hasMany('App\Models\Call','task_id','id')->where('status',2); + } + } diff --git a/app/Service/Callcenter.php b/app/Service/Callcenter.php new file mode 100644 index 00000000..4a9b945a --- /dev/null +++ b/app/Service/Callcenter.php @@ -0,0 +1,123 @@ +call = $call; + $this->fs = new SwooleFreeswitch(); + if (!$this->fs->connect()) { + return false; + } + + } + + public function run() + { + $record_url = config('freeswitch.record_url'); + $fs_dir = '/usr/local/freeswitch'; + + $uuid = uuid_generate(); + //更新为正在呼叫 + $this->call->update([ + 'status' => 2, + 'uuid' => $uuid, + 'datetime_originate_phone' => date('Y-m-d H:i:s') + ]); + Log::info("更新号码: " . $this->call->phone . " 状态为:2"); + + $phone = $this->task->gateway->prefix ? $this->task->gateway->prefix . $this->call->phone : $this->call->phone; + $varStr = "{origination_uuid=" . $uuid . "}"; + $varStr .= "{ignore_early_media=true}"; + $varStr .= "{effective_caller_id_number=" . $this->call->phone . "}"; + $varStr .= "{effective_caller_id_name=" . $this->call->phone . "}"; + if ($this->task->gateway->outbound_caller_id) { + $varStr .= "{origination_caller_id_number=" . $this->task->gateway->outbound_caller_id . "}"; + $varStr .= "{origination_caller_id_name=" . $this->task->gateway->outbound_caller_id . "}"; + } + $varStr .= "{cc_export_vars=effective_caller_id_number,effective_caller_id_name}"; + $dail_string = "originate " . $varStr . "sofia/gateway/gw" . $this->task->gateway->id . "/" . $phone . " &callcenter(queue" . $this->task->queue->id . ")"; + Log::info("呼叫:" . $dail_string); + + $this->fs->bgapi($dail_string); + $this->fs->events("CUSTOM callcenter::info"); + $this->fs->filteruuid($this->call->uuid); + + while (true) { + $received_parameters = $this->fs->recvEvent(); + if (!empty($received_parameters)) { + $json = $this->fs->serialize($received_parameters); + $action = Arr::get($json, "CC-Action"); + $uuid = Arr::get($json, "CC-Member-Session-UUID"); + switch ($action) { + //呼叫进入队列 + case 'member-queue-start': + $this->call->update([ + 'datetime_entry_queue' => date('Y-m-d H:i:s'), + 'status' => 3 + ]); + break; + // 坐席应答 + case 'bridge-agent-start': + $agent_name = Arr::get($json, "CC-Agent"); + $id = (int)Str::after($agent_name, 'agent'); + $filepath = $fs_dir . '/recordings/' . date('Y/m/d/'); + $file = $filepath . 'callcenter_' . $uuid . '.wav'; + $this->fs->bgapi("uuid_record " . $uuid . " start " . $file . " 1800"); + $this->call->update([ + 'datetime_agent_answered' => date('Y-m-d H:i:s'), + 'status' => 4, + 'agent_id' => $id, + 'record_file' => str_replace($fs_dir, $record_url, $file), + ]); + break; + //坐席结束 + case 'bridge-agent-end': + $this->call->update([ + 'datetime_end' => date('Y-m-d H:i:s'), + 'status' => 4 + ]); + break; + //桥接结束,通话结束 + case 'member-queue-end': + $cause = Arr::get($json, "CC-Cause"); + $answered_time = Arr::get($json, "CC-Agent-Answered-Time"); + $leaving_time = Arr::get($json, "CC-Member-Leaving-Time"); + if ($cause == 'Cancel') { + $billsec = 0; + } else { + if ($leaving_time && $answered_time) { + $billsec = $leaving_time - $answered_time > 0 ? $leaving_time - $answered_time : 0; + } else { + $billsec = 0; + } + } + $this->call->update([ + 'billsec' => $billsec, + ]); + break; + default: + } + } + } + $this->fs->disconnect(); + } + +} diff --git a/config/freeswitch.php b/config/freeswitch.php index 2aa42d8a..ab5e9c52 100644 --- a/config/freeswitch.php +++ b/config/freeswitch.php @@ -31,6 +31,8 @@ return [ 'directory' => 'http://127.0.0.1:9501/directory', //生成拨号计划 'dialplan' => 'http://127.0.0.1:9501/dialplan', + //生成群呼 + 'callcenter' => 'http://127.0.0.1:9501/callcenter', ], 'esl' => [ @@ -42,6 +44,7 @@ return [ 'redis_key' => [ 'dial' => 'dial_uuid_queue', 'api' => 'api_exec_queue', + 'callcenter_task' => 'callcenter_task_queue', ], 'record_url' => env('APP_URL','http://localhost'), 'host' => env('FS_HOST','127.0.0.1'), @@ -85,4 +88,12 @@ return [ 4 => '微信', 5 => '其它', ], + + //群呼状态 + 'callcenter_call_status' => [ + 1 => '待呼叫', + 2 => '呼叫失败', + 3 => '漏接', + 4 => '成功', + ], ]; diff --git a/database/migrations/2021_04_02_154147_callcenter_task_call.php b/database/migrations/2021_04_02_154147_callcenter_task_call.php index 164b99e9..28660646 100644 --- a/database/migrations/2021_04_02_154147_callcenter_task_call.php +++ b/database/migrations/2021_04_02_154147_callcenter_task_call.php @@ -18,6 +18,9 @@ class CallcenterTaskCall extends Migration $table->unsignedBigInteger('task_id')->comment('任务ID'); $table->string('phone')->comment('待呼叫号码'); $table->tinyInteger('status')->default(1)->comment('1-待呼叫,2-呼叫中,3-队列等待,4-已通话'); + $table->string('uuid')->nullable()->comment('UUID'); + $table->string('aleg_uuid')->nullable()->comment('客户通话UUID'); + $table->string('bleg_uuid')->nullable()->comment('坐席通话UUID'); $table->string('uuid')->nullable()->comment('客户通话UUID'); $table->timestamp('datetime_originate_phone')->nullable()->comment('呼叫时间'); $table->timestamp('datetime_entry_queue')->nullable()->comment('进入队列时间'); diff --git a/database/seeds/MenuTableSeeder.php b/database/seeds/MenuTableSeeder.php index 88787bd0..324149e6 100644 --- a/database/seeds/MenuTableSeeder.php +++ b/database/seeds/MenuTableSeeder.php @@ -116,6 +116,14 @@ class MenuTableSeeder extends Seeder 'type' => 1, 'permission_name' => 'callcenter.queue', ], + [ + 'name' => '任务管理', + 'route' => 'callcenter.task', + 'url' => null, + 'icon' => 'layui-icon-template-1', + 'type' => 1, + 'permission_name' => 'callcenter.task', + ], ] ], [ diff --git a/database/seeds/UserTableSeeder.php b/database/seeds/UserTableSeeder.php index 4ba4e2ea..13cac881 100644 --- a/database/seeds/UserTableSeeder.php +++ b/database/seeds/UserTableSeeder.php @@ -137,6 +137,18 @@ class UserTableSeeder extends Seeder ['name' => 'callcenter.queue.updateXml', 'display_name' => '更新配置'], ] ], + [ + 'name' => 'callcenter.task', + 'display_name' => '任务管理', + 'child' => [ + ['name' => 'callcenter.task.create', 'display_name' => '添加'], + ['name' => 'callcenter.task.show', 'display_name' => '详情'], + ['name' => 'callcenter.task.edit', 'display_name' => '编辑'], + ['name' => 'callcenter.task.destroy', 'display_name' => '删除'], + ['name' => 'callcenter.task.importCall', 'display_name' => '导入号码'], + ['name' => 'callcenter.task.setStatus', 'display_name' => '设置状态'], + ] + ], ], ], [ diff --git a/public/template/calls.xlsx b/public/template/calls.xlsx new file mode 100644 index 00000000..9ed6a893 Binary files /dev/null and b/public/template/calls.xlsx differ diff --git a/public/template/outgoing.csv b/public/template/outgoing.csv deleted file mode 100644 index 76cfebf0..00000000 --- a/public/template/outgoing.csv +++ /dev/null @@ -1,7 +0,0 @@ -18908221080 -13512293513 -13512293514 -13512293515 -13512293516 -13512293517 -13512293517 \ No newline at end of file diff --git a/resources/views/callcenter/task/_form.blade.php b/resources/views/callcenter/task/_form.blade.php new file mode 100644 index 00000000..b97c0e30 --- /dev/null +++ b/resources/views/callcenter/task/_form.blade.php @@ -0,0 +1,65 @@ +{{csrf_field()}} +
+ +
+ +
+
+
+
+ +
+ +
+
-
+
+ +
+
+
+
+
+ +
+ +
+
-
+
+ +
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
最大并发,默认:0 为不限制,系统将自动调节
+
+
+
+ +
+
diff --git a/resources/views/callcenter/task/_js.blade.php b/resources/views/callcenter/task/_js.blade.php new file mode 100644 index 00000000..93bdd5fe --- /dev/null +++ b/resources/views/callcenter/task/_js.blade.php @@ -0,0 +1,14 @@ + \ No newline at end of file diff --git a/resources/views/callcenter/task/create.blade.php b/resources/views/callcenter/task/create.blade.php new file mode 100644 index 00000000..ab20fce7 --- /dev/null +++ b/resources/views/callcenter/task/create.blade.php @@ -0,0 +1,15 @@ +@extends('base') + +@section('content') +
+
+
+ @include('callcenter.task._form') +
+
+
+@endsection + +@section('script') + @include('callcenter.task._js') +@endsection diff --git a/resources/views/callcenter/task/edit.blade.php b/resources/views/callcenter/task/edit.blade.php new file mode 100644 index 00000000..b5a40536 --- /dev/null +++ b/resources/views/callcenter/task/edit.blade.php @@ -0,0 +1,16 @@ +@extends('base') + +@section('content') +
+
+
+ {{method_field('put')}} + @include('callcenter.task._form') +
+
+
+@endsection + +@section('script') + @include('callcenter.task._js') +@endsection diff --git a/resources/views/callcenter/task/import.blade.php b/resources/views/callcenter/task/import.blade.php new file mode 100644 index 00000000..15ce4e25 --- /dev/null +++ b/resources/views/callcenter/task/import.blade.php @@ -0,0 +1,63 @@ +@extends('base') + +@section('content') +
+
+
+
+
+ +
+ +
+
+
+
+
+
+ + +
+
+
+
+
+@endsection + +@section('script') + +@endsection diff --git a/resources/views/callcenter/task/index.blade.php b/resources/views/callcenter/task/index.blade.php new file mode 100644 index 00000000..97aeefd3 --- /dev/null +++ b/resources/views/callcenter/task/index.blade.php @@ -0,0 +1,150 @@ +@extends('base') + +@section('content') +
+
+
+ @can('callcenter.task.destroy') + + @endcan + @can('callcenter.task.setStatus') + + + @endcan + @can('callcenter.task.create') + + @endcan + 模板下载 +
+
+
+
+ + +
+
+@endsection + +@section('script') + +@endsection diff --git a/resources/views/callcenter/task/show.blade.php b/resources/views/callcenter/task/show.blade.php new file mode 100644 index 00000000..58b5acc0 --- /dev/null +++ b/resources/views/callcenter/task/show.blade.php @@ -0,0 +1,206 @@ +@extends('base') + +@section('content') +
+
+
+
+
+
+ +
{{$task->name}}
+
+
+
+
+ +
{{$task->date}}
+
+
+
+
+ +
{{$task->time}}
+
+
+
+
+ +
{{$task->gateway_name}}
+
+
+
+
+ +
{{$task->queue_name}}
+
+
+
+
+ +
{{$task->max_channel}}
+
+
+
+
+ +
{{$task->calls_count}}
+
+
+
+
+ +
{{$task->has_calls_count}}
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+ +
+
呼叫图表
+
+
+
+
+
+
+
+
呼叫结果
+
+ + + + + + + + + +
状态数量占比
成功{{$task->success_calls_count}}{{$task->has_calls_count>0?100*round($task->success_calls_count/$task->has_calls_count,4).'%':'0.00%'}}
失败{{$task->fail_calls_count}}{{$task->has_calls_count>0?100*round($task->fail_calls_count/$task->has_calls_count,4).'%':'0.00%'}}
漏接{{$task->miss_calls_count}}{{$task->has_calls_count>0?100*round($task->miss_calls_count/$task->has_calls_count,4).'%':'0.00%'}}
+
+
+
+
+
+
+ +
+
+ 呼叫记录 +
+
+
+ +
+ +
+
+
+
+ +
+
+
+
+
+
+
+ +
+
+ +@endsection + +@section('script') + +@endsection diff --git a/routes/web.php b/routes/web.php index 756e1763..3af7c952 100644 --- a/routes/web.php +++ b/routes/web.php @@ -211,6 +211,27 @@ Route::group(['prefix'=>'callcenter','namespace'=>'Callcenter','middleware'=>['a Route::post('queue/updateXml','QueueController@updateXml')->name('callcenter.queue.updateXml')->middleware('permission:callcenter.queue.updateXml'); }); + //任务管理 + Route::group([],function (){ + Route::get('task','TaskController@index')->name('callcenter.task')->middleware('permission:callcenter.task'); + //添加 + Route::get('task/create','TaskController@create')->name('callcenter.task.create')->middleware('permission:callcenter.task.create'); + Route::post('task/store','TaskController@store')->name('callcenter.task.store')->middleware('permission:callcenter.task.create'); + //编辑 + Route::get('task/{id}/edit','TaskController@edit')->name('callcenter.task.edit')->middleware('permission:callcenter.task.edit'); + Route::put('task/{id}/update','TaskController@update')->name('callcenter.task.update')->middleware('permission:callcenter.task.edit'); + //删除 + Route::delete('task/destroy','TaskController@destroy')->name('callcenter.task.destroy')->middleware('permission:callcenter.task.destroy'); + //详情 + Route::get('task/{id}/show','TaskController@show')->name('callcenter.task.show')->middleware('permission:callcenter.task.show'); + //设置状态 + Route::post('task/setStatus','TaskController@setStatus')->name('callcenter.task.setStatus')->middleware('permission:callcenter.task.setStatus'); + //导入号码 + Route::match(['get','post'],'task/{id}/importCall','TaskController@importCall')->name('callcenter.task.importCall')->middleware('permission:callcenter.task.importCall'); + //呼叫记录 + Route::get('task/calls','TaskController@calls')->name('callcenter.task.calls'); + }); + });