diff --git a/README.md b/README.md
index 0168d4c..495e604 100644
--- a/README.md
+++ b/README.md
@@ -1,50 +1,31 @@
-## 聚合DNS管理系统
+# 彩虹聚合DNS管理系统
-聚合DNS管理系统可以实现在一个网站内管理多个平台的域名解析,目前已支持的域名平台有:阿里云、腾讯云、华为云、百度云、西部数码、火山引擎、DNSLA、CloudFlare、Namesilo
+
-### 功能特性
+[](https://github.com/netcccyun/dnsmgr/stargazers)
+[](https://github.com/netcccyun/dnsmgr/forks)
+[](https://hub.docker.com/r/netcccyun/dnsmgr)
+[](https://github.com/netcccyun/dnsmgr/releases)
+[](https://github.com/netcccyun/dnsmgr/commits/main)
-- 多用户管理,可为每个用户可分配不同的域名解析权限
-- 提供API接口,可获取域名单独的登录链接,方便各种IDC系统对接
-- 容灾切换功能,支持ping、tcp、http(s)检测协议并自动暂停/修改域名解析,并支持邮件、微信公众号、TG群机器人通知
-- CF优选IP功能,支持获取最新的Cloudflare优选IP,并自动更新到解析记录
-- SSL证书申请与自动部署功能,支持从Let's Encrypt等渠道申请SSL证书,并自动部署到各种面板、云服务商、服务器等
+
-### 演示截图
+彩虹聚合DNS管理系统 是一款基于ThinkPHP开发的网站程序,可实现在单一网站内管理多个平台的域名解析,目前已支持的域名解析平台有:阿里云、腾讯云、华为云、百度云、西部数码、火山引擎、DNSLA、CloudFlare、Namesilo、PowerDNS
-添加域名账户
+## 功能特性
-
+- 多用户管理,可为每个用户可分配不同的域名解析权限;
+- 提供API接口,可获取域名单独的登录链接,方便各种IDC系统对接;
+- 容灾切换功能,支持ping、tcp、http(s)检测协议并自动暂停/修改域名解析,并支持发送通知;
+- CF优选IP功能,支持获取最新的Cloudflare优选IP,并自动更新到解析记录;
+- SSL证书申请与自动部署功能,支持从Let's Encrypt等渠道申请SSL证书,并自动部署到各种面板、云服务商、服务器等;
+- 支持邮件、微信公众号、Telegram、钉钉、飞书、企业微信等多种通知渠道。
-域名管理列表
+## 部署方式
-
+### 自部署
-域名DNS解析管理,支持解析批量操作
-
-
-
-用户管理添加用户,支持为用户开启API接口
-
-
-
-CF优选IP功能,添加优选IP任务
-
-
-
-SSL证书申请功能
-
-
-
-
-
-SSL证书自动部署功能
-
-
-
-
-
-### 部署方法
+可以使用宝塔、Kangle等任意支持PHP-MySQL的环境部署
* 从[Release](https://github.com/netcccyun/dnsmgr/releases)页面下载安装包
@@ -64,6 +45,8 @@ SSL证书自动部署功能
* 访问首页登录控制面板
+* 后续更新方式:重新下载安装包上传覆盖即可
+
##### 伪静态规则
* Nginx
@@ -89,7 +72,7 @@ location / {
```
-### Docker部署方法
+### Docker 部署
首先需要安装Docker,然后执行以下命令拉取镜像并启动(启动后监听8081端口):
@@ -103,7 +86,7 @@ docker run --name dnsmgr -dit -p 8081:80 -v /var/dnsmgr:/app/www netcccyun/dnsmg
docker restart dnsmgr
```
-### docker-compose部署方法
+### docker-compose 部署
```
version: '3'
@@ -144,6 +127,7 @@ networks:
```
在运行之前请创建好目录
+
```
mkdir -p ./web
mkdir -p ./mysql/conf
@@ -156,6 +140,7 @@ sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_
```
登陆mysql容器创建数据库
+
```
docker exec -it dnsmgr-mysql /bin/bash
mysql -uroot -p123456
@@ -164,9 +149,45 @@ create database dnsmgr;
在install界面链接IP填写dnsmgr-mysql
-### 作者信息
+## 演示截图
-消失的彩虹海(https://blog.cccyun.cn)
+添加域名账户
+
+
+
+域名管理列表
+
+
+
+域名DNS解析管理,支持解析批量操作
+
+
+
+用户管理添加用户,支持为用户开启API接口
+
+
+
+CF优选IP功能,添加优选IP任务
+
+
+
+SSL证书申请功能
+
+
+
+
+
+SSL证书自动部署功能
+
+
+
+
+
+## 支持与反馈
+
+🌐 作者信息:消失的彩虹海(https://blog.cccyun.cn)
+
+⭐ 如果您觉得本项目对您有帮助,欢迎给项目点个 Star
### 其他推荐
diff --git a/app/controller/Cert.php b/app/controller/Cert.php
index 324f79c..fe4cb7f 100644
--- a/app/controller/Cert.php
+++ b/app/controller/Cert.php
@@ -435,6 +435,35 @@ class Cert extends BaseController
$file = app()->getRuntimePath().'log/'.$processid.'.log';
if(!file_exists($file)) return json(['code' => -1, 'msg' => '日志文件不存在']);
return json(['code' => 0, 'data' => file_get_contents($file), 'time'=>filemtime($file)]);
+ } elseif ($action == 'operation') {
+ $ids = input('post.ids');
+ $success = 0;
+ foreach ($ids as $id) {
+ if (input('post.action') == 'delete') {
+ $dcount = DB::name('cert_deploy')->where('oid', $id)->count();
+ if ($dcount > 0) continue;
+ try {
+ (new CertOrderService($id))->cancel();
+ } catch (Exception $e) {
+ }
+ Db::name('cert_order')->where('id', $id)->delete();
+ Db::name('cert_domain')->where('oid', $id)->delete();
+ $success++;
+ } elseif (input('post.action') == 'reset') {
+ try {
+ $service = new CertOrderService($id);
+ $service->cancel();
+ $service->reset();
+ $success++;
+ } catch (Exception $e) {
+ }
+ } elseif (input('post.action') == 'open' || input('post.action') == 'close') {
+ $isauto = input('post.action') == 'open' ? 1 : 0;
+ Db::name('cert_order')->where('id', $id)->update(['isauto' => $isauto]);
+ $success++;
+ }
+ }
+ return json(['code' => 0, 'msg' => '成功操作' . $success . '个证书订单']);
}
return json(['code' => -3]);
}
@@ -645,6 +674,27 @@ class Cert extends BaseController
$file = app()->getRuntimePath().'log/'.$processid.'.log';
if(!file_exists($file)) return json(['code' => -1, 'msg' => '日志文件不存在']);
return json(['code' => 0, 'data' => file_get_contents($file), 'time'=>filemtime($file)]);
+ } elseif ($action == 'operation') {
+ $ids = input('post.ids');
+ $success = 0;
+ foreach ($ids as $id) {
+ if (input('post.action') == 'delete') {
+ Db::name('cert_deploy')->where('id', $id)->delete();
+ $success++;
+ } elseif (input('post.action') == 'reset') {
+ try {
+ $service = new CertDeployService($id);
+ $service->reset();
+ $success++;
+ } catch (Exception $e) {
+ }
+ } elseif (input('post.action') == 'open' || input('post.action') == 'close') {
+ $active = input('post.action') == 'open' ? 1 : 0;
+ Db::name('cert_deploy')->where('id', $id)->update(['active' => $active]);
+ $success++;
+ }
+ }
+ return json(['code' => 0, 'msg' => '成功操作' . $success . '个任务']);
}
return json(['code' => -3]);
}
diff --git a/app/lib/DnsHelper.php b/app/lib/DnsHelper.php
index 150d4c2..6e71ba9 100644
--- a/app/lib/DnsHelper.php
+++ b/app/lib/DnsHelper.php
@@ -85,6 +85,19 @@ class DnsHelper
'weight' => true,
'page' => false,
],
+ 'jdcloud' => [
+ 'name' => '京东云',
+ 'config' => [
+ 'ak' => 'AccessKeyId',
+ 'sk' => 'AccessKeySecret',
+ ],
+ 'remark' => 0,
+ 'status' => true,
+ 'redirect' => true,
+ 'log' => false,
+ 'weight' => true,
+ 'page' => false,
+ ],
'dnsla' => [
'name' => 'DNSLA',
'config' => [
diff --git a/app/lib/client/AliyunNew.php b/app/lib/client/AliyunNew.php
index c8632a8..eca2a89 100644
--- a/app/lib/client/AliyunNew.php
+++ b/app/lib/client/AliyunNew.php
@@ -34,13 +34,15 @@ class AliyunNew
public function request($method, $action, $path = '/', $params = null)
{
if (!empty($params)) {
- $params = array_filter($params, function ($a) { return $a !== null;});
+ $params = array_filter($params, function ($a) {
+ return $a !== null;
+ });
}
- if($method == 'GET' || $method == 'DELETE'){
+ if ($method == 'GET' || $method == 'DELETE') {
$query = $params;
$body = '';
- }else{
+ } else {
$query = [];
$body = !empty($params) ? json_encode($params) : '';
}
@@ -59,13 +61,13 @@ class AliyunNew
$authorization = $this->generateSign($method, $path, $query, $headers, $body);
$headers['Authorization'] = $authorization;
- $url = 'https://'.$this->Endpoint.$path;
+ $url = 'https://' . $this->Endpoint . $path;
if (!empty($query)) {
- $url .= '?'.http_build_query($query);
+ $url .= '?' . http_build_query($query);
}
$header = [];
foreach ($headers as $key => $value) {
- $header[] = $key.': '.$value;
+ $header[] = $key . ': ' . $value;
}
return $this->curl($method, $url, $body, $header);
}
@@ -80,17 +82,17 @@ class AliyunNew
$canonicalQueryString = $this->getCanonicalQueryString($query);
[$canonicalHeaders, $signedHeaders] = $this->getCanonicalHeaders($headers);
$hashedRequestPayload = hash("sha256", $body);
- $canonicalRequest = $httpRequestMethod."\n"
- .$canonicalUri."\n"
- .$canonicalQueryString."\n"
- .$canonicalHeaders."\n"
- .$signedHeaders."\n"
- .$hashedRequestPayload;
+ $canonicalRequest = $httpRequestMethod . "\n"
+ . $canonicalUri . "\n"
+ . $canonicalQueryString . "\n"
+ . $canonicalHeaders . "\n"
+ . $signedHeaders . "\n"
+ . $hashedRequestPayload;
// step 2: build string to sign
$hashedCanonicalRequest = hash("sha256", $canonicalRequest);
- $stringToSign = $algorithm."\n"
- .$hashedCanonicalRequest;
+ $stringToSign = $algorithm . "\n"
+ . $hashedCanonicalRequest;
// step 3: sign string
$signature = hash_hmac("sha256", $stringToSign, $this->AccessKeySecret);
@@ -125,7 +127,7 @@ class AliyunNew
ksort($parameters);
$canonicalQueryString = '';
foreach ($parameters as $key => $value) {
- $canonicalQueryString .= '&' . $this->escape($key). '=' . $this->escape($value);
+ $canonicalQueryString .= '&' . $this->escape($key) . '=' . $this->escape($value);
}
return substr($canonicalQueryString, 1);
}
@@ -176,10 +178,10 @@ class AliyunNew
if ($httpCode == 200) {
return $arr;
} elseif ($arr) {
- if(strpos($arr['Message'], '.') > 0) $arr['Message'] = substr($arr['Message'], 0, strpos($arr['Message'], '.')+1);
+ if (strpos($arr['Message'], '.') > 0) $arr['Message'] = substr($arr['Message'], 0, strpos($arr['Message'], '.') + 1);
throw new Exception($arr['Message']);
} else {
throw new Exception('返回数据解析失败');
}
}
-}
\ No newline at end of file
+}
diff --git a/app/lib/client/Jdcloud.php b/app/lib/client/Jdcloud.php
new file mode 100644
index 0000000..75fd7cf
--- /dev/null
+++ b/app/lib/client/Jdcloud.php
@@ -0,0 +1,190 @@
+AccessKeyId = $AccessKeyId;
+ $this->AccessKeySecret = $AccessKeySecret;
+ $this->endpoint = $endpoint;
+ $this->service = $service;
+ $this->region = $region;
+ $this->proxy = $proxy;
+ }
+
+ /**
+ * @param string $method 请求方法
+ * @param string $path 请求路径
+ * @param array $params 请求参数
+ * @return array
+ * @throws Exception
+ */
+ public function request($method, $path, $params = [])
+ {
+ if (!empty($params)) {
+ $params = array_filter($params, function ($a) {
+ return $a !== null;
+ });
+ }
+
+ if ($method == 'GET' || $method == 'DELETE') {
+ $query = $params;
+ $body = '';
+ } else {
+ $query = [];
+ $body = !empty($params) ? json_encode($params) : '';
+ }
+
+ $date = gmdate("Ymd\THis\Z");
+ $headers = [
+ 'Host' => $this->endpoint,
+ 'x-jdcloud-algorithm' => self::$algorithm,
+ 'x-jdcloud-date' => $date,
+ 'x-jdcloud-nonce' => uniqid('php', true),
+ ];
+ if ($body) {
+ $headers['Content-Type'] = 'application/json';
+ }
+
+ $authorization = $this->generateSign($method, $path, $query, $headers, $body, $date);
+ $headers['authorization'] = $authorization;
+
+ $url = 'https://' . $this->endpoint . $path;
+ if (!empty($query)) {
+ $url .= '?' . http_build_query($query);
+ }
+ $header = [];
+ foreach ($headers as $key => $value) {
+ $header[] = $key . ': ' . $value;
+ }
+ return $this->curl($method, $url, $body, $header);
+ }
+
+ private function generateSign($method, $path, $query, $headers, $body, $date)
+ {
+ // step 1: build canonical request string
+ $httpRequestMethod = $method;
+ $canonicalUri = $path;
+ $canonicalQueryString = $this->getCanonicalQueryString($query);
+ [$canonicalHeaders, $signedHeaders] = $this->getCanonicalHeaders($headers);
+ $hashedRequestPayload = hash("sha256", $body);
+ $canonicalRequest = $httpRequestMethod . "\n"
+ . $canonicalUri . "\n"
+ . $canonicalQueryString . "\n"
+ . $canonicalHeaders . "\n"
+ . $signedHeaders . "\n"
+ . $hashedRequestPayload;
+
+ // step 2: build string to sign
+ $shortDate = substr($date, 0, 8);
+ $credentialScope = $shortDate . '/' . $this->region . '/' . $this->service . '/jdcloud2_request';
+ $hashedCanonicalRequest = hash("sha256", $canonicalRequest);
+ $stringToSign = self::$algorithm . "\n"
+ . $date . "\n"
+ . $credentialScope . "\n"
+ . $hashedCanonicalRequest;
+
+ // step 3: sign string
+ $kDate = hash_hmac("sha256", $shortDate, 'JDCLOUD2' . $this->AccessKeySecret, true);
+ $kRegion = hash_hmac("sha256", $this->region, $kDate, true);
+ $kService = hash_hmac("sha256", $this->service, $kRegion, true);
+ $kSigning = hash_hmac("sha256", "jdcloud2_request", $kService, true);
+ $signature = hash_hmac("sha256", $stringToSign, $kSigning);
+
+ // step 4: build authorization
+ $credential = $this->AccessKeyId . '/' . $credentialScope;
+ $authorization = self::$algorithm . ' Credential=' . $credential . ", SignedHeaders=" . $signedHeaders . ", Signature=" . $signature;
+
+ return $authorization;
+ }
+
+ private function escape($str)
+ {
+ $search = ['+', '*', '%7E'];
+ $replace = ['%20', '%2A', '~'];
+ return str_replace($search, $replace, urlencode($str));
+ }
+
+ private function getCanonicalQueryString($parameters)
+ {
+ if (empty($parameters)) return '';
+ ksort($parameters);
+ $canonicalQueryString = '';
+ foreach ($parameters as $key => $value) {
+ $canonicalQueryString .= '&' . $this->escape($key) . '=' . $this->escape($value);
+ }
+ return substr($canonicalQueryString, 1);
+ }
+
+ private function getCanonicalHeaders($oldheaders)
+ {
+ $headers = array();
+ foreach ($oldheaders as $key => $value) {
+ $headers[strtolower($key)] = trim($value);
+ }
+ ksort($headers);
+
+ $canonicalHeaders = '';
+ $signedHeaders = '';
+ foreach ($headers as $key => $value) {
+ $canonicalHeaders .= $key . ':' . $value . "\n";
+ $signedHeaders .= $key . ';';
+ }
+ $signedHeaders = substr($signedHeaders, 0, -1);
+ return [$canonicalHeaders, $signedHeaders];
+ }
+
+ private function curl($method, $url, $body, $header)
+ {
+ $ch = curl_init($url);
+ if ($this->proxy) {
+ curl_set_proxy($ch);
+ }
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
+ curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
+ curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($ch, CURLOPT_TIMEOUT, 10);
+ curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
+ if (!empty($body)) {
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
+ }
+ $response = curl_exec($ch);
+ $errno = curl_errno($ch);
+ if ($errno) {
+ curl_close($ch);
+ throw new Exception('Curl error: ' . curl_error($ch));
+ }
+ $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+ curl_close($ch);
+
+ $arr = json_decode($response, true);
+ if ($httpCode == 200) {
+ if (isset($arr['result'])) {
+ return $arr['result'];
+ }
+ return $arr;
+ } else {
+ if (isset($arr['error']['message'])) {
+ throw new Exception($arr['error']['message']);
+ } else {
+ throw new Exception('返回数据解析失败(http_code=' . $httpCode . ')');
+ }
+ }
+ }
+}
diff --git a/app/lib/dns/jdcloud.php b/app/lib/dns/jdcloud.php
new file mode 100644
index 0000000..dfee9cc
--- /dev/null
+++ b/app/lib/dns/jdcloud.php
@@ -0,0 +1,246 @@
+AccessKeyId = $config['ak'];
+ $this->AccessKeySecret = $config['sk'];
+ $proxy = isset($config['proxy']) ? $config['proxy'] == 1 : false;
+ $this->client = new JdcloudClient($this->AccessKeyId, $this->AccessKeySecret, $this->endpoint, $this->service, $this->region, $proxy);
+ $this->domain = $config['domain'];
+ $this->domainid = $config['domainid'];
+ }
+
+ public function getError()
+ {
+ return $this->error;
+ }
+
+ public function check()
+ {
+ if ($this->getDomainList() != false) {
+ return true;
+ }
+ return false;
+ }
+
+ //获取域名列表
+ public function getDomainList($KeyWord = null, $PageNumber = 1, $PageSize = 20)
+ {
+ $query = ['pageNumber' => $PageNumber, 'pageSize' => $PageSize, 'domainName' => $KeyWord];
+ $data = $this->send_request('GET', '/domain', $query);
+ if ($data) {
+ $list = [];
+ if (!empty($data['dataList'])) {
+ foreach ($data['dataList'] as $row) {
+ $list[] = [
+ 'DomainId' => $row['id'],
+ 'Domain' => $row['domainName'],
+ 'RecordCount' => 0,
+ ];
+ }
+ }
+ return ['total' => $data['totalCount'], 'list' => $list];
+ }
+ return false;
+ }
+
+ //获取解析记录列表
+ public function getDomainRecords($PageNumber = 1, $PageSize = 20, $KeyWord = null, $SubDomain = null, $Value = null, $Type = null, $Line = null, $Status = null)
+ {
+ $query = ['pageNumber' => $PageNumber, 'pageSize' => $PageSize];
+ if (!empty($SubDomain)) {
+ $query += ['search' => $SubDomain];
+ } elseif (!empty($KeyWord)) {
+ $query += ['search' => $KeyWord];
+ }
+ $data = $this->send_request('GET', '/domain/'.$this->domainid.'/ResourceRecord', $query);
+ if ($data) {
+ $list = [];
+ foreach ($data['dataList'] as $row) {
+ if ($row['type'] == 'SRV') {
+ $row['hostValue'] = $row['mxPriority'].' '.$row['weight'].' '.$row['port'].' '.$row['hostValue'];
+ }
+ $list[] = [
+ 'RecordId' => $row['id'],
+ 'Domain' => $this->domain,
+ 'Name' => $row['hostRecord'],
+ 'Type' => $row['type'],
+ 'Value' => $row['hostValue'],
+ 'Line' => array_pop($row['viewValue']),
+ 'TTL' => $row['ttl'],
+ 'MX' => isset($row['mxPriority']) ? $row['mxPriority'] : null,
+ 'Status' => $row['resolvingStatus'] == '2' ? '1' : '0',
+ 'Weight' => $row['weight'],
+ 'Remark' => null,
+ 'UpdateTime' => date('Y-m-d H:i:s', $row['updateTime']),
+ ];
+ }
+ return ['total' => $data['totalCount'], 'list' => $list];
+ }
+ return false;
+ }
+
+ //获取子域名解析记录列表
+ public function getSubDomainRecords($SubDomain, $PageNumber = 1, $PageSize = 20, $Type = null, $Line = null)
+ {
+ return $this->getDomainRecords($PageNumber, $PageSize, null, $SubDomain, null, $Type, $Line);
+ }
+
+ //获取解析记录详细信息
+ public function getDomainRecordInfo($RecordId)
+ {
+ return false;
+ }
+
+ //添加解析记录
+ public function addDomainRecord($Name, $Type, $Value, $Line = '0', $TTL = 600, $MX = 1, $Weight = null, $Remark = null)
+ {
+ $params = ['hostRecord' => $Name, 'type' => $this->convertType($Type), 'hostValue' => $Value, 'viewValue' => intval($Line), 'ttl' => intval($TTL)];
+ if ($Type == 'MX') $params['mxPriority'] = intval($MX);
+ if (!isNullOrEmpty($Weight)) $params['weight'] = intval($Weight);
+ if ($Type == 'SRV') {
+ $values = explode(' ', $Value);
+ $params['mxPriority'] = intval($values[0]);
+ $params['weight'] = intval($values[1]);
+ $params['port'] = intval($values[2]);
+ $params['hostValue'] = $values[3];
+ }
+ $data = $this->send_request('POST', '/domain/'.$this->domainid.'/ResourceRecord', ['req'=>$params]);
+ return is_array($data) ? $data['dataList']['id'] : false;
+ }
+
+ //修改解析记录
+ public function updateDomainRecord($RecordId, $Name, $Type, $Value, $Line = '0', $TTL = 600, $MX = 1, $Weight = null, $Remark = null)
+ {
+ $params = ['domainName'=>$this->domain, 'hostRecord' => $Name, 'type' => $this->convertType($Type), 'hostValue' => $Value, 'viewValue' => intval($Line), 'ttl' => intval($TTL)];
+ if ($Type == 'MX') $params['mxPriority'] = intval($MX);
+ if (!isNullOrEmpty($Weight)) $params['weight'] = intval($Weight);
+ if ($Type == 'SRV') {
+ $values = explode(' ', $Value);
+ $params['mxPriority'] = intval($values[0]);
+ $params['weight'] = intval($values[1]);
+ $params['port'] = intval($values[2]);
+ $params['hostValue'] = $values[3];
+ }
+ return $this->send_request('PUT', '/domain/'.$this->domainid.'/ResourceRecord/'.$RecordId, ['req'=>$params]);
+ }
+
+ //修改解析记录备注
+ public function updateDomainRecordRemark($RecordId, $Remark)
+ {
+ return false;
+ }
+
+ //删除解析记录
+ public function deleteDomainRecord($RecordId)
+ {
+ return $this->send_request('DELETE', '/domain/'.$this->domainid.'/ResourceRecord/'.$RecordId);
+ }
+
+ //设置解析记录状态
+ public function setDomainRecordStatus($RecordId, $Status)
+ {
+ $params = ['action' => $Status == '1' ? 'enable' : 'disable'];
+ $data = $this->send_request('PUT', '/domain/'.$this->domainid.'/ResourceRecord/'.$RecordId.'/status', $params);
+ return is_array($data);
+ }
+
+ //获取解析记录操作日志
+ public function getDomainRecordLog($PageNumber = 1, $PageSize = 20, $KeyWord = null, $StartDate = null, $endDate = null)
+ {
+ return false;
+ }
+
+ //获取解析线路列表
+ public function getRecordLine()
+ {
+ $domainInfo = $this->getDomainInfo();
+ if (!$domainInfo) return false;
+ $packId = $domainInfo['packId'];
+ $data = $this->send_request('GET', '/domain/'.$this->domainid.'/viewTree', ['packId'=>$packId, 'viewId'=>'0']);
+ if ($data) {
+ $list = [];
+ $this->processLineList($list, $data['data'], null);
+ return $list;
+ }
+ return false;
+ }
+
+ private function processLineList(&$list, $line_list, $parent)
+ {
+ foreach ($line_list as $row) {
+ if ($row['disabled']) continue;
+ if (!isset($list[$row['value']])) {
+ $list[$row['value']] = ['name' => $row['label'], 'parent' => $parent];
+ if (!$row['leaf'] && $row['children']) {
+ $this->processLineList($list, $row['children'], $row['value']);
+ }
+ }
+ }
+ }
+
+ //获取域名概览信息
+ public function getDomainInfo()
+ {
+ if (!empty($this->domainInfo)) return $this->domainInfo;
+ $query = ['domainId' => intval($this->domainid)];
+ $data = $this->send_request('GET', '/domain', $query);
+ if ($data && $data['dataList']) {
+ return $data['dataList'][0];
+ }
+ return false;
+ }
+
+ //获取域名最低TTL
+ public function getMinTTL()
+ {
+ return false;
+ }
+
+ private function convertType($type)
+ {
+ $convert_dict = ['REDIRECT_URL' => 'EXPLICIT_URL', 'FORWARD_URL' => 'IMPLICIT_URL'];
+ if (array_key_exists($type, $convert_dict)) {
+ return $convert_dict[$type];
+ }
+ return $type;
+ }
+
+ private function send_request($method, $action, $params = [])
+ {
+ $path = '/'.$this->version.'/regions/'.$this->region.$action;
+ try{
+ return $this->client->request($method, $path, $params);
+ }catch(Exception $e){
+ $this->setError($e->getMessage());
+ return false;
+ }
+ }
+
+ private function setError($message)
+ {
+ $this->error = $message;
+ //file_put_contents('logs.txt',date('H:i:s').' '.$message."\r\n", FILE_APPEND);
+ }
+}
diff --git a/app/service/CertTaskService.php b/app/service/CertTaskService.php
index 93578e2..b360b3e 100644
--- a/app/service/CertTaskService.php
+++ b/app/service/CertTaskService.php
@@ -20,7 +20,7 @@ class CertTaskService
private function execute_order()
{
$days = config_get('cert_renewdays', 7);
- $list = Db::name('cert_order')->field('id,status,issend')->whereRaw('status NOT IN (3,4) AND (retrytime IS NULL OR retrytime date('Y-m-d H:i:s', time() + $days * 86400)])->select();
+ $list = Db::name('cert_order')->field('id,status,issend')->whereRaw('isauto=1 AND status NOT IN (3,4) AND (retrytime IS NULL OR retrytime date('Y-m-d H:i:s', time() + $days * 86400)])->select();
//print_r($list);exit;
$failcount = 0;
foreach ($list as $row) {
@@ -67,7 +67,7 @@ class CertTaskService
}
}
- $list = Db::name('cert_deploy')->field('id,status,issend')->whereRaw('status IN (0,-1) AND (retrytime IS NULL OR retrytimeselect();
+ $list = Db::name('cert_deploy')->field('id,status,issend')->whereRaw('active=1 AND status IN (0,-1) AND (retrytime IS NULL OR retrytimeselect();
//print_r($list);exit;
$count = 0;
foreach ($list as $row) {
diff --git a/app/view/cert/certorder.html b/app/view/cert/certorder.html
index 9e7bfde..c1bcb75 100644
--- a/app/view/cert/certorder.html
+++ b/app/view/cert/certorder.html
@@ -2,7 +2,7 @@
{block name="title"}SSL证书订单列表{/block}
{block name="main"}
@@ -35,6 +35,10 @@ pre.pre-log{height: 330px;overflow-y: auto;width: 100%;background-color: rgba(51
刷新
添加
+
+
+
+
@@ -64,6 +68,10 @@ $(document).ready(function(){
classes: 'table table-striped table-hover table-bordered',
uniqueId: 'id',
columns: [
+ {
+ field: '',
+ checkbox: true
+ },
{
field: 'id',
title: 'ID'
@@ -285,5 +293,39 @@ function showLog(processid){
}
}, '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;
+ }else if(action == 'reset'){
+ if(!confirm('重置任务后,任务将变成待处理状态,是否确定重置?')) return;
+ }
+
+ var ii = layer.load(2);
+ $.ajax({
+ type : 'POST',
+ url : '/cert/deploy/operation',
+ data : {action: 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/config/app.php b/config/app.php
index 590c1bf..ec7e6f0 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' => '1030',
+ 'version' => '1031',
'dbversion' => '1028'
];
diff --git a/public/static/images/jdcloud.ico b/public/static/images/jdcloud.ico
new file mode 100644
index 0000000..5f246e6
Binary files /dev/null and b/public/static/images/jdcloud.ico differ