批量修改与添加

This commit is contained in:
net909 2024-05-10 19:43:52 +08:00
parent d4b7bcfbf6
commit 7a58292fb9
6 changed files with 426 additions and 9 deletions

View File

@ -232,7 +232,8 @@ function getMillisecond()
} }
function getDnsType($value){ function getDnsType($value){
if(filter_var($value, FILTER_VALIDATE_IP))return 'A'; if(filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4))return 'A';
else if(filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6))return 'AAAA';
else return 'CNAME'; else return 'CNAME';
} }

View File

@ -563,6 +563,121 @@ class Domain extends BaseController
return json(['code'=>0, 'msg'=>$msg]); return json(['code'=>0, 'msg'=>$msg]);
} }
public function record_batch_edit(){
$id = input('param.id/d');
$drow = Db::name('domain')->where('id', $id)->find();
if(!$drow){
return json(['code'=>-1, 'msg'=>'域名不存在']);
}
if(!checkPermission(0, $drow['name'])) return $this->alert('error', '无权限');
$action = input('post.action', null, 'trim');
$recordinfo = input('post.recordinfo', null, 'trim');
$recordinfo = json_decode($recordinfo, true);
if($action == 'value'){
$type = input('post.type', null, 'trim');
$value = input('post.value', null, 'trim');
if(empty($recordinfo) || empty($type) || empty($value)){
return json(['code'=>-1, 'msg'=>'参数不能为空']);
}
$dns = DnsHelper::getModel($drow['aid'], $drow['name'], $drow['thirdid']);
$success = 0; $fail = 0;
foreach($recordinfo as $record){
$recordid = $dns->updateDomainRecord($record['recordid'], $record['name'], $type, $value, $record['line'], $record['ttl'], $record['mx'], $record['remark']);
if($recordid){
$this->add_log($drow['name'], '修改解析', $type.'记录 '.$record['name'].' '.$value.' (线路:'.$record['line'].' TTL:'.$record['ttl'].')');
$success++;
}else{
$fail++;
}
}
return json(['code'=>0, 'msg'=>'批量修改解析记录,成功'.$success.'条,失败'.$fail.'条']);
}else if($action == 'line'){
$line = input('post.line', null, 'trim');
if(empty($recordinfo) || empty($line)){
return json(['code'=>-1, 'msg'=>'参数不能为空']);
}
$dns = DnsHelper::getModel($drow['aid'], $drow['name'], $drow['thirdid']);
$success = 0; $fail = 0;
foreach($recordinfo as $record){
$recordid = $dns->updateDomainRecord($record['recordid'], $record['name'], $record['type'], $record['value'], $line, $record['ttl'], $record['mx'], $record['remark']);
if($recordid){
$this->add_log($drow['name'], '修改解析', $record['type'].'记录 '.$record['name'].' '.$record['value'].' (线路:'.$line.' TTL:'.$record['ttl'].')');
$success++;
}else{
$fail++;
}
}
return json(['code'=>0, 'msg'=>'批量修改解析线路,成功'.$success.'条,失败'.$fail.'条']);
}
}
public function record_batch_add(){
$id = input('param.id/d');
$drow = Db::name('domain')->where('id', $id)->find();
if(!$drow){
return $this->alert('error', '域名不存在');
}
$dnstype = Db::name('account')->where('id', $drow['aid'])->value('type');
if(!checkPermission(0, $drow['name'])) return $this->alert('error', '无权限');
if(request()->isAjax()){
$record = input('post.record', null, 'trim');
$type = input('post.type', null, 'trim');
$line = input('post.line', null, 'trim');
$ttl = input('post.ttl/d', 600);
$mx = input('post.mx/d', 1);
$recordlist = explode("\n", $record);
if(empty($record) || empty($recordlist)){
return json(['code'=>-1, 'msg'=>'参数不能为空']);
}
$dns = DnsHelper::getModel($drow['aid'], $drow['name'], $drow['thirdid']);
$success = 0; $fail = 0;
foreach($recordlist as $record){
$record = trim($record);
$arr = explode(' ', $record);
if(empty($record) || empty($arr[0]) || empty($arr[1])) continue;
$thistype = empty($type) ? getDnsType($arr[1]) : $type;
$recordid = $dns->addDomainRecord($arr[0], $thistype, $arr[1], $line, $ttl, $mx);
if($recordid){
$this->add_log($drow['name'], '添加解析', $thistype.'记录 '.$arr[0].' '.$arr[1].' (线路:'.$line.' TTL:'.$ttl.')');
$success++;
}else{
$fail++;
}
}
return json(['code'=>0, 'msg'=>'批量添加解析,成功'.$success.'条,失败'.$fail.'条']);
}
list($recordLine, $minTTL) = $this->get_line_and_ttl($drow);
$recordLineArr = [];
foreach($recordLine as $key=>$item){
$recordLineArr[] = ['id'=>strval($key), 'name'=>$item['name'], 'parent'=>$item['parent']];
}
$dnsconfig = DnsHelper::$dns_config[$dnstype];
$dnsconfig['type'] = $dnstype;
View::assign('domainId', $id);
View::assign('domainName', $drow['name']);
View::assign('recordLine', $recordLineArr);
View::assign('minTTL', $minTTL?$minTTL:1);
View::assign('dnsconfig', $dnsconfig);
return view('batchadd');
}
public function record_log(){ public function record_log(){
$id = input('param.id/d'); $id = input('param.id/d');
$drow = Db::name('domain')->where('id', $id)->find(); $drow = Db::name('domain')->where('id', $id)->find();

View File

@ -103,7 +103,7 @@
{if request()->user['type'] eq 'user'}<li class="{:checkIfActive('index')}"> {if request()->user['type'] eq 'user'}<li class="{:checkIfActive('index')}">
<a href="/"><i class="fa fa-home fa-fw"></i> <span>后台首页</span></a> <a href="/"><i class="fa fa-home fa-fw"></i> <span>后台首页</span></a>
</li>{/if} </li>{/if}
<li class="{:checkIfActive('domain,record,record_log')}"> <li class="{:checkIfActive('domain,record,record_log,record_batch_add')}">
<a href="/domain"><i class="fa fa-list-ul fa-fw"></i> <span>域名管理</span></a> <a href="/domain"><i class="fa fa-list-ul fa-fw"></i> <span>域名管理</span></a>
</li> </li>
{if request()->user['level'] eq 2} {if request()->user['level'] eq 2}

View File

@ -0,0 +1,139 @@
{extend name="common/layout" /}
{block name="title"}批量添加解析 - {$domainName}{/block}
{block name="main"}
<div class="row" id="app">
<div class="col-xs-12 center-block" style="float: none;">
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title"><a href="/record/{$domainId}" class="btn btn-sm btn-default pull-right" style="margin-top:-6px"><i class="fa fa-reply fa-fw"></i> 返回</a>批量添加解析 - {$domainName}</h3></div>
<div class="panel-body">
<form onsubmit="return false" method="post" class="form-horizontal" role="form" id="form-store">
<div class="form-group">
<label class="col-sm-3 col-xs-12 control-label no-padding-right">主机记录&记录值</label>
<div class="col-sm-6">
<textarea name="record" placeholder="主机记录和记录值用空格隔开,一行一个" class="form-control" rows="8" required></textarea>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">记录类型</label>
<div class="col-sm-6">
<select name="type" class="form-control">
<option value="">A / CNAME / AAAA 自动识别</option>
<option value="A">A</option>
<option value="CNAME">CNAME</option>
<option value="AAAA">AAAA</option>
<option value="NS">NS</option>
<option value="MX">MX</option>
<option value="SRV">SRV</option>
<option value="TXT">TXT</option>
<option value="CAA">CAA</option>
{if $dnsconfig.redirect}<option value="REDIRECT_URL">显性URL</option>
<option value="FORWARD_URL">隐性URL</option>{/if}
</select>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">线路类型</label>
<div class="col-sm-6" id="line_list">
</div>
</div>
<div class="form-group" style="display:none" id="mx_type">
<label class="col-sm-3 control-label no-padding-right">MX优先级</label>
<div class="col-sm-6">
<input type="text" class="form-control" name="mx" value="10">
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">TTL</label>
<div class="col-sm-6">
<input type="text" class="form-control" name="ttl" value="600" placeholder="指解析结果在DNS服务器中的缓存时间" required min="{$minTTL}">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-6"><button type="button" class="btn btn-primary" onclick="save()">保存</button></div>
</div>
</form>
</div>
</div>
{/block}
{block name="script"}
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
<script src="/static/js/bootstrapValidator.min.js"></script>
<script>
var recordLine = {$recordLine|json_encode|raw};
var dnsconfig = {$dnsconfig|json_encode|raw};
var defaultLine = recordLine[0].id;
$(document).ready(function(){
$("select[name=type]").change(function(){
if($(this).val() == 'MX'){
$("#mx_type").show();
}else{
$("#mx_type").hide();
}
});
$("#form-store").bootstrapValidator();
initLine();
});
function initLine(option, elem){
option = option || '';
elem = elem || 'line_list';
$("#"+elem).empty();
$.each(recordLine, function(index, item){
if(item.parent == null){
option += '<option value="'+item.id+'">'+item.name+'</option>';
}
})
$("#"+elem).append('<select name="line" class="form-control" onchange="changeLine(this, \''+elem+'\')">'+option+'</select>');
}
function changeLine(obj, elem){
var line = $(obj).val();
var flag = false;
$("#"+elem).children().each(function(index, elem){
if(flag) $(elem).remove()
if(obj == elem){
flag = true;
}
})
if($(obj).find("option:selected").text() == '子集线路(非必填)') return;
var tempLine = recordLine.filter((x) => x.parent == line)
if(tempLine.length > 0){
var option = '<option value="'+line+'">子集线路(非必填)</option>';
$.each(tempLine, function(index, item){
option += '<option value="'+item.id+'">'+item.name+'</option>';
})
$("#"+elem).append('<select name="line" class="form-control" onchange="changeLine(this, \''+elem+'\')">'+option+'</select>');
}
}
function save(){
$("#form-store").data("bootstrapValidator").validate();
if(!$("#form-store").data("bootstrapValidator").isValid()){
return;
}
var act = $("#form-store input[name=action]").val();
var ii = layer.load(2);
$.ajax({
type : 'POST',
url : '/record/batchadd/{$domainId}',
data : $("#form-store").serialize(),
dataType : 'json',
success : function(data) {
layer.close(ii);
if(data.code == 0){
layer.alert(data.msg,{
icon: 1,
closeBtn: false
}, function(){
if(document.referrer.indexOf('/record?') > 0)
window.location.href = document.referrer;
else
window.location.href = '/record/{$domainId}';
});
}else{
layer.alert(data.msg, {icon: 2})
}
}
});
}
</script>
{/block}

View File

@ -78,6 +78,78 @@ td{overflow: hidden;text-overflow: ellipsis;white-space: nowrap;max-width:360px;
</div> </div>
</div> </div>
</div> </div>
<div class="modal" id="modal-store2" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true" data-backdrop="static">
<div class="modal-dialog">
<div class="modal-content animated flipInX">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span
aria-hidden="true">&times;</span><span
class="sr-only">Close</span></button>
<h4 class="modal-title" id="modal-title">批量修改解析记录</h4>
</div>
<div class="modal-body">
<form class="form-horizontal" id="form-store2">
<input type="hidden" name="action" value="value"/>
<input type="hidden" name="recordinfo"/>
<div class="form-group">
<label class="col-sm-3 control-label">记录类型</label>
<div class="col-sm-9">
<select name="type" class="form-control">
<option value="A">A</option>
<option value="CNAME">CNAME</option>
<option value="AAAA">AAAA</option>
<option value="NS">NS</option>
<option value="MX">MX</option>
<option value="SRV">SRV</option>
<option value="TXT">TXT</option>
<option value="CAA">CAA</option>
{if $dnsconfig.redirect}<option value="REDIRECT_URL">显性URL</option>
<option value="FORWARD_URL">隐性URL</option>{/if}
</select>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">记录值</label>
<div class="col-sm-9">
<input type="text" class="form-control" name="value" placeholder="输入记录值" required>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-white" data-dismiss="modal">关闭</button>
<button type="button" class="btn btn-primary" id="store" onclick="batch_save()">保存</button>
</div>
</div>
</div>
</div>
<div class="modal" id="modal-store3" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true" data-backdrop="static">
<div class="modal-dialog">
<div class="modal-content animated flipInX">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span
aria-hidden="true">&times;</span><span
class="sr-only">Close</span></button>
<h4 class="modal-title" id="modal-title">批量修改解析线路</h4>
</div>
<div class="modal-body">
<form class="form-horizontal" id="form-store3">
<input type="hidden" name="action" value="line"/>
<input type="hidden" name="recordinfo"/>
<div class="form-group">
<label class="col-sm-3 control-label">线路类型</label>
<div class="col-sm-9" id="line_list3">
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-white" data-dismiss="modal">关闭</button>
<button type="button" class="btn btn-primary" id="store" onclick="batch_save_line()">保存</button>
</div>
</div>
</div>
</div>
<div class="row"> <div class="row">
<div class="col-xs-12 center-block" style="float: none;"> <div class="col-xs-12 center-block" style="float: none;">
<div class="panel panel-default panel-default"> <div class="panel panel-default panel-default">
@ -99,7 +171,7 @@ td{overflow: hidden;text-overflow: ellipsis;white-space: nowrap;max-width:360px;
<a href="javascript:addframe()" class="btn btn-success"><i class="fa fa-plus"></i> 添加记录</a> <a href="javascript:addframe()" class="btn btn-success"><i class="fa fa-plus"></i> 添加记录</a>
<div class="btn-group" role="group"> <div class="btn-group" role="group">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">批量操作 <span class="caret"></span></button> <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">批量操作 <span class="caret"></span></button>
<ul class="dropdown-menu"><li><a href="javascript:operation('open')">启用</a></li><li><a href="javascript:operation('pause')">暂停</a></li><li><a href="javascript:operation('delete')">删除</a></li></ul> <ul class="dropdown-menu"><li><a href="/record/batchadd/{$domainId}">添加</a></li><li><a href="javascript:operation('open')">启用</a></li><li><a href="javascript:operation('pause')">暂停</a></li><li><a href="javascript:operation('edit')">修改记录</a></li><li><a href="javascript:operation('editline')">修改线路</a></li><li><a href="javascript:operation('delete')">删除</a></li></ul>
</div> </div>
<div class="btn-group" role="group"> <div class="btn-group" role="group">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">日志 <span class="caret"></span></button> <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">日志 <span class="caret"></span></button>
@ -229,21 +301,23 @@ $(document).ready(function(){
}); });
$("#form-store").bootstrapValidator(); $("#form-store").bootstrapValidator();
$("#form-store2").bootstrapValidator();
}) })
function initLine(option){ function initLine(option, elem){
option = option || ''; option = option || '';
$("#line_list").empty(); elem = elem || 'line_list';
$("#"+elem).empty();
$.each(recordLine, function(index, item){ $.each(recordLine, function(index, item){
if(item.parent == null){ if(item.parent == null){
option += '<option value="'+item.id+'">'+item.name+'</option>'; option += '<option value="'+item.id+'">'+item.name+'</option>';
} }
}) })
$("#line_list").append('<select name="line" class="form-control" onchange="changeLine(this)">'+option+'</select>'); $("#"+elem).append('<select name="line" class="form-control" onchange="changeLine(this, \''+elem+'\')">'+option+'</select>');
} }
function changeLine(obj){ function changeLine(obj, elem){
var line = $(obj).val(); var line = $(obj).val();
var flag = false; var flag = false;
$("#line_list").children().each(function(index, elem){ $("#"+elem).children().each(function(index, elem){
if(flag) $(elem).remove() if(flag) $(elem).remove()
if(obj == elem){ if(obj == elem){
flag = true; flag = true;
@ -256,7 +330,7 @@ function changeLine(obj){
$.each(tempLine, function(index, item){ $.each(tempLine, function(index, item){
option += '<option value="'+item.id+'">'+item.name+'</option>'; option += '<option value="'+item.id+'">'+item.name+'</option>';
}) })
$("#line_list").append('<select name="line" class="form-control" onchange="changeLine(this)">'+option+'</select>'); $("#"+elem).append('<select name="line" class="form-control" onchange="changeLine(this, \''+elem+'\')">'+option+'</select>');
} }
} }
function addframe(){ function addframe(){
@ -409,6 +483,22 @@ function operation(action){
layer.msg('请选择要操作的记录'); layer.msg('请选择要操作的记录');
return; return;
} }
if(action == 'edit'){
var records = [];
$.each(rows, function(index, item){
records.push({recordid:item.RecordId, name:item.Name, line:item.Line, mx:item.MX, ttl:item.TTL, remark:item.Remark});
})
batch_edit(records)
return;
}else if(action == 'editline'){
var records = [];
$.each(rows, function(index, item){
records.push({recordid:item.RecordId, name:item.Name, type:item.Type, value:item.Value, mx:item.MX, ttl:item.TTL, remark:item.Remark});
})
batch_edit_line(records)
return;
}
var ids = []; var ids = [];
$.each(rows, function(index, item){ $.each(rows, function(index, item){
ids.push(item.RecordId); ids.push(item.RecordId);
@ -437,5 +527,75 @@ function operation(action){
layer.close(confirmobj); layer.close(confirmobj);
}); });
} }
function batch_edit(records){
var row = $("#listTable").bootstrapTable('getSelections')[0];
$("#batch_num").text(records.length);
$("#modal-store2").modal('show');
$("#form-store2 input[name=recordinfo]").val(JSON.stringify(records));
$("#form-store2 input[name=recordid]").val(row.RecordId);
$("#form-store2 input[name=name]").val(row.Name);
$("#form-store2 select[name=type]").val(row.Type);
$("select[name=type]").change();
$("#form-store2 input[name=value]").val(row.Value);
$("#form-store2").data("bootstrapValidator").resetForm();
}
function batch_save(){
$("#form-store2").data("bootstrapValidator").validate();
if(!$("#form-store2").data("bootstrapValidator").isValid()){
return;
}
var ii = layer.load(2);
$.ajax({
type : 'POST',
url : '/record/batchedit/{$domainId}',
data : $("#form-store2").serialize(),
dataType : 'json',
success : function(data) {
layer.close(ii);
if(data.code == 0){
layer.alert(data.msg,{
icon: 1,
closeBtn: false
}, function(){
layer.closeAll();
$("#modal-store2").modal('hide');
searchSubmit();
});
}else{
layer.alert(data.msg, {icon: 2})
}
}
});
}
function batch_edit_line(records){
$("#batch_num").text(records.length);
$("#modal-store3").modal('show');
$("#form-store3 input[name=recordinfo]").val(JSON.stringify(records));
initLine('', 'line_list3');
}
function batch_save_line(){
var ii = layer.load(2);
$.ajax({
type : 'POST',
url : '/record/batchedit/{$domainId}',
data : $("#form-store3").serialize(),
dataType : 'json',
success : function(data) {
layer.close(ii);
if(data.code == 0){
layer.alert(data.msg,{
icon: 1,
closeBtn: false
}, function(){
layer.closeAll();
$("#modal-store3").modal('hide');
searchSubmit();
});
}else{
layer.alert(data.msg, {icon: 2})
}
}
});
}
</script> </script>
{/block} {/block}

View File

@ -56,6 +56,8 @@ Route::group(function () {
Route::post('/record/status/:id', 'domain/record_status'); Route::post('/record/status/:id', 'domain/record_status');
Route::post('/record/remark/:id', 'domain/record_remark'); Route::post('/record/remark/:id', 'domain/record_remark');
Route::post('/record/batch/:id', 'domain/record_batch'); Route::post('/record/batch/:id', 'domain/record_batch');
Route::post('/record/batchedit/:id', 'domain/record_batch_edit');
Route::any('/record/batchadd/:id', 'domain/record_batch_add');
Route::any('/record/log/:id', 'domain/record_log'); Route::any('/record/log/:id', 'domain/record_log');
Route::post('/record/list', 'domain/record_list'); Route::post('/record/list', 'domain/record_list');
Route::get('/record/:id', 'domain/record'); Route::get('/record/:id', 'domain/record');