新增定时切换解析功能

This commit is contained in:
net909
2025-08-22 21:25:42 +08:00
parent 9f529e2528
commit fd21a55d01
18 changed files with 1036 additions and 126 deletions

View File

@@ -15,6 +15,7 @@ use think\facade\Config;
use app\service\OptimizeService;
use app\service\CertTaskService;
use app\service\ExpireNoticeService;
use app\service\ScheduleService;
class Certtask extends Command
{
@@ -22,7 +23,7 @@ class Certtask extends Command
{
// 指令配置
$this->setName('certtask')
->setDescription('SSL证书续签与部署、域名到期提醒、CF优选IP更新');
->setDescription('SSL证书续签与部署、域名到期提醒、定时切换解析、CF优选IP更新');
}
protected function execute(Input $input, Output $output)
@@ -30,6 +31,7 @@ class Certtask extends Command
$res = Db::name('config')->cache('configs', 0)->column('value', 'key');
Config::set($res, 'sys');
(new ScheduleService())->execute();
$res = (new OptimizeService())->execute();
if (!$res) {
(new CertTaskService())->execute();

View File

@@ -65,102 +65,125 @@ class Dmonitor extends BaseController
$list = $select->order('A.id', 'desc')->limit($offset, $limit)->field('A.*,B.name domain')->select()->toArray();
foreach ($list as &$row) {
$row['checktimestr'] = date('Y-m-d H:i:s', $row['checktime']);
$row['addtimestr'] = date('Y-m-d H:i:s', $row['addtime']);
$row['checktimestr'] = $row['checktime'] > 0 ? date('Y-m-d H:i:s', $row['checktime']) : '未运行';
}
return json(['total' => $total, 'rows' => $list]);
}
public function task_op()
{
if (!checkPermission(2)) return $this->alert('error', '无权限');
$action = input('param.action');
if ($action == 'add') {
$task = [
'did' => input('post.did/d'),
'rr' => input('post.rr', null, 'trim'),
'recordid' => input('post.recordid', null, 'trim'),
'type' => input('post.type/d'),
'main_value' => input('post.main_value', null, 'trim'),
'backup_value' => input('post.backup_value', null, 'trim'),
'checktype' => input('post.checktype/d'),
'checkurl' => input('post.checkurl', null, 'trim'),
'tcpport' => !empty(input('post.tcpport')) ? input('post.tcpport/d') : null,
'frequency' => input('post.frequency/d'),
'cycle' => input('post.cycle/d'),
'timeout' => input('post.timeout/d'),
'proxy' => input('post.proxy/d'),
'cdn' => input('post.cdn') == 'true' || input('post.cdn') == '1' ? 1 : 0,
'remark' => input('post.remark', null, 'trim'),
'recordinfo' => input('post.recordinfo', null, 'trim'),
'addtime' => time(),
'active' => 1
];
if (empty($task['did']) || empty($task['rr']) || empty($task['recordid']) || empty($task['main_value']) || empty($task['frequency']) || empty($task['cycle'])) {
return json(['code' => -1, 'msg' => '必填项不能为空']);
}
if ($task['checktype'] > 0 && $task['timeout'] > $task['frequency']) {
return json(['code' => -1, 'msg' => '为保障容灾切换任务正常运行,最大超时时间不能大于检测间隔']);
}
if ($task['type'] == 2 && $task['backup_value'] == $task['main_value']) {
return json(['code' => -1, 'msg' => '主备地址不能相同']);
}
if (Db::name('dmtask')->where('recordid', $task['recordid'])->find()) {
return json(['code' => -1, 'msg' => '当前容灾切换策略已存在']);
}
Db::name('dmtask')->insert($task);
return json(['code' => 0, 'msg' => '添加成功']);
} elseif ($action == 'edit') {
$id = input('post.id/d');
$task = [
'did' => input('post.did/d'),
'rr' => input('post.rr', null, 'trim'),
'recordid' => input('post.recordid', null, 'trim'),
'type' => input('post.type/d'),
'main_value' => input('post.main_value', null, 'trim'),
'backup_value' => input('post.backup_value', null, 'trim'),
'checktype' => input('post.checktype/d'),
'checkurl' => input('post.checkurl', null, 'trim'),
'tcpport' => !empty(input('post.tcpport')) ? input('post.tcpport/d') : null,
'frequency' => input('post.frequency/d'),
'cycle' => input('post.cycle/d'),
'timeout' => input('post.timeout/d'),
'proxy' => input('post.proxy/d'),
'cdn' => input('post.cdn') == 'true' || input('post.cdn') == '1' ? 1 : 0,
'remark' => input('post.remark', null, 'trim'),
'recordinfo' => input('post.recordinfo', null, 'trim'),
];
if (empty($task['did']) || empty($task['rr']) || empty($task['recordid']) || empty($task['main_value']) || empty($task['frequency']) || empty($task['cycle'])) {
return json(['code' => -1, 'msg' => '必填项不能为空']);
}
if ($task['checktype'] > 0 && $task['timeout'] > $task['frequency']) {
return json(['code' => -1, 'msg' => '为保障容灾切换任务正常运行,最大超时时间不能大于检测间隔']);
}
if ($task['type'] == 2 && $task['backup_value'] == $task['main_value']) {
return json(['code' => -1, 'msg' => '主备地址不能相同']);
}
if (Db::name('dmtask')->where('recordid', $task['recordid'])->where('id', '<>', $id)->find()) {
return json(['code' => -1, 'msg' => '当前容灾切换策略已存在']);
}
Db::name('dmtask')->where('id', $id)->update($task);
return json(['code' => 0, 'msg' => '修改成功']);
} elseif ($action == 'setactive') {
$id = input('post.id/d');
$active = input('post.active/d');
Db::name('dmtask')->where('id', $id)->update(['active' => $active]);
return json(['code' => 0, 'msg' => '设置成功']);
} elseif ($action == 'del') {
$id = input('post.id/d');
Db::name('dmtask')->where('id', $id)->delete();
Db::name('dmlog')->where('taskid', $id)->delete();
return json(['code' => 0, 'msg' => '删除成功']);
} elseif ($action == 'operation') {
$ids = input('post.ids');
$success = 0;
foreach ($ids as $id) {
if (input('post.act') == 'delete') {
Db::name('dmtask')->where('id', $id)->delete();
Db::name('dmlog')->where('taskid', $id)->delete();
$success++;
} elseif (input('post.act') == 'retry') {
Db::name('dmtask')->where('id', $id)->update(['checknexttime' => time()]);
$success++;
} elseif (input('post.act') == 'open' || input('post.act') == 'close') {
$isauto = input('post.act') == 'open' ? 1 : 0;
Db::name('dmtask')->where('id', $id)->update(['active' => $isauto]);
$success++;
}
}
return json(['code' => 0, 'msg' => '成功操作' . $success . '个容灾切换策略']);
} else {
return json(['code' => -1, 'msg' => '参数错误']);
}
}
public function taskform()
{
if (!checkPermission(2)) return $this->alert('error', '无权限');
$action = input('param.action');
if ($this->request->isPost()) {
if ($action == 'add') {
$task = [
'did' => input('post.did/d'),
'rr' => input('post.rr', null, 'trim'),
'recordid' => input('post.recordid', null, 'trim'),
'type' => input('post.type/d'),
'main_value' => input('post.main_value', null, 'trim'),
'backup_value' => input('post.backup_value', null, 'trim'),
'checktype' => input('post.checktype/d'),
'checkurl' => input('post.checkurl', null, 'trim'),
'tcpport' => !empty(input('post.tcpport')) ? input('post.tcpport/d') : null,
'frequency' => input('post.frequency/d'),
'cycle' => input('post.cycle/d'),
'timeout' => input('post.timeout/d'),
'proxy' => input('post.proxy/d'),
'cdn' => input('post.cdn') == 'true' || input('post.cdn') == '1' ? 1 : 0,
'remark' => input('post.remark', null, 'trim'),
'recordinfo' => input('post.recordinfo', null, 'trim'),
'addtime' => time(),
'active' => 1
];
if (empty($task['did']) || empty($task['rr']) || empty($task['recordid']) || empty($task['main_value']) || empty($task['frequency']) || empty($task['cycle'])) {
return json(['code' => -1, 'msg' => '必填项不能为空']);
}
if ($task['checktype'] > 0 && $task['timeout'] > $task['frequency']) {
return json(['code' => -1, 'msg' => '为保障容灾切换任务正常运行,最大超时时间不能大于检测间隔']);
}
if ($task['type'] == 2 && $task['backup_value'] == $task['main_value']) {
return json(['code' => -1, 'msg' => '主备地址不能相同']);
}
if (Db::name('dmtask')->where('recordid', $task['recordid'])->find()) {
return json(['code' => -1, 'msg' => '当前容灾切换策略已存在']);
}
Db::name('dmtask')->insert($task);
return json(['code' => 0, 'msg' => '添加成功']);
} elseif ($action == 'edit') {
$id = input('post.id/d');
$task = [
'did' => input('post.did/d'),
'rr' => input('post.rr', null, 'trim'),
'recordid' => input('post.recordid', null, 'trim'),
'type' => input('post.type/d'),
'main_value' => input('post.main_value', null, 'trim'),
'backup_value' => input('post.backup_value', null, 'trim'),
'checktype' => input('post.checktype/d'),
'checkurl' => input('post.checkurl', null, 'trim'),
'tcpport' => !empty(input('post.tcpport')) ? input('post.tcpport/d') : null,
'frequency' => input('post.frequency/d'),
'cycle' => input('post.cycle/d'),
'timeout' => input('post.timeout/d'),
'proxy' => input('post.proxy/d'),
'cdn' => input('post.cdn') == 'true' || input('post.cdn') == '1' ? 1 : 0,
'remark' => input('post.remark', null, 'trim'),
'recordinfo' => input('post.recordinfo', null, 'trim'),
];
if (empty($task['did']) || empty($task['rr']) || empty($task['recordid']) || empty($task['main_value']) || empty($task['frequency']) || empty($task['cycle'])) {
return json(['code' => -1, 'msg' => '必填项不能为空']);
}
if ($task['checktype'] > 0 && $task['timeout'] > $task['frequency']) {
return json(['code' => -1, 'msg' => '为保障容灾切换任务正常运行,最大超时时间不能大于检测间隔']);
}
if ($task['type'] == 2 && $task['backup_value'] == $task['main_value']) {
return json(['code' => -1, 'msg' => '主备地址不能相同']);
}
if (Db::name('dmtask')->where('recordid', $task['recordid'])->where('id', '<>', $id)->find()) {
return json(['code' => -1, 'msg' => '当前容灾切换策略已存在']);
}
Db::name('dmtask')->where('id', $id)->update($task);
return json(['code' => 0, 'msg' => '修改成功']);
} elseif ($action == 'setactive') {
$id = input('post.id/d');
$active = input('post.active/d');
Db::name('dmtask')->where('id', $id)->update(['active' => $active]);
return json(['code' => 0, 'msg' => '设置成功']);
} elseif ($action == 'del') {
$id = input('post.id/d');
Db::name('dmtask')->where('id', $id)->delete();
Db::name('dmlog')->where('taskid', $id)->delete();
return json(['code' => 0, 'msg' => '删除成功']);
} else {
return json(['code' => -1, 'msg' => '参数错误']);
}
}
$task = null;
if ($action == 'edit') {
$id = input('get.id/d');

View File

@@ -276,6 +276,7 @@ class Domain extends BaseController
Db::name('domain')->where('id', $id)->delete();
Db::name('dmtask')->where('did', $id)->delete();
Db::name('optimizeip')->where('did', $id)->delete();
Db::name('sctask')->where('did', $id)->delete();
return json(['code' => 0]);
} elseif ($act == 'batchadd') {
if (!checkPermission(2)) return $this->alert('error', '无权限');
@@ -318,6 +319,7 @@ class Domain extends BaseController
Db::name('domain')->where('id', 'in', $ids)->delete();
Db::name('dmtask')->where('did', 'in', $ids)->delete();
Db::name('optimizeip')->where('did', 'in', $ids)->delete();
Db::name('sctask')->where('did', 'in', $ids)->delete();
return json(['code' => 0, 'msg' => '成功删除' . count($ids) . '个域名!']);
}
return json(['code' => -3]);

165
app/controller/Schedule.php Normal file
View File

@@ -0,0 +1,165 @@
<?php
namespace app\controller;
use app\BaseController;
use think\facade\Db;
use think\facade\View;
use think\facade\Cache;
use app\service\ScheduleService;
class Schedule extends BaseController
{
public function stask()
{
if (!checkPermission(2)) return $this->alert('error', '无权限');
return View::fetch();
}
public function stask_data()
{
if (!checkPermission(2)) return json(['total' => 0, 'rows' => []]);
$type = input('post.type/d', 1);
$kw = input('post.kw', null, 'trim');
$stype = input('post.stype', null);
$offset = input('post.offset/d');
$limit = input('post.limit/d');
$select = Db::name('sctask')->alias('A')->join('domain B', 'A.did = B.id');
if (!empty($kw)) {
if ($type == 1) {
$select->whereLike('rr|B.name', '%' . $kw . '%');
} elseif ($type == 2) {
$select->where('recordid', $kw);
} elseif ($type == 3) {
$select->where('value', $kw);
} elseif ($type == 4) {
$select->whereLike('remark', '%' . $kw . '%');
}
}
if (!isNullOrEmpty($stype)) {
$select->where('type', $stype);
}
$total = $select->count();
$list = $select->order('A.id', 'desc')->limit($offset, $limit)->field('A.*,B.name domain')->select()->toArray();
foreach ($list as &$row) {
$row['addtimestr'] = date('Y-m-d H:i:s', $row['addtime']);
$row['updatetimestr'] = $row['updatetime'] > 0 ? date('Y-m-d H:i:s', $row['updatetime']) : '未运行';
$row['nexttimestr'] = $row['nexttime'] > 0 ? date('Y-m-d H:i:s', $row['nexttime']) : '无';
}
return json(['total' => $total, 'rows' => $list]);
}
public function stask_op()
{
if (!checkPermission(2)) return $this->alert('error', '无权限');
$action = input('param.action');
if ($action == 'add') {
$task = [
'did' => input('post.did/d'),
'rr' => input('post.rr', null, 'trim'),
'recordid' => input('post.recordid', null, 'trim'),
'type' => input('post.type/d'),
'cycle' => input('post.cycle/d'),
'switchtype' => input('post.switchtype/d'),
'switchdate' => input('post.switchdate', null, 'trim'),
'switchtime' => input('post.switchtime', null, 'trim'),
'value' => input('post.value', null, 'trim'),
'line' => input('post.value', null, 'trim'),
'remark' => input('post.remark', null, 'trim'),
'recordinfo' => input('post.recordinfo', null, 'trim'),
'addtime' => time(),
'active' => 1
];
if (empty($task['did']) || empty($task['rr']) || empty($task['recordid'])) {
return json(['code' => -1, 'msg' => '必填项不能为空']);
}
if (Db::name('sctask')->where('recordid', $task['recordid'])->where('switchtype', $task['switchtype'])->where('switchtime', $task['switchtime'])->find()) {
return json(['code' => -1, 'msg' => '当前定时切换策略已存在']);
}
$id = Db::name('sctask')->insertGetId($task);
$row = Db::name('sctask')->where('id', $id)->find();
(new ScheduleService())->update_nexttime($row);
return json(['code' => 0, 'msg' => '添加成功']);
} elseif ($action == 'edit') {
$id = input('post.id/d');
$task = [
'did' => input('post.did/d'),
'rr' => input('post.rr', null, 'trim'),
'recordid' => input('post.recordid', null, 'trim'),
'type' => input('post.type/d'),
'cycle' => input('post.cycle/d'),
'switchtype' => input('post.switchtype/d'),
'switchdate' => input('post.switchdate', null, 'trim'),
'switchtime' => input('post.switchtime', null, 'trim'),
'value' => input('post.value', null, 'trim'),
'line' => input('post.value', null, 'trim'),
'remark' => input('post.remark', null, 'trim'),
'recordinfo' => input('post.recordinfo', null, 'trim'),
];
if (empty($task['did']) || empty($task['rr']) || empty($task['recordid'])) {
return json(['code' => -1, 'msg' => '必填项不能为空']);
}
if (Db::name('sctask')->where('recordid', $task['recordid'])->where('switchtype', $task['switchtype'])->where('switchtime', $task['switchtime'])->where('id', '<>', $id)->find()) {
return json(['code' => -1, 'msg' => '当前定时切换策略已存在']);
}
Db::name('sctask')->where('id', $id)->update($task);
$row = Db::name('sctask')->where('id', $id)->find();
(new ScheduleService())->update_nexttime($row);
return json(['code' => 0, 'msg' => '修改成功']);
} elseif ($action == 'setactive') {
$id = input('post.id/d');
$active = input('post.active/d');
Db::name('sctask')->where('id', $id)->update(['active' => $active]);
return json(['code' => 0, 'msg' => '设置成功']);
} elseif ($action == 'del') {
$id = input('post.id/d');
Db::name('sctask')->where('id', $id)->delete();
return json(['code' => 0, 'msg' => '删除成功']);
} elseif ($action == 'operation') {
$ids = input('post.ids');
$success = 0;
foreach ($ids as $id) {
if (input('post.act') == 'delete') {
Db::name('sctask')->where('id', $id)->delete();
$success++;
} elseif (input('post.act') == 'open' || input('post.act') == 'close') {
$isauto = input('post.act') == 'open' ? 1 : 0;
Db::name('sctask')->where('id', $id)->update(['active' => $isauto]);
$success++;
}
}
return json(['code' => 0, 'msg' => '成功操作' . $success . '个定时切换策略']);
} else {
return json(['code' => -1, 'msg' => '参数错误']);
}
}
public function staskform()
{
if (!checkPermission(2)) return $this->alert('error', '无权限');
$action = input('param.action');
$task = null;
if ($action == 'edit') {
$id = input('get.id/d');
$task = Db::name('sctask')->where('id', $id)->find();
if (empty($task)) return $this->alert('error', '切换策略不存在');
}
$domains = [];
$domainList = Db::name('domain')->alias('A')->join('account B', 'A.aid = B.id')->field('A.id,A.name,B.type')->select();
foreach ($domainList as $row) {
$domains[] = ['id'=>$row['id'], 'name'=>$row['name'], 'type'=>$row['type']];
}
View::assign('domains', $domains);
View::assign('info', $task);
View::assign('action', $action);
return View::fetch();
}
}

View File

@@ -10,6 +10,7 @@ use think\facade\Cache;
use app\service\OptimizeService;
use app\service\CertTaskService;
use app\service\ExpireNoticeService;
use app\service\ScheduleService;
class System extends BaseController
{
@@ -137,6 +138,7 @@ class System extends BaseController
if (config_get('cron_type', '0') != '1' || empty($cron_key)) exit('未开启当前方式');
if ($key != $cron_key) exit('访问密钥错误');
(new ScheduleService())->execute();
$res = (new OptimizeService())->execute();
if (!$res) {
(new CertTaskService())->execute();

View File

@@ -171,7 +171,7 @@ class User extends BaseController
$select->where('domain', $this->request->user['name']);
} elseif ($this->request->user['level'] == 1) {
$select->where('uid', $this->request->user['id']);
} elseif (!empty($uid)) {
} elseif (!isNullOrEmpty($uid)) {
$select->where('uid', $uid);
}
if (!empty($kw)) {

View File

@@ -0,0 +1,118 @@
<?php
namespace app\service;
use Exception;
use think\facade\Db;
use app\lib\DnsHelper;
/**
* 域名定时切换解析
*/
class ScheduleService
{
public function execute()
{
$list = Db::name('sctask')->where('nexttime', '>', 0)->where('nexttime', '<=', time())->where('active', 1)->select();
if (count($list) == 0) {
return false;
}
echo '开始执行定时切换解析任务,共获取到' . count($list) . '个待执行任务' . "\n";
foreach ($list as $row) {
try {
$this->execute_one($row);
echo '定时切换任务' . $row['id'] . '执行成功' . "\n";
} catch (Exception $e) {
echo '定时切换任务' . $row['id'] . '执行失败,' . $e->getMessage() . "\n";
}
}
config_set('schedule_time', date("Y-m-d H:i:s"));
return true;
}
public function execute_one($row)
{
$drow = Db::name('domain')->alias('A')->join('account B', 'A.aid = B.id')->where('A.id', $row['did'])->field('A.*,B.type,B.ak,B.sk,B.ext')->find();
if (!$drow) throw new Exception('域名不存在');
Db::name('sctask')->where('id', $row['id'])->update(['updatetime' => time()]);
$domain = $row['rr'] . '.' . $drow['name'];
$dns = DnsHelper::getModel2($drow);
if ($row['switchtype'] == 1) {
$res = $dns->setDomainRecordStatus($row['recordid'], '1');
if ($res) {
$this->add_log($domain, '启用解析', '定时启用解析成功');
} else {
$this->add_log($domain, '启用解析失败', $dns->getError());
}
} elseif ($row['switchtype'] == 2) {
$res = $dns->setDomainRecordStatus($row['recordid'], '0');
if ($res) {
$this->add_log($domain, '暂停解析', '定时暂停解析成功');
} else {
$this->add_log($domain, '暂停解析失败', $dns->getError());
}
} elseif ($row['switchtype'] == 3) {
$res = $dns->deleteDomainRecord($row['recordid']);
if ($res) {
$this->add_log($domain, '删除解析', '定时删除解析成功');
} else {
$this->add_log($domain, '删除解析失败', $dns->getError());
}
} else {
$recordinfo = json_decode($row['recordinfo'], true);
if ($drow['type'] == 'cloudflare' && !isNullOrEmpty($row['line'])) {
$recordinfo['Line'] = $row['line'];
}
$res = $dns->updateDomainRecord($row['recordid'], $row['rr'], getDnsType($row['value']), $row['value'], $recordinfo['Line'], $recordinfo['TTL']);
if ($res) {
$this->add_log($domain, '修改解析', $row['rr'].' ['.getDnsType($row['value']).'] '.$row['value'].' (线路:'.$recordinfo['Line'].' TTL:'.$recordinfo['TTL'].')');
} else {
$this->add_log($domain, '修改解析失败', $dns->getError());
}
}
$this->update_nexttime($row);
}
public function update_nexttime($row)
{
if ($row['type'] == 1) {
if ($row['cycle'] == 2) {
$date = intval($row['switchdate']);
$nexttime = strtotime(date('Y-m-') . $date . ' ' . $row['switchtime'] . ':00');
if ($nexttime <= time()) {
$nexttime = strtotime("+1 month", $nexttime);
}
} elseif ($row['cycle'] == 1) {
$weekday = intval($row['switchdate']); // 0-6, 0=周日
$nexttime = strtotime("last Sunday +{$weekday} days {$row['switchtime']}:00");
if ($nexttime <= time()) {
$nexttime = strtotime("+1 week", $nexttime);
if ($nexttime <= time()) {
$nexttime = strtotime("+1 week", $nexttime);
}
}
} else {
$nexttime = strtotime(date('Y-m-d') . ' ' . $row['switchtime'] . ':00');
if ($nexttime <= time()) {
$nexttime = strtotime("+1 day", $nexttime);
}
}
} else {
$nexttime = strtotime($row['switchtime'] . ':00');
if ($nexttime <= time()) {
$nexttime = 0;
}
}
Db::name('sctask')->where('id', $row['id'])->update(['nexttime' => $nexttime]);
}
private function add_log($domain, $action, $data)
{
if (strlen($data) > 500) $data = substr($data, 0, 500);
Db::name('log')->insert(['uid' => 0, 'domain' => $domain, 'action' => $action, 'data' => $data, 'addtime' => date("Y-m-d H:i:s")]);
}
}

View File

@@ -5,7 +5,7 @@ CREATE TABLE `dnsmgr_config` (
PRIMARY KEY (`key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `dnsmgr_config` VALUES ('version', '1033');
INSERT INTO `dnsmgr_config` VALUES ('version', '1040');
INSERT INTO `dnsmgr_config` VALUES ('notice_mail', '0');
INSERT INTO `dnsmgr_config` VALUES ('notice_wxtpl', '0');
INSERT INTO `dnsmgr_config` VALUES ('mail_smtp', 'smtp.qq.com');
@@ -230,4 +230,27 @@ CREATE TABLE `dnsmgr_cert_cname` (
`addtime` datetime DEFAULT NULL,
`status` tinyint(1) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
DROP TABLE IF EXISTS `dnsmgr_sctask`;
CREATE TABLE `dnsmgr_sctask` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`did` int(11) unsigned NOT NULL,
`rr` varchar(128) NOT NULL,
`recordid` varchar(60) NOT NULL,
`type` tinyint(1) NOT NULL DEFAULT 0,
`cycle` tinyint(1) NOT NULL DEFAULT 0,
`switchtype` tinyint(1) NOT NULL DEFAULT 0,
`switchdate` varchar(10) DEFAULT NULL,
`switchtime` varchar(20) DEFAULT NULL,
`value` varchar(128) DEFAULT NULL,
`line` varchar(20) DEFAULT NULL,
`addtime` int(11) NOT NULL DEFAULT 0,
`updatetime` int(11) NOT NULL DEFAULT 0,
`nexttime` int(11) NOT NULL DEFAULT 0,
`active` tinyint(1) NOT NULL DEFAULT 0,
`recordinfo` varchar(200) DEFAULT NULL,
`remark` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `did` (`did`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

View File

@@ -163,4 +163,26 @@ ADD COLUMN `regtime` datetime DEFAULT NULL,
ADD COLUMN `expiretime` datetime DEFAULT NULL,
ADD COLUMN `checktime` datetime DEFAULT NULL,
ADD COLUMN `noticetime` datetime DEFAULT NULL,
ADD COLUMN `checkstatus` tinyint(1) NOT NULL DEFAULT '0';
ADD COLUMN `checkstatus` tinyint(1) NOT NULL DEFAULT '0';
CREATE TABLE IF NOT EXISTS `dnsmgr_sctask` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`did` int(11) unsigned NOT NULL,
`rr` varchar(128) NOT NULL,
`recordid` varchar(60) NOT NULL,
`type` tinyint(1) NOT NULL DEFAULT 0,
`cycle` tinyint(1) NOT NULL DEFAULT 0,
`switchtype` tinyint(1) NOT NULL DEFAULT 0,
`switchdate` varchar(10) DEFAULT NULL,
`switchtime` varchar(20) DEFAULT NULL,
`value` varchar(128) DEFAULT NULL,
`line` varchar(20) DEFAULT NULL,
`addtime` int(11) NOT NULL DEFAULT 0,
`updatetime` int(11) NOT NULL DEFAULT 0,
`nexttime` int(11) NOT NULL DEFAULT 0,
`active` tinyint(1) NOT NULL DEFAULT 0,
`recordinfo` varchar(200) DEFAULT NULL,
`remark` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `did` (`did`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

View File

@@ -126,18 +126,8 @@
<li class="{:checkIfActive('task,taskform')}"><a href="/dmonitor/task"><i class="fa fa-circle-o"></i> 切换策略</a></li>
</ul>
</li>
<li class="treeview {:checkIfActive('opipset,opiplist,opipform')}">
<a href="javascript:;">
<i class="fa fa-globe fa-fw"></i>
<span>CF优选IP</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li class="{:checkIfActive('opipset')}"><a href="/optimizeip/opipset"><i class="fa fa-circle-o"></i> 优选设置</a></li>
<li class="{:checkIfActive('opiplist,opipform')}"><a href="/optimizeip/opiplist"><i class="fa fa-circle-o"></i> 任务管理</a></li>
</ul>
<li class="{:checkIfActive('stask,staskform')}">
<a href="/schedule/stask"><i class="fa fa-calendar fa-fw"></i> <span>定时切换</span></a>
</li>
<li class="treeview {:checkIfActive('certaccount,account_form,certorder,order_form,order_import,deployaccount,deploytask,deploy_form,certset,cname')}">
<a href="javascript:;">
@@ -156,6 +146,19 @@
<li class="{:checkIfActive('certset')}"><a href="/cert/certset"><i class="fa fa-circle-o"></i> 自动续签设置</a></li>
</ul>
</li>
<li class="treeview {:checkIfActive('opipset,opiplist,opipform')}">
<a href="javascript:;">
<i class="fa fa-globe fa-fw"></i>
<span>CF优选IP</span>
<span class="pull-right-container">
<i class="fa fa-angle-left pull-right"></i>
</span>
</a>
<ul class="treeview-menu">
<li class="{:checkIfActive('opipset')}"><a href="/optimizeip/opipset"><i class="fa fa-circle-o"></i> 优选设置</a></li>
<li class="{:checkIfActive('opiplist,opipform')}"><a href="/optimizeip/opiplist"><i class="fa fa-circle-o"></i> 任务管理</a></li>
</ul>
</li>
<li class="treeview {:checkIfActive('cronset,loginset,noticeset,proxyset')}">
<a href="javascript:;">
<i class="fa fa-cogs fa-fw"></i>

View File

@@ -2,7 +2,8 @@
{block name="title"}容灾切换策略{/block}
{block name="main"}
<style>
tbody tr>td:nth-child(2){overflow: hidden;text-overflow: ellipsis;white-space: nowrap;max-width:180px;}
tbody tr>td:nth-child(3){overflow: hidden;text-overflow: ellipsis;white-space: nowrap;max-width:180px;}
tbody tr>td:nth-child(4){overflow: hidden;text-overflow: ellipsis;white-space: nowrap;max-width:200px;}
</style>
<div class="row">
<div class="col-xs-12 center-block" style="float: none;">
@@ -27,6 +28,10 @@ tbody tr>td:nth-child(2){overflow: hidden;text-overflow: ellipsis;white-space: n
<button type="submit" class="btn btn-primary"><i class="fa fa-search"></i> 搜索</button>
<a href="javascript:searchClear()" class="btn btn-default" title="刷新域名账户列表"><i class="fa fa-refresh"></i> 刷新</a>
<a href="/dmonitor/task/add" class="btn btn-success"><i class="fa fa-plus"></i> 添加</a>
<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>
<ul class="dropdown-menu"><li><a href="javascript:operation('open')">开启运行</a></li><li><a href="javascript:operation('close')">停止运行</a></li><li><a href="javascript:operation('retry')">立即重试</a></li><li><a href="javascript:operation('delete')">删除</a></li></ul>
</div>
</form>
<table id="listTable">
@@ -54,6 +59,10 @@ $(document).ready(function(){
pageSize: pageSize,
classes: 'table table-striped table-hover table-bordered',
columns: [
{
field: '',
checkbox: true
},
{
field: 'id',
title: 'ID'
@@ -87,21 +96,28 @@ $(document).ready(function(){
}
}
},
{
field: 'checktype',
title: '检测协议',
formatter: function(value, row, index) {
if(row.type <= 2){
if(value == 1) {
return '<span title="" data-toggle="tooltip" data-placement="bottom" data-original-title="'+row.tcpport+'端口" class="tips">TCP</span>';
} else if(value == 2) {
return '<span title="" data-toggle="tooltip" data-placement="bottom" data-original-title="'+row.checkurl+'" class="tips">HTTP(S)</span>';
} else {
return 'PING';
}
} else {
return '无';
}
}
},
{
field: 'frequency',
title: '检测间隔',
formatter: function(value, row, index) {
if(row.type <= 2){
var checktype = 'PING';
if(row.checktype == 2){
checktype = row.checkurl;
}else if(row.checktype == 1){
checktype = 'TCP('+row.tcpport+'端口)';
}
}else{
var checktype = '';
}
return '<span title="" data-toggle="tooltip" data-placement="bottom" data-original-title="'+checktype+'" class="tips">' + value + '秒</span>';
return value + '秒';
}
},
{
@@ -127,11 +143,18 @@ $(document).ready(function(){
}
},
{
field: 'checktime',
title: '上次检测时间',
formatter: function(value, row, index) {
return value > 0 ? row.checktimestr : '未运行';
}
field: 'checktimestr',
title: '上次检测时间'
},
{
field: 'addtimestr',
title: '添加时间',
visible: false
},
{
field: 'remark',
title: '备注',
visible: false
},
{
field: 'action',
@@ -139,7 +162,7 @@ $(document).ready(function(){
formatter: function(value, row, index) {
var html = '<a href="/dmonitor/task/info/'+row.id+'" class="btn btn-info btn-xs">切换日志</a>&nbsp;&nbsp;';
html += '<a href="/dmonitor/task/edit?id='+row.id+'" class="btn btn-primary btn-xs">修改</a>&nbsp;&nbsp;';
html += '<a href="/record/'+row.did+'?keyword='+row.rr+'" class="btn btn-default btn-xs" target="_blank">解析</a>&nbsp;&nbsp;';
html += '<a href="/record/'+row.did+'?subdomain='+row.rr+'" class="btn btn-default btn-xs" target="_blank">解析</a>&nbsp;&nbsp;';
html += '<a href="javascript:delItem(\''+row.id+'\')" class="btn btn-danger btn-xs">删除</a>&nbsp;&nbsp;';
return html;
}
@@ -174,5 +197,37 @@ function delItem(id){
}, 'json');
});
}
function operation(action){
var rows = $("#listTable").bootstrapTable('getSelections');
if(rows.length == 0){
layer.msg('请选择要操作的策略');
return;
}
var ids = [];
for(var i in rows){
ids.push(rows[i].id);
}
if(action == 'delete'){
if(!confirm('确定要删除所选策略吗?')) return;
}
var ii = layer.load(2);
$.ajax({
type : 'POST',
url : '/dmonitor/task/operation',
data : {act: action, ids: ids},
dataType : 'json',
success : function(data) {
layer.close(ii);
if(data.code == 0){
layer.closeAll();
layer.alert(data.msg, {icon: 1});
searchRefresh();
}else{
layer.alert(data.msg, {icon: 2});
}
}
});
}
</script>
{/block}

View File

@@ -301,7 +301,7 @@ $(document).ready(function(){
},
onPageChange: function(number, size){
if(size != defaultPageSize){
setCookie('domain_pagesize', size);
setCookie('domain_pagesize', size, 24 * 3600 * 30);
}
},
})

View File

@@ -359,7 +359,7 @@ $(document).ready(function(){
],
onPageChange: function(number, size){
if(size != defaultPageSize){
setCookie('record_pagesize', size);
setCookie('record_pagesize', size, 24 * 3600 * 30);
}
},
});

View File

@@ -0,0 +1,216 @@
{extend name="common/layout" /}
{block name="title"}定时切换策略{/block}
{block name="main"}
<style>
tbody tr>td:nth-child(3){overflow: hidden;text-overflow: ellipsis;white-space: nowrap;max-width:180px;}
tbody tr>td:nth-child(5){overflow: hidden;text-overflow: ellipsis;white-space: nowrap;max-width:200px;}
</style>
<div class="row">
<div class="col-xs-12 center-block" style="float: none;">
<div class="panel panel-default panel-intro">
<div class="panel-body">
<form onsubmit="return searchSubmit()" method="GET" class="form-inline" id="searchToolbar">
<div class="form-group">
<label>搜索</label>
<div class="form-group">
<select name="type" class="form-control"><option value="1">域名</option><option value="3">备用解析记录</option><option value="2">解析记录ID</option><option value="4">备注</option></select>
</div>
</div>
<div class="form-group">
<input type="text" class="form-control" name="kw" placeholder="">
</div>
<div class="form-group">
<div class="form-group">
<select name="stype" class="form-control"><option value="">执行方式</option><option value="0">单次执行</option><option value="1">周期执行</option></select>
</div>
</div>
<button type="submit" class="btn btn-primary"><i class="fa fa-search"></i> 搜索</button>
<a href="javascript:searchClear()" class="btn btn-default" title="刷新列表"><i class="fa fa-refresh"></i> 刷新</a>
<a href="/schedule/stask/add" class="btn btn-success"><i class="fa fa-plus"></i> 添加</a>
<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>
<ul class="dropdown-menu"><li><a href="javascript:operation('open')">开启运行</a></li><li><a href="javascript:operation('close')">停止运行</a></li><li><a href="javascript:operation('delete')">删除</a></li></ul>
</div>
</form>
<table id="listTable">
</table>
</div>
</div>
</div>
</div>
{/block}
{block name="script"}
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
<script src="{$cdnpublic}bootstrap-table/1.21.4/bootstrap-table.min.js"></script>
<script src="{$cdnpublic}bootstrap-table/1.21.4/extensions/page-jump-to/bootstrap-table-page-jump-to.min.js"></script>
<script src="/static/js/custom.js"></script>
<script>
$(document).ready(function(){
updateToolbar();
const defaultPageSize = 15;
const pageNumber = typeof window.$_GET['pageNumber'] != 'undefined' ? parseInt(window.$_GET['pageNumber']) : 1;
const pageSize = typeof window.$_GET['pageSize'] != 'undefined' ? parseInt(window.$_GET['pageSize']) : defaultPageSize;
$("#listTable").bootstrapTable({
url: '/schedule/stask/data',
pageNumber: pageNumber,
pageSize: pageSize,
classes: 'table table-striped table-hover table-bordered',
columns: [
{
field: '',
checkbox: true
},
{
field: 'id',
title: 'ID'
},
{
field: 'rr',
title: '域名',
formatter: function(value, row, index) {
return '<span title="'+row.remark+'" data-toggle="tooltip" data-placement="right">' + value + '.' + row.domain + '</span>';
}
},
{
field: 'type',
title: '时间设置',
formatter: function(value, row, index) {
if(value == 1){
var text = '<span class="label bg-purple">周期执行</span> ';
if(row.cycle == 1) {
weekday = ['日', '一', '二', '三', '四', '五', '六'];
text += '每周'+weekday[row.switchdate]+' ';
} else if(row.cycle == 2) {
text += '每月'+row.switchdate+'日 ';
} else {
text += '每天 ';
}
return text + row.switchtime;
}else{
return '<span class="label bg-aqua">单次执行</span> '+row.switchtime.replace('T', ' ');
}
}
},
{
field: 'switchtype',
title: '切换设置',
formatter: function(value, row, index) {
if(value == 1) {
return '启用解析';
} else if(value == 2) {
return '暂停解析';
} else if(value == 3) {
return '删除解析';
} else {
return '修改解析['+row.value+']';
}
}
},
{
field: 'active',
title: '运行开关',
formatter: function(value, row, index) {
if(value == 1){
return '<div class="material-switch"><input id="active'+row.id+'" type="checkbox" checked onchange="setActive('+row.id+',0)"/><label for="active'+row.id+'" class="label-primary"></label></div>';
}else{
return '<div class="material-switch"><input id="active'+row.id+'" type="checkbox" onchange="setActive('+row.id+',1)"/><label for="active'+row.id+'" class="label-primary"></label></div>';
}
}
},
{
field: 'updatetimestr',
title: '上次切换时间'
},
{
field: 'nexttimestr',
title: '下次切换时间',
visible: false
},
{
field: 'addtimestr',
title: '添加时间',
visible: false
},
{
field: 'remark',
title: '备注'
},
{
field: 'action',
title: '操作',
formatter: function(value, row, index) {
var domain = row.rr + '.' + row.domain;
var html = '<a href="/log?uid=0&domain='+domain+'" class="btn btn-info btn-xs">切换日志</a>&nbsp;&nbsp;';
html += '<a href="/schedule/stask/edit?id='+row.id+'" class="btn btn-primary btn-xs">修改</a>&nbsp;&nbsp;';
html += '<a href="/record/'+row.did+'?subdomain='+row.rr+'" class="btn btn-default btn-xs" target="_blank">解析</a>&nbsp;&nbsp;';
html += '<a href="javascript:delItem(\''+row.id+'\')" class="btn btn-danger btn-xs">删除</a>&nbsp;&nbsp;';
return html;
}
},
],
onLoadSuccess: function(data) {
$('[data-toggle="tooltip"]').tooltip()
}
})
})
function setActive(id, active){
$.post('/schedule/stask/setactive', {id: id, active: active}, function(data){
if(data.code == 0) {
layer.msg('修改成功', {icon: 1, time:800});
searchRefresh();
} else {
layer.msg(data.msg, {icon: 2});
}
}, 'json');
}
function delItem(id){
layer.confirm('确定要删除此切换策略吗?', {
btn: ['确定','取消']
}, function(){
$.post('/schedule/stask/del', {id: id}, function(data){
if(data.code == 0) {
layer.msg('删除成功', {icon: 1, time:800});
searchRefresh();
} else {
layer.msg(data.msg, {icon: 2});
}
}, 'json');
});
}
function operation(action){
var rows = $("#listTable").bootstrapTable('getSelections');
if(rows.length == 0){
layer.msg('请选择要操作的策略');
return;
}
var ids = [];
for(var i in rows){
ids.push(rows[i].id);
}
if(action == 'delete'){
if(!confirm('确定要删除所选策略吗?')) return;
}
var ii = layer.load(2);
$.ajax({
type : 'POST',
url : '/schedule/stask/operation',
data : {act: action, ids: ids},
dataType : 'json',
success : function(data) {
layer.close(ii);
if(data.code == 0){
layer.closeAll();
layer.alert(data.msg, {icon: 1});
searchRefresh();
}else{
layer.alert(data.msg, {icon: 2});
}
}
});
}
</script>
{/block}

View File

@@ -0,0 +1,269 @@
{extend name="common/layout" /}
{block name="title"}定时切换策略{/block}
{block name="main"}
<style>
.dselect::before{
content: '.';
position: absolute;
left: 0;
}
.control-label[is-required]:before {
content: "*";
color: #f56c6c;
margin-right: 4px;
}
.tips{color: #f6a838; padding-left: 5px;}
</style>
<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="/schedule/stask" class="btn btn-sm btn-default pull-right" style="margin-top:-6px"><i class="fa fa-reply fa-fw"></i> 返回</a>{if $action=='edit'}编辑{else}添加{/if}定时切换策略</h3></div>
<div class="panel-body">
<form onsubmit="return false" method="post" class="form-horizontal" role="form" id="taskform">
<div class="form-group">
<label class="col-sm-3 col-xs-12 control-label no-padding-right" is-required>域名选择</label>
<div class="col-sm-6">
<div class="input-group">
<input type="text" name="rr" v-model="set.rr" placeholder="主机记录" class="form-control" required>
<span class="input-group-addon">.</span>
<select name="did" v-model="set.did" class="form-control" required>
<option value="">--主域名--</option>
<option v-for="option in domainList" :value="option.id">{{option.name}}</option>
</select>
</div>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right" is-required>解析记录</label>
<div class="col-sm-6"><div class="input-group">
<select name="recordid" v-model="set.recordid" id="recordid" class="form-control" required>
<option v-for="option in recordList" :value="option.RecordId">{{option.Value}} (线路:{{option.LineName}})</option>
</select>
<div class="input-group-btn">
<button type="button" @click="getRecordList" class="btn btn-info">点击获取</button>
</div>
</div></div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right" is-required>执行方式</label>
<div class="col-sm-6">
<label class="radio-inline">
<input type="radio" name="type" value="0" v-model="set.type"> 单次执行
</label>
<label class="radio-inline">
<input type="radio" name="type" value="1" v-model="set.type"> 周期执行
</label>
</div>
</div>
<div class="form-group" v-show="set.type==0">
<label class="col-sm-3 control-label no-padding-right" is-required>时间设置</label>
<div class="col-sm-6">
<input type="datetime-local" name="switchtime" v-model="set.switchtime" class="form-control" required>
</div>
</div>
<div class="form-group" v-show="set.type==1">
<label class="col-sm-3 control-label no-padding-right" is-required>时间设置</label>
<div class="col-sm-6">
<div class="input-group">
<select name="cycle" v-model="set.cycle" class="form-control" required>
<option value="0">每天</option>
<option value="1">每周</option>
<option value="2">每月</option>
</select>
<span class="input-group-addon" v-show="set.cycle!=0"></span>
<select name="switchdate" v-model="set.switchdate" class="form-control" required v-show="set.cycle==1">
<option value="0"></option>
<option value="1"></option>
<option value="2"></option>
<option value="3"></option>
<option value="4"></option>
<option value="5"></option>
<option value="6"></option>
</select>
<input type="number" name="switchdate" v-model="set.switchdate" class="form-control" required min="1" max="31" v-show="set.cycle==2" placeholder="日期1~31">
<span class="input-group-addon"></span>
<input type="time" name="switchtime" v-model="set.switchtime" class="form-control" required>
</div>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right" is-required>切换设置</label>
<div class="col-sm-6">
<label class="radio-inline">
<input type="radio" name="switchtype" value="0" v-model="set.switchtype"> 修改解析
</label>
<label class="radio-inline">
<input type="radio" name="switchtype" value="1" v-model="set.switchtype"> 启用解析
</label>
<label class="radio-inline">
<input type="radio" name="switchtype" value="2" v-model="set.switchtype"> 暂停解析
</label>
<label class="radio-inline" v-show="set.type==0">
<input type="radio" name="switchtype" value="3" v-model="set.switchtype"> 删除解析
</label>
</div>
</div>
<div class="form-group" v-show="set.switchtype==0">
<label class="col-sm-3 control-label no-padding-right" is-required>记录值</label>
<div class="col-sm-6">
<input type="text" name="value" v-model="set.value" placeholder="支持填写IPv4或CNAME地址" class="form-control" required>
</div>
</div>
<div class="form-group" v-show="set.switchtype==0&&dnstype=='cloudflare'">
<label class="col-sm-3 control-label no-padding-right" is-required>线路</label>
<div class="col-sm-6">
<label class="radio-inline">
<input type="radio" name="line" value="" v-model="set.line"> 不修改
</label>
<label class="radio-inline">
<input type="radio" name="line" value="0" v-model="set.line"> 改为仅DNS模式
</label>
<label class="radio-inline">
<input type="radio" name="line" value="1" v-model="set.line"> 改为代理模式
</label>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label no-padding-right">备注</label>
<div class="col-sm-6">
<input type="text" name="remark" v-model="set.remark" placeholder="可留空" class="form-control">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-6"><button type="button" class="btn btn-primary" @click="submit">提交</button></div>
</div>
</form>
</div>
<div class="panel-footer">
<p>添加定时切换策略后,还需要配置好<a href="/system/cronset">计划任务</a>,才能自动切换。</p>
</div>
</div>
{/block}
{block name="script"}
<script src="{$cdnpublic}vue/2.6.14/vue.min.js"></script>
<script src="{$cdnpublic}layer/3.1.1/layer.js"></script>
<script src="/static/js/bootstrapValidator.min.js"></script>
<script>
var action = '{$action}';
var info = {$info|json_encode|raw};
var domainList = {$domains|json_encode|raw};
new Vue({
el: '#app',
data: {
action: '{$action}',
set: {
id: '',
remark: '',
rr: '',
did: '',
recordid: '',
recordinfo: '',
type: 0,
cycle: 0,
switchtype: 0,
switchdate: '',
switchtime: '',
value: '',
line: '',
},
dnstype: null,
domainList: domainList,
recordList: [],
},
watch: {
'set.recordid': function(val){
if(val == '') return;
var record = this.recordList.find(item => item.RecordId == val);
if(record){
this.set.recordinfo = JSON.stringify({Value:record.Value, Line:record.Line, LineName:record.LineName, TTL:record.TTL});
}
},
'set.did': function(val){
if(val == '') return;
this.dnstype = this.domainList.find(item => item.id == val).type;
}
},
mounted() {
if(this.action == 'edit'){
Object.keys(info).forEach((key) => {
this.$set(this.set, key, info[key])
})
var recordinfo = JSON.parse(this.set.recordinfo);
this.recordList = [{RecordId:this.set.recordid, Value:recordinfo.Value, Line:recordinfo.Line, LineName:recordinfo.LineName, TTL:recordinfo.TTL}];
}
$("#taskform").bootstrapValidator({
live: 'submitted',
});
$('[data-toggle="tooltip"]').tooltip();
},
methods: {
getRecordList(){
var that = this;
if(this.set.did == ''){
layer.msg('请先选择域名', {time: 800});return;
}
if(this.set.rr == ''){
layer.msg('主机记录不能为空', {time: 800});return;
}
var ii = layer.load(2, {shade:[0.1,'#fff']});
$.ajax({
type : 'POST',
url : '/record/list',
data : {id:this.set.did, rr:this.set.rr},
dataType : 'json',
success : function(data) {
layer.close(ii);
if(data.code == 0){
layer.msg('成功获取到'+data.data.length+'条解析记录', {icon:1, time:800});
that.recordList = data.data;
if(that.set.recordid){
var record = that.recordList.find(item => item.RecordId == that.set.recordid);
if(record){
that.set.recordinfo = JSON.stringify({Value:record.Value, Line:record.Line, LineName:record.LineName, TTL:record.TTL});
}
}
}else{
layer.alert(data.msg, {icon:2});
}
},
error:function(data){
layer.close(ii);
layer.msg('服务器错误');
}
});
},
submit(){
var that=this;
$("#taskform").data("bootstrapValidator").validate();
if(!$("#taskform").data("bootstrapValidator").isValid()){
return false;
}
var ii = layer.load(2, {shade:[0.1,'#fff']});
$.ajax({
type: "POST",
url: "",
data: this.set,
dataType: 'json',
success: function(data) {
layer.close(ii);
if(data.code == 0){
layer.alert(data.msg, {icon: 1}, function(){
if(document.referrer.indexOf('task?') > 0)
window.location.href = document.referrer;
else
window.location.href = '/dmonitor/task';
});
}else{
layer.alert(data.msg, {icon: 2});
}
},
error: function(data){
layer.close(ii);
layer.msg('服务器错误');
}
});
}
},
});
</script>
{/block}

View File

@@ -68,6 +68,10 @@
<td>CF优选IP更新</td>
<td><font color="green">{:config_get('optimize_ip_time', '未运行', true)}</font></td>
</tr>
<tr>
<td>定时切换解析</td>
<td><font color="green">{:config_get('schedule_time', '未运行', true)}</font></td>
</tr>
</tbody>
</table>
</div>

View File

@@ -31,7 +31,7 @@ return [
'show_error_msg' => true,
'exception_tmpl' => \think\facade\App::getAppPath() . 'view/exception.tpl',
'version' => '1039',
'version' => '1040',
'dbversion' => '1033'
'dbversion' => '1040'
];

View File

@@ -79,7 +79,8 @@ Route::group(function () {
Route::post('/dmonitor/task/data', 'dmonitor/task_data');
Route::post('/dmonitor/task/log/data/:id', 'dmonitor/tasklog_data');
Route::get('/dmonitor/task/info/:id', 'dmonitor/taskinfo');
Route::any('/dmonitor/task/:action', 'dmonitor/taskform');
Route::post('/dmonitor/task/:action', 'dmonitor/task_op');
Route::get('/dmonitor/task/:action', 'dmonitor/taskform');
Route::get('/dmonitor/task', 'dmonitor/task');
Route::post('/dmonitor/clean', 'dmonitor/clean');
@@ -113,6 +114,11 @@ Route::group(function () {
Route::get('/cert/certset', 'cert/certset');
Route::post('/schedule/stask/data', 'schedule/stask_data');
Route::post('/schedule/stask/:action', 'schedule/stask_op');
Route::get('/schedule/stask/:action', 'schedule/staskform');
Route::get('/schedule/stask', 'schedule/stask');
Route::get('/system/loginset', 'system/loginset');
Route::get('/system/noticeset', 'system/noticeset');
Route::get('/system/proxyset', 'system/proxyset');