From fd21a55d01d70309e6e97703310a62680e7d3982 Mon Sep 17 00:00:00 2001 From: net909 Date: Fri, 22 Aug 2025 21:25:42 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=AE=9A=E6=97=B6=E5=88=87?= =?UTF-8?q?=E6=8D=A2=E8=A7=A3=E6=9E=90=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/command/Certtask.php | 4 +- app/controller/Dmonitor.php | 197 ++++++++++++---------- app/controller/Domain.php | 2 + app/controller/Schedule.php | 165 +++++++++++++++++++ app/controller/System.php | 2 + app/controller/User.php | 2 +- app/service/ScheduleService.php | 118 ++++++++++++++ app/sql/install.sql | 25 ++- app/sql/update.sql | 24 ++- app/view/common/layout.html | 27 ++-- app/view/dmonitor/task.html | 91 ++++++++--- app/view/domain/domain.html | 2 +- app/view/domain/record.html | 2 +- app/view/schedule/stask.html | 216 +++++++++++++++++++++++++ app/view/schedule/staskform.html | 269 +++++++++++++++++++++++++++++++ app/view/system/cronset.html | 4 + config/app.php | 4 +- route/app.php | 8 +- 18 files changed, 1036 insertions(+), 126 deletions(-) create mode 100644 app/controller/Schedule.php create mode 100644 app/service/ScheduleService.php create mode 100644 app/view/schedule/stask.html create mode 100644 app/view/schedule/staskform.html diff --git a/app/command/Certtask.php b/app/command/Certtask.php index 74331a5..d75f8e4 100644 --- a/app/command/Certtask.php +++ b/app/command/Certtask.php @@ -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(); diff --git a/app/controller/Dmonitor.php b/app/controller/Dmonitor.php index 9e1de1a..c69b0a7 100644 --- a/app/controller/Dmonitor.php +++ b/app/controller/Dmonitor.php @@ -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'); diff --git a/app/controller/Domain.php b/app/controller/Domain.php index ebc8e8e..85c7df4 100644 --- a/app/controller/Domain.php +++ b/app/controller/Domain.php @@ -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]); diff --git a/app/controller/Schedule.php b/app/controller/Schedule.php new file mode 100644 index 0000000..9b83cd4 --- /dev/null +++ b/app/controller/Schedule.php @@ -0,0 +1,165 @@ +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(); + } + +} diff --git a/app/controller/System.php b/app/controller/System.php index 727b490..fd5dbd7 100644 --- a/app/controller/System.php +++ b/app/controller/System.php @@ -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(); diff --git a/app/controller/User.php b/app/controller/User.php index 092b690..1c58560 100644 --- a/app/controller/User.php +++ b/app/controller/User.php @@ -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)) { diff --git a/app/service/ScheduleService.php b/app/service/ScheduleService.php new file mode 100644 index 0000000..94685c4 --- /dev/null +++ b/app/service/ScheduleService.php @@ -0,0 +1,118 @@ +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")]); + } +} diff --git a/app/sql/install.sql b/app/sql/install.sql index 3ab4039..5f25bd6 100644 --- a/app/sql/install.sql +++ b/app/sql/install.sql @@ -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; \ No newline at end of file diff --git a/app/sql/update.sql b/app/sql/update.sql index 3c9db10..7caab52 100644 --- a/app/sql/update.sql +++ b/app/sql/update.sql @@ -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'; \ No newline at end of file +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; \ No newline at end of file diff --git a/app/view/common/layout.html b/app/view/common/layout.html index 3b65dea..db40085 100644 --- a/app/view/common/layout.html +++ b/app/view/common/layout.html @@ -126,18 +126,8 @@
  • 切换策略
  • -
  • - - - CF优选IP - - - - - +
  • + 定时切换
  • @@ -156,6 +146,19 @@
  • 自动续签设置
  • +
  • + + + CF优选IP + + + + + +
  • diff --git a/app/view/dmonitor/task.html b/app/view/dmonitor/task.html index a3a47a9..b05a4aa 100644 --- a/app/view/dmonitor/task.html +++ b/app/view/dmonitor/task.html @@ -2,7 +2,8 @@ {block name="title"}容灾切换策略{/block} {block name="main"}
    @@ -27,6 +28,10 @@ tbody tr>td:nth-child(2){overflow: hidden;text-overflow: ellipsis;white-space: n 刷新 添加 + @@ -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 'TCP'; + } else if(value == 2) { + return 'HTTP(S)'; + } 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 '' + value + '秒'; + 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 = '切换日志  '; html += '修改  '; - html += '解析  '; + html += '解析  '; html += '删除  '; 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}); + } + } + }); +} {/block} \ No newline at end of file diff --git a/app/view/domain/domain.html b/app/view/domain/domain.html index a0beb10..48430a8 100644 --- a/app/view/domain/domain.html +++ b/app/view/domain/domain.html @@ -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); } }, }) diff --git a/app/view/domain/record.html b/app/view/domain/record.html index 4f42403..fe95a77 100644 --- a/app/view/domain/record.html +++ b/app/view/domain/record.html @@ -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); } }, }); diff --git a/app/view/schedule/stask.html b/app/view/schedule/stask.html new file mode 100644 index 0000000..60f6bc3 --- /dev/null +++ b/app/view/schedule/stask.html @@ -0,0 +1,216 @@ +{extend name="common/layout" /} +{block name="title"}定时切换策略{/block} +{block name="main"} + +
    +
    +
    +
    + +
    +
    + +
    + +
    +
    +
    + +
    +
    +
    + +
    +
    + + 刷新 + 添加 +
    + + +
    + + +
    +
    +
    +
    + + +{/block} +{block name="script"} + + + + + +{/block} \ No newline at end of file diff --git a/app/view/schedule/staskform.html b/app/view/schedule/staskform.html new file mode 100644 index 0000000..ae34e9b --- /dev/null +++ b/app/view/schedule/staskform.html @@ -0,0 +1,269 @@ +{extend name="common/layout" /} +{block name="title"}定时切换策略{/block} +{block name="main"} + +
    +
    +
    +

    返回{if $action=='edit'}编辑{else}添加{/if}定时切换策略

    +
    +
    +
    + +
    +
    + + . + +
    +
    +
    +
    + +
    + +
    + +
    +
    +
    +
    + +
    + + +
    +
    +
    + +
    + +
    +
    +
    + +
    +
    + + + + + + +
    +
    +
    +
    + +
    + + + + +
    +
    +
    + +
    + +
    +
    +
    + +
    + + + +
    +
    +
    + +
    + +
    +
    +
    +
    +
    +
    +
    + +
    +{/block} +{block name="script"} + + + + +{/block} \ No newline at end of file diff --git a/app/view/system/cronset.html b/app/view/system/cronset.html index 6b8c960..8bf5564 100644 --- a/app/view/system/cronset.html +++ b/app/view/system/cronset.html @@ -68,6 +68,10 @@ CF优选IP更新 {:config_get('optimize_ip_time', '未运行', true)} + + 定时切换解析 + {:config_get('schedule_time', '未运行', true)} +
    diff --git a/config/app.php b/config/app.php index bb2c457..660ea29 100644 --- a/config/app.php +++ b/config/app.php @@ -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' ]; diff --git a/route/app.php b/route/app.php index 1630a46..7dccb74 100644 --- a/route/app.php +++ b/route/app.php @@ -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');