完善webrtc打电话功能
This commit is contained in:
parent
b6390db61b
commit
b661c87eb9
|
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\Call;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class asr_listen extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'asr:listen';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'asr listen';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
//定义日志
|
||||
$monolog = Log::getMonolog();
|
||||
$monolog->popHandler();
|
||||
Log::useFiles(storage_path('logs/asr_listen.log'));
|
||||
|
||||
$fs = new \Freeswitchesl();
|
||||
if (!$fs->connect(config('freeswitch.event_socket.host'), config('freeswitch.event_socket.port'), config('freeswitch.event_socket.password'))){
|
||||
echo "ESL未连接";
|
||||
return 1;
|
||||
}
|
||||
$fs->events('json', 'CUSTOM asr');
|
||||
while (true){
|
||||
$received_parameters = $fs->recvEvent();
|
||||
if (!empty($received_parameters)) {
|
||||
//记录日志
|
||||
$info = $fs->serialize($received_parameters,"json");
|
||||
Log::info($info);
|
||||
$response = $fs->getHeader($received_parameters,"ASR-Response");
|
||||
$response = json_decode(urldecode($response),true);
|
||||
if($response['status_code']==200&&isset($response['result'])&&$response['result']['status_code']==0&&!empty($response['result']['text'])){
|
||||
$text = $response['result']['text'];
|
||||
$uuid = $fs->getHeader($received_parameters,"Core-UUID");
|
||||
DB::table('cdr_asr')->insert([
|
||||
'uuid' => $uuid,
|
||||
'text' => $text,
|
||||
'created_at' => Carbon::now(),
|
||||
'updated_at' => Carbon::now(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
$fs->disconnect();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\Agent;
|
||||
use App\Models\Call;
|
||||
use Illuminate\Console\Command;
|
||||
use Log;
|
||||
|
||||
class callcenter_listen extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'callcenter:listen';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'callcenter listen';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
//定义日志
|
||||
$monolog = Log::getMonolog();
|
||||
$monolog->popHandler();
|
||||
Log::useFiles(storage_path('logs/callcenter_listen.log'));
|
||||
|
||||
$fs = new \Freeswitchesl();
|
||||
if (!$fs->connect(config('freeswitch.event_socket.host'), config('freeswitch.event_socket.port'), config('freeswitch.event_socket.password'))){
|
||||
echo "ESL未连接";
|
||||
return 1;
|
||||
}
|
||||
$fs->events('json', 'CUSTOM callcenter::info');
|
||||
while (true){
|
||||
$received_parameters = $fs->recvEvent();
|
||||
if (!empty($received_parameters)) {
|
||||
//记录日志
|
||||
$info = $fs->serialize($received_parameters,"json");
|
||||
Log::info($info);
|
||||
$action = $fs->getHeader($received_parameters,"CC-Action");
|
||||
switch ($action){
|
||||
//坐席状态
|
||||
case 'agent-status-change':
|
||||
$agent_name = $fs->getHeader($received_parameters,"CC-Agent");
|
||||
$status = $fs->getHeader($received_parameters,"CC-Agent-Status");
|
||||
Agent::where('name',$agent_name)->update(['status'=>$status]);
|
||||
break;
|
||||
//坐席呼叫状态
|
||||
case 'agent-state-change':
|
||||
$agent_name = $fs->getHeader($received_parameters,"CC-Agent");
|
||||
$state = $fs->getHeader($received_parameters,"CC-Agent-State");
|
||||
Agent::where('name',$agent_name)->update(['state'=>$state]);
|
||||
break;
|
||||
//呼叫进入队列
|
||||
case 'member-queue-start':
|
||||
$uuid = $fs->getHeader($received_parameters,"CC-Member-Session-UUID");
|
||||
$datetime = urldecode($fs->getHeader($received_parameters,"variable_cc_queue_joined_epoch"));
|
||||
Call::where('uuid',$uuid)->update(['datetime_entry_queue'=>date('Y-m-d H:i:s',$datetime),'status'=>3]);
|
||||
break;
|
||||
//呼叫坐席
|
||||
case 'agent-offering':
|
||||
$uuid = $fs->getHeader($received_parameters,"CC-Member-Session-UUID");
|
||||
$agent_name = $fs->getHeader($received_parameters,"CC-Agent");
|
||||
$datetime = urldecode($fs->getHeader($received_parameters,"Event-Date-Local"));
|
||||
Call::where('uuid',$uuid)->update(['datetime_agent_called'=>$datetime,'agent_name'=>$agent_name]);
|
||||
break;
|
||||
// 坐席应答
|
||||
case 'bridge-agent-start':
|
||||
$uuid = $fs->getHeader($received_parameters,"CC-Member-Session-UUID");
|
||||
$datetime = $fs->getHeader($received_parameters,"CC-Agent-Answered-Time");
|
||||
Call::where('uuid',$uuid)->update(['datetime_agent_answered'=>date('Y-m-d H:i:s',$datetime),'status'=>4]);
|
||||
break;
|
||||
//坐席结束
|
||||
case 'bridge-agent-end':
|
||||
$uuid = $fs->getHeader($received_parameters,"CC-Member-Session-UUID");
|
||||
$datetime = $fs->getHeader($received_parameters,"CC-Bridge-Terminated-Time");
|
||||
Call::where('uuid',$uuid)->update(['datetime_end'=>date('Y-m-d H:i:s',$datetime),'status'=>4]);
|
||||
break;
|
||||
//桥接结束,通话结束
|
||||
case 'member-queue-end':
|
||||
$uuid = $fs->getHeader($received_parameters,"CC-Member-Session-UUID");
|
||||
$cause = $fs->getHeader($received_parameters,"CC-Cause");
|
||||
$answered_time = $fs->getHeader($received_parameters,"CC-Agent-Answered-Time");
|
||||
$leaving_time = $fs->getHeader($received_parameters,"CC-Member-Leaving-Time");
|
||||
$joined_time = $fs->getHeader($received_parameters,"CC-Member-Joined-Time");
|
||||
if ($leaving_time && $joined_time){
|
||||
$duration = $leaving_time - $joined_time > 0 ? $leaving_time - $joined_time : 0;
|
||||
}else{
|
||||
$duration = 0;
|
||||
}
|
||||
if ($leaving_time && $answered_time){
|
||||
$billsec = $leaving_time - $answered_time > 0 ? $leaving_time - $answered_time : 0;
|
||||
}else{
|
||||
$billsec = 0;
|
||||
}
|
||||
Call::where('uuid',$uuid)->update([
|
||||
'cause' => $cause,
|
||||
'duration' => $duration,
|
||||
'billsec' => $billsec,
|
||||
]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
$fs->disconnect();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\Call;
|
||||
use App\Models\Task;
|
||||
use Carbon\Carbon;
|
||||
use Faker\Provider\Uuid;
|
||||
use Illuminate\Console\Command;
|
||||
use Log;
|
||||
|
||||
class callcenter_start extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'callcenter:start';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'callcenter start';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
//定义日志
|
||||
$monolog = Log::getMonolog();
|
||||
$monolog->popHandler();
|
||||
Log::useFiles(storage_path('logs/task.log'));
|
||||
$fs = new \Freeswitchesl();
|
||||
if ($fs->connect(config('freeswitch.event_socket.host'), config('freeswitch.event_socket.port'), config('freeswitch.event_socket.password'))){
|
||||
while (true){
|
||||
$now_date = date('Y-m-d');
|
||||
$now_time = date('H:i:s');
|
||||
$tasks = Task::with(['queue','gateway'])
|
||||
->where('status',2)
|
||||
->where('date_start','<=',$now_date)
|
||||
->where('date_end','>=',$now_date)
|
||||
->where('time_start','<=',$now_time)
|
||||
->where('time_end','>=',$now_time)
|
||||
->get();
|
||||
//检测是否有启动的任务
|
||||
if ($tasks->isEmpty()){
|
||||
//延迟5秒
|
||||
usleep(5000000);
|
||||
continue;
|
||||
}
|
||||
//循环任务
|
||||
foreach ($tasks as $task){
|
||||
//检测网关信息
|
||||
if ($task->gateway==null){
|
||||
Log::info("任务ID:".$task->name." 的网关不存在");
|
||||
continue;
|
||||
}
|
||||
$gw_info = $fs->api("sofia status gateway gw".$task->gateway->id);
|
||||
if (trim($gw_info)=='Invalid Gateway!'){
|
||||
Log::info("任务ID: ".$task->name."的网关 ".$task->gateway->name."的网关配置不存在");
|
||||
continue;
|
||||
}
|
||||
$gw_status = 0;
|
||||
foreach (explode("\n",$gw_info) as $str){
|
||||
if (str_contains($str,"REGED")){
|
||||
$gw_status = 1;
|
||||
}
|
||||
}
|
||||
if ($gw_status==0){
|
||||
Log::info("任务ID: ".$task->name."的网关 ".$task->gateway->name."未注册成功");
|
||||
continue;
|
||||
}
|
||||
//检测队列
|
||||
if ($task->queue==null){
|
||||
Log::info("任务ID:".$task->name." 的队列不存在");
|
||||
continue;
|
||||
}
|
||||
//并发数调节
|
||||
$channel = 0;
|
||||
if ($task->max_channel){
|
||||
$channel = $task->max_channel;
|
||||
}else{
|
||||
//队列总空闲坐席数
|
||||
$wait_num = $fs->api("callcenter_config queue count agents ".$task->queue->name." Available Waiting");
|
||||
$channel = (int)$wait_num;
|
||||
}
|
||||
//如果通道数还是0,则不需要呼叫
|
||||
if ($channel==0) continue;
|
||||
//否则进行呼叫
|
||||
Log::info("任务:".$task->name." 将呼叫 ".$channel." 个号码");
|
||||
$calls = Call::where('status',1)->orderBy('id','asc')->limit($channel)->get();
|
||||
if ($calls->isEmpty()){
|
||||
Log::info("任务:".$task->name."已完成");
|
||||
$task->update(['status'=>3]);
|
||||
continue;
|
||||
}
|
||||
foreach ($calls as $call){
|
||||
$uuid = Uuid::uuid();
|
||||
//更新为正在呼叫
|
||||
$call->update(['status'=>2,'uuid'=>$uuid]);
|
||||
Log::info("更新号码: ".$call->phone." 状态为:2");
|
||||
$phone = $task->gateway->prefix ? $task->gateway->prefix.$call->phone : $call->phone;
|
||||
$var_str = "{origination_uuid=".$uuid."}";
|
||||
if ($task->gateway->outbound_caller_id) $var_str = "{origination_uuid=".$uuid.",outbound_caller_id=".$task->gateway->outbound_caller_id."}";
|
||||
$dail_string = "originate ".$var_str."sofia/gateway/gw".$task->gateway->id."/".$phone." &callcenter(".$task->queue->name.")";
|
||||
Log::info("呼叫:".$dail_string);
|
||||
$fs->bgapi($dail_string);
|
||||
usleep(500);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}else{
|
||||
echo "ESL未连接";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Models\Action;
|
||||
use App\Models\Condition;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class ActionController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index($condition_id)
|
||||
{
|
||||
$condition = Condition::findOrFail($condition_id);
|
||||
return view('admin.dialplan.action.index',compact('condition'));
|
||||
}
|
||||
|
||||
public function data(Request $request,$condition_id)
|
||||
{
|
||||
$res = Action::where('condition_id',$condition_id)->orderBy('sort')->orderBy('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($condition_id)
|
||||
{
|
||||
$condition = Condition::findOrFail($condition_id);
|
||||
return view('admin.dialplan.action.create',compact('condition'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(Request $request,$condition_id)
|
||||
{
|
||||
$condition = Condition::findOrFail($condition_id);
|
||||
$data = $request->all(['display_name','application','data','sort']);
|
||||
$data['condition_id'] = $condition->id;
|
||||
if (Action::create($data)){
|
||||
return redirect(route('admin.action',['condition_id'=>$condition->id]))->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($condition_id,$id)
|
||||
{
|
||||
$condition = Condition::findOrFail($condition_id);
|
||||
$model = Action::findOrFail($id);
|
||||
return view('admin.dialplan.action.edit',compact('condition','model'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(Request $request, $condition_id, $id)
|
||||
{
|
||||
$condition = Condition::findOrFail($condition_id);
|
||||
$model = Action::findOrFail($id);
|
||||
$data = $request->all(['display_name','application','data','sort']);
|
||||
if ($model->update($data)){
|
||||
return redirect(route('admin.action',['condition_id'=>$condition->id]))->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 (Action::destroy($ids)){
|
||||
return response()->json(['code'=>0,'msg'=>'删除成功']);
|
||||
}
|
||||
return response()->json(['code'=>1,'msg'=>'删除失败']);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
<?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()
|
||||
{
|
||||
return view('admin.agent.create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(AgentRequest $request)
|
||||
{
|
||||
$data = $request->all();
|
||||
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);
|
||||
return view('admin.agent.edit',compact('model'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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']);
|
||||
if ($model->update($data)){
|
||||
return redirect(route('admin.agent'))->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 (Agent::destroy($ids)){
|
||||
return response()->json(['code'=>0,'msg'=>'删除成功']);
|
||||
}
|
||||
return response()->json(['code'=>1,'msg'=>'删除失败']);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,183 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Models\Audio;
|
||||
use GuzzleHttp\Client;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class AudioController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return view('admin.audio.index');
|
||||
}
|
||||
|
||||
public function data(Request $request)
|
||||
{
|
||||
$res = Audio::orderBy('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()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$text = $request->get('text');
|
||||
if ($text==null){
|
||||
return response()->json(['code'=>1,'msg'=>'请输入待合成文本']);
|
||||
}
|
||||
$url = 'http://api.xfyun.cn/v1/service/v1/tts';
|
||||
$appid = config('freeswitch.xfyun.appid');
|
||||
$apikey = config('freeswitch.xfyun.apikey');
|
||||
$param = array (
|
||||
'auf' => 'audio/L16;rate=8000',
|
||||
'aue' => 'raw',
|
||||
'voice_name' => 'xiaoyan',
|
||||
'speed' => '50', //这三个参数必需是字符串
|
||||
'volume' => '50', //这三个参数必需是字符串
|
||||
'pitch' => '50', //这三个参数必需是字符串
|
||||
'engine_type' => 'intp65',
|
||||
);
|
||||
$time = (string)time();
|
||||
$xparam = base64_encode(json_encode(($param)));
|
||||
$checksum = md5($apikey.$time.$xparam);
|
||||
$header = array(
|
||||
'X-CurTime:'.$time,
|
||||
'X-Param:'.$xparam,
|
||||
'X-Appid:'.$appid,
|
||||
'X-CheckSum:'.$checksum,
|
||||
'X-Real-Ip:127.0.0.1',
|
||||
'Content-Type:application/x-www-form-urlencoded; charset=utf-8'
|
||||
);
|
||||
$content = [
|
||||
'text' => $text,
|
||||
];
|
||||
try{
|
||||
$response = $this->tocurl($url, $header, $content);
|
||||
$header = $response['header'];
|
||||
if($header['content_type'] == 'audio/mpeg'){
|
||||
$ext = $param['aue']=='raw'?'.wav':'.mp3';
|
||||
$filename = config('freeswitch.xfyun.sounds').$time.$ext;
|
||||
file_put_contents($filename, $response['body']);
|
||||
Audio::create(array_merge($param,[
|
||||
'url' => $filename,
|
||||
'text' => $text
|
||||
]));
|
||||
return response()->json(['code'=>0,'msg'=>'合成成功','data'=>['url'=>$filename]]);
|
||||
}
|
||||
return response()->json(['code'=>1,'msg'=>'合成失败','data'=>json_decode($response['body'],true)]);
|
||||
}catch (\Exception $exception){
|
||||
return response()->json(['code'=>1,'msg'=>'合成失败:'.$exception->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(Request $request)
|
||||
{
|
||||
$ids = $request->get('ids');
|
||||
$audio = Audio::where('id',$ids[0])->first();
|
||||
if ($ids == null){
|
||||
return response()->json(['code'=>1,'msg'=>'请选择删除项']);
|
||||
}
|
||||
try{
|
||||
if (file_exists($audio->url)){
|
||||
unlink($audio->url);
|
||||
}
|
||||
$audio->delete();
|
||||
return response()->json(['code'=>0,'msg'=>'删除成功']);
|
||||
}catch (\Exception $exception){
|
||||
return response()->json(['code'=>1,'msg'=>'删除失败:'.$exception->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
public function tocurl($url, $header, $content){
|
||||
$ch = curl_init();
|
||||
if(substr($url,0,5)=='https'){
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 跳过证书检查
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, true); // 从证书中检查SSL加密算法是否存在
|
||||
}
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($content));
|
||||
$response = curl_exec($ch);
|
||||
$error=curl_error($ch);
|
||||
//var_dump($error);
|
||||
if($error){
|
||||
die($error);
|
||||
}
|
||||
$header = curl_getinfo($ch);
|
||||
|
||||
curl_close($ch);
|
||||
$data = array('header' => $header,'body' => $response);
|
||||
return $data;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,142 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Requests\BillRequest;
|
||||
use App\Models\Bill;
|
||||
use App\Models\Merchant;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use DB;
|
||||
|
||||
class BillController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$merchants = Merchant::orderByDesc('id')->get();
|
||||
return view('admin.bill.index',compact('merchants'));
|
||||
}
|
||||
|
||||
public function data(Request $request)
|
||||
{
|
||||
$merchant_id = $request->post('merchant_id');
|
||||
$type = $request->post('type');
|
||||
$created_at_start = $request->post('created_at_start');
|
||||
$created_at_end = $request->post('created_at_end');
|
||||
$res = Bill::with('merchant')->orderBy('id','desc')
|
||||
->when($merchant_id,function ($query) use ($merchant_id){
|
||||
return $query->where('merchant_id',$merchant_id);
|
||||
})
|
||||
->when($type,function ($query) use ($type){
|
||||
return $query->where('type',$type);
|
||||
})
|
||||
->when($created_at_start&&!$created_at_end,function ($query) use ($created_at_start){
|
||||
return $query->where('created_at','>=',$created_at_start);
|
||||
})
|
||||
->when(!$created_at_start&&$created_at_end,function ($query) use ($created_at_end){
|
||||
return $query->where('created_at','<=',$created_at_end);
|
||||
})
|
||||
->when($created_at_start&&$created_at_end,function ($query) use ($created_at_start,$created_at_end){
|
||||
return $query->whereBetween('created_at',[$created_at_start,$created_at_end]);
|
||||
})
|
||||
->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()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(BillRequest $request)
|
||||
{
|
||||
$data = $request->all(['merchant_id','type','money','remark']);
|
||||
$merchant = Merchant::where('id',$data['merchant_id'])->first();
|
||||
if (!$merchant){
|
||||
return response()->json(['code'=>1, 'msg'=>'商户不存在']);
|
||||
}
|
||||
$data = array_prepend($data, $request->user()->id, 'created_user_id');
|
||||
|
||||
//金额转换
|
||||
$data['money'] = $data['type']==1?abs($data['money']):-1*abs($data['money']);
|
||||
//开启事务
|
||||
DB::beginTransaction();
|
||||
try{
|
||||
DB::table('bill')->insert(array_merge($data,['created_at'=>Carbon::now(),'updated_at'=>Carbon::now()]));
|
||||
DB::table('merchant')->where('id',$data['merchant_id'])->increment('money',$data['money']);
|
||||
DB::commit();
|
||||
return response()->json(['code'=>0,'msg'=>'操作成功']);
|
||||
}catch (\Exception $exception){
|
||||
DB::rollback();
|
||||
return response()->json(['code'=>1,'msg'=>'操作失败:'.$exception->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy($id)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,154 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Models\Asr;
|
||||
use App\Models\Cdr;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class CdrController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return view('admin.cdr.index');
|
||||
}
|
||||
|
||||
public function data(Request $request)
|
||||
{
|
||||
$query = Cdr::query();
|
||||
$search = $request->all(['caller_id_number','destination_number','start_stamp_start','start_stamp_end']);
|
||||
if ($search['caller_id_number']){
|
||||
$query = $query->where('caller_id_number',$search['caller_id_number']);
|
||||
}
|
||||
if ($search['destination_number']){
|
||||
$query = $query->where('destination_number',$search['destination_number']);
|
||||
}
|
||||
if ($search['start_stamp_start'] && !$search['start_stamp_end']){
|
||||
$query = $query->where('start_stamp','>=',$search['start_stamp_start']);
|
||||
}else if (!$search['start_stamp_start'] && $search['start_stamp_end']){
|
||||
$query = $query->where('start_stamp','<=',$search['start_stamp_end']);
|
||||
}else if ($search['start_stamp_start'] && $search['start_stamp_end']){
|
||||
$query = $query->whereBetween('start_stamp',[$search['start_stamp_start'],$search['start_stamp_end']]);
|
||||
}
|
||||
$res = $query->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()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function show($id)
|
||||
{
|
||||
$cdr = Cdr::find($id);
|
||||
$record = [];
|
||||
if ($cdr!=null){
|
||||
$record = Asr::whereIn('uuid',[$cdr->aleg_uuid,$cdr->bleg_uuid])->orderByDesc('id')->get();
|
||||
}
|
||||
return view('admin.cdr.asr',compact('record'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy($id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放录音
|
||||
* @param $uuid
|
||||
* @return array
|
||||
*/
|
||||
public function play($uuid)
|
||||
{
|
||||
$cdr = Cdr::where(['aleg_uuid'=>$uuid])->first();
|
||||
if ($cdr==null){
|
||||
return ['code'=>'1','msg'=>'通话记录不存在'];
|
||||
}
|
||||
if (empty($cdr->sofia_record_file)){
|
||||
return ['code'=>'1','msg'=>'未找到录音文件'];
|
||||
}
|
||||
return ['code'=>0,'msg'=>'请求成功','data'=>$cdr->sofia_record_file];
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载录音
|
||||
* @param $uuid
|
||||
* @return \Illuminate\Http\RedirectResponse|\Symfony\Component\HttpFoundation\BinaryFileResponse
|
||||
*/
|
||||
public function download($uuid)
|
||||
{
|
||||
$cdr = Cdr::where(['aleg_uuid'=>$uuid])->first();
|
||||
if ($cdr==null){
|
||||
return back()->withErrors(['error'=>'通话记录不存在']);
|
||||
}
|
||||
if (!file_exists($cdr->sofia_record_file)){
|
||||
return back()->withErrors(['error'=>'未找到录音文件']);
|
||||
}
|
||||
return response()->download($cdr->sofia_record_file,$uuid.".wav");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Requests\ConditionRequest;
|
||||
use App\Models\Condition;
|
||||
use App\Models\Extension;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class ConditionController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index($extension_id)
|
||||
{
|
||||
$extension = Extension::findOrFail($extension_id);
|
||||
return view('admin.dialplan.condition.index',compact('extension'));
|
||||
}
|
||||
|
||||
public function data(Request $request,$extension_id)
|
||||
{
|
||||
$res = Condition::where('extension_id',$extension_id)->orderBy('sort')->orderBy('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($extension_id)
|
||||
{
|
||||
$extension = Extension::findOrFail($extension_id);
|
||||
return view('admin.dialplan.condition.create',compact('extension'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(ConditionRequest $request,$extension_id)
|
||||
{
|
||||
$extension = Extension::findOrFail($extension_id);
|
||||
$data = $request->all(['display_name','field','expression','break','sort']);
|
||||
$data['extension_id'] = $extension->id;
|
||||
if (Condition::create($data)){
|
||||
return redirect(route('admin.condition',['extension_id'=>$extension->id]))->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($extension_id,$id)
|
||||
{
|
||||
$extension = Extension::findOrFail($extension_id);
|
||||
$model = Condition::findOrFail($id);
|
||||
return view('admin.dialplan.condition.edit',compact('extension','model'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(Request $request, $extension_id, $id)
|
||||
{
|
||||
$extension = Extension::findOrFail($extension_id);
|
||||
$model = Condition::findOrFail($id);
|
||||
$data = $request->all(['display_name','field','expression','break','sort']);
|
||||
if ($model->update($data)){
|
||||
return redirect(route('admin.condition',['extension_id'=>$extension->id]))->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 (Condition::destroy($ids)){
|
||||
return response()->json(['code'=>0,'msg'=>'删除成功']);
|
||||
}
|
||||
return response()->json(['code'=>1,'msg'=>'删除失败']);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Models\Digits;
|
||||
use function foo\func;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class DigitsController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$ivr_id = $request->get('ivr_id');
|
||||
return view('admin.digits.index',compact('ivr_id'));
|
||||
}
|
||||
|
||||
public function data(Request $request)
|
||||
{
|
||||
$ivr_id = $request->get('ivr_id');
|
||||
$res = Digits::when($ivr_id,function ($query) use ($ivr_id){
|
||||
$query->where('ivr_id',$ivr_id);
|
||||
})->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()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$data = $request->get('parm');
|
||||
try{
|
||||
foreach ($data as $d){
|
||||
Digits::create($d);
|
||||
}
|
||||
return response()->json(['code'=>0,'msg'=>'添加成功']);
|
||||
}catch (\Exception $exception){
|
||||
return response()->json(['code'=>1,'msg'=>'添加失败']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy($id)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Requests\ExtensionRequest;
|
||||
use App\Models\Extension;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class ExtensionController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return view('admin.dialplan.extension.index');
|
||||
}
|
||||
|
||||
public function data(Request $request)
|
||||
{
|
||||
$query = Extension::query();
|
||||
$res = $query->orderBy('sort')->orderBy('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()
|
||||
{
|
||||
return view('admin.dialplan.extension.create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(ExtensionRequest $request)
|
||||
{
|
||||
$data = $request->all(['display_name','name','sort','continue','context']);
|
||||
if (Extension::create($data)){
|
||||
return redirect(route('admin.extension'))->with(['success'=>'添加成功']);
|
||||
}
|
||||
return back()->withErrors(['error'=>'添加失败']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function show($id)
|
||||
{
|
||||
$extension = Extension::with('conditions')->findOrFail($id);
|
||||
|
||||
return view('admin.dialplan.extension.show',compact('extension'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
$model = Extension::findOrFail($id);
|
||||
return view('admin.dialplan.extension.edit',compact('model'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(ExtensionRequest $request, $id)
|
||||
{
|
||||
$model = Extension::findOrFail($id);
|
||||
$data = $request->all(['display_name','name','sort','continue','context']);
|
||||
if ($model->update($data)){
|
||||
return redirect(route('admin.extension'))->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 (Extension::destroy($ids)){
|
||||
return response()->json(['code'=>0,'msg'=>'删除成功']);
|
||||
}
|
||||
return response()->json(['code'=>1,'msg'=>'删除失败']);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,151 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Requests\GatewayRequest;
|
||||
use App\Models\Gateway;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class GatewayController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return view('admin.gateway.index');
|
||||
}
|
||||
|
||||
public function data(Request $request)
|
||||
{
|
||||
$res = Gateway::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()
|
||||
{
|
||||
return view('admin.gateway.create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(GatewayRequest $request)
|
||||
{
|
||||
$data = $request->except(['_method','_token']);
|
||||
if (Gateway::create($data)){
|
||||
return redirect(route('admin.gateway'))->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 = Gateway::findOrFail($id);
|
||||
return view('admin.gateway.edit',compact('model'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(GatewayRequest $request, $id)
|
||||
{
|
||||
$model = Gateway::findOrFail($id);
|
||||
$data = $request->except(['_method','_token']);
|
||||
if ($model->update($data)){
|
||||
return redirect(route('admin.gateway'))->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 (Gateway::destroy($ids)){
|
||||
return response()->json(['code'=>0,'msg'=>'删除成功']);
|
||||
}
|
||||
return response()->json(['code'=>1,'msg'=>'删除失败']);
|
||||
}
|
||||
|
||||
public function updateXml()
|
||||
{
|
||||
set_time_limit(0);
|
||||
$gateway = Gateway::get();
|
||||
if ($gateway->isEmpty()){
|
||||
return response()->json(['code'=>1,'msg'=>'无数据需要更新']);
|
||||
}
|
||||
try{
|
||||
foreach ($gateway as $gw){
|
||||
$xml = "<include>\n";
|
||||
$xml .= " <gateway name=\"gw".$gw->id."\">\n";
|
||||
$xml .= " <param name=\"username\" value=\"".$gw->username."\"/>\n";
|
||||
$xml .= " <param name=\"realm\" value=\"".$gw->realm."\"/>\n";
|
||||
$xml .= " <param name=\"password\" value=\"".$gw->password."\"/>\n";
|
||||
$xml .= " </gateway>\n";
|
||||
$xml .= "</include>";
|
||||
file_put_contents(config('freeswitch.gateway_dir')."gw".$gw->id.".xml",$xml);
|
||||
}
|
||||
//生产环境,并且debug关闭的情况下自动更新网关注册信息
|
||||
if (config('app.env')=='production' && config('app.debug')==false){
|
||||
$freeswitch = new \Freeswitchesl();
|
||||
if (!$freeswitch->connect(config('freeswitch.event_socket.host'), config('freeswitch.event_socket.port'), config('freeswitch.event_socket.password'))){
|
||||
return response()->json(['code'=>1,'msg'=>'ESL未连接']);
|
||||
}
|
||||
$freeswitch->bgapi("sofia profile external rescan");
|
||||
$freeswitch->disconnect();
|
||||
return response()->json(['code'=>0,'msg'=>'更新成功']);
|
||||
}
|
||||
return response()->json(['code'=>1,'msg'=>'请在生产环境下更新配置']);
|
||||
}catch (\Exception $exception){
|
||||
return response()->json(['code'=>1,'msg'=>'更新失败','data'=>$exception->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,182 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Requests\IvrRequest;
|
||||
use App\Models\Digits;
|
||||
use App\Models\Ivr;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class IvrController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return view('admin.ivr.index');
|
||||
}
|
||||
|
||||
public function data(Request $request)
|
||||
{
|
||||
$res = Ivr::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()
|
||||
{
|
||||
return view('admin.ivr.create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(IvrRequest $request)
|
||||
{
|
||||
$data = $request->all();
|
||||
try{
|
||||
Ivr::create($data);
|
||||
return redirect()->to(route('admin.ivr'))->with(['success'=>'添加成功']);
|
||||
}catch (\Exception $exception){
|
||||
return back()->withInput()->withErrors('添加失败:'.$exception->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 = Ivr::findOrFail($id);
|
||||
return view('admin.ivr.edit',compact('model'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(IvrRequest $request, $id)
|
||||
{
|
||||
$model = Ivr::findOrFail($id);
|
||||
$data = $request->all();
|
||||
try{
|
||||
$model->update($data);
|
||||
return redirect()->to(route('admin.ivr'))->with(['success'=>'更新成功']);
|
||||
}catch (\Exception $exception){
|
||||
return back()->withInput()->withErrors('更新失败:'.$exception->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(Request $request)
|
||||
{
|
||||
$ids = $request->get('ids');
|
||||
$ivr = Ivr::whereIn('id',$ids)->first();
|
||||
if ($ivr==null){
|
||||
return response()->json(['code'=>1,'msg'=>'记录不存在']);
|
||||
}
|
||||
$digits = Digits::where('ivr_id',$ivr->id)->orWhere(function ($query) use ($ivr) {
|
||||
$query->where('action','menu-sub')->where('param',$ivr->name);
|
||||
})->count();
|
||||
if ($digits){
|
||||
return response()->json(['code'=>1,'msg'=>'IVR被使用,禁止删除']);
|
||||
}
|
||||
try{
|
||||
$ivr->delete();
|
||||
return response()->json(['code'=>0,'msg'=>'删除成功']);
|
||||
}catch (\Exception $exception){
|
||||
return response()->json(['code'=>1,'msg'=>'删除失败:'.$exception->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
public function updateXml()
|
||||
{
|
||||
set_time_limit(0);
|
||||
$datas = Ivr::with('digits')->get();
|
||||
if ($datas->isEmpty()){
|
||||
return response()->json(['code'=>1,'msg'=>'无数据需要更新']);
|
||||
}
|
||||
try{
|
||||
foreach ($datas as $data){
|
||||
$xml ="<include>\n";
|
||||
$xml .="<menu name=\"".$data->name."\"\n";
|
||||
$xml .="greet-long=\"".$data->greet_long."\"\n";
|
||||
$xml .="greet-short=\"".$data->greet_short."\"\n";
|
||||
$xml .="invalid-sound=\"".$data->invalid_sound."\"\n";
|
||||
$xml .="exit-sound=\"".$data->exit_sound."\"\n";
|
||||
$xml .="confirm-macro=\"".$data->confirm_macro."\"\n";
|
||||
$xml .="confirm-key=\"".$data->confirm_key."\"\n";
|
||||
$xml .="tts-engine=\"".$data->tts_engine."\"\n";
|
||||
$xml .="tts-voice=\"".$data->tts_voice."\"\n";
|
||||
$xml .="confirm-attempts=\"".$data->confirm_attempts."\"\n";
|
||||
$xml .="timeout=\"".$data->timeout."\"\n";
|
||||
$xml .="inter-digit-timeout=\"".$data->inter_digit_timeout."\"\n";
|
||||
$xml .="max-failures=\"".$data->max_failures."\"\n";
|
||||
$xml .="max-timeouts=\"".$data->max_timeout."\"\n";
|
||||
$xml .="digit-len=\"".$data->digit_len."\">\n";
|
||||
|
||||
if ($data->digits->isNotEmpty()){
|
||||
foreach ($data->digits as $digit){
|
||||
$xml .="<entry action=\"".$digit->action."\" digits=\"".$digit->digit."\" param=\"".$digit->param."\"/>\n";
|
||||
}
|
||||
}
|
||||
|
||||
$xml .="</menu>\n";
|
||||
$xml .="</include>\n";
|
||||
file_put_contents(config('freeswitch.ivr_dir').$data->name.".xml",$xml);
|
||||
}
|
||||
//生产环境,并且debug关闭的情况下自动更新网关注册信息
|
||||
if (config('app.env')=='production' && config('app.debug')==false){
|
||||
$freeswitch = new \Freeswitchesl();
|
||||
if (!$freeswitch->connect(config('freeswitch.event_socket.host'), config('freeswitch.event_socket.port'), config('freeswitch.event_socket.password'))){
|
||||
return response()->json(['code'=>1,'msg'=>'ESL未连接']);
|
||||
}
|
||||
$freeswitch->bgapi("reloadxml");
|
||||
$freeswitch->disconnect();
|
||||
return response()->json(['code'=>0,'msg'=>'更新成功']);
|
||||
}
|
||||
return response()->json(['code'=>1,'msg'=>'请在生产环境下更新配置']);
|
||||
}catch (\Exception $exception){
|
||||
return response()->json(['code'=>1,'msg'=>'更新失败','data'=>$exception->getMessage()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,203 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Requests\MerchantCreateRequest;
|
||||
use App\Http\Requests\MerchantRequest;
|
||||
use App\Http\Requests\MerchantUpdateRequest;
|
||||
use App\Models\Gateway;
|
||||
use App\Models\Merchant;
|
||||
use Faker\Provider\Uuid;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class MerchantController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return view('admin.merchant.index');
|
||||
}
|
||||
|
||||
public function data(Request $request)
|
||||
{
|
||||
$data = $request->all(['username','company_name','status','expires_at_start','expires_at_end']);
|
||||
$res = Merchant::withCount('sips')->orderBy('id','desc')
|
||||
->when($data['username'],function ($query) use ($data){
|
||||
return $query->where('username','like','%'.$data['username'].'%');
|
||||
})
|
||||
->when($data['company_name'],function ($query) use ($data){
|
||||
return $query->where('company_name','like','%'.$data['company_name'].'%');
|
||||
})
|
||||
->when($data['status'],function ($query) use ($data){
|
||||
return $query->where('status',$data['status']);
|
||||
})
|
||||
->when($data['expires_at_start']&&!$data['expires_at_end'],function ($query) use ($data){
|
||||
return $query->where('expires_at','>=',$data['expires_at_start']);
|
||||
})
|
||||
->when(!$data['expires_at_start']&&$data['expires_at_end'],function ($query) use ($data){
|
||||
return $query->where('expires_at','<=',$data['expires_at_end']);
|
||||
})
|
||||
->when($data['expires_at_start']&&$data['expires_at_end'],function ($query) use ($data){
|
||||
return $query->whereBetween('expires_at',[$data['expires_at_start'],$data['expires_at_end']]);
|
||||
})
|
||||
->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()
|
||||
{
|
||||
return view('admin.merchant.create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(MerchantCreateRequest $request)
|
||||
{
|
||||
$data = $request->all();
|
||||
$data = array_prepend($data, Uuid::uuid(), 'uuid');
|
||||
$data = array_prepend($data, $request->user()->id, 'created_user_id');
|
||||
$data['password'] = bcrypt($data['password']);
|
||||
try{
|
||||
Merchant::create($data);
|
||||
return redirect()->to(route('admin.merchant'))->with(['success'=>'添加成功']);
|
||||
}catch (\Exception $e){
|
||||
return back()->withInput()->withErrors($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 = Merchant::findOrFail($id);
|
||||
return view('admin.merchant.edit',compact('model'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(MerchantUpdateRequest $request, $id)
|
||||
{
|
||||
$model = Merchant::findOrFail($id);
|
||||
$data = $request->all();
|
||||
if (isset($data['password'])&&!empty($data['password'])){
|
||||
$data['password'] = bcrypt($data['password']);
|
||||
}else{
|
||||
array_pull($data,'password');
|
||||
}
|
||||
try{
|
||||
$model->update($data);
|
||||
return redirect()->to(route('admin.merchant'))->with(['success'=>'更新成功']);
|
||||
}catch (\Exception $e){
|
||||
return back()->withErrors($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(Request $request)
|
||||
{
|
||||
$ids = $request->get('ids');
|
||||
//验证参数
|
||||
if (!is_array($ids)||empty($ids)){
|
||||
return response()->json(['code'=>1, 'msg'=>'请选择删除项']);
|
||||
}
|
||||
//删除
|
||||
try{
|
||||
Merchant::whereIn('id',$ids)->delete();
|
||||
return response()->json(['code'=>0, 'msg'=>'删除成功']);
|
||||
}catch (\Exception $exception){
|
||||
return response()->json(['code'=>1, 'msg'=>$exception->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 帐单
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function bill(Request $request)
|
||||
{
|
||||
$merchant_id = $request->get('merchant_id');
|
||||
$merchant = Merchant::findOrFail($merchant_id);
|
||||
return view('admin.merchant.bill',compact('merchant'));
|
||||
}
|
||||
|
||||
public function gateway($id)
|
||||
{
|
||||
$merchant = Merchant::with('gateways')->findOrFail($id);
|
||||
$gateways = Gateway::get();
|
||||
foreach ($gateways as $gateway){
|
||||
if ($merchant->gateways->isNotEmpty()){
|
||||
foreach ($merchant->gateways as $g1){
|
||||
if ($g1->id == $gateway->id){
|
||||
$gateway->rate = $g1->pivot->rate;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return view('admin.merchant.gateway',compact('merchant','gateways'));
|
||||
}
|
||||
|
||||
public function assignGateway(Request $request, $id)
|
||||
{
|
||||
$merchant = Merchant::with('gateways')->findOrFail($id);
|
||||
$gateway_ids = $request->get('gateways',[]);
|
||||
try{
|
||||
$sync_data = [];
|
||||
foreach ($gateway_ids as $v){
|
||||
if (isset($v['id']) && is_numeric($v['rate'])){
|
||||
$sync_data[$v['id']] = ['rate'=>$v['rate']];
|
||||
}
|
||||
}
|
||||
$merchant->gateways()->sync($sync_data);
|
||||
return redirect()->to(route('admin.merchant'))->with(['success'=>'更新成功']);
|
||||
}catch (\Exception $exception){
|
||||
return back()->withErrors('更新失败');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,211 @@
|
|||
<?php
|
||||
|
||||
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;
|
||||
use DB;
|
||||
|
||||
class QueueController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return view('admin.queue.index');
|
||||
}
|
||||
|
||||
public function data(Request $request)
|
||||
{
|
||||
$res = Queue::withCount(['agents'])->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()
|
||||
{
|
||||
return view('admin.queue.create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(QueueRequest $request)
|
||||
{
|
||||
$data = $request->all();
|
||||
if (Queue::create($data)){
|
||||
return redirect(route('admin.queue'))->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 = Queue::findOrFail($id);
|
||||
return view('admin.queue.edit',compact('model'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(QueueRequest $request, $id)
|
||||
{
|
||||
$model = Queue::findOrFail($id);
|
||||
$data = $request->except(['_method','_token']);
|
||||
if ($model->update($data)){
|
||||
return redirect(route('admin.queue'))->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 (Queue::destroy($ids)){
|
||||
return response()->json(['code'=>0,'msg'=>'删除成功,请更新配置']);
|
||||
}
|
||||
return response()->json(['code'=>1,'msg'=>'删除失败']);
|
||||
|
||||
}
|
||||
|
||||
public function updateXml()
|
||||
{
|
||||
$queues = Queue::with('agents')->whereHas('agents')->get();
|
||||
if ($queues->isEmpty()){
|
||||
return response()->json(['code'=>1,'msg'=>'无数据需要更新']);
|
||||
}
|
||||
try{
|
||||
//生产环境,并且debug关闭的情况下自动更新网关注册信息
|
||||
if (config('app.env')=='production' && config('app.debug')==false){
|
||||
$freeswitch = new \Freeswitchesl();
|
||||
if (!$freeswitch->connect(config('freeswitch.event_socket.host'), config('freeswitch.event_socket.port'), config('freeswitch.event_socket.password'))){
|
||||
return response()->json(['code'=>1,'msg'=>'ESL未连接']);
|
||||
}
|
||||
$queues = Queue::with("agents")->get();
|
||||
$agents = Agent::get();
|
||||
|
||||
$xml = "<configuration name=\"callcenter.conf\" description=\"CallCenter\">\n";
|
||||
$xml .= " <settings>\n";
|
||||
$xml .= " <!--<param name=\"odbc-dsn\" value=\"dsn:user:pass\"/>-->\n";
|
||||
$xml .= " <!--<param name=\"dbname\" value=\"/dev/shm/callcenter.db\"/>-->\n";
|
||||
$xml .= " <!--<param name=\"cc-instance-id\" value=\"single_box\"/>-->\n";
|
||||
$xml .= " <param name=\"truncate-tiers-on-load\" value=\"true\"/>\n";
|
||||
$xml .= " <param name=\"truncate-agents-on-load\" value=\"true\"/>\n";
|
||||
$xml .= " </settings>\n";
|
||||
//---------------------------------- 写入队列信息 ------------------------------------
|
||||
$xml .= "<queues>\n";
|
||||
foreach ($queues as $queue){
|
||||
$xml .= " <queue name=\"".$queue->name."\">\n";
|
||||
$xml .= " <param name=\"strategy\" value=\"".$queue->strategy."\"/>\n";
|
||||
$xml .= " <param name=\"moh-sound\" value=\"".$queue->moh_sound."\"/>\n";
|
||||
$xml .= " <param name=\"record-template\" value=\"\$\${recordings_dir}/\${strftime(%Y)}/\${strftime(%m)}/\${strftime(%d)}/.\${destination_number}.\${caller_id_number}.\${uuid}.wav\"/>\n";
|
||||
$xml .= " <param name=\"time-base-score\" value=\"".$queue->time_base_score."\"/>\n";
|
||||
$xml .= " <param name=\"max-wait-time\" value=\"".$queue->max_wait_time."\"/>\n";
|
||||
$xml .= " <param name=\"max-wait-time-with-no-agent\" value=\"".$queue->max_wait_time_with_no_agent."\"/>\n";
|
||||
$xml .= " <param name=\"max-wait-time-with-no-agent-time-reached\" value=\"".$queue->max_wait_time_with_no_agent_time_reached."\"/>\n";
|
||||
$xml .= " <param name=\"tier-rules-apply\" value=\"".$queue->tier_rules_apply."\"/>\n";
|
||||
$xml .= " <param name=\"tier-rule-wait-second\" value=\"".$queue->tier_rule_wait_second."\"/>\n";
|
||||
$xml .= " <param name=\"tier-rule-wait-multiply-level\" value=\"".$queue->tier_rule_wait_multiply_level."\"/>\n";
|
||||
$xml .= " <param name=\"tier-rule-no-agent-no-wait\" value=\"".$queue->tier_rule_no_agent_no_wait."\"/>\n";
|
||||
$xml .= " <param name=\"discard-abandoned-after\" value=\"".$queue->discard_abandoned_after."\"/>\n";
|
||||
$xml .= " <param name=\"abandoned-resume-allowed\" value=\"".$queue->abandoned_resume_allowed."\"/>\n";
|
||||
$xml .= " </queue>\n";
|
||||
}
|
||||
$xml .= "</queues>\n";
|
||||
|
||||
//---------------------------------- 写入坐席信息 ------------------------------------
|
||||
$xml .= "<agents>\n";
|
||||
foreach ($agents as $agent){
|
||||
$xml .= "<agent name=\"".$agent->name."\" type=\"".$agent->type."\" contact=\"[leg_timeout=10]".$agent->originate_type."/".$agent->originate_number."\" status=\"".$agent->status."\" max-no-answer=\"".$agent->max_no_answer."\" wrap-up-time=\"".$agent->wrap_up_time."\" reject-delay-time=\"".$agent->reject_delay_time."\" busy-delay-time=\"".$agent->busy_delay_time."\" no-answer-delay-time=\"".$agent->no_answer_delay_time."\" />\n";
|
||||
}
|
||||
$xml .= "</agents>\n";
|
||||
|
||||
//---------------------------------- 写入队列-坐席信息 ------------------------------------
|
||||
$xml .= "<tiers>\n";
|
||||
foreach ($queues as $queue){
|
||||
foreach ($queue->agents as $agent){
|
||||
$xml .= "<tier agent=\"".$agent->name."\" queue=\"".$queue->name."\" level=\"1\" position=\"1\"/>\n";
|
||||
}
|
||||
}
|
||||
$xml .= "</tiers>\n";
|
||||
$xml .= "</configuration>\n";
|
||||
//生成配置文件
|
||||
file_put_contents(config('freeswitch.callcenter_dir'),$xml);
|
||||
$freeswitch->bgapi("reload mod_callcenter");
|
||||
$freeswitch->disconnect();
|
||||
return response()->json(['code'=>0,'msg'=>'更新成功']);
|
||||
}
|
||||
return response()->json(['code'=>1,'msg'=>'请在生产环境下更新配置']);
|
||||
}catch (\Exception $exception){
|
||||
return response()->json(['code'=>1,'msg'=>'更新失败','data'=>$exception->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
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(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,223 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Requests\SipListRequest;
|
||||
use App\Http\Requests\SipRequest;
|
||||
use App\Models\Merchant;
|
||||
use App\Models\Sip;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Validation\Validator;
|
||||
|
||||
class SipController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return view('admin.sip.index');
|
||||
}
|
||||
|
||||
public function data(Request $request)
|
||||
{
|
||||
$query = Sip::query();
|
||||
$username = $request->get('username');
|
||||
if ($username){
|
||||
$query = $query->where('username',$username);
|
||||
}
|
||||
$res = $query->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()
|
||||
{
|
||||
$merchants = Merchant::orderByDesc('id')->where('status',1)->get();
|
||||
|
||||
return view('admin.sip.create',compact('merchants'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(SipRequest $request)
|
||||
{
|
||||
$data = $request->all([
|
||||
'merchant_gateway',
|
||||
'gateway_id',
|
||||
'expense_id',
|
||||
'merchant_id',
|
||||
'username',
|
||||
'password',
|
||||
'effective_caller_id_name',
|
||||
'effective_caller_id_number',
|
||||
'outbound_caller_id_name',
|
||||
'outbound_caller_id_number',
|
||||
]);
|
||||
$mg = explode(',',$data['merchant_gateway']);
|
||||
$data['merchant_id'] = $mg[0];
|
||||
$data['gateway_id'] = $mg[1];
|
||||
if ($data['effective_caller_id_name']==null){
|
||||
$data['effective_caller_id_name'] = $data['username'];
|
||||
}
|
||||
if ($data['effective_caller_id_number']==null){
|
||||
$data['effective_caller_id_number'] = $data['username'];
|
||||
}
|
||||
//验证商户允许的最大分机数
|
||||
$merchant = Merchant::withCount('sips')->findOrFail($data['merchant_id']);
|
||||
if ($merchant->sips_count >= $merchant->sip_num){
|
||||
return back()->withInput()->withErrors(['error'=>'添加失败:超出商户最大允许分机数量']);
|
||||
}
|
||||
try{
|
||||
Sip::create($data);
|
||||
return redirect(route('admin.sip'))->with(['success'=>'添加成功']);
|
||||
}catch (\Exception $exception){
|
||||
return back()->withInput()->withErrors(['error'=>'添加失败:'.$exception->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 = Sip::findOrFail($id);
|
||||
$merchants = Merchant::orderByDesc('id')->where('status',1)->get();
|
||||
return view('admin.sip.edit',compact('model','merchants'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update(SipRequest $request, $id)
|
||||
{
|
||||
$model = Sip::findOrFail($id);
|
||||
$data = $request->all([
|
||||
'merchant_gateway',
|
||||
'gateway_id',
|
||||
'expense_id',
|
||||
'merchant_id',
|
||||
'username',
|
||||
'password',
|
||||
'effective_caller_id_name',
|
||||
'effective_caller_id_number',
|
||||
'outbound_caller_id_name',
|
||||
'outbound_caller_id_number',
|
||||
]);
|
||||
$mg = explode(',',$data['merchant_gateway']);
|
||||
$data['merchant_id'] = $mg[0];
|
||||
$data['gateway_id'] = $mg[1];
|
||||
if ($data['effective_caller_id_name']==null){
|
||||
$data['effective_caller_id_name'] = $data['username'];
|
||||
}
|
||||
if ($data['effective_caller_id_number']==null){
|
||||
$data['effective_caller_id_number'] = $data['username'];
|
||||
}
|
||||
try{
|
||||
$model->update($data);
|
||||
return redirect(route('admin.sip'))->with(['success'=>'更新成功']);
|
||||
}catch (\Exception $exception){
|
||||
return back()->withErrors(['error'=>'更新失败:'.$exception->getMessage()]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 (Sip::destroy($ids)){
|
||||
return response()->json(['code'=>0,'msg'=>'删除成功']);
|
||||
}
|
||||
return response()->json(['code'=>1,'msg'=>'删除失败']);
|
||||
}
|
||||
|
||||
public function createList()
|
||||
{
|
||||
$merchants = Merchant::orderByDesc('id')->where('status',1)->get();
|
||||
return view('admin.sip.create_list',compact('merchants'));
|
||||
}
|
||||
|
||||
public function storeList(SipListRequest $request)
|
||||
{
|
||||
$data = $request->all(['sip_start','sip_end','password','merchant_gateway']);
|
||||
$mg = explode(',',$data['merchant_gateway']);
|
||||
$data['merchant_id'] = $mg[0];
|
||||
$data['gateway_id'] = $mg[1];
|
||||
if ($data['sip_start'] <= $data['sip_end']){
|
||||
//验证商户允许的最大分机数
|
||||
$merchant = Merchant::withCount('sips')->findOrFail($data['merchant_id']);
|
||||
if (($merchant->sips_count+($data['sip_end']-$data['sip_start']+1)) >= $merchant->sip_num){
|
||||
return back()->withInput()->withErrors(['error'=>'添加失败:超出商户最大允许分机数量']);
|
||||
}
|
||||
//开启事务
|
||||
DB::beginTransaction();
|
||||
try{
|
||||
for ($i=$data['sip_start'];$i<=$data['sip_end'];$i++){
|
||||
DB::table('sip')->insert([
|
||||
'merchant_id' => $data['merchant_id'],
|
||||
'gateway_id' => $data['gateway_id'],
|
||||
'username' => $i,
|
||||
'password' => $data['password'],
|
||||
'effective_caller_id_name' => $i,
|
||||
'effective_caller_id_number' => $i,
|
||||
'created_at' => Carbon::now(),
|
||||
'updated_at' => Carbon::now(),
|
||||
]);
|
||||
}
|
||||
DB::commit();
|
||||
return redirect(route('admin.sip'))->with(['success'=>'添加成功']);
|
||||
}catch (\Exception $e) {
|
||||
DB::rollback();
|
||||
return back()->withInput()->withErrors(['error'=>'添加失败:'.$e->getMessage()]);
|
||||
}
|
||||
}
|
||||
return back()->withInput()->withErrors(['error'=>'开始分机号必须小于等于结束分机号']);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,241 @@
|
|||
<?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 Log;
|
||||
|
||||
|
||||
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('queue_agent')->where('queue_id',$task->queue_id)->pluck('agent_id');
|
||||
$agents = Agent::whereIn('id',$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()]);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -51,4 +51,371 @@ class ApiController extends Controller
|
|||
}
|
||||
return response()->json($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分机动态注册
|
||||
* @param Request $request
|
||||
* @return bool
|
||||
*/
|
||||
public function directory(Request $request)
|
||||
{
|
||||
$sips = Sip::get();
|
||||
$groups = Group::with('sips')->whereHas('sips')->get();
|
||||
|
||||
$xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n";
|
||||
$xml .= "<document type=\"freeswitch/xml\">\n";
|
||||
$xml .= "<section name=\"directory\" >\n";
|
||||
$xml .= "<domain name=\"\$\${domain}\">\n";
|
||||
$xml .= "<params>\n";
|
||||
$xml .= "<param name=\"dial-string\" value=\"{presence_id=\${dialed_user}@\${dialed_domain}}\${sofia_contact(\${dialed_user}@\${dialed_domain})}\"/>\n";
|
||||
$xml .= "</params>\n";
|
||||
$xml .= "<groups>\n";
|
||||
|
||||
//默认用户组default
|
||||
$xml .= "<group name=\"default\">\n";
|
||||
$xml .= " <users>\n";
|
||||
foreach ($sips as $sip){
|
||||
$outbound_caller_id_number = $sip->outbound_caller_id_number??"\$\${outbound_caller_id}";
|
||||
$xml .= " <user id=\"".$sip->username."\">\n";
|
||||
$xml .= " <params>";
|
||||
$xml .= " <param name=\"password\" value=\"".$sip->password."\"/>\n";
|
||||
$xml .= " <param name=\"vm-password\" value=\"".$sip->password."\"/>\n";
|
||||
$xml .= " </params>\n";
|
||||
$xml .= " <variables>\n";
|
||||
$xml .= " <variable name=\"toll_allow\" value=\"domestic,international,local\"/>\n";
|
||||
$xml .= " <variable name=\"accountcode\" value=\"".$sip->username."\"/>\n";
|
||||
$xml .= " <variable name=\"user_context\" value=\"".$sip->context."\"/>\n";
|
||||
$xml .= " <variable name=\"effective_caller_id_name\" value=\"".$sip->effective_caller_id_name."\"/>\n";
|
||||
$xml .= " <variable name=\"effective_caller_id_number\" value=\"".$sip->effective_caller_id_number."\"/>\n";
|
||||
$xml .= " <variable name=\"outbound_caller_id_name\" value=\"\$\${outbound_caller_name}\"/>\n";
|
||||
$xml .= " <variable name=\"outbound_caller_id_number\" value=\"".$outbound_caller_id_number."\"/>\n";
|
||||
$xml .= " </variables>\n";
|
||||
$xml .= " </user>";
|
||||
}
|
||||
$xml .= " </users>\n";
|
||||
$xml .= "</group>\n";
|
||||
|
||||
//自定义用户组
|
||||
foreach ($groups as $group){
|
||||
$xml .= "<group name=\"".$group->name."\">\n";
|
||||
$xml .= " <users>\n";
|
||||
foreach ($group->sips as $sip){
|
||||
$xml .= " <user id=\"".$sip->username."\" type=\"pointer\"/>";
|
||||
}
|
||||
$xml .= " </users>\n";
|
||||
$xml .= "</group>\n";
|
||||
}
|
||||
|
||||
$xml .= "</groups>\n";
|
||||
$xml .= "</domain>\n";
|
||||
$xml .= "</section>\n";
|
||||
$xml .= "</document>\n";
|
||||
return response($xml,200)->header("Content-type","text/xml");
|
||||
}
|
||||
|
||||
/**
|
||||
* 动态拨号计划
|
||||
* @param Request $request
|
||||
* @return mixed
|
||||
*/
|
||||
public function dialplan(Request $request)
|
||||
{
|
||||
if ($request->get('section')=='dialplan'){
|
||||
$context = $request->get('Caller-Context','default');
|
||||
|
||||
$xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n";
|
||||
$xml .= "<document type=\"freeswitch/xml\">\n";
|
||||
$xml .= "<section name=\"dialplan\" description=\"RE Dial Plan For FreeSwitch\">\n";
|
||||
$xml .= "<context name=\"".$context."\">\n";
|
||||
|
||||
//拨号计划
|
||||
$extension = Extension::with('conditions')->whereHas('conditions')->where('context',$context)->orderBy('sort')->orderBy('id')->get();
|
||||
foreach ($extension as $exten){
|
||||
$xml .= "<extension name=\"" . $exten->name . "\" continue=\"" . $exten->continue . "\" >\n";
|
||||
if ($exten->conditions->isNotEmpty()){
|
||||
foreach ($exten->conditions as $condition){
|
||||
$xml .= "<condition field=\"" . $condition->field . "\" expression=\"" . $condition->expression . "\" break=\"" . $condition->break . "\">\n";
|
||||
if ($condition->actions->isNotEmpty()){
|
||||
foreach ($condition->actions as $action){
|
||||
$xml .= "<action application=\"" . $action->application . "\" data=\"" . $action->data . "\" />\n";
|
||||
}
|
||||
}
|
||||
$xml .= "</condition>\n";
|
||||
}
|
||||
}
|
||||
$xml .= "</extension>\n";
|
||||
}
|
||||
|
||||
$xml .= "</context>\n";
|
||||
$xml .= "</section>\n";
|
||||
$xml .= "</document>\n";
|
||||
return response($xml,200)->header("Content-type","text/xml");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 动态configuration 包含动态网关
|
||||
* @param Request $request
|
||||
* @return mixed
|
||||
*/
|
||||
public function configuration(Request $request)
|
||||
{
|
||||
$xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n";
|
||||
$xml .= "<document type=\"freeswitch/xml\">\n";
|
||||
$xml .= "<section name=\"configuration\" description=\"FreeSwitch configuration\">\n";
|
||||
|
||||
$xml .= "<configuration name=\"sofia.conf\" description=\"sofia Endpoint\">\n";
|
||||
$xml .= " <global_settings>\n";
|
||||
$xml .= " <param name=\"log-level\" value=\"0\"/>\n";
|
||||
$xml .= " <!-- <param name=\"auto-restart\" value=\"false\"/> -->\n";
|
||||
$xml .= " <param name=\"debug-presence\" value=\"0\"/>\n";
|
||||
$xml .= " <!-- <param name=\"capture-server\" value=\"udp:homer.domain.com:5060\"/> -->\n";
|
||||
$xml .= " <!-- <param name=\"capture-server\" value=\"udp:homer.domain.com:5060;hep=3;capture_id=100\"/> -->\n";
|
||||
$xml .= " </global_settings>\n";
|
||||
$xml .= " <profiles>\n";
|
||||
$xml .= " <profile name=\"external\">\n";
|
||||
$xml .= " <gateways>\n";
|
||||
$gateways = Gateway::orderByDesc('id')->get();
|
||||
foreach ($gateways as $gateway){
|
||||
$xml .= " <gateway name=\"gw".$gateway->id."\">\n";
|
||||
$xml .= " <param name=\"username\" value=\"".$gateway->username."\"/>\n";
|
||||
$xml .= " <param name=\"realm\" value=\"".$gateway->realm."\"/>\n";
|
||||
$xml .= " <param name=\"password\" value=\"".$gateway->password."\"/>\n";
|
||||
$xml .= " </gateway>\n";
|
||||
}
|
||||
$xml .= " </gateways>\n";
|
||||
$xml .= " <aliases>\n";
|
||||
$xml .= " </aliases>\n";
|
||||
$xml .= " <domains>\n";
|
||||
$xml .= " <domain name=\"all\" alias=\"false\" parse=\"true\"/>\n";
|
||||
$xml .= " </domains>\n";
|
||||
$xml .= " <settings>\n";
|
||||
$xml .= " <param name=\"debug\" value=\"0\"/>\n";
|
||||
$xml .= " <!-- If you want FreeSWITCH to shutdown if this profile fails to load, uncomment the next line. -->\n";
|
||||
$xml .= " <!-- <param name=\"shutdown-on-fail\" value=\"true\"/> -->\n";
|
||||
$xml .= " <param name=\"sip-trace\" value=\"no\"/>\n";
|
||||
$xml .= " <param name=\"sip-capture\" value=\"no\"/>\n";
|
||||
$xml .= " <param name=\"rfc2833-pt\" value=\"101\"/>\n";
|
||||
$xml .= " <!-- RFC 5626 : Send reg-id and sip.instance -->\n";
|
||||
$xml .= " <!--<param name=\"enable-rfc-5626\" value=\"true\"/> -->\n";
|
||||
$xml .= " <param name=\"sip-port\" value=\"\$\${external_sip_port}\"/>\n";
|
||||
$xml .= " <param name=\"dialplan\" value=\"XML\"/>\n";
|
||||
$xml .= " <param name=\"context\" value=\"public\"/>\n";
|
||||
$xml .= " <param name=\"dtmf-duration\" value=\"2000\"/>\n";
|
||||
$xml .= " <param name=\"inbound-codec-prefs\" value=\"\$$\{global_codec_prefs}\"/>\n";
|
||||
$xml .= " <param name=\"outbound-codec-prefs\" value=\"\$\${outbound_codec_prefs}\"/>\n";
|
||||
$xml .= " <param name=\"hold-music\" value=\"\$\${hold_music}\"/>\n";
|
||||
$xml .= " <param name=\"rtp-timer-name\" value=\"soft\"/>\n";
|
||||
$xml .= " <!--<param name=\"enable-100rel\" value=\"true\"/>-->\n";
|
||||
$xml .= " <!--<param name=\"disable-srv503\" value=\"true\"/>-->\n";
|
||||
$xml .= " <!-- This could be set to \"passive\" -->\n";
|
||||
$xml .= " <param name=\"local-network-acl\" value=\"localnet.auto\"/>\n";
|
||||
$xml .= " <param name=\"manage-presence\" value=\"false\"/>\n";
|
||||
$xml .= " <!-- Name of the db to use for this profile -->\n";
|
||||
$xml .= " <!--<param name=\"dbname\" value=\"share_presence\"/>-->\n";
|
||||
$xml .= " <!--<param name=\"presence-hosts\" value=\"\$\${domain}\"/>-->\n";
|
||||
$xml .= " <!--<param name=\"force-register-domain\" value=\"\$\${domain}\"/>-->\n";
|
||||
$xml .= " <!--all inbound reg will stored in the db using this domain -->\n";
|
||||
$xml .= " <!--<param name=\"force-register-db-domain\" value=\"\$\${domain}\"/>--> \n";
|
||||
$xml .= " <!--<param name=\"aggressive-nat-detection\" value=\"true\"/>-->\n";
|
||||
$xml .= " <param name=\"inbound-codec-negotiation\" value=\"generous\"/>\n";
|
||||
$xml .= " <param name=\"nonce-ttl\" value=\"60\"/>\n";
|
||||
$xml .= " <param name=\"auth-calls\" value=\"false\"/>\n";
|
||||
$xml .= " <param name=\"inbound-late-negotiation\" value=\"true\"/>\n";
|
||||
$xml .= " <param name=\"inbound-zrtp-passthru\" value=\"true\"/>\n";
|
||||
$xml .= " <param name=\"rtp-ip\" value=\"\$\${local_ip_v4}\"/>\n";
|
||||
$xml .= " <param name=\"sip-ip\" value=\"\$\${local_ip_v4}\"/>\n";
|
||||
$xml .= " <param name=\"ext-rtp-ip\" value=\"auto-nat\"/>\n";
|
||||
$xml .= " <param name=\"ext-sip-ip\" value=\"auto-nat\"/>\n";
|
||||
$xml .= " <param name=\"rtp-timeout-sec\" value=\"300\"/>\n";
|
||||
$xml .= " <param name=\"rtp-hold-timeout-sec\" value=\"1800\"/>\n";
|
||||
$xml .= " <!--<param name=\"enable-3pcc\" value=\"true\"/>-->\n";
|
||||
$xml .= " <param name=\"tls\" value=\"\$\${external_ssl_enable}\"/>\n";
|
||||
$xml .= " <param name=\"tls-only\" value=\"false\"/>\n";
|
||||
$xml .= " <param name=\"tls-bind-params\" value=\"transport=tls\"/>\n";
|
||||
$xml .= " <param name=\"tls-sip-port\" value=\"\$\${external_tls_port}\"/>\n";
|
||||
$xml .= " <!--<param name=\"tls-cert-dir\" value=\"\"/>-->\n";
|
||||
$xml .= " <param name=\"tls-passphrase\" value=\"\"/>\n";
|
||||
$xml .= " <!-- Verify the date on TLS certificates -->\n";
|
||||
$xml .= " <param name=\"tls-verify-date\" value=\"true\"/>\n";
|
||||
$xml .= " <param name=\"tls-verify-policy\" value=\"none\"/>\n";
|
||||
$xml .= " <param name=\"tls-verify-depth\" value=\"2\"/>\n";
|
||||
$xml .= " <param name=\"tls-verify-in-subjects\" value=\"\"/>\n";
|
||||
$xml .= " <param name=\"tls-version\" value=\"\$\${sip_tls_version}\"/>\n";
|
||||
$xml .= " </settings>\n";
|
||||
$xml .= " </profile>\n";
|
||||
//$xml .= file_get_contents('etc_freeswitch/sip_profiles/internal.xml');
|
||||
$xml .= " </profiles>\n";
|
||||
$xml .= "</configuration>\n";
|
||||
$xml .= "</section>\n";
|
||||
$xml .= "</document>\n";
|
||||
return response($xml,200)->header("Content-type","text/xml");
|
||||
}
|
||||
|
||||
/**
|
||||
* 动态configuration 包含动态网关
|
||||
* @param Request $request
|
||||
* @return mixed
|
||||
*/
|
||||
public function configuration1(Request $request)
|
||||
{
|
||||
$xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n";
|
||||
$xml .= "<document type=\"freeswitch/xml\">\n";
|
||||
$xml .= "<section name=\"configuration\" description=\"FreeSwitch configuration\">\n";
|
||||
|
||||
foreach (scandir('etc_freeswitch/autoload_configs/') as $conf){
|
||||
if ($conf=='.'||$conf=='..')
|
||||
{
|
||||
continue;
|
||||
}elseif ($conf=='sofia.conf.xml') {
|
||||
|
||||
$xml .= "<configuration name=\"sofia.conf\" description=\"sofia Endpoint\">\n";
|
||||
$xml .= " <global_settings>\n";
|
||||
$xml .= " <param name=\"log-level\" value=\"0\"/>\n";
|
||||
$xml .= " <!-- <param name=\"auto-restart\" value=\"false\"/> -->\n";
|
||||
$xml .= " <param name=\"debug-presence\" value=\"0\"/>\n";
|
||||
$xml .= " <!-- <param name=\"capture-server\" value=\"udp:homer.domain.com:5060\"/> -->\n";
|
||||
$xml .= " <!-- <param name=\"capture-server\" value=\"udp:homer.domain.com:5060;hep=3;capture_id=100\"/> -->\n";
|
||||
$xml .= " </global_settings>\n";
|
||||
$xml .= " <profiles>\n";
|
||||
$xml .= " <profile name=\"external\">\n";
|
||||
$xml .= " <gateways>\n";
|
||||
$gateways = Gateway::orderByDesc('id')->get();
|
||||
foreach ($gateways as $gateway){
|
||||
$xml .= " <gateway name=\"gw".$gateway->id."\">\n";
|
||||
$xml .= " <param name=\"username\" value=\"".$gateway->username."\"/>\n";
|
||||
$xml .= " <param name=\"realm\" value=\"".$gateway->realm."\"/>\n";
|
||||
$xml .= " <param name=\"password\" value=\"".$gateway->password."\"/>\n";
|
||||
$xml .= " </gateway>\n";
|
||||
}
|
||||
$xml .= " </gateways>\n";
|
||||
$xml .= " <aliases>\n";
|
||||
$xml .= " </aliases>\n";
|
||||
$xml .= " <domains>\n";
|
||||
$xml .= " <domain name=\"all\" alias=\"false\" parse=\"true\"/>\n";
|
||||
$xml .= " </domains>\n";
|
||||
$xml .= " <settings>\n";
|
||||
$xml .= " <param name=\"debug\" value=\"0\"/>\n";
|
||||
$xml .= " <!-- If you want FreeSWITCH to shutdown if this profile fails to load, uncomment the next line. -->\n";
|
||||
$xml .= " <!-- <param name=\"shutdown-on-fail\" value=\"true\"/> -->\n";
|
||||
$xml .= " <param name=\"sip-trace\" value=\"no\"/>\n";
|
||||
$xml .= " <param name=\"sip-capture\" value=\"no\"/>\n";
|
||||
$xml .= " <param name=\"rfc2833-pt\" value=\"101\"/>\n";
|
||||
$xml .= " <!-- RFC 5626 : Send reg-id and sip.instance -->\n";
|
||||
$xml .= " <!--<param name=\"enable-rfc-5626\" value=\"true\"/> -->\n";
|
||||
$xml .= " <param name=\"sip-port\" value=\"\$\${external_sip_port}\"/>\n";
|
||||
$xml .= " <param name=\"dialplan\" value=\"XML\"/>\n";
|
||||
$xml .= " <param name=\"context\" value=\"public\"/>\n";
|
||||
$xml .= " <param name=\"dtmf-duration\" value=\"2000\"/>\n";
|
||||
$xml .= " <param name=\"inbound-codec-prefs\" value=\"\$$\{global_codec_prefs}\"/>\n";
|
||||
$xml .= " <param name=\"outbound-codec-prefs\" value=\"\$\${outbound_codec_prefs}\"/>\n";
|
||||
$xml .= " <param name=\"hold-music\" value=\"\$\${hold_music}\"/>\n";
|
||||
$xml .= " <param name=\"rtp-timer-name\" value=\"soft\"/>\n";
|
||||
$xml .= " <!--<param name=\"enable-100rel\" value=\"true\"/>-->\n";
|
||||
$xml .= " <!--<param name=\"disable-srv503\" value=\"true\"/>-->\n";
|
||||
$xml .= " <!-- This could be set to \"passive\" -->\n";
|
||||
$xml .= " <param name=\"local-network-acl\" value=\"localnet.auto\"/>\n";
|
||||
$xml .= " <param name=\"manage-presence\" value=\"false\"/>\n";
|
||||
$xml .= " <!-- Name of the db to use for this profile -->\n";
|
||||
$xml .= " <!--<param name=\"dbname\" value=\"share_presence\"/>-->\n";
|
||||
$xml .= " <!--<param name=\"presence-hosts\" value=\"\$\${domain}\"/>-->\n";
|
||||
$xml .= " <!--<param name=\"force-register-domain\" value=\"\$\${domain}\"/>-->\n";
|
||||
$xml .= " <!--all inbound reg will stored in the db using this domain -->\n";
|
||||
$xml .= " <!--<param name=\"force-register-db-domain\" value=\"\$\${domain}\"/>--> \n";
|
||||
$xml .= " <!--<param name=\"aggressive-nat-detection\" value=\"true\"/>-->\n";
|
||||
$xml .= " <param name=\"inbound-codec-negotiation\" value=\"generous\"/>\n";
|
||||
$xml .= " <param name=\"nonce-ttl\" value=\"60\"/>\n";
|
||||
$xml .= " <param name=\"auth-calls\" value=\"false\"/>\n";
|
||||
$xml .= " <param name=\"inbound-late-negotiation\" value=\"true\"/>\n";
|
||||
$xml .= " <param name=\"inbound-zrtp-passthru\" value=\"true\"/>\n";
|
||||
$xml .= " <param name=\"rtp-ip\" value=\"\$\${local_ip_v4}\"/>\n";
|
||||
$xml .= " <param name=\"sip-ip\" value=\"\$\${local_ip_v4}\"/>\n";
|
||||
$xml .= " <param name=\"ext-rtp-ip\" value=\"auto-nat\"/>\n";
|
||||
$xml .= " <param name=\"ext-sip-ip\" value=\"auto-nat\"/>\n";
|
||||
$xml .= " <param name=\"rtp-timeout-sec\" value=\"300\"/>\n";
|
||||
$xml .= " <param name=\"rtp-hold-timeout-sec\" value=\"1800\"/>\n";
|
||||
$xml .= " <!--<param name=\"enable-3pcc\" value=\"true\"/>-->\n";
|
||||
$xml .= " <param name=\"tls\" value=\"\$\${external_ssl_enable}\"/>\n";
|
||||
$xml .= " <param name=\"tls-only\" value=\"false\"/>\n";
|
||||
$xml .= " <param name=\"tls-bind-params\" value=\"transport=tls\"/>\n";
|
||||
$xml .= " <param name=\"tls-sip-port\" value=\"\$\${external_tls_port}\"/>\n";
|
||||
$xml .= " <!--<param name=\"tls-cert-dir\" value=\"\"/>-->\n";
|
||||
$xml .= " <param name=\"tls-passphrase\" value=\"\"/>\n";
|
||||
$xml .= " <!-- Verify the date on TLS certificates -->\n";
|
||||
$xml .= " <param name=\"tls-verify-date\" value=\"true\"/>\n";
|
||||
$xml .= " <param name=\"tls-verify-policy\" value=\"none\"/>\n";
|
||||
$xml .= " <param name=\"tls-verify-depth\" value=\"2\"/>\n";
|
||||
$xml .= " <param name=\"tls-verify-in-subjects\" value=\"\"/>\n";
|
||||
$xml .= " <param name=\"tls-version\" value=\"\$\${sip_tls_version}\"/>\n";
|
||||
$xml .= " </settings>\n";
|
||||
$xml .= " </profile>\n";
|
||||
$xml .= file_get_contents('etc_freeswitch/sip_profiles/internal.xml');
|
||||
$xml .= " </profiles>\n";
|
||||
$xml .= "</configuration>\n";
|
||||
|
||||
}elseif ($conf=='ivr.conf.xml'){
|
||||
|
||||
$xml .= "<configuration name=\"ivr.conf\" description=\"IVR menus\">\n";
|
||||
$xml .= "<menus>\n";
|
||||
foreach (scandir("etc_freeswitch/ivr_menus") as $file){
|
||||
if ($file=='.'||$file=='..') continue;
|
||||
$xml .= file_get_contents('etc_freeswitch/ivr_menus/'.$file);
|
||||
}
|
||||
$xml .= "</menus>\n";
|
||||
$xml .= "</configuration>\n";
|
||||
|
||||
}elseif ($conf=='dingaling.conf.xml'){
|
||||
|
||||
$xml .= "<configuration name=\"dingaling.conf\" description=\"XMPP Jingle Endpoint\">\n";
|
||||
$xml .= "<settings>\n";
|
||||
$xml .= "<param name=\"debug\" value=\"0\"/>\n";
|
||||
$xml .= "<param name=\"codec-prefs\" value=\"H264,PCMU\"/>\n";
|
||||
$xml .= "</settings>\n";
|
||||
foreach (scandir("etc_freeswitch/jingle_profiles") as $file){
|
||||
if ($file=='.'||$file=='..') continue;
|
||||
$xml .= file_get_contents('etc_freeswitch/jingle_profiles/'.$file);
|
||||
}
|
||||
$xml .= "</configuration>\n";
|
||||
|
||||
}elseif ($conf=='skinny.conf.xml'){
|
||||
|
||||
$xml .= "<configuration name=\"skinny.conf\" description=\"Skinny Endpoints\">\n";
|
||||
$xml .= "<profiles>\n";
|
||||
foreach (scandir("etc_freeswitch/sip_profiles") as $file){
|
||||
if ($file=='.'||$file=='..') continue;
|
||||
$xml .= file_get_contents('etc_freeswitch/sip_profiles/'.$file);
|
||||
}
|
||||
$xml .= "</profiles>\n";
|
||||
$xml .= "</configuration>\n";
|
||||
|
||||
}elseif ($conf=='unimrcp.conf.xml'){
|
||||
|
||||
$xml .= "<configuration name=\"unimrcp.conf\" description=\"UniMRCP Client\">\n";
|
||||
$xml .= "<settings>\n";
|
||||
$xml .= "<param name=\"default-tts-profile\" value=\"voxeo-prophecy8.0-mrcp1\"/>\n";
|
||||
$xml .= "<param name=\"default-asr-profile\" value=\"voxeo-prophecy8.0-mrcp1\"/>\n";
|
||||
$xml .= "<param name=\"log-level\" value=\"DEBUG\"/>\n";
|
||||
$xml .= "<param name=\"enable-profile-events\" value=\"false\"/>\n";
|
||||
$xml .= "<param name=\"max-connection-count\" value=\"100\"/>\n";
|
||||
$xml .= "<param name=\"offer-new-connection\" value=\"1\"/>\n";
|
||||
$xml .= "<param name=\"request-timeout\" value=\"3000\"/>\n";
|
||||
$xml .= "</settings>\n";
|
||||
$xml .= "<profiles>\n";
|
||||
foreach (scandir("etc_freeswitch/mrcp_profiles") as $file){
|
||||
if ($file=='.'||$file=='..') continue;
|
||||
$xml .= file_get_contents('etc_freeswitch/mrcp_profiles/'.$file);
|
||||
}
|
||||
$xml .= "</profiles>\n";
|
||||
$xml .= "</configuration>\n";
|
||||
|
||||
}else{
|
||||
$xml .= file_get_contents('etc_freeswitch/autoload_configs/'.$conf);
|
||||
}
|
||||
|
||||
}
|
||||
$xml .= "</section>\n";
|
||||
$xml .= "</document>\n";
|
||||
return response($xml,200)->header("Content-type","text/xml");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
class Action extends Model
|
||||
{
|
||||
protected $table = 'action';
|
||||
protected $fillable = ['display_name','application','data','sort','condition_id'];
|
||||
protected $appends = ['application_name'];
|
||||
|
||||
public function getApplicationNameAttribute()
|
||||
{
|
||||
return Arr::get(config('freeswitch.application'),$this->application)."(".$this->application.")";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Agent extends Model
|
||||
{
|
||||
protected $table = 'agent';
|
||||
protected $fillable = [
|
||||
'display_name',
|
||||
'name',
|
||||
'originate_type',
|
||||
'originate_number',
|
||||
'status',
|
||||
'max_no_answer',
|
||||
'wrap_up_time',
|
||||
'reject_delay_time',
|
||||
'busy_delay_time',
|
||||
'no_answer_delay_time',
|
||||
];
|
||||
|
||||
protected $appends = ['originate_type_name','status_name'];
|
||||
|
||||
public function getOriginateTypeNameAttribute()
|
||||
{
|
||||
return $this->attributes['originate_type_name'] = array_get([
|
||||
'user' => '分机',
|
||||
'group' => '分机组',
|
||||
'gateway' => '网关',
|
||||
],$this->originate_type);
|
||||
}
|
||||
|
||||
public function getStatusNameAttribute()
|
||||
{
|
||||
return $this->attributes['status_name'] = array_get(config('freeswitch.agent_status'),$this->status);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Asr extends Model
|
||||
{
|
||||
protected $table = 'cdr_asr';
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Audio extends Model
|
||||
{
|
||||
protected $table = 'audio';
|
||||
protected $fillable = [
|
||||
'url',
|
||||
'text',
|
||||
'auf',
|
||||
'aue',
|
||||
'voice_name',
|
||||
'speed',
|
||||
'volume',
|
||||
'pitch',
|
||||
'engine_type',
|
||||
];
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Bill extends Model
|
||||
{
|
||||
protected $table = 'bill';
|
||||
protected $fillable = ['merchant_id','type','money','remark','created_user_id'];
|
||||
protected $appends = ['created_user_name'];
|
||||
|
||||
public function getCreatedUserNameAttribute()
|
||||
{
|
||||
return $this->attributes['created_user_name'] = $this->user->name??'系统操作';
|
||||
}
|
||||
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo('App\Models\User', 'created_user_id', 'id')->withDefault();
|
||||
}
|
||||
|
||||
public function merchant()
|
||||
{
|
||||
return $this->belongsTo('App\Models\Merchant', 'merchant_id', 'id');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Bleg extends Model
|
||||
{
|
||||
protected $table = 'cdr_b_leg';
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Call extends Model
|
||||
{
|
||||
protected $table = 'call';
|
||||
|
||||
protected $guarded = ['id'];
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Cdr extends Model
|
||||
{
|
||||
protected $table = 'cdr_a_leg';
|
||||
|
||||
public function bleg()
|
||||
{
|
||||
return $this->hasOne('App\Models\Bleg','aleg_uuid','aleg_uuid');
|
||||
}
|
||||
|
||||
public function getBillsecAttribute($value)
|
||||
{
|
||||
if (!empty($this->bleg_uuid)){
|
||||
$value = $this->bleg->billsec;
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Condition extends Model
|
||||
{
|
||||
protected $table = 'condition';
|
||||
protected $fillable = ['display_name','field','expression','break','extension_id','sort'];
|
||||
protected $with = 'actions';
|
||||
|
||||
public function actions()
|
||||
{
|
||||
return $this->hasMany('App\Models\Action','condition_id','id')->orderBy('sort')->orderBy('id');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Digits extends Model
|
||||
{
|
||||
protected $table = 'digits';
|
||||
protected $fillable = ['ivr_id','action','digits','param'];
|
||||
protected $appends = ['action_name','ivr_name'];
|
||||
|
||||
|
||||
public function getActionNameAttribute()
|
||||
{
|
||||
return $this->attributes['action_name'] = array_get(config('freeswitch.ivr_action'),$this->action);
|
||||
}
|
||||
|
||||
public function getIvrNameAttribute()
|
||||
{
|
||||
return $this->attributes['ivr_name'] = $this->ivr->display_name."(".$this->ivr->name.")";
|
||||
}
|
||||
|
||||
public function ivr()
|
||||
{
|
||||
return $this->belongsTo('App\Models\Ivr');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class District extends Model
|
||||
{
|
||||
protected $table = 'districts';
|
||||
protected $fillable = ['citycode','adcode','name','center','level'];
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
class Extension extends Model
|
||||
{
|
||||
protected $table = 'extension';
|
||||
protected $fillable = ['display_name','name','sort','continue','context'];
|
||||
protected $appends = ['context_name'];
|
||||
|
||||
public function getContextNameAttribute()
|
||||
{
|
||||
return Arr::get(['default'=>'呼出','public'=>'呼入'],$this->context);
|
||||
}
|
||||
|
||||
public function conditions()
|
||||
{
|
||||
return $this->hasMany('App\Models\Condition','extension_id','id')->orderBy('sort')->orderBy('id');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Gateway extends Model
|
||||
{
|
||||
protected $table = 'gateway';
|
||||
protected $fillable = ['name','realm','username','password','prefix','outbound_caller_id','rate'];
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Icon extends Model
|
||||
{
|
||||
protected $table = 'icons';
|
||||
protected $fillable = ['unicode','class','name','sort'];
|
||||
|
||||
//对应菜单
|
||||
public function menus()
|
||||
{
|
||||
return $this->hasMany('App\Models\Menu','icon_id','id');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Ivr extends Model
|
||||
{
|
||||
protected $table = 'ivr';
|
||||
protected $fillable = [
|
||||
'display_name',
|
||||
'name',
|
||||
'greet_long',
|
||||
'greet_short',
|
||||
'invalid_sound',
|
||||
'exit_sound',
|
||||
'confirm_macro',
|
||||
'confirm_key',
|
||||
'tts_engine',
|
||||
'tts_voice',
|
||||
'confirm_attempts',
|
||||
'timeout',
|
||||
'inter_digit_timeout',
|
||||
'max_failures',
|
||||
'max_timeouts',
|
||||
'digit_len',
|
||||
];
|
||||
|
||||
public function digits()
|
||||
{
|
||||
return $this->hasMany('App\Models\Digits');
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class Merchant extends Model
|
||||
{
|
||||
use SoftDeletes;
|
||||
|
||||
protected $table = 'merchant';
|
||||
protected $fillable = [
|
||||
'uuid',
|
||||
'username',
|
||||
'password',
|
||||
'status',
|
||||
'company_name',
|
||||
'expires_at',
|
||||
'sip_num',
|
||||
'money',
|
||||
'created_user_id',
|
||||
];
|
||||
protected $hidden = ['uuid','password'];
|
||||
protected $dates = ['expires_at'];
|
||||
protected $appends = ['status_name','created_user_name'];
|
||||
|
||||
public function getStatusNameAttribute()
|
||||
{
|
||||
return $this->attributes['status_name'] = array_get(config('freeswitch.merchant_status'),$this->status);
|
||||
}
|
||||
|
||||
public function getCreatedUserNameAttribute()
|
||||
{
|
||||
return $this->attributes['created_user_name'] = $this->user->name??'未知';
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建用户
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo('App\Models\User', 'created_user_id', 'id');
|
||||
}
|
||||
|
||||
/**
|
||||
* 可使用的网关
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
|
||||
*/
|
||||
public function gateways()
|
||||
{
|
||||
return $this->belongsToMany('App\Models\Gateway', 'merchant_gateway','gateway_id','merchant_id')->withPivot(['rate']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 拥有的分机
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||
*/
|
||||
public function sips()
|
||||
{
|
||||
return $this->hasMany('App\Models\Sip','merchant_id','id');
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Queue extends Model
|
||||
{
|
||||
protected $table = 'queue';
|
||||
protected $fillable = [
|
||||
'display_name',
|
||||
'name',
|
||||
'strategy',
|
||||
'max_wait_time',
|
||||
];
|
||||
protected $appends = ['strategy_name'];
|
||||
|
||||
|
||||
public function agents()
|
||||
{
|
||||
return $this->belongsToMany('App\Models\Agent','queue_agent');
|
||||
}
|
||||
|
||||
public function getStrategyNameAttribute()
|
||||
{
|
||||
return $this->attributes['strategy_name'] = array_get(config('freeswitch.strategy'),$this->strategy);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Sip extends Model
|
||||
{
|
||||
protected $table = 'sip';
|
||||
protected $fillable = [
|
||||
'username',
|
||||
'password',
|
||||
'effective_caller_id_name',
|
||||
'effective_caller_id_number',
|
||||
'outbound_caller_id_name',
|
||||
'outbound_caller_id_number',
|
||||
'merchant_id',
|
||||
'gateway_id',
|
||||
'expense_id',
|
||||
];
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Task extends Model
|
||||
{
|
||||
protected $table = 'task';
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'date_start',
|
||||
'date_end',
|
||||
'time_start',
|
||||
'time_end',
|
||||
'gateway_id',
|
||||
'queue_id',
|
||||
'max_channel',
|
||||
'status',
|
||||
];
|
||||
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->display_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=5
|
||||
public function failCalls()
|
||||
{
|
||||
return $this->hasMany('App\Models\Call','task_id','id')->where('status',5);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,224 @@
|
|||
<?php
|
||||
|
||||
|
||||
class Freeswitchesl {
|
||||
|
||||
public function __construct() {
|
||||
$this->socket = "";
|
||||
$this->sorts = "";
|
||||
$this->length = 1024;
|
||||
}
|
||||
|
||||
public function eliminate($parameter)
|
||||
{
|
||||
$array = array(" "," ","\t","\n","\r");
|
||||
return str_replace($array, '', $parameter);
|
||||
}
|
||||
|
||||
public function eliminateLine($parameter)
|
||||
{
|
||||
return str_replace("\n\n", "\n", $parameter);
|
||||
}
|
||||
|
||||
public function typeClear($response)
|
||||
{
|
||||
$commenType = array("Content-Type: text/event-xml\n","Content-Type: text/event-plain\n","Content-Type: text/event-json\n");
|
||||
return str_replace($commenType, '', $response);
|
||||
}
|
||||
|
||||
public function connect($host,$port,$password)
|
||||
{
|
||||
$this->socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
|
||||
$connection = socket_connect($this->socket, $host,$port);
|
||||
$connect = false;
|
||||
$error = "";
|
||||
while ($socket_info = @socket_read($this->socket, 1024, PHP_NORMAL_READ)) {
|
||||
$eliminate_socket_info = $this->eliminate($socket_info);
|
||||
if ($eliminate_socket_info == "Content-Type:auth/request") {
|
||||
socket_write($this->socket, "auth ".$password."\r\n\r\n");
|
||||
}elseif ($eliminate_socket_info == "") {
|
||||
continue;
|
||||
}elseif ($eliminate_socket_info == "Content-Type:command/reply") {
|
||||
continue;
|
||||
}elseif ($eliminate_socket_info == "Reply-Text:+OKaccepted") {
|
||||
$connect = true;
|
||||
break;
|
||||
} else {
|
||||
$error .= $eliminate_socket_info."\r\n";
|
||||
}
|
||||
}
|
||||
if (!$connect) {
|
||||
echo $error;
|
||||
}
|
||||
return $connect;
|
||||
}
|
||||
|
||||
public function api($api,$args="")
|
||||
{
|
||||
if ($this->socket) {
|
||||
socket_write($this->socket, "api ".$api." ".$args."\r\n\r\n");
|
||||
}
|
||||
$response = $this->recvEvent("common");
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function bgapi($api,$args="",$custom_job_uuid="")
|
||||
{
|
||||
if ($this->socket) {
|
||||
socket_write($this->socket, "bgapi ".$api." ".$args." ".$custom_job_uuid."\r\n\r\n");
|
||||
}
|
||||
return "executed";
|
||||
}
|
||||
|
||||
public function execute($app,$args,$uuid)
|
||||
{
|
||||
if ($this->socket) {
|
||||
$str = "sendmsg ".$uuid."\ncall-command: execute\nexecute-app-name: ".$app."\nexecute-app-arg: ".$args."\n\n";
|
||||
socket_write($this->socket, $str);
|
||||
}
|
||||
$response = $this->recvEvent("common");
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function executeAsync($app,$args,$uuid)
|
||||
{
|
||||
if ($this->socket) {
|
||||
$str = "sendmsg ".$uuid."\ncall-command: executeAsync\nexecute-app-name: ".$app."\nexecute-app-arg: ".$args."\n\n";
|
||||
socket_write($this->socket, $str);
|
||||
}
|
||||
return "executed";
|
||||
}
|
||||
|
||||
public function sendmsg($uuid)
|
||||
{
|
||||
if ($this->socket) {
|
||||
socket_write($this->socket, "sendmsg ".$uuid."\r\n\r\n");
|
||||
}
|
||||
return "executed";
|
||||
}
|
||||
|
||||
public function events($sorts,$args)
|
||||
{
|
||||
$this->sorts = $sorts;
|
||||
if ($sorts == "json") {
|
||||
$sorts = "xml";
|
||||
}
|
||||
if ($this->socket) {
|
||||
socket_write($this->socket, "event ".$sorts." ".$args."\r\n\r\n");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getHeader($response,$args)
|
||||
{
|
||||
$serialize = $this->serialize($response,"json");
|
||||
$serializearray = json_decode($serialize);
|
||||
try {
|
||||
return $serializearray->$args;
|
||||
} catch (Exception $e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public function recvEvent($type="event")
|
||||
{
|
||||
$response = '';
|
||||
$length = 0;
|
||||
$x = 0;
|
||||
while ($socket_info = @socket_read($this->socket, 1024, PHP_NORMAL_READ)){
|
||||
$x++;
|
||||
usleep(100);
|
||||
if ($length > 0) {
|
||||
$response .= $socket_info;
|
||||
}
|
||||
if ($length == 0 && strpos($socket_info, 'Content-Length:') !== false) {
|
||||
$lengtharray = explode("Content-Length:",$socket_info);
|
||||
if ($type == "event") {
|
||||
$length = (int)$lengtharray[1]+30;
|
||||
} else {
|
||||
$length = (int)$lengtharray[1];
|
||||
}
|
||||
}
|
||||
|
||||
if ($length > 0 && strlen($response) >= $length) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ($x > 10000) break;
|
||||
}
|
||||
|
||||
|
||||
if ($this->sorts == "json" && $type == "event") {
|
||||
$response = $this->typeClear($response);
|
||||
$responsedata = simplexml_load_string($response);
|
||||
$response = [];
|
||||
foreach ($responsedata->headers->children() as $key => $value) {
|
||||
$response[(string)$key] = (string)$value;
|
||||
}
|
||||
return json_encode($response);
|
||||
} else {
|
||||
$response = $this->eliminateLine($response);
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function serialize($response,$type)
|
||||
{
|
||||
$response = $this->typeClear($response);
|
||||
if ($this->sorts == $type) return $response;
|
||||
if ($this->sorts == "json") {
|
||||
$responsedata = json_decode($response);
|
||||
if ($type == "plain") {
|
||||
$response = "";
|
||||
foreach ($responsedata as $key => $value) {
|
||||
$responseline = $key.": ".$value."\r\n";
|
||||
$response .= $responseline;
|
||||
}
|
||||
} else {
|
||||
$response = "<event>\r\n <headers>\r\n";
|
||||
foreach ($responsedata as $key => $value) {
|
||||
$responseline = " <".$key.">".$value."</".$key.">"."\r\n";
|
||||
$response .= $responseline;
|
||||
}
|
||||
$response .= " </headers>\r\n</event>";
|
||||
}
|
||||
return $response;
|
||||
} elseif ($this->sorts == "xml") {
|
||||
$responsedata = simplexml_load_string($response);
|
||||
if ($type == "plain") {
|
||||
$response = "";
|
||||
foreach ($responsedata->headers->children() as $key => $value) {
|
||||
$responseline = (string)$key.": ".(string)$value."\r\n";
|
||||
$response .= $responseline;
|
||||
}
|
||||
return $response;
|
||||
} else {
|
||||
$response = [];
|
||||
foreach ($responsedata->headers->children() as $key => $value) {
|
||||
$response[(string)$key] = (string)$value;
|
||||
}
|
||||
return json_encode($response);
|
||||
}
|
||||
} else {
|
||||
$response = str_replace("\n", '","', $response);
|
||||
$response = str_replace(": ", '":"', $response);
|
||||
$response = substr($response, 0, -2);
|
||||
$response = '{"'.$response.'}';
|
||||
if ($type == "json") return $response;
|
||||
$responsedata = json_decode($response);
|
||||
$response = "<event>\r\n <headers>\r\n";
|
||||
foreach ($responsedata as $key => $value) {
|
||||
$responseline = " <".$key.">".$value."</".$key.">"."\r\n";
|
||||
$response .= $responseline;
|
||||
}
|
||||
$response .= " </headers>\r\n</event>";
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
||||
public function disconnect()
|
||||
{
|
||||
socket_close($this->socket);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -40,6 +40,9 @@
|
|||
"classmap": [
|
||||
"database/seeds",
|
||||
"database/factories"
|
||||
],
|
||||
"files": [
|
||||
"bootstrap/Freeswitchesl.php"
|
||||
]
|
||||
},
|
||||
"autoload-dev": {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,85 @@
|
|||
<?php
|
||||
return [
|
||||
|
||||
//socket连接授权
|
||||
'event_socket' => [
|
||||
'host' => '172.16.2.12',
|
||||
'port' => 8021,
|
||||
'password' => 'ClueCon',
|
||||
],
|
||||
|
||||
//网关目录
|
||||
'gateway_dir' => '/usr/local/freeswitch/etc/freeswitch/sip_profiles/external/',
|
||||
|
||||
//IVR 目录
|
||||
'ivr_dir' => '/usr/local/freeswitch/etc/freeswitch/ivr_menus/',
|
||||
|
||||
//callcenter目录
|
||||
'callcenter_dir' => '/usr/local/freeswitch/etc/freeswitch/autoload_configs/callcenter.conf.xml',
|
||||
|
||||
//application
|
||||
'application' => [
|
||||
'set' => '设置变量',
|
||||
'answer' => '应答',
|
||||
'sleep' => '睡眠',
|
||||
'hangup' => '挂断',
|
||||
'record_session' => '录音',
|
||||
'export' => '导入变量',
|
||||
'bridge' => '桥接呼叫',
|
||||
'echo' => '回音',
|
||||
'park' => '停泊',
|
||||
'transfer' => '呼叫转移',
|
||||
'info' => '显示信息',
|
||||
'lua' => 'lua脚本',
|
||||
'detect_speech'=> 'detect_speech',
|
||||
'play_and_detect_speech'=>'play_and_detect_speech',
|
||||
'log' => 'log',
|
||||
],
|
||||
|
||||
//队列响铃模式
|
||||
'strategy' => [
|
||||
'top-down' => '顺序振铃',
|
||||
'ring-all' => '所有振铃',
|
||||
'longest-idle-agent' => '空闲时长最长振铃',
|
||||
'round-robin' => '轮循振铃',
|
||||
'agent-with-least-talk-time' => '通话时长最小振铃',
|
||||
'agent-with-fewest-calls' => '接听最少振铃',
|
||||
'sequentially-by-agent-order' => '优先级振铃',
|
||||
'random' => '随机振铃',
|
||||
],
|
||||
|
||||
//坐席状态status
|
||||
'agent_status' => [
|
||||
'Logged Out' => '签出',
|
||||
'Available' => '示闲',
|
||||
'On Break' => '休息(不接收呼叫)',
|
||||
],
|
||||
//坐席呼叫状态state
|
||||
'agent_state' => [
|
||||
'Idle' => '空闲(不接收呼叫)',
|
||||
'Waiting' => '等待',
|
||||
'Receiving' => '电话呼入',
|
||||
'In a queue call' => '通话中',
|
||||
],
|
||||
|
||||
//商户状态
|
||||
'merchant_status' => [
|
||||
1 => '正常',
|
||||
2 => '禁用',
|
||||
],
|
||||
|
||||
//讯飞在线语音合成参数
|
||||
'xfyun' => [
|
||||
'appid' => '5bc842c0',
|
||||
'apikey' => '33e3e90871156122614cbe26d2992ab0',
|
||||
'sounds' => '/usr/local/freeswitch/share/freeswitch/sounds/en/us/callie/custom/8000/'
|
||||
],
|
||||
|
||||
//IVR
|
||||
'ivr_action' => [
|
||||
'menu-exec-app' => '应用',
|
||||
'menu-sub' => '子菜单',
|
||||
'enu-top' => '父菜单',
|
||||
],
|
||||
|
||||
];
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateDistrictTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('districts', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('adcode')->comment('行政编码');
|
||||
$table->string('name')->comment('名字');
|
||||
$table->string('center')->comment('经纬度');
|
||||
$table->string('level')->comment('级别');
|
||||
$table->integer('parent_id')->default(0);
|
||||
$table->integer('sort')->default(0)->comment('排序');
|
||||
$table->timestamps();
|
||||
});
|
||||
\DB::statement("ALTER TABLE `districts` comment '地区表'");
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('districts');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateGatewayTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('gateway', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('name')->comment('网关名称');
|
||||
$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->decimal('rate',10,2)->default(0)->comment('费率:每分钟多少元');
|
||||
$table->timestamps();
|
||||
});
|
||||
\DB::statement("ALTER TABLE `gateway` comment '中继网关表'");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('gateway');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateExtensionTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('extension', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->tinyInteger('sort')->default(0)->comment('序号');
|
||||
$table->string('display_name')->comment('名称');
|
||||
$table->string('name')->unique()->comment('标识符');
|
||||
$table->string('continue')->default("false")->comment('true:表示不管该extension中是否有condition匹配,都继续执行dialplan。false:表示如果该extension中有匹配的condition,那么就停止了dialplan。false是默认值');
|
||||
$table->string('context')->default('default')->comment('标识呼出还是呼入,default==呼出,public==呼入');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('extension');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateConditionTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('condition', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->tinyInteger('sort')->default(0)->comment('序号');
|
||||
$table->string('display_name')->comment('名称');
|
||||
$table->string('field')->default('destination_number')->comment('字段,默认被叫号码');
|
||||
$table->string('expression')->nullable()->comment('正则');
|
||||
$table->string('break')->default('on-false')->comment('on-false(默认),on-true,always,never');
|
||||
$table->unsignedInteger('extension_id')->comment('所属拨号计划的ID');
|
||||
$table->timestamps();
|
||||
$table->foreign('extension_id')->references('id')->on('extension')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('condition');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateActionTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('action', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->tinyInteger('sort')->default(0)->comment('序号');
|
||||
$table->string('display_name')->comment('名称');
|
||||
$table->string('application')->comment('应用');
|
||||
$table->string('data')->nullable()->comment('数据');
|
||||
$table->unsignedInteger('condition_id')->comment('路由规则ID');
|
||||
$table->timestamps();
|
||||
$table->foreign('condition_id')->references('id')->on('condition')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('action');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateCdrABLeg extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('cdr_ab_leg', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('uuid')->comment('通话uuid');
|
||||
$table->string('caller_id_name')->nullable()->comment('主叫昵称');
|
||||
$table->string('caller_id_number')->nullable()->comment('主叫号码');
|
||||
$table->string('destination_number')->nullable()->comment('被叫号码');
|
||||
$table->timestamp('start_stamp')->nullable()->comment('呼叫发起时间');
|
||||
$table->timestamp('answer_stamp')->nullable()->comment('呼叫应答时间');
|
||||
$table->timestamp('end_stamp')->nullable()->comment('呼叫结束时间');
|
||||
$table->integer('duration')->default(0)->comment('总通话时长(主叫通话时长)');
|
||||
$table->integer('billsec')->default(0)->comment('接听时长(被叫通话时长)');
|
||||
$table->string('hangup_cause')->nullable()->comment('挂断原因');
|
||||
$table->string('sofia_record_file')->nullable()->comment('录音文件地址');
|
||||
$table->string('extend_content')->nullable()->comment('预留扩展字段内容');
|
||||
});
|
||||
Schema::create('cdr_a_leg', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('aleg_uuid')->comment('aleg_uuid');
|
||||
$table->string('bleg_uuid')->nullable()->comment('bleg_uuid');
|
||||
$table->string('caller_id_name')->nullable()->comment('主叫昵称');
|
||||
$table->string('caller_id_number')->nullable()->comment('主叫号码');
|
||||
$table->string('destination_number')->nullable()->comment('被叫号码');
|
||||
$table->timestamp('start_stamp')->nullable()->comment('呼叫发起时间');
|
||||
$table->timestamp('answer_stamp')->nullable()->comment('呼叫应答时间');
|
||||
$table->timestamp('end_stamp')->nullable()->comment('呼叫结束时间');
|
||||
$table->integer('duration')->default(0)->comment('总通话时长(主叫通话时长)');
|
||||
$table->integer('billsec')->default(0)->comment('接听时长(被叫通话时长)');
|
||||
$table->string('hangup_cause')->nullable()->comment('挂断原因');
|
||||
$table->string('sofia_record_file')->nullable()->comment('录音文件地址');
|
||||
$table->string('extend_content')->nullable()->comment('预留扩展字段内容');
|
||||
});
|
||||
Schema::create('cdr_b_leg', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('aleg_uuid')->comment('aleg_uuid');
|
||||
$table->string('bleg_uuid')->comment('bleg_uuid');
|
||||
$table->string('caller_id_name')->nullable()->comment('主叫昵称');
|
||||
$table->string('caller_id_number')->nullable()->comment('主叫号码');
|
||||
$table->string('destination_number')->nullable()->comment('被叫号码');
|
||||
$table->timestamp('start_stamp')->nullable()->comment('呼叫发起时间');
|
||||
$table->timestamp('answer_stamp')->nullable()->comment('呼叫应答时间');
|
||||
$table->timestamp('end_stamp')->nullable()->comment('呼叫结束时间');
|
||||
$table->integer('duration')->default(0)->comment('总通话时长(主叫通话时长)');
|
||||
$table->integer('billsec')->default(0)->comment('接听时长(被叫通话时长)');
|
||||
$table->string('hangup_cause')->nullable()->comment('挂断原因');
|
||||
$table->string('sofia_record_file')->nullable()->comment('录音文件地址');
|
||||
$table->string('extend_content')->nullable()->comment('预留扩展字段内容');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('cdr_ab_leg');
|
||||
Schema::dropIfExists('cdr_a_leg');
|
||||
Schema::dropIfExists('cdr_b_leg');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateCdrAsrTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('cdr_asr', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('uuid')->comment('当前识别通道uuid');
|
||||
$table->string('text')->comment('识别结果');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('cdr_asr');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
<?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->date('date_start')->nullable()->comment('任务开始日期');
|
||||
$table->date('date_end')->nullable()->comment('任务结束日期');
|
||||
$table->time('time_start')->nullable()->comment('任务开始时间');
|
||||
$table->time('time_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,45 @@
|
|||
<?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_phone')->nullable()->comment('呼叫时间');
|
||||
$table->timestamp('datetime_entry_queue')->nullable()->comment('进入队列时间');
|
||||
$table->timestamp('datetime_agent_called')->nullable()->comment('呼叫坐席时间');
|
||||
$table->timestamp('datetime_agent_answered')->nullable()->comment('坐席应答时间');
|
||||
$table->timestamp('datetime_end')->nullable()->comment('结束通话时间');
|
||||
$table->string('agent_name')->nullable()->comment('接听坐席');
|
||||
$table->integer('duration')->default(0)->comment('主叫通话时长');
|
||||
$table->integer('billsec')->default(0)->comment('被叫通话时长');
|
||||
$table->string('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');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class CreateCallcenterTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('queue', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('display_name')->comment('队列名称');
|
||||
$table->string('name')->unique()->comment('队列号码');
|
||||
$table->string('strategy')->default('top-down')->comment('振铃策略');
|
||||
$table->string('moh_sound')->default('$${hold_music}')->comment('队列语音');
|
||||
$table->string('time_base_score')->default('system');
|
||||
$table->integer('max_wait_time')->default(0)->comment('最大等待时间(超过时间未被接通将退出callcenter)0为禁用');
|
||||
$table->integer('max_wait_time_with_no_agent')->default(0)->comment('无成员(没有成员的状态是available)等待超时时间: 超出时间电话会退出callcenter 0为禁用');
|
||||
$table->integer('max_wait_time_with_no_agent_time_reached')->default(5)->comment('如果有电话有因为(max-wait-time-with-no-agent)的原因退出队列, 队列将在延迟一定时间不允许新的电话呼入到队列');
|
||||
$table->string('tier_rules_apply')->default('false')->comment('梯队匹配');
|
||||
$table->integer('tier_rule_wait_second')->default(300)->comment('梯队的等待时间(进入下个梯队的时间)');
|
||||
$table->string('tier_rule_wait_multiply_level')->default('true')->comment('梯队等待级别');
|
||||
$table->string('tier_rule_no_agent_no_wait')->default('true')->comment('是否跳过no-agent的梯队,(no-agent就是这个梯队中不存在状态为available的成员agent )');
|
||||
$table->integer('discard_abandoned_after')->default(60)->comment('最大丢弃时长(丢弃超过此时长,将不可以恢复)与abandoned_resume_allowed同时生效');
|
||||
$table->string('abandoned_resume_allowed')->default('false')->comment('丢弃后是否允许恢复或者重新进入队列');
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('agent', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('display_name')->comment('坐席名称');
|
||||
$table->string('name')->unique()->comment('坐席号码');
|
||||
$table->string('type')->default('callback');
|
||||
$table->string('originate_type')->default('user')->comment('呼叫类型:user-分机,group-分机组,gateway-网关');
|
||||
$table->string('originate_number')->comment('呼叫号码');
|
||||
$table->string('status')->default('Available')->comment('Logged Out签出,Available空闲,Available (On Demand)一次空闲,On Break未忙');
|
||||
$table->string('state')->nullable()->comment('坐席呼叫状态');
|
||||
$table->integer('max_no_answer')->default(3)->comment('最大无应答次数,超过次数,status变为On Break状态');
|
||||
$table->integer('wrap_up_time')->default(1)->comment('通话完成间隔时间,成功处理一个通话后,多久才会有电话进入等待时长');
|
||||
$table->integer('reject_delay_time')->default(10)->comment('挂机间隔时间,来电拒接后多久才会有电话进入的等待时长');
|
||||
$table->integer('busy_delay_time')->default(10)->comment('忙重试间隔时间,来电遇忙后多久才会有电话进入的等待时长');
|
||||
$table->integer('no_answer_delay_time')->default(10)->comment('无应答重试间隔,来电无应答后多久才会有电话进入的等待时长');
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('queue_agent', function (Blueprint $table) {
|
||||
$table->unsignedInteger('queue_id');
|
||||
$table->unsignedInteger('agent_id');
|
||||
|
||||
$table->foreign('queue_id')
|
||||
->references('id')
|
||||
->on('queue')
|
||||
->onDelete('cascade');
|
||||
$table->foreign('agent_id')
|
||||
->references('id')
|
||||
->on('agent')
|
||||
->onDelete('cascade');
|
||||
$table->primary(['queue_id', 'agent_id']);
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('queue_agent');
|
||||
Schema::dropIfExists('agent');
|
||||
Schema::dropIfExists('queue');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class Merchant extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('merchant', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->uuid('uuid');
|
||||
$table->string('username')->unique()->comment('商户帐号');
|
||||
$table->string('password')->comment('商户密码');
|
||||
$table->tinyInteger('status')->default(1)->comment('商户状态:1正常,2禁用');
|
||||
$table->string('company_name')->nullable()->comment('公司名称');
|
||||
$table->timestamp('expires_at')->nullable()->comment('到期时间');
|
||||
$table->integer('sip_num')->default(0)->comment('可添加的分机数量');
|
||||
$table->decimal('money',10)->default(0)->comment('帐户余额');
|
||||
$table->unsignedInteger('created_user_id')->default(0)->comment('创建用户ID');
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
});
|
||||
\DB::statement("ALTER TABLE `merchant` comment '商户表'");
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('merchant');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class Sip extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('sip', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('username')->unique()->comment('分机号');
|
||||
$table->string('password')->comment('分机密码');
|
||||
$table->string('context')->comment('拨号文本')->default('default');
|
||||
$table->string('effective_caller_id_name')->nullable()->comment('外显名称,针对分机与分机');
|
||||
$table->string('effective_caller_id_number')->nullable()->comment('外显号码,针对分机与分机');
|
||||
$table->string('outbound_caller_id_name')->nullable()->comment('出局名称,针对中继');
|
||||
$table->string('outbound_caller_id_number')->nullable()->comment('出局名称,针对中继');
|
||||
$table->unsignedInteger('merchant_id')->nullable()->comment('商户ID');
|
||||
$table->unsignedBigInteger('gateway_id')->nullable()->comment('网关ID');
|
||||
$table->unsignedBigInteger('expense_id')->nullable()->comment('资费套餐ID');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('sip');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class Bill extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('bill', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->unsignedInteger('merchant_id')->comment('商户ID');
|
||||
$table->tinyInteger('type')->comment('流水类型:1增加,2减少');
|
||||
$table->decimal('money',10)->default(0)->comment('金额');
|
||||
$table->text('remark')->comment('备注');
|
||||
$table->unsignedInteger('created_user_id')->default(0)->comment('user用户ID');
|
||||
$table->timestamps();
|
||||
});
|
||||
\DB::statement("ALTER TABLE `bill` comment '商户帐单表'");
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('bill');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class MerchantGateway extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('merchant_gateway', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->unsignedInteger('merchant_id')->comment('商户ID');
|
||||
$table->unsignedInteger('gateway_id')->comment('网关ID');
|
||||
$table->decimal('rate',10,2)->comment('每分钟多少钱,单位:元。');
|
||||
});
|
||||
\DB::statement("ALTER TABLE `merchant_gateway` comment '商户-网关多对多表'");
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('merchant_gateway');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class Ivr extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('ivr', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('display_name')->comment('名称');
|
||||
$table->string('name')->unique()->comment('标识');
|
||||
$table->string('greet_long')->comment('开始的欢迎音');
|
||||
$table->string('greet_short')->comment('简短提示音,用户长时间没有按键提示');
|
||||
$table->string('invalid_sound')->default('ivr/ivr-that_was_an_invalid_entry.wav')->comment('错误提示音,如果用户按错了键,则会使用该提示');
|
||||
$table->string('exit_sound')->default('voicemail/vm-goodbye.wav')->comment('菜单退出时提示音');
|
||||
$table->string('confirm_macro')->nullable()->default('')->comment('确认宏');
|
||||
$table->string('confirm_key')->nullable()->default('')->comment('确认键');
|
||||
$table->string('tts_engine')->nullable()->default('flite')->comment('语音合成引擎');
|
||||
$table->string('tts_voice')->nullable()->default('rms')->comment('语音合成声音');
|
||||
$table->string('confirm_attempts')->nullable()->default('3')->comment('确认次数');
|
||||
$table->integer('timeout')->default(10000)->comment('超时时间(毫秒),即多长时间没有收到按键就超时,播放其他提示音');
|
||||
$table->integer('inter_digit_timeout')->default(2000)->comment('两次按键的最大间隔(毫秒)');
|
||||
$table->integer('max_failures')->default(3)->comment('用户按键错误的次数');
|
||||
$table->integer('max_timeouts')->default(3)->comment('最大超时次数');
|
||||
$table->integer('digit_len')->default(4)->comment('菜单项的长度,即最大收号位数');
|
||||
$table->timestamps();
|
||||
});
|
||||
\DB::statement("ALTER TABLE `ivr` comment 'ivr语音导航'");
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('ivr');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class Digits extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('digits', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->unsignedInteger('ivr_id')->comment('IVR ID');
|
||||
$table->string('action')->comment('action应用:menu-exec-app、menu-sub、menu-top');
|
||||
$table->string('digits')->comment('用户按键数值,0-9或者正则表达式');
|
||||
$table->string('param')->nullable()->comment('应用执行参数,可为空');
|
||||
$table->timestamps();
|
||||
});
|
||||
\DB::statement("ALTER TABLE `ivr` comment 'ivr语音导航'");
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('digits');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
|
||||
class Audio extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('audio', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('url')->comment('音频路径');
|
||||
$table->text('text')->comment('待合成文字');
|
||||
$table->string('auf')->comment('音频采样率:audio/L16;rate=16000 , audio/L16;rate=8000');
|
||||
$table->string('aue')->comment('音频编码:aw(未压缩的wav格式),lame(mp3格式)');
|
||||
$table->string('voice_name')->comment('发音人:xiaoyan,aisjiuxu,aisxping,aisjinger,aisbabyxu');
|
||||
$table->string('speed')->comment('语速:50,0-100');
|
||||
$table->string('volume')->comment('音量:50,0-100');
|
||||
$table->string('pitch')->comment('音高:50,0-100');
|
||||
$table->string('engine_type')->comment('aisound(普通效果)
|
||||
intp65(中文)
|
||||
intp65_en(英文)
|
||||
mtts(小语种,需配合小语种发音人使用)
|
||||
x(优化效果)
|
||||
默认为intp65');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('audio');
|
||||
}
|
||||
}
|
||||
|
|
@ -14,6 +14,7 @@ class DatabaseSeeder extends Seeder
|
|||
$this->call([
|
||||
UserSeeder::class,
|
||||
ConfigGroupSeeder::class,
|
||||
PbxSeeder::class,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,80 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
|
||||
class DistrictTableSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
set_time_limit(0);
|
||||
//清空表
|
||||
\App\Models\District::truncate();
|
||||
/**
|
||||
规则:设置显示下级行政区级数(行政区级别包括:国家、省/直辖市、市、区/县、乡镇/街道多级数据)
|
||||
可选值:0、1、2、3等数字,并以此类推
|
||||
0:不返回下级行政区;
|
||||
1:返回下一级行政区;
|
||||
2:返回下两级行政区;
|
||||
3:返回下三级行政区;
|
||||
*/
|
||||
$dep = 3;
|
||||
$url = 'http://restapi.amap.com/v3/config/district?key=5f6d1733b6b08927f8c44f9fd70e1026&subdistrict='.$dep;
|
||||
$client = new \GuzzleHttp\Client();
|
||||
$response = $client->get($url);
|
||||
if ($response->getStatusCode()==200){
|
||||
$res = \GuzzleHttp\json_decode($response->getBody());
|
||||
$data = $res->districts[0]->districts;
|
||||
foreach ($data as $d1){
|
||||
//插入省
|
||||
$province = \App\Models\District::create([
|
||||
'adcode' => $d1->adcode,
|
||||
'name' => $d1->name,
|
||||
'center' => $d1->center,
|
||||
'level' => $d1->level
|
||||
]);
|
||||
if (isset($d1->districts) && !empty($d1->districts)){
|
||||
foreach ($d1->districts as $d2){
|
||||
//插入市
|
||||
$city = \App\Models\District::create([
|
||||
'adcode' => $d2->adcode,
|
||||
'name' => $d2->name,
|
||||
'center' => $d2->center,
|
||||
'level' => $d2->level,
|
||||
'parent_id' => $province->id
|
||||
]);
|
||||
if (isset($d2->districts) && !empty($d2->districts)){
|
||||
foreach ($d2->districts as $d3){
|
||||
//插入区县
|
||||
$qu = \App\Models\District::create([
|
||||
'adcode' => $d3->adcode,
|
||||
'name' => $d3->name,
|
||||
'center' => $d3->center,
|
||||
'level' => $d3->level,
|
||||
'parent_id' => $city->id
|
||||
]);
|
||||
if (isset($d3->districts) && !empty($d3->districts)){
|
||||
foreach ($d3->districts as $d4){
|
||||
//插入乡镇
|
||||
$zhen = \App\Models\District::create([
|
||||
'adcode' => $d4->adcode,
|
||||
'name' => $d4->name,
|
||||
'center' => $d4->center,
|
||||
'level' => $d4->level,
|
||||
'parent_id' => $qu->id
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,227 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Seeder;
|
||||
|
||||
class PbxSeeder extends Seeder
|
||||
{
|
||||
/**
|
||||
* Run the database seeds.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
//清空表
|
||||
\Illuminate\Support\Facades\DB::statement('SET FOREIGN_KEY_CHECKS=0;');
|
||||
\App\Models\Action::truncate();
|
||||
\App\Models\Condition::truncate();
|
||||
\App\Models\Extension::truncate();
|
||||
\Illuminate\Support\Facades\DB::statement('SET FOREIGN_KEY_CHECKS=1;');
|
||||
|
||||
//拨号计划
|
||||
$data = [
|
||||
[
|
||||
'display_name' => '本地分机互拨',
|
||||
'name' => 'Local_Extension',
|
||||
'context' => 'default',
|
||||
'sort' => 0,
|
||||
'conditions' => [
|
||||
[
|
||||
'display_name' => '规则一',
|
||||
'field' => 'destination_number',
|
||||
'expression' => '^(\d{5,9})$',
|
||||
'break' => 'on-false',
|
||||
'sort' => 0,
|
||||
'actions' => [
|
||||
[
|
||||
'display_name' => '系统应答',
|
||||
'application' => 'answer',
|
||||
'data' => null,
|
||||
'sort' => 0,
|
||||
],
|
||||
[
|
||||
'display_name' => '媒体绕过',
|
||||
'application' => 'set',
|
||||
'data' => 'bypass_media=true',
|
||||
'sort' => 1,
|
||||
],
|
||||
[
|
||||
'display_name' => '被叫挂断后主叫也挂断',
|
||||
'application' => 'set',
|
||||
'data' => 'hangup_after_bridge=true',
|
||||
'sort' => 2,
|
||||
],
|
||||
[
|
||||
'display_name' => '呼叫',
|
||||
'application' => 'bridge',
|
||||
'data' => 'user/$1',
|
||||
'sort' => 3,
|
||||
],
|
||||
]
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'display_name' => '回音测试',
|
||||
'name' => 'echo_test',
|
||||
'context' => 'default',
|
||||
'sort' => 1,
|
||||
'conditions' => [
|
||||
[
|
||||
'display_name' => '规则一',
|
||||
'field' => 'destination_number',
|
||||
'expression' => '^9996$',
|
||||
'break' => 'on-false',
|
||||
'sort' => 0,
|
||||
'actions' => [
|
||||
[
|
||||
'display_name' => '系统应答',
|
||||
'application' => 'answer',
|
||||
'data' => null,
|
||||
'sort' => 0,
|
||||
],
|
||||
[
|
||||
'display_name' => '回音',
|
||||
'application' => 'echo',
|
||||
'data' => null,
|
||||
'sort' => 1,
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'display_name' => '控制台显示info',
|
||||
'name' => 'info_test',
|
||||
'context' => 'default',
|
||||
'sort' => 1,
|
||||
'conditions' => [
|
||||
[
|
||||
'display_name' => '规则一',
|
||||
'field' => 'destination_number',
|
||||
'expression' => '^9992$',
|
||||
'break' => 'on-false',
|
||||
'sort' => 0,
|
||||
'actions' => [
|
||||
[
|
||||
'display_name' => '系统应答',
|
||||
'application' => 'answer',
|
||||
'data' => null,
|
||||
'sort' => 0,
|
||||
],
|
||||
[
|
||||
'display_name' => '输出信息',
|
||||
'application' => 'info',
|
||||
'data' => null,
|
||||
'sort' => 1,
|
||||
],
|
||||
[
|
||||
'display_name' => '挂断',
|
||||
'application' => 'hangup',
|
||||
'data' => null,
|
||||
'sort' => 2,
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'display_name' => '内线拨打外线电话',
|
||||
'name' => 'internal_to_external',
|
||||
'context' => 'default',
|
||||
'sort' => 1,
|
||||
'conditions' => [
|
||||
[
|
||||
'display_name' => '规则一',
|
||||
'field' => 'destination_number',
|
||||
'expression' => '^(\d{11})$',
|
||||
'break' => 'on-false',
|
||||
'sort' => 0,
|
||||
'actions' => [
|
||||
[
|
||||
'display_name' => '系统应答',
|
||||
'application' => 'answer',
|
||||
'data' => null,
|
||||
'sort' => 0,
|
||||
],
|
||||
[
|
||||
'display_name' => '主叫随被叫一起挂断',
|
||||
'application' => 'set',
|
||||
'data' => 'hangup_after_bridge=true',
|
||||
'sort' => 1,
|
||||
],
|
||||
[
|
||||
'display_name' => '设置录音文件',
|
||||
'application' => 'set',
|
||||
'data' => 'sofia_record_file=$${base_dir}/var/lib/freeswitch/recordings/${strftime(%Y)}/${strftime(%m)}/${strftime(%d)}/${strftime(%Y-%m-%d-%H-%M-%S)}_${destination_number}_${caller_id_number}.wav',
|
||||
'sort' => 2,
|
||||
],
|
||||
[
|
||||
'display_name' => '接通后才进行录音',
|
||||
'application' => 'set',
|
||||
'data' => 'media_bug_answer_req=true',
|
||||
'sort' => 3,
|
||||
],
|
||||
[
|
||||
'display_name' => '最小录音时间',
|
||||
'application' => 'set',
|
||||
'data' => 'RECORD_MIN_SEC=3',
|
||||
'sort' => 4,
|
||||
],
|
||||
[
|
||||
'display_name' => '立体声',
|
||||
'application' => 'set',
|
||||
'data' => 'RECORD_STEREO=true',
|
||||
'sort' => 5,
|
||||
],
|
||||
[
|
||||
'display_name' => '录音',
|
||||
'application' => 'record_session',
|
||||
'data' => '${sofia_record_file}',
|
||||
'sort' => 6,
|
||||
],
|
||||
[
|
||||
'display_name' => '呼叫',
|
||||
'application' => 'bridge',
|
||||
'data' => '{outbound_caller_id=900013}sofia/gateway/900013/$1',
|
||||
'sort' => 7,
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
foreach ($data as $d1){
|
||||
$extension = \App\Models\Extension::create([
|
||||
'display_name' => $d1['display_name'],
|
||||
'name' => $d1['name'],
|
||||
'context' => $d1['context'],
|
||||
'sort' => $d1['sort'],
|
||||
]);
|
||||
if (isset($d1['conditions'])&&!empty($d1['conditions'])){
|
||||
foreach ($d1['conditions'] as $d2){
|
||||
$condition = \App\Models\Condition::create([
|
||||
'display_name' => $d2['display_name'],
|
||||
'field' => $d2['field'],
|
||||
'expression' => $d2['expression'],
|
||||
'break' => $d2['break'],
|
||||
'sort' => $d2['sort'],
|
||||
'extension_id' => $extension->id,
|
||||
]);
|
||||
if (isset($d2['actions'])&&!empty($d2['actions'])){
|
||||
foreach ($d2['actions'] as $d3){
|
||||
\App\Models\Action::create([
|
||||
'display_name' => $d3['display_name'],
|
||||
'application' => $d3['application'],
|
||||
'data' => $d3['data'],
|
||||
'sort' => $d3['sort'],
|
||||
'condition_id' => $condition->id,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -117,6 +117,158 @@ class UserSeeder extends Seeder
|
|||
],
|
||||
]
|
||||
],
|
||||
[
|
||||
'name' => 'pbx.manage',
|
||||
'display_name' => '平台管理',
|
||||
'route' => '',
|
||||
'icon' => 'layui-icon-fonts-strong',
|
||||
'child' => [
|
||||
[
|
||||
'name' => 'pbx.merchant',
|
||||
'display_name' => '商户管理',
|
||||
'route' => 'admin.merchant',
|
||||
'child' => [
|
||||
['name' => 'pbx.merchant.create', 'display_name' => '添加','route'=>'admin.merchant.create'],
|
||||
['name' => 'pbx.merchant.edit', 'display_name' => '编辑','route'=>'admin.merchant.edit'],
|
||||
['name' => 'pbx.merchant.destroy', 'display_name' => '删除','route'=>'admin.merchant.destroy'],
|
||||
['name' => 'pbx.merchant.gateway', 'display_name' => '分配网关','route'=>'admin.merchant.gateway'],
|
||||
]
|
||||
],
|
||||
[
|
||||
'name' => 'pbx.bill',
|
||||
'display_name' => '帐单管理',
|
||||
'route' => 'admin.bill',
|
||||
'child' => [
|
||||
['name' => 'pbx.bill.create', 'display_name' => '添加','route'=>'admin.bill.create'],
|
||||
]
|
||||
],
|
||||
[
|
||||
'name' => 'pbx.sip',
|
||||
'display_name' => '分机管理',
|
||||
'route' => 'admin.sip',
|
||||
'child' => [
|
||||
['name' => 'pbx.sip.create', 'display_name' => '添加','route'=>'admin.sip.create'],
|
||||
['name' => 'pbx.sip.create_list', 'display_name' => '批量添加','route'=>'admin.sip.create_list'],
|
||||
['name' => 'pbx.sip.edit', 'display_name' => '编辑','route'=>'admin.sip.edit'],
|
||||
['name' => 'pbx.sip.destroy', 'display_name' => '删除','route'=>'admin.sip.destroy'],
|
||||
]
|
||||
],
|
||||
[
|
||||
'name' => 'pbx.gateway',
|
||||
'display_name' => '网关管理',
|
||||
'route' => 'admin.gateway',
|
||||
'child' => [
|
||||
['name' => 'pbx.gateway.create', 'display_name' => '添加','route'=>'admin.gateway.create'],
|
||||
['name' => 'pbx.gateway.edit', 'display_name' => '编辑','route'=>'admin.gateway.edit'],
|
||||
['name' => 'pbx.gateway.destroy', 'display_name' => '删除','route'=>'admin.gateway.destroy'],
|
||||
['name' => 'pbx.gateway.updateXml', 'display_name' => '更新配置','route'=>'admin.gateway.updateXml'],
|
||||
]
|
||||
],
|
||||
[
|
||||
'name' => 'pbx.extension',
|
||||
'display_name' => '拨号计划',
|
||||
'route' => 'admin.extension',
|
||||
'child' => [
|
||||
['name' => 'pbx.extension.show', 'display_name' => '详情','route'=>'admin.extension.show'],
|
||||
['name' => 'pbx.extension.create', 'display_name' => '添加','route'=>'admin.extension.create'],
|
||||
['name' => 'pbx.extension.edit', 'display_name' => '编辑','route'=>'admin.extension.edit'],
|
||||
['name' => 'pbx.extension.destroy', 'display_name' => '删除','route'=>'admin.extension.destroy'],
|
||||
]
|
||||
],
|
||||
[
|
||||
'name' => 'pbx.queue',
|
||||
'display_name' => '队列管理',
|
||||
'route' => 'admin.queue',
|
||||
'child' => [
|
||||
['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'],
|
||||
['name' => 'pbx.queue.updateXml', 'display_name' => '更新配置','route'=>'admin.queue.updateXml'],
|
||||
['name' => 'pbx.queue.agent', 'display_name' => '分配坐席','route'=>'admin.queue.agent'],
|
||||
['name' => 'pbx.queue.agentStatus', 'display_name' => '坐席状态','route'=>'admin.queue.agentStatus'],
|
||||
]
|
||||
],
|
||||
[
|
||||
'name' => 'pbx.agent',
|
||||
'display_name' => '坐席管理',
|
||||
'route' => 'admin.agent',
|
||||
'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'],
|
||||
]
|
||||
],
|
||||
[
|
||||
'name' => 'pbx.ivr',
|
||||
'display_name' => 'IVR管理',
|
||||
'route' => 'admin.ivr',
|
||||
'child' => [
|
||||
['name' => 'pbx.ivr.create', 'display_name' => '添加','route'=>'admin.ivr.create'],
|
||||
['name' => 'pbx.ivr.edit', 'display_name' => '编辑','route'=>'admin.ivr.edit'],
|
||||
['name' => 'pbx.ivr.destroy', 'display_name' => '删除','route'=>'admin.ivr.destroy'],
|
||||
['name' => 'pbx.ivr.updateXml', 'display_name' => '更新配置','route'=>'admin.ivr.updateXml'],
|
||||
]
|
||||
],
|
||||
[
|
||||
'name' => 'pbx.digits',
|
||||
'display_name' => '按键管理',
|
||||
'route' => 'admin.digits',
|
||||
'child' => [
|
||||
['name' => 'pbx.digits.create', 'display_name' => '添加','route'=>'admin.digits.create'],
|
||||
['name' => 'pbx.digits.edit', 'display_name' => '编辑','route'=>'admin.digits.edit'],
|
||||
['name' => 'pbx.digits.destroy', 'display_name' => '删除','route'=>'admin.digits.destroy'],
|
||||
]
|
||||
],
|
||||
[
|
||||
'name' => 'pbx.audio',
|
||||
'display_name' => '音频管理',
|
||||
'route' => 'admin.audio',
|
||||
'child' => [
|
||||
['name' => 'pbx.audio.create', 'display_name' => '添加','route'=>'admin.audio.create'],
|
||||
['name' => 'pbx.audio.destroy', 'display_name' => '删除','route'=>'admin.audio.destroy'],
|
||||
]
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'record.manage',
|
||||
'display_name' => '录音管理',
|
||||
'route' => '',
|
||||
'icon' => 'layui-icon-theme',
|
||||
'child' => [
|
||||
[
|
||||
'name' => 'record.cdr',
|
||||
'display_name' => 'CDR录音',
|
||||
'route' => 'admin.cdr',
|
||||
'child' => [
|
||||
['name' => 'pbx.cdr.show', 'display_name' => '通话详单','route'=>'admin.cdr.show'],
|
||||
['name' => 'pbx.cdr.play', 'display_name' => '播放','route'=>'admin.cdr.play'],
|
||||
['name' => 'pbx.cdr.download', 'display_name' => '下载','route'=>'admin.cdr.download'],
|
||||
]
|
||||
],
|
||||
]
|
||||
],
|
||||
[
|
||||
'name' => 'ai.manage',
|
||||
'display_name' => '批量外呼',
|
||||
'route' => '',
|
||||
'icon' => 'layui-icon-carousel',
|
||||
'child' => [
|
||||
[
|
||||
'name' => 'ai.task',
|
||||
'display_name' => '任务管理',
|
||||
'route' => 'admin.task',
|
||||
'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'],
|
||||
]
|
||||
],
|
||||
]
|
||||
],
|
||||
[
|
||||
'name' => 'information',
|
||||
'display_name' => '资讯管理',
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,209 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||
<script src="js/jquery.js" type="text/javascript"></script>
|
||||
<script src="js/sip.js" type="text/javascript"></script>
|
||||
</head>
|
||||
<body>
|
||||
<video id="remoteVideo" name="remoteVideo" style=" background:#0C6"></video>
|
||||
<video id="localVideo" name="localVideo" muted="muted" style="background:#f00"></video>
|
||||
<br>
|
||||
<input type="input" id='number' placeholder="number">
|
||||
<input type="checkbox" id="autopickup" name="autopickup" value="1" />自动接听
|
||||
<br>
|
||||
<input type="button" onClick="callphone()" id='ringout' value="拨号">
|
||||
<input type="button" onClick="acceptphone()" id='acceptphone' value="接听">
|
||||
<input type="button" onClick="hangup()" id='hangup' value="挂机">
|
||||
<input type="button" onClick="hold()" id='hold' value="保持"><br>
|
||||
<br>
|
||||
<input type="number" id='dtmf' placeholder="dtmf"><br>
|
||||
<input type="button" onClick="senddtmf()" value="send dtmf"><br>
|
||||
<br>
|
||||
<div style="background:#0C6;width:100%; height:20px;">注册状态:<span id='state'>已断开</span></div>
|
||||
<div style="background:#0ff;width:100%; height:20px;">呼叫状态:<span id='state0'></span></div>
|
||||
<div style="background:#fC6;width:100%; overflow:visible">对端状态:<span id='state2'></span></div>
|
||||
<div style="background:#cc0;width:100%; overflow:visible">本端状态:<span id='state3'></span></div>
|
||||
<div id="play" style="display:none"></div>
|
||||
|
||||
<script type="text/javascript">
|
||||
var userAgentSession;
|
||||
var holdstate = false;
|
||||
var userAgent = new SIP.UA({
|
||||
uri: '1003@call.dgg188.cn',
|
||||
wsServers: ['wss://call.dgg188.cn:7443'],
|
||||
authorizationUser: '1003',
|
||||
password: 'dgg123456',
|
||||
hackIpInContact: true,
|
||||
rtcpMuxPolicy: 'negotiate',
|
||||
hackWssInTransport: true
|
||||
});
|
||||
//注册成功
|
||||
userAgent.on('registered', function () {
|
||||
$('#state').text('已连接');
|
||||
});
|
||||
//未注册成功
|
||||
userAgent.on('unregistered', function () {
|
||||
$('#state').text('已断开');
|
||||
});
|
||||
//监听来电
|
||||
userAgent.on('invite', function (session) {
|
||||
userAgentSession = session;
|
||||
userAgentSession.on('bye', function (request) {//挂机
|
||||
$('#state0').html('bye:');
|
||||
});
|
||||
userAgentSession.on('terminated', function (message, cause) {//结束
|
||||
$('#state0').html('terminated:' + message + '|cause:' + cause);
|
||||
});
|
||||
play('ringin', 'start');
|
||||
alert('来电事件');
|
||||
if ($('#autopickup').is(':checked')) {
|
||||
acceptphone();
|
||||
}
|
||||
});
|
||||
//监听是否接了电话
|
||||
userAgent.on('accepted', function (data) {
|
||||
$('#state3').text('accepted:' + data);
|
||||
});
|
||||
//监听拒接
|
||||
userAgent.on('rejected', function (response, cause) {
|
||||
$('#state3').text('rejected:' + response + '|cause:' + cause);
|
||||
});
|
||||
//监听拨号
|
||||
userAgent.on('progress', function (response) {
|
||||
$('#state3').text('progress:' + response);
|
||||
});
|
||||
//错误
|
||||
userAgent.on('failed', function (response, cause) {
|
||||
$('#state3').text('failed:' + response + '|cause:' + cause);
|
||||
});
|
||||
//监听结束
|
||||
userAgent.on('ended', function (response, cause) {
|
||||
$('#state3').text('ended:' + response + '|cause:' + cause);
|
||||
});
|
||||
//播放音乐
|
||||
function play(type, action) {
|
||||
if (action == 'start') {
|
||||
if (type == 'ringin') {
|
||||
audio = 'ringin.wav';
|
||||
loop = ' loop="loop"';
|
||||
} else if (type == 'ringout') {
|
||||
audio = 'ringout.wav';
|
||||
loop = ' loop="loop"';
|
||||
} else if (type == 'hangup') {
|
||||
audio = 'hangup.wav';
|
||||
loop = '';
|
||||
}
|
||||
if (type != '') {
|
||||
$('#play').html('<audio autoplay="autoplay" ' + loop + '><source src="audio/' + audio + '"'
|
||||
+ 'type="audio/wav"/><source src="audio/' + audio + '" type="audio/mpeg"/></audio>');
|
||||
}
|
||||
} else if (action == 'end') {
|
||||
$('#play').html('');
|
||||
}
|
||||
}
|
||||
//接听来电
|
||||
function acceptphone() {
|
||||
userAgentSession.accept({
|
||||
media: {
|
||||
render: {
|
||||
remote: document.getElementById('remoteVideo'),
|
||||
local: document.getElementById('localVideo')
|
||||
},
|
||||
constraints: {
|
||||
audio: true,
|
||||
video: false
|
||||
}
|
||||
}
|
||||
});
|
||||
play('ringin', 'end');
|
||||
alert('摘机事件');
|
||||
}
|
||||
//发送dtmf
|
||||
function senddtmf() {
|
||||
var dtmf = $('#dtmf').val();
|
||||
if (dtmf){
|
||||
userAgentSession.dtmf(dtmf);
|
||||
}
|
||||
}
|
||||
//挂机
|
||||
function hangup() {
|
||||
play('hangup', 'start');
|
||||
userAgentSession.terminate();
|
||||
play('hangup', 'end');
|
||||
alert('挂机事件');
|
||||
}
|
||||
//呼叫保持
|
||||
function hold() {
|
||||
if (holdstate) {
|
||||
holdstate = false;
|
||||
userAgentSession.unhold();
|
||||
} else {
|
||||
userAgentSession = true;
|
||||
sss.hold();
|
||||
}
|
||||
}
|
||||
//拨打电话,呼出
|
||||
function callphone() {
|
||||
var phone = $('#number').val();
|
||||
if (!phone) return false;
|
||||
var options = {
|
||||
media: {
|
||||
constraints: {
|
||||
audio: true,
|
||||
video: false
|
||||
},
|
||||
render: {
|
||||
remote: document.getElementById('remoteVideo'),
|
||||
local: document.getElementById('localVideo')
|
||||
}
|
||||
}
|
||||
};
|
||||
userAgentSession = userAgent.invite('sip:' + phone + '@call.dgg188.cn', options);
|
||||
//接听
|
||||
userAgentSession.on('accepted', function (data) {
|
||||
$('#state0').html('接听');
|
||||
});
|
||||
//取消呼叫
|
||||
userAgentSession.on('cancel', function () {
|
||||
$('#state0').html('取消呼叫');
|
||||
});
|
||||
//呼叫失败
|
||||
userAgentSession.on('failed', function (response, cause) {
|
||||
$('#state0').html('呼叫失败');
|
||||
});
|
||||
//无法接通
|
||||
userAgentSession.on('rejected', function (response, cause) {
|
||||
$('#state0').html('无法接通');
|
||||
});
|
||||
//挂机
|
||||
userAgentSession.on('bye', function (request) {
|
||||
$('#state0').html('挂机');
|
||||
});
|
||||
//结束
|
||||
userAgentSession.on('terminated', function (message, cause) {
|
||||
$('#state0').html('结束');
|
||||
});
|
||||
//拨号中
|
||||
userAgentSession.on('progress', function (response) {
|
||||
$('#state0').html('拨号中');
|
||||
if (response.status_code === 183 && response.body && this.hasOffer && !this.dialog) {
|
||||
if (!response.hasHeader('require') || response.getHeader('require').indexOf('100rel') === -1) {
|
||||
if (this.mediaHandler.hasDescription(response)) {
|
||||
if (!this.createDialog(response, 'UAC')) return;
|
||||
this.hasAnswer = true;
|
||||
this.dialog.pracked.push(response.getHeader('rseq'));
|
||||
this.status = 11;
|
||||
this.mute();
|
||||
this.mediaHandler.setDescription(response).catch((reason) => {
|
||||
this.logger.warn(reason);
|
||||
this.failed(response, C.causes.BAD_MEDIA_DESCRIPTION);
|
||||
this.terminate({status_code: 488, reason_phrase: 'Bad Media Description'});
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,78 @@
|
|||
{{csrf_field()}}
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">坐席名称</label>
|
||||
<div class="layui-input-inline">
|
||||
<input class="layui-input" type="text" name="display_name" lay-verify="required" value="{{$model->display_name??old('display_name')}}" placeholder="请输入坐席名称">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">坐席号码</label>
|
||||
<div class="layui-input-inline">
|
||||
<input class="layui-input" type="text" maxlength="4" name="name" lay-verify="required|number" value="{{$model->name??old('name')}}" placeholder="坐席号码">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">请输入坐席号码,7000-7999</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)&&$k=='Available') || (isset($model->status)&&$model->status==$k) ) checked @endif >
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">呼叫类型</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="originate_type" value="user" title="分机" @if( !isset($model->originate_type) || (isset($model->originate_type)&&$model->originate_type=='user') ) checked @endif >
|
||||
<input type="radio" name="originate_type" value="group" title="分机组" @if(isset($model->originate_type)&&$model->originate_type=='group') checked @endif >
|
||||
<input type="radio" name="originate_type" value="gateway" title="网关" @if(isset($model->originate_type)&&$model->originate_type=='gateway') checked @endif >
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">呼叫号码</label>
|
||||
<div class="layui-input-inline">
|
||||
<input class="layui-input" type="text" name="originate_number" lay-verify="required" value="{{$model->originate_number??old('originate_number')}}" placeholder="">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">分机号码 / 分机组标识 / 网关呼出 ,与类型对应</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">无应答数</label>
|
||||
<div class="layui-input-inline">
|
||||
<input class="layui-input" type="text" name="max_no_answer" lay-verify="required|number" value="{{$model->max_no_answer??3}}" placeholder="">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">最大无应答次数,超过次数将不再分配话务</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">通话间隔</label>
|
||||
<div class="layui-input-inline">
|
||||
<input class="layui-input" type="text" name="wrap_up_time" lay-verify="required|number" value="{{$model->wrap_up_time??1}}" placeholder="">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">通话完成间隔时间,成功处理一个通话后,多久才会有电话进入等待时长</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">挂机间隔</label>
|
||||
<div class="layui-input-inline">
|
||||
<input class="layui-input" type="text" name="reject_delay_time" lay-verify="required|number" value="{{$model->reject_delay_time??1}}" placeholder="">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">挂机间隔时间,来电拒接后多久才会有电话进入的等待时长</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">繁忙间隔</label>
|
||||
<div class="layui-input-inline">
|
||||
<input class="layui-input" type="text" name="busy_delay_time" lay-verify="required|number" value="{{$model->busy_delay_time??1}}" placeholder="">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">忙重试间隔时间,来电遇忙后多久才会有电话进入的等待时长</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">未接间隔</label>
|
||||
<div class="layui-input-inline">
|
||||
<input class="layui-input" type="text" name="no_answer_delay_time" lay-verify="required|number" value="{{$model->no_answer_delay_time??1}}" placeholder="">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">无应答重试间隔,来电无应答后多久才会有电话进入的等待时长</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,101 @@
|
|||
@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: 'display_name', title: '坐席名称'}
|
||||
,{field: 'name', title: '坐席号码'}
|
||||
,{field: 'originate_type_name', title: '呼叫类型'}
|
||||
,{field: 'originate_number', title: '呼叫号码'}
|
||||
,{field: 'status_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
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
@extends('admin.base')
|
||||
|
||||
@section('content')
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header layuiadmin-card-header-auto">
|
||||
<form class="layui-form">
|
||||
<div class="layui-form-item">
|
||||
<textarea name="text" class="layui-textarea" placeholder="请输入要合成的文本"></textarea>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<button lay-submit lay-filter="tts" class="layui-btn">合成</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<table id="dataTable" lay-filter="dataTable"></table>
|
||||
<script type="text/html" id="options">
|
||||
<div class="layui-btn-group">
|
||||
@can('pbx.audio.destroy')
|
||||
<a class="layui-btn layui-btn-danger layui-btn-sm " lay-event="del">删除</a>
|
||||
@endcan
|
||||
</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.audio.data') }}" //数据接口
|
||||
,page: true //开启分页
|
||||
,cols: [[ //表头
|
||||
{checkbox: true,fixed: true}
|
||||
//,{field: 'id', title: 'ID', sort: true,width:80}
|
||||
,{field: 'text', title: '文本'}
|
||||
,{field: 'url', title: '地址'}
|
||||
,{field: 'auf', title: '采样率'}
|
||||
,{field: 'aue', title: '编码'}
|
||||
,{field: 'voice_name', title: '发音人'}
|
||||
,{field: 'speed', title: '语速'}
|
||||
,{field: 'volume', title: '音量'}
|
||||
,{field: 'pitch', title: '音高'}
|
||||
,{field: 'engine_type', 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.audio.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})
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
//提交
|
||||
form.on('submit(tts)', function (data) {
|
||||
layer.load();
|
||||
parms = data.field;
|
||||
parms['_token'] = "{{csrf_token()}}";
|
||||
$.post("{{route('admin.audio.store')}}",parms,function (res) {
|
||||
layer.closeAll('loading');
|
||||
if (res.code==0){
|
||||
layer.msg(res.msg,{icon:6},function () {
|
||||
dataTable.reload({
|
||||
page:{curr:1}
|
||||
});
|
||||
})
|
||||
} else {
|
||||
layer.msg(res.msg,{icon:5})
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
})
|
||||
</script>
|
||||
@endsection
|
||||
|
|
@ -31,7 +31,7 @@
|
|||
base: '/static/admin/layuiadmin/' //静态资源所在路径
|
||||
}).extend({
|
||||
index: 'lib/index' //主入口模块
|
||||
}).use(['layer'],function () {
|
||||
}).use(['layer','jquery'],function () {
|
||||
var $ = layui.jquery;
|
||||
var layer = layui.layer;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,100 @@
|
|||
@extends('admin.base')
|
||||
|
||||
@section('content')
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header layuiadmin-card-header-auto">
|
||||
<form class="layui-form">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<label for="" class="layui-form-label">商家</label>
|
||||
<div class="layui-input-inline">
|
||||
<select name="merchant_id">
|
||||
<option value="">请选择</option>
|
||||
@foreach($merchants as $merchant)
|
||||
<option value="{{$merchant->id}}">{{$merchant->username}}({{$merchant->company_name}})</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<label for="" class="layui-form-label">类型</label>
|
||||
<div class="layui-input-inline" style="width: 100px;">
|
||||
<select name="type">
|
||||
<option value="">请选择</option>
|
||||
<option value="1">增加</option>
|
||||
<option value="2">减少</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<label for="" class="layui-form-label">时间</label>
|
||||
<div class="layui-input-inline" style="width: 150px">
|
||||
<input type="text" name="created_at_start" id="created_at_start" placeholder="开始时间" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">-</div>
|
||||
<div class="layui-input-inline" style="width: 150px">
|
||||
<input type="text" name="created_at_end" id="created_at_end" placeholder="结束时间" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<div class="layui-input-inline" style="width: 100px">
|
||||
<button class="layui-btn" lay-submit lay-filter="search" >搜 索</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<table id="dataTable" lay-filter="dataTable"></table>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@section('script')
|
||||
<script>
|
||||
layui.use(['layer','table','form','element','laydate'],function () {
|
||||
var layer = layui.layer;
|
||||
var form = layui.form;
|
||||
var table = layui.table;
|
||||
var laydate = layui.laydate;
|
||||
|
||||
//用户表格初始化
|
||||
var dataTable = table.render({
|
||||
elem: '#dataTable'
|
||||
,height: 500
|
||||
,url: "{{ route('admin.bill.data') }}"
|
||||
,page: true //开启分页
|
||||
,cols: [[ //表头
|
||||
{checkbox: true,fixed: true}
|
||||
,{field: 'id', title: 'ID', sort: true,width:80}
|
||||
,{field: 'company_name', title: '公司名称', templet:function (d) {
|
||||
return d.merchant.company_name;
|
||||
}}
|
||||
,{field: 'username', title: '商家帐号', templet:function (d) {
|
||||
return d.merchant.username;
|
||||
}}
|
||||
,{field: 'type', title: '类型', width: 80, templet:function (d) {
|
||||
return d.type==1?'<span class="layui-badge layui-bg-green">增加</span>':'<span class="layui-badge layui-bg-cyan">减少</span>';
|
||||
}}
|
||||
,{field: 'money', title: '金额'}
|
||||
,{field: 'remark', title: '备注'}
|
||||
,{field: 'created_user_name', title: '创建人'}
|
||||
,{field: 'created_at', title: '时间'}
|
||||
]]
|
||||
});
|
||||
//时间选择
|
||||
laydate.render({elem:'#created_at_start',type:'datetime'})
|
||||
laydate.render({elem:'#created_at_end',type:'datetime'})
|
||||
//搜索
|
||||
form.on('submit(search)', function (data) {
|
||||
parms = data.field;
|
||||
dataTable.reload({
|
||||
where:parms,
|
||||
page:{curr:1}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
})
|
||||
</script>
|
||||
@endsection
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
@extends('admin.base')
|
||||
|
||||
@section('content')
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">
|
||||
<span class="layui-bg-cyan">通话详单需要开启语音识别事件监听!!!</span>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<table class="layui-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>UUID</th>
|
||||
<th>内容</th>
|
||||
<th>时间</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse($record as $v)
|
||||
<tr>
|
||||
<td>{{$v->uuid}}</td>
|
||||
<td>{{$v->text}}</td>
|
||||
<td>{{$v->created_at}}</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr><td colspan="3" align="center">暂无数据</td></tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@section('script')
|
||||
<script>
|
||||
layui.use(['layer','table','form','laydate'],function () {
|
||||
var layer = layui.layer;
|
||||
var form = layui.form;
|
||||
var table = layui.table;
|
||||
var laydate = layui.laydate;
|
||||
|
||||
})
|
||||
</script>
|
||||
@endsection
|
||||
|
|
@ -0,0 +1,128 @@
|
|||
@extends('admin.base')
|
||||
|
||||
@section('content')
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header layuiadmin-card-header-auto">
|
||||
<form class="layui-form">
|
||||
<button class="layui-btn layui-btn-sm" lay-submit lay-filter="*" >搜索</button>
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<label for="" class="layui-form-label">主叫号码</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="caller_id_number" class="layui-input" placeholder="主叫号码">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<label for="" class="layui-form-label">被叫号码</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="destination_number" class="layui-input" placeholder="被叫号码">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<label for="" class="layui-form-label">呼叫时间</label>
|
||||
<div class="layui-input-inline" style="width: 160px">
|
||||
<input type="text" name="start_stamp_start" id="start_stamp_start" class="layui-input" placeholder="开始时间">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">-</div>
|
||||
<div class="layui-input-inline" style="width: 160px">
|
||||
<input type="text" name="start_stamp_end" id="start_stamp_end" class="layui-input" placeholder="结束时间">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<table id="dataTable" lay-filter="dataTable"></table>
|
||||
<script type="text/html" id="options">
|
||||
<div class="layui-btn-group">
|
||||
<a class="layui-btn layui-btn-sm" lay-event="show">通话详单</a>
|
||||
<a class="layui-btn layui-btn-sm" lay-event="play">播放</a>
|
||||
<a class="layui-btn layui-btn-sm" lay-event="download">下载</a>
|
||||
</div>
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@section('script')
|
||||
<script>
|
||||
layui.use(['layer','table','form','laydate'],function () {
|
||||
var layer = layui.layer;
|
||||
var form = layui.form;
|
||||
var table = layui.table;
|
||||
var laydate = layui.laydate;
|
||||
//用户表格初始化
|
||||
var dataTable = table.render({
|
||||
elem: '#dataTable'
|
||||
,height: 500
|
||||
,url: "{{ route('admin.cdr.data') }}" //数据接口
|
||||
,page: true //开启分页
|
||||
,cols: [[ //表头
|
||||
//{checkbox: true,fixed: true}
|
||||
{field: 'id', title: 'ID', sort: true,width:80,fixed:'left'}
|
||||
,{field: 'caller_id_number', title: '主叫号码',width:100, style:'color:green'}
|
||||
,{field: 'destination_number', title: '被叫号码',width:120, style:'color:#2F4056'}
|
||||
,{field: 'start_stamp', title: '呼叫时间', sort: true,width:160}
|
||||
,{field: 'answer_stamp', title: '应答时间', sort: true,width:160}
|
||||
,{field: 'end_stamp', title: '挂断时间', sort: true,width:160}
|
||||
,{field: 'duration', title: '主叫时长(秒)', sort: true, width:120, style:'color:#2F4056'}
|
||||
,{field: 'billsec', title: '被叫时长(秒)', sort: true, width:120, style:'color: green'}
|
||||
,{field: 'hangup_cause', title: '挂断原因', width:200}
|
||||
,{field: 'aleg_uuid', title: '主叫UUID', width:300}
|
||||
,{field: 'bleg_uuid', title: '被叫UUID', width:300}
|
||||
,{field: 'caller_id_name', title: '主叫名称', width:160}
|
||||
,{fixed: 'right', width: 220, align:'center', toolbar: '#options', title:'操作',fixed:'right'}
|
||||
]]
|
||||
});
|
||||
|
||||
//监听工具条
|
||||
table.on('tool(dataTable)', function(obj){ //注:tool是工具条事件名,dataTable是table原始容器的属性 lay-filter="对应的值"
|
||||
var data = obj.data //获得当前行数据
|
||||
,layEvent = obj.event; //获得 lay-event 对应的值
|
||||
if(layEvent === 'show'){
|
||||
layer.open({
|
||||
title : '通话详单',
|
||||
shadeClose : true,
|
||||
type : 2,
|
||||
area : ['800px','600px'],
|
||||
content : '/admin/cdr/'+data.id+'/show'
|
||||
})
|
||||
} else if (layEvent === 'play'){
|
||||
var index = layer.load()
|
||||
$.get('/admin/cdr/'+data.aleg_uuid+'/play',function (res) {
|
||||
layer.close(index);
|
||||
if (res.code==0){
|
||||
var _html = '<div style="padding:20px;">';
|
||||
_html += '<audio controls="controls" autoplay src="'+res.data+'"></audio>';
|
||||
_html += '</div>';
|
||||
layer.open({
|
||||
title : '播放录音',
|
||||
type : 1,
|
||||
area : ['360px','auto'],
|
||||
content : _html
|
||||
})
|
||||
}else {
|
||||
layer.msg(res.msg,{icon:5})
|
||||
}
|
||||
})
|
||||
} else if (layEvent === 'download'){
|
||||
location.href = '/admin/cdr/'+data.aleg_uuid+'/download';
|
||||
}
|
||||
});
|
||||
|
||||
//时间选择
|
||||
laydate.render({type: 'datetime', elem: '#start_stamp_start'});
|
||||
laydate.render({type: 'datetime', elem: '#start_stamp_end'});
|
||||
|
||||
//监听搜索提交
|
||||
form.on('submit(*)', function(data){
|
||||
dataTable.reload({
|
||||
where: data.field,
|
||||
page: {curr:1}
|
||||
})
|
||||
return false;
|
||||
});
|
||||
|
||||
})
|
||||
</script>
|
||||
@endsection
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
{{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="display_name" lay-verify="required" value="{{$model->display_name??old('display_name')}}" placeholder="如:挂断">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">应用</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="application">
|
||||
<option ></option>
|
||||
@foreach(config('freeswitch.application') as $key => $val)
|
||||
<option value="{{$key}}" @if(isset($model->application)&&$model->application==$key) selected @endif >{{$val}}</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="text" name="data" value="{{$model->data??old('data')}}" 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="number" name="sort" lay-verify="required" value="{{$model->sort??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.action',['condition_id'=>$condition->id])}}" 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.action.store',['condition_id'=>$condition->id])}}" method="post" class="layui-form">
|
||||
@include('admin.dialplan.action._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.action.update',['condition_id'=>$condition->id,'id'=>$model->id])}}" method="post" class="layui-form">
|
||||
{{method_field('put')}}
|
||||
@include('admin.dialplan.action._form')
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
@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.action.create',['condition_id'=>$condition->id]) }}">添 加</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.action.data',['condition_id'=>$condition->id]) }}" //数据接口
|
||||
,page: true //开启分页
|
||||
,cols: [[ //表头
|
||||
{checkbox: true,fixed: true}
|
||||
,{field: 'id', title: 'ID', sort: true,width:80}
|
||||
,{field: 'display_name', title: '名称'}
|
||||
,{field: 'application_name', title: '应用'}
|
||||
,{field: 'data', title: '数据'}
|
||||
,{field: 'sort', title: '序号',width:80}
|
||||
,{field: 'created_at', title: '添加时间',width:170}
|
||||
,{fixed: 'right', width: 220, align:'center', toolbar: '#options', title:'操作'}
|
||||
]]
|
||||
});
|
||||
|
||||
//监听工具条
|
||||
table.on('tool(dataTable)', function(obj){ //注:tool是工具条事件名,dataTable是table原始容器的属性 lay-filter="对应的值"
|
||||
var data = obj.data //获得当前行数据
|
||||
,layEvent = obj.event; //获得 lay-event 对应的值
|
||||
if(layEvent === 'del'){
|
||||
layer.confirm('确认删除吗?', function(index){
|
||||
$.post("{{ route('admin.action.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/condition/'+data.condition_id+'/action/'+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.action.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
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
{{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="display_name" lay-verify="required" value="{{$model->display_name??old('display_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="field" lay-verify="required" value="{{$model->field??'destination_number'}}" placeholder="默认:destination_number">
|
||||
</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="expression" lay-verify="required" value="{{$model->expression??old('expression')}}" placeholder="正则表达式">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">break</label>
|
||||
<div class="layui-input-block">
|
||||
<select name="break">
|
||||
<option value="on-false" @if(isset($model->break)&&$model->break=='on-false') selected @endif >on-false</option>
|
||||
<option value="on-true" @if(isset($model->break)&&$model->break=='on-true') selected @endif >on-true</option>
|
||||
<option value="always" @if(isset($model->break)&&$model->break=='always') selected @endif >always</option>
|
||||
<option value="never" @if(isset($model->break)&&$model->break=='never') selected @endif >never</option>
|
||||
</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="sort" lay-verify="required" value="{{$model->sort??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.condition',['extension_id'=>$extension->id])}}" 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.condition.store',['extension_id'=>$extension->id])}}" method="post" class="layui-form">
|
||||
@include('admin.dialplan.condition._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.condition.update',['extension_id'=>$extension->id,'id'=>$model->id])}}" method="post" class="layui-form">
|
||||
{{method_field('put')}}
|
||||
@include('admin.dialplan.condition._form')
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
@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.condition.create',['extension_id'=>$extension->id]) }}">添 加</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-sm" lay-event="action">拨号应用</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.condition.data',['extension_id'=>$extension->id]) }}" //数据接口
|
||||
,page: true //开启分页
|
||||
,cols: [[ //表头
|
||||
{checkbox: true,fixed: true}
|
||||
,{field: 'id', title: 'ID', sort: true,width:80}
|
||||
,{field: 'display_name', title: '名称'}
|
||||
,{field: 'field', title: '字段'}
|
||||
,{field: 'expression', title: '正则'}
|
||||
,{field: 'break', title: 'break'}
|
||||
,{field: 'sort', title: '序号',width:80}
|
||||
,{field: 'created_at', title: '添加时间',width:170}
|
||||
,{fixed: 'right', width: 220, align:'center', toolbar: '#options', title:'操作'}
|
||||
]]
|
||||
});
|
||||
|
||||
//监听工具条
|
||||
table.on('tool(dataTable)', function(obj){ //注:tool是工具条事件名,dataTable是table原始容器的属性 lay-filter="对应的值"
|
||||
var data = obj.data //获得当前行数据
|
||||
,layEvent = obj.event; //获得 lay-event 对应的值
|
||||
if(layEvent === 'del'){
|
||||
layer.confirm('确认删除吗?', function(index){
|
||||
$.post("{{ route('admin.condition.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/extension/'+data.extension_id+'/condition/'+data.id+'/edit';
|
||||
} else if(layEvent === 'action'){
|
||||
newTab('/admin/condition/'+data.id+'/action',data.display_name+' - 拨号应用');
|
||||
}
|
||||
});
|
||||
|
||||
//按钮批量删除
|
||||
$("#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.condition.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
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
{{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="display_name" lay-verify="required" value="{{$model->display_name??old('display_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="name" lay-verify="required" value="{{$model->name??old('name')}}" placeholder="如:local_extension">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">类型</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="context" value="default" title="呼出" @if(!isset($model->context) || $model->context=="default") checked @endif>
|
||||
<input type="radio" name="context" value="public" title="呼入" @if(isset($model->context)&&$model->context=="public") checked @endif>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">continue</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="radio" name="continue" value="false" title="false" @if(!isset($model->continue) || $model->continue=="false") checked @endif>
|
||||
<input type="radio" name="continue" value="true" title="true" @if(isset($model->continue)&&$model->continue=="true") checked @endif >
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">true:表示不管该extension中是否有condition匹配,都继续执行dialplan。false:表示如果该extension中有匹配的condition,那么就停止了dialplan</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="sort" lay-verify="required" value="{{$model->sort??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.extension')}}" 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.extension.store')}}" method="post" class="layui-form">
|
||||
@include('admin.dialplan.extension._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.extension.update',['id'=>$model->id])}}" method="post" class="layui-form">
|
||||
{{method_field('put')}}
|
||||
@include('admin.dialplan.extension._form')
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
@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.extension.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="show">详情</a>
|
||||
<a class="layui-btn layui-btn-sm" lay-event="edit">编辑</a>
|
||||
<a class="layui-btn layui-btn-sm" lay-event="condition">拨号规则</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','jquery'],function () {
|
||||
var $ = layui.jquery;
|
||||
var layer = layui.layer;
|
||||
var form = layui.form;
|
||||
var table = layui.table;
|
||||
//用户表格初始化
|
||||
var dataTable = table.render({
|
||||
elem: '#dataTable'
|
||||
,height: 500
|
||||
,url: "{{ route('admin.extension.data') }}" //数据接口
|
||||
,page: true //开启分页
|
||||
,cols: [[ //表头
|
||||
{checkbox: true,fixed: true}
|
||||
,{field: 'id', title: 'ID', sort: true,width:80}
|
||||
,{field: 'display_name', title: '名称'}
|
||||
,{field: 'name', title: '标识符'}
|
||||
,{field: 'context_name', title: '类型'}
|
||||
,{field: 'continue', title: 'continue'}
|
||||
,{field: 'sort', title: '序号',width:80}
|
||||
,{field: 'created_at', title: '添加时间',width:170}
|
||||
,{fixed: 'right', width: 260, 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.extension.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/extension/'+data.id+'/edit';
|
||||
} else if(layEvent === 'condition'){
|
||||
newTab('/admin/extension/'+data.id+'/condition',data.display_name+' - 拨号规则');
|
||||
} else if(layEvent === 'show'){
|
||||
newTab('/admin/extension/'+data.id+'/show',data.display_name+' - 详情');
|
||||
}
|
||||
});
|
||||
|
||||
//按钮批量删除
|
||||
$("#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.extension.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
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
@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">
|
||||
<table class="layui-table" lay-skin="nob">
|
||||
<tr>
|
||||
@php
|
||||
$tips1 = "名称:".$extension->display_name."<br/>标识符:".$extension->name."<br/>continue:".$extension->continue."<br/>类型:".$extension->context_name;
|
||||
@endphp
|
||||
<td onmouseleave="layer.closeAll()" onmouseenter="layer.tips('{{$tips1}}', this, {tips: 2,time:0});" >
|
||||
<span>{{$extension->display_name}}</span>
|
||||
</td>
|
||||
<td>
|
||||
@if($extension->conditions->isNotEmpty())
|
||||
<table class="layui-table" lay-skin="row">
|
||||
@foreach($extension->conditions as $condition)
|
||||
<tr>
|
||||
@php
|
||||
$tips2 = "名称:".$condition->display_name."<br/>字段:".$condition->field."<br/>正则:".$condition->expression."<br/>break:".$condition->break;
|
||||
@endphp
|
||||
<td onmouseleave="layer.closeAll()" onmouseenter="layer.tips('{{$tips2}}', this, {tips: 4,time:0});" >
|
||||
<span class="layui-badge layui-bg-cyan">{{$condition->sort}}</span>
|
||||
<span>{{$condition->display_name}}</span>
|
||||
</td>
|
||||
<td>
|
||||
@if($condition->actions->isNotEmpty())
|
||||
<table class="layui-table" lay-skin="line">
|
||||
@foreach($condition->actions as $action)
|
||||
<tr>
|
||||
@php
|
||||
$tips3 = "名称:".$action->display_name."<br/>应用:".$action->application_name."<br/>数据:".$action->data;
|
||||
@endphp
|
||||
<td onmouseleave="layer.closeAll()" onmouseenter="layer.tips('{{$tips3}}', this, {tips: 4,time:0});">
|
||||
<span class="layui-badge layui-bg-cyan">{{$action->sort}}</span>
|
||||
<span>{{$action->display_name}}</span>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</table>
|
||||
@endif
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</table>
|
||||
@endif
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
|
@ -0,0 +1,167 @@
|
|||
@extends('admin.base')
|
||||
|
||||
@section('content')
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header layuiadmin-card-header-auto">
|
||||
<form class="layui-form">
|
||||
<div id="digits-box">
|
||||
<div class="layui-form-item">
|
||||
<div class="layui-inline">
|
||||
<label for="" class="layui-form-label">按键</label>
|
||||
<div class="layui-input-inline" style="width: 80px">
|
||||
<input type="number" lay-verify="required|number" class="layui-input digits" placeholder="0-9">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<label for="" class="layui-form-label">应用</label>
|
||||
<div class="layui-input-inline">
|
||||
<select class="action" lay-verify="required">
|
||||
<option value="">请选择</option>
|
||||
<option value="menu-exec-app">应用</option>
|
||||
<option value="mmenu-sub">子菜单</option>
|
||||
<option value="enu-top">父菜单</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<label for="" class="layui-form-label">参数</label>
|
||||
<div class="layui-input-inline">
|
||||
<input type="text" class="layui-input param" placeholder="请输入应用参数">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<button type="button" class="layui-btn layui-btn-primary layui-btn-sm" onclick="digits_add();">增加</button>
|
||||
<button type="button" class="layui-btn layui-btn-primary layui-btn-sm">删除</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<button lay-submit lay-filter="digits-submit" class="layui-btn">确认</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<table id="dataTable" lay-filter="dataTable"></table>
|
||||
<script type="text/html" id="options">
|
||||
<div class="layui-btn-group">
|
||||
@can('pbx.digits.destroy')
|
||||
<a class="layui-btn layui-btn-danger layui-btn-sm " lay-event="del">删除</a>
|
||||
@endcan
|
||||
</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;
|
||||
|
||||
window.digits_add = function() {
|
||||
var _html = '<div class="layui-form-item">\n' +
|
||||
' <div class="layui-inline">\n' +
|
||||
' <label for="" class="layui-form-label">按键</label>\n' +
|
||||
' <div class="layui-input-inline" style="width: 80px">\n' +
|
||||
' <input type="number" lay-verify="required|number" class="layui-input digits" placeholder="0-9">\n' +
|
||||
' </div>\n' +
|
||||
' </div>\n' +
|
||||
' <div class="layui-inline">\n' +
|
||||
' <label for="" class="layui-form-label">应用</label>\n' +
|
||||
' <div class="layui-input-inline">\n' +
|
||||
' <select class="action" lay-verify="required">\n' +
|
||||
' <option value="">请选择</option>\n' +
|
||||
' <option value="menu-exec-app">应用</option>\n' +
|
||||
' <option value="mmenu-sub">子菜单</option>\n' +
|
||||
' <option value="enu-top">父菜单</option>\n' +
|
||||
' </select>\n' +
|
||||
' </div>\n' +
|
||||
' </div>\n' +
|
||||
' <div class="layui-inline">\n' +
|
||||
' <label for="" class="layui-form-label">参数</label>\n' +
|
||||
' <div class="layui-input-inline">\n' +
|
||||
' <input type="text" class="layui-input param" placeholder="请输入应用参数">\n' +
|
||||
' </div>\n' +
|
||||
' </div>\n' +
|
||||
' <div class="layui-inline">\n' +
|
||||
' <button type="button" class="layui-btn layui-btn-primary layui-btn-sm" onclick="digits_add();">增加</button>\n' +
|
||||
' <button type="button" class="layui-btn layui-btn-primary layui-btn-sm" onclick="digits_del(this);">删除</button>\n' +
|
||||
' </div>\n' +
|
||||
' </div>'
|
||||
$("#digits-box").append(_html);
|
||||
form.render();
|
||||
}
|
||||
|
||||
window.digits_del = function (obj) {
|
||||
$(obj).parent().parent('.layui-form-item').remove();
|
||||
}
|
||||
|
||||
//用户表格初始化
|
||||
var dataTable = table.render({
|
||||
elem: '#dataTable'
|
||||
,height: 500
|
||||
,url: "{{ route('admin.digits.data',['ivr_id'=>$ivr_id]) }}" //数据接口
|
||||
,page: true //开启分页
|
||||
,cols: [[ //表头
|
||||
{checkbox: true,fixed: true}
|
||||
//,{field: 'id', title: 'ID', sort: true,width:80}
|
||||
,{field: 'ivr_name', title: 'IVR名称'}
|
||||
,{field: 'digits', title: '按键'}
|
||||
,{field: 'action_name', title: '应用'}
|
||||
,{field: 'param', title: '参数'}
|
||||
,{field: 'created_at', 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.audio.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})
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
//提交
|
||||
form.on('submit(digits-submit)', function (data) {
|
||||
layer.load();
|
||||
var parm = [];
|
||||
$("#digits-box .layui-form-item").each(function (index,elem) {
|
||||
parm[index] = {
|
||||
"digits":$(elem).find(".digits").val(),
|
||||
"action":$(elem).find(".action").val(),
|
||||
"param":$(elem).find(".param").val(),
|
||||
"ivr_id":"{{$ivr_id}}"
|
||||
}
|
||||
})
|
||||
if (parm.length<=0){
|
||||
layer.closeAll('loading');
|
||||
return false;
|
||||
}
|
||||
|
||||
$.post("{{route('admin.digits.store')}}",{parm:parm,_token:"{{csrf_token()}}"},function (res) {
|
||||
layer.closeAll('loading');
|
||||
if (res.code==0){
|
||||
layer.msg(res.msg,{icon:6},function () {
|
||||
location.reload()
|
||||
})
|
||||
} else {
|
||||
layer.msg(res.msg,{icon:5})
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
})
|
||||
</script>
|
||||
@endsection
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
{{csrf_field()}}
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">网关名称</label>
|
||||
<div class="layui-input-inline">
|
||||
<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-inline">
|
||||
<input class="layui-input" type="text" name="realm" lay-verify="required" value="{{$model->realm??old('realm')}}" placeholder="格式:192.168.254.100:5066">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">默认5060端口</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">帐号</label>
|
||||
<div class="layui-input-inline">
|
||||
<input class="layui-input" type="text" name="username" lay-verify="required" value="{{$model->username??old('username')}}" placeholder="如:Job">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">密码</label>
|
||||
<div class="layui-input-inline">
|
||||
<input class="layui-input" type="text" 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-inline">
|
||||
<input class="layui-input" type="text" name="rate" lay-verify="required" value="{{$model->rate??old('rate')}}" placeholder="如:0.01">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">元/分钟</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">前缀</label>
|
||||
<div class="layui-input-inline">
|
||||
<input class="layui-input" type="text" 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-inline">
|
||||
<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>
|
||||
<a href="{{route('admin.gateway')}}" 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.gateway.store')}}" method="post" class="layui-form">
|
||||
@include('admin.gateway._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.gateway.update',['id'=>$model->id])}}" method="post" class="layui-form">
|
||||
{{method_field('put')}}
|
||||
@include('admin.gateway._form')
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
@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.gateway.create') }}">添 加</a>
|
||||
<button class="layui-btn layui-btn-sm" id="updateXml">更新配置</button>
|
||||
</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.gateway.data') }}" //数据接口
|
||||
,page: true //开启分页
|
||||
,cols: [[ //表头
|
||||
{checkbox: true,fixed: true}
|
||||
,{field: 'id', title: 'ID', sort: true,width:80}
|
||||
,{field: 'name', title: '名称'}
|
||||
,{field: 'realm', title: '地址'}
|
||||
,{field: 'username', title: '帐号'}
|
||||
,{field: 'password', title: '密码'}
|
||||
,{field: 'rate', title: '费率(元/分钟)'}
|
||||
,{field: 'prefix', title: '前缀'}
|
||||
,{field: 'outbound_caller_id', title: '出局号码'}
|
||||
,{field: 'created_at', title: '添加时间'}
|
||||
,{fixed: 'right', width: 220, align:'center', toolbar: '#options', title:'操作'}
|
||||
]]
|
||||
});
|
||||
|
||||
//监听工具条
|
||||
table.on('tool(dataTable)', function(obj){ //注:tool是工具条事件名,dataTable是table原始容器的属性 lay-filter="对应的值"
|
||||
var data = obj.data //获得当前行数据
|
||||
,layEvent = obj.event; //获得 lay-event 对应的值
|
||||
if(layEvent === 'del'){
|
||||
layer.confirm('确认删除吗?', function(index){
|
||||
$.post("{{ route('admin.gateway.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/gateway/'+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.gateway.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})
|
||||
}
|
||||
})
|
||||
|
||||
//更新配置
|
||||
$("#updateXml").click(function () {
|
||||
layer.confirm('该操作将重新注册所有网关,确认操作吗?', function(index){
|
||||
$.post("{{ route('admin.gateway.updateXml') }}",{_method:'post',_token:'{{csrf_token()}}'},function (result) {
|
||||
var icon = result.code==0?6:5;
|
||||
layer.msg(result.msg,{icon:icon})
|
||||
});
|
||||
})
|
||||
})
|
||||
})
|
||||
</script>
|
||||
@endsection
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
{{csrf_field()}}
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">显示名称</label>
|
||||
<div class="layui-input-inline">
|
||||
<input class="layui-input" type="text" name="display_name" lay-verify="required" value="{{$model->display_name??old('display_name')}}" placeholder="请输入名称">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">标识</label>
|
||||
<div class="layui-input-inline">
|
||||
<input class="layui-input" type="text" name="name" lay-verify="required" value="{{$model->name??old('name')}}" placeholder="请输入唯一标识,如demo1">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">欢迎音</label>
|
||||
<div class="layui-input-inline">
|
||||
<input class="layui-input" type="text" name="greet_long" lay-verify="required" value="{{$model->greet_long??old('greet_long')}}" placeholder="路径或者在线合成">
|
||||
</div>
|
||||
<div class="layui-word-aux layui-form-mid">首次进入语音导航的欢迎音</div>
|
||||
<div class="layui-input-inline">
|
||||
<button type="button" class="layui-btn tts-btn">在线合成</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">简短提示</label>
|
||||
<div class="layui-input-inline">
|
||||
<input class="layui-input" type="text" name="greet_short" lay-verify="required" value="{{$model->greet_short??old('greet_short')}}" placeholder="路径或者在线合成">
|
||||
</div>
|
||||
<div class="layui-word-aux layui-form-mid">用户长时间没有按键时提示</div>
|
||||
<div class="layui-input-inline">
|
||||
<button type="button" class="layui-btn tts-btn">在线合成</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">超时时间</label>
|
||||
<div class="layui-input-inline">
|
||||
<input class="layui-input" type="text" name="timeout" lay-verify="required" value="{{$model->timeout??10000}}" placeholder="">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">多长时间没有收到按键就超时(毫秒)</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">按键间隔</label>
|
||||
<div class="layui-input-inline">
|
||||
<input class="layui-input" type="number" name="inter_digit_timeout" lay-verify="required|number" value="{{$model->inter_digit_timeout??2000}}" placeholder="">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">两次按键的最大间隔(毫秒)</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">错误次数</label>
|
||||
<div class="layui-input-inline">
|
||||
<input class="layui-input" type="number" name="max_failures" lay-verify="required|number" value="{{$model->max_failures??3}}" placeholder="">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">用户按键错误的次数</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">超时次数</label>
|
||||
<div class="layui-input-inline">
|
||||
<input class="layui-input" type="number" name="max_timeouts" lay-verify="required|number" value="{{$model->max_timeouts??3}}" placeholder="">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">挂机间隔时间,来电拒接后多久才会有电话进入的等待时长</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">按键位数</label>
|
||||
<div class="layui-input-inline">
|
||||
<input class="layui-input" type="number" name="digit_len" lay-verify="required|number" value="{{$model->digit_len??4}}" placeholder="">
|
||||
</div>
|
||||
<div class="layui-form-mid layui-word-aux">菜单项的长度,即最大收号位数</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.ivr')}}" class="layui-btn" >返 回</a>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
<script>
|
||||
layui.use(['layer','table','form'],function () {
|
||||
var layer = layui.layer;
|
||||
var form = layui.form;
|
||||
var table = layui.table;
|
||||
|
||||
$(".tts-btn").click(function () {
|
||||
layer.open({
|
||||
type:2,
|
||||
title:'语音在线合成',
|
||||
area:['80%','80%'],
|
||||
shadeClose:true,
|
||||
content:"{{route('admin.audio')}}"
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
</script>
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
@extends('admin.base')
|
||||
|
||||
@section('content')
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header layuiadmin-card-header-auto">
|
||||
<h2>添加IVR</h2>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<form action="{{route('admin.ivr.store')}}" method="post" class="layui-form">
|
||||
@include('admin.ivr._form')
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@section('script')
|
||||
@include('admin.ivr._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>更新IVR</h2>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<form action="{{route('admin.ivr.update',['id'=>$model->id])}}" method="post" class="layui-form">
|
||||
{{method_field('put')}}
|
||||
@include('admin.ivr._form')
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@section('script')
|
||||
@include('admin.ivr._js')
|
||||
@endsection
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
@extends('admin.base')
|
||||
|
||||
@section('content')
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header layuiadmin-card-header-auto">
|
||||
<div class="layui-btn-group">
|
||||
@can('pbx.ivr.create')
|
||||
<a class="layui-btn layui-btn-sm" href="{{ route('admin.ivr.create') }}">添 加</a>
|
||||
@endcan
|
||||
@can('pbx.ivr.updateXml')
|
||||
<button class="layui-btn layui-btn-sm" id="updateXml" >更新配置</button>
|
||||
@endcan
|
||||
</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="digits">按键</a>
|
||||
@can('pbx.ivr.edit')
|
||||
<a class="layui-btn layui-btn-sm" lay-event="edit">编辑</a>
|
||||
@endcan
|
||||
@can('pbx.ivr.destroy')
|
||||
<a class="layui-btn layui-btn-danger layui-btn-sm " lay-event="del">删除</a>
|
||||
@endcan
|
||||
</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.ivr.data') }}" //数据接口
|
||||
,page: true //开启分页
|
||||
,cols: [[ //表头
|
||||
{checkbox: true,fixed: true}
|
||||
//,{field: 'id', title: 'ID', sort: true,width:80}
|
||||
,{field: 'display_name', title: '名称'}
|
||||
,{field: 'name', title: '标识'}
|
||||
,{field: 'greet_long', title: '欢迎音'}
|
||||
,{field: 'greet_short', title: '简短提示'}
|
||||
,{field: 'timeout', title: '超时时间(毫秒)'}
|
||||
,{field: 'inter_digit_timeout', title: '按键间隔(毫秒)'}
|
||||
,{field: 'max_failures', title: '错误次数'}
|
||||
,{field: 'max_timeouts', title: '超时次数'}
|
||||
,{field: 'digit_len', 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.ivr.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/ivr/'+data.id+'/edit';
|
||||
} else if(layEvent === 'digits'){
|
||||
layer.open({
|
||||
type:2,
|
||||
title:'IVR按键菜单',
|
||||
area:['80%','80%'],
|
||||
shadeClose:true,
|
||||
content:"/admin/digits?ivr_id="+data.id
|
||||
})
|
||||
}
|
||||
});
|
||||
//更新配置
|
||||
$("#updateXml").click(function () {
|
||||
layer.confirm('该操作将重新配置所有IVR,确认操作吗?', function(index){
|
||||
$.post("{{ route('admin.ivr.updateXml') }}",{_method:'post',_token:'{{csrf_token()}}'},function (result) {
|
||||
var icon = result.code==0?6:5;
|
||||
layer.msg(result.msg,{icon:icon})
|
||||
});
|
||||
})
|
||||
})
|
||||
})
|
||||
</script>
|
||||
@endsection
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
{{csrf_field()}}
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">帐号</label>
|
||||
<div class="layui-input-inline">
|
||||
<input class="layui-input" type="text" name="username" lay-verify="required" value="{{$model->username??old('username')}}" placeholder="商家帐号">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">密码</label>
|
||||
<div class="layui-input-inline">
|
||||
<input class="layui-input" type="password" name="password" @if(!isset($model)) lay-verify="required" @endif value="{{old('password')}}" placeholder="商家密码">
|
||||
</div>
|
||||
<div class="layui-word-aux layui-form-mid">不修改则留空</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">公司名称</label>
|
||||
<div class="layui-input-inline">
|
||||
<input class="layui-input" type="text" name="company_name" lay-verify="required" value="{{$model->company_name??old('company_name')}}" placeholder="公司名称">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">分机数量</label>
|
||||
<div class="layui-input-inline">
|
||||
<input class="layui-input" type="number" name="sip_num" lay-verify="required|number" value="{{$model->sip_num??old('sip_num')}}" placeholder="分机数量">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">到期时间</label>
|
||||
<div class="layui-input-inline">
|
||||
<input class="layui-input" type="text" name="expires_at" id="expires_at" lay-verify="required" value="{{$model->expires_at??old('expires_at')}}" placeholder="点击选择" readonly>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label">状态</label>
|
||||
<div class="layui-input-inline">
|
||||
<select name="status" lay-verify="required">
|
||||
<option value="">请选择</option>
|
||||
@foreach(config('freeswitch.merchant_status') as $k=>$v)
|
||||
<option value="{{$k}}" @if(isset($model)&&$model->status==$k) selected @endif >{{$v}}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label for="" class="layui-form-label"></label>
|
||||
<div class="layui-input-inline">
|
||||
<button type="submit" class="layui-btn" lay-submit lay-filter="*" >确 认</button>
|
||||
<a href="{{route('admin.merchant')}}" class="layui-btn" >返 回</a>
|
||||
</div>
|
||||
</div>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue