diff --git a/app/Http/Controllers/Admin/AgentController.php b/app/Http/Controllers/Admin/AgentController.php
new file mode 100644
index 00000000..b9ba23ec
--- /dev/null
+++ b/app/Http/Controllers/Admin/AgentController.php
@@ -0,0 +1,136 @@
+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()]);
+ }
+ }
+}
diff --git a/app/Http/Controllers/Admin/GatewayController.php b/app/Http/Controllers/Admin/GatewayController.php
index cf2c2336..a8c931c0 100644
--- a/app/Http/Controllers/Admin/GatewayController.php
+++ b/app/Http/Controllers/Admin/GatewayController.php
@@ -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'=>'更新成功']);
}
diff --git a/app/Http/Controllers/Admin/QueueController.php b/app/Http/Controllers/Admin/QueueController.php
index 19943b0f..0d6f1694 100644
--- a/app/Http/Controllers/Admin/QueueController.php
+++ b/app/Http/Controllers/Admin/QueueController.php
@@ -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 = "\n";
+ $xml .= " \n";
+ $xml .= " \n";
+ $xml .= " \n";
+ $xml .= " \n";
+ $xml .= " \n";
+ $xml .= " \n";
+ foreach ($queues->toArray() as $q){
+ $xml .= " \n";
+ $xml .= " \n";
+ $xml .= " \n";
+ $xml .= " \n";
+ $xml .= " \n";
+ $xml .= " \n";
+ $xml .= " \n";
+ $xml .= " \n";
+ $xml .= " \n";
+ $xml .= " \n";
+ $xml .= " \n";
+ $xml .= " \n";
+ $xml .= " \n";
+ $xml .= " \n";
+ $xml .= " \n";
+ }
+ $xml .= " \n";
+ $xml .= " \n";
+ $xml .= " \n";
+ $xml .= " \n";
+ $xml .= " \n";
+ $xml .= " \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'=>'更新失败']);
}
}
diff --git a/app/Http/Controllers/Admin/TaskController.php b/app/Http/Controllers/Admin/TaskController.php
new file mode 100644
index 00000000..7b1c8702
--- /dev/null
+++ b/app/Http/Controllers/Admin/TaskController.php
@@ -0,0 +1,240 @@
+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()]);
+
+ }
+
+}
diff --git a/app/Http/Controllers/PublicController.php b/app/Http/Controllers/PublicController.php
index 5e9d0786..d57d723f 100644
--- a/app/Http/Controllers/PublicController.php
+++ b/app/Http/Controllers/PublicController.php
@@ -1,7 +1,6 @@
'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' => '无应答重试间隔',
+ ];
+ }
+
+}
diff --git a/app/Http/Requests/QueueRequest.php b/app/Http/Requests/QueueRequest.php
index 5535b3db..71262f69 100644
--- a/app/Http/Requests/QueueRequest.php
+++ b/app/Http/Requests/QueueRequest.php
@@ -13,7 +13,7 @@ class QueueRequest extends FormRequest
*/
public function authorize()
{
- return false;
+ return true;
}
/**
diff --git a/app/Http/Requests/TaskRequest.php b/app/Http/Requests/TaskRequest.php
new file mode 100644
index 00000000..d5fae198
--- /dev/null
+++ b/app/Http/Requests/TaskRequest.php
@@ -0,0 +1,48 @@
+ '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' => '最大并发',
+ ];
+ }
+
+}
diff --git a/app/Models/Agent.php b/app/Models/Agent.php
new file mode 100644
index 00000000..62699cb3
--- /dev/null
+++ b/app/Models/Agent.php
@@ -0,0 +1,38 @@
+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);
+ }
+
+}
diff --git a/app/Models/Call.php b/app/Models/Call.php
new file mode 100644
index 00000000..c754b8a6
--- /dev/null
+++ b/app/Models/Call.php
@@ -0,0 +1,10 @@
+belongsToMany('App\Models\Agent','tiers','queue','agent','name','name');
+ }
+
+ public function getStrategyNameAttribute()
+ {
+ return $this->attributes['strategy_name'] = array_get(config('freeswitch.strategy'),$this->strategy);
+ }
+
}
diff --git a/app/Models/Task.php b/app/Models/Task.php
new file mode 100644
index 00000000..77752daa
--- /dev/null
+++ b/app/Models/Task.php
@@ -0,0 +1,71 @@
+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);
+ }
+
+}
diff --git a/config/filesystems.php b/config/filesystems.php
index bd3015a4..dd68bec2 100644
--- a/config/filesystems.php
+++ b/config/filesystems.php
@@ -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
],
diff --git a/config/freeswitch.php b/config/freeswitch.php
index 67930b79..b1903424 100644
--- a/config/freeswitch.php
+++ b/config/freeswitch.php
@@ -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' => '通话中'
+ ],
];
diff --git a/database/migrations/2019_05_07_111537_create_gateway_table.php b/database/migrations/2019_05_07_111537_create_gateway_table.php
index 155c0125..6db2d923 100644
--- a/database/migrations/2019_05_07_111537_create_gateway_table.php
+++ b/database/migrations/2019_05_07_111537_create_gateway_table.php
@@ -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();
});
}
diff --git a/database/migrations/2019_05_16_173543_create_callcenter_table.php b/database/migrations/2019_05_16_173543_create_callcenter_table.php
index c61d9b9b..de392982 100644
--- a/database/migrations/2019_05_16_173543_create_callcenter_table.php
+++ b/database/migrations/2019_05_16_173543_create_callcenter_table.php
@@ -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) {
diff --git a/database/migrations/2019_05_22_090855_create_task.php b/database/migrations/2019_05_22_090855_create_task.php
new file mode 100644
index 00000000..23df47da
--- /dev/null
+++ b/database/migrations/2019_05_22_090855_create_task.php
@@ -0,0 +1,38 @@
+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');
+ }
+}
diff --git a/database/migrations/2019_05_22_094625_create_call.php b/database/migrations/2019_05_22_094625_create_call.php
new file mode 100644
index 00000000..c91dc134
--- /dev/null
+++ b/database/migrations/2019_05_22_094625_create_call.php
@@ -0,0 +1,44 @@
+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');
+ }
+}
diff --git a/database/seeds/UserTableSeeder.php b/database/seeds/UserTableSeeder.php
index e6150ea4..034c86d8 100644
--- a/database/seeds/UserTableSeeder.php
+++ b/database/seeds/UserTableSeeder.php
@@ -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) {
diff --git a/public/static/outgoing.csv b/public/static/outgoing.csv
new file mode 100644
index 00000000..76cfebf0
--- /dev/null
+++ b/public/static/outgoing.csv
@@ -0,0 +1,7 @@
+18908221080
+13512293513
+13512293514
+13512293515
+13512293516
+13512293517
+13512293517
\ No newline at end of file
diff --git a/resources/views/admin/agent/_form.blade.php b/resources/views/admin/agent/_form.blade.php
new file mode 100644
index 00000000..983e206e
--- /dev/null
+++ b/resources/views/admin/agent/_form.blade.php
@@ -0,0 +1,70 @@
+{{csrf_field()}}
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/resources/views/admin/agent/create.blade.php b/resources/views/admin/agent/create.blade.php
new file mode 100644
index 00000000..ff8fd9b7
--- /dev/null
+++ b/resources/views/admin/agent/create.blade.php
@@ -0,0 +1,14 @@
+@extends('admin.base')
+
+@section('content')
+
+@endsection
\ No newline at end of file
diff --git a/resources/views/admin/agent/edit.blade.php b/resources/views/admin/agent/edit.blade.php
new file mode 100644
index 00000000..2ce725ab
--- /dev/null
+++ b/resources/views/admin/agent/edit.blade.php
@@ -0,0 +1,15 @@
+@extends('admin.base')
+
+@section('content')
+
+@endsection
\ No newline at end of file
diff --git a/resources/views/admin/agent/index.blade.php b/resources/views/admin/agent/index.blade.php
new file mode 100644
index 00000000..d9d61a14
--- /dev/null
+++ b/resources/views/admin/agent/index.blade.php
@@ -0,0 +1,100 @@
+@extends('admin.base')
+
+@section('content')
+
+@endsection
+
+@section('script')
+
+@endsection
\ No newline at end of file
diff --git a/resources/views/admin/gateway/_form.blade.php b/resources/views/admin/gateway/_form.blade.php
index b9be87d0..4f1fc0d1 100644
--- a/resources/views/admin/gateway/_form.blade.php
+++ b/resources/views/admin/gateway/_form.blade.php
@@ -23,6 +23,18 @@
+
+