From 5ba7c324afcd01556880b31165912f064556447e Mon Sep 17 00:00:00 2001 From: net909 Date: Tue, 3 Jun 2025 22:06:02 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=B7=BB=E5=8A=A0=E9=83=A8?= =?UTF-8?q?=E7=BD=B2=E8=B4=A6=E6=88=B7=E9=A1=B5=E9=9D=A2=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E9=83=A8=E5=88=86=E5=B7=B2=E7=9F=A5=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/controller/Cert.php | 50 ++++++++-- app/lib/CertHelper.php | 4 +- app/lib/DeployHelper.php | 79 ++++++++-------- app/lib/deploy/allwaf.php | 146 ------------------------------ app/service/CertDeployService.php | 3 + app/service/CertOrderService.php | 3 + app/view/cert/account_form.html | 126 +++++++++++++++++++++++--- app/view/cert/certaccount.html | 6 +- app/view/cert/certorder.html | 1 + app/view/cert/deployaccount.html | 6 +- app/view/cert/deploytask.html | 2 + public/static/images/aliyun.png | Bin 0 -> 4622 bytes public/static/images/aws.png | Bin 0 -> 8626 bytes public/static/images/bt.ico | Bin 4286 -> 0 bytes public/static/images/bt.png | Bin 0 -> 8729 bytes public/static/images/huawei.ico | Bin 1150 -> 38078 bytes public/static/images/maoyun.png | Bin 0 -> 2597 bytes public/static/images/tencent.ico | Bin 949 -> 0 bytes public/static/images/tencent.png | Bin 0 -> 7459 bytes 19 files changed, 210 insertions(+), 216 deletions(-) delete mode 100644 app/lib/deploy/allwaf.php create mode 100644 public/static/images/aliyun.png create mode 100644 public/static/images/aws.png delete mode 100644 public/static/images/bt.ico create mode 100644 public/static/images/bt.png create mode 100644 public/static/images/maoyun.png delete mode 100644 public/static/images/tencent.ico create mode 100644 public/static/images/tencent.png diff --git a/app/controller/Cert.php b/app/controller/Cert.php index bea1528..9838479 100644 --- a/app/controller/Cert.php +++ b/app/controller/Cert.php @@ -43,8 +43,17 @@ class Cert extends BaseController $list = []; foreach ($rows as $row) { - $row['typename'] = $deploy == 1 ? DeployHelper::$deploy_config[$row['type']]['name'] : CertHelper::$cert_config[$row['type']]['name']; - $row['icon'] = $deploy == 1 ? DeployHelper::$deploy_config[$row['type']]['icon'] : CertHelper::$cert_config[$row['type']]['icon']; + if ($deploy == 1) { + if (!empty($row['type']) && isset(DeployHelper::$deploy_config[$row['type']])) { + $row['typename'] = DeployHelper::$deploy_config[$row['type']]['name']; + $row['icon'] = DeployHelper::$deploy_config[$row['type']]['icon']; + } + } else { + if (!empty($row['type']) && isset(CertHelper::$cert_config[$row['type']])) { + $row['typename'] = CertHelper::$cert_config[$row['type']]['name']; + $row['icon'] = CertHelper::$cert_config[$row['type']]['icon']; + } + } $list[] = $row; } @@ -202,6 +211,7 @@ class Cert extends BaseController if (!checkPermission(2)) return $this->alert('error', '无权限'); $domain = $this->request->post('domain', null, 'trim'); $id = input('post.id'); + $aid = input('post.aid', null, 'trim'); $type = input('post.type', null, 'trim'); $status = input('post.status', null, 'trim'); $offset = input('post.offset/d'); @@ -214,6 +224,9 @@ class Cert extends BaseController $oids = Db::name('cert_domain')->where('domain', 'like', '%' . $domain . '%')->column('oid'); $select->whereIn('A.id', $oids); } + if (!empty($aid)) { + $select->where('A.aid', $aid); + } if (!empty($type)) { $select->where('B.type', $type); } @@ -233,7 +246,7 @@ class Cert extends BaseController $list = []; foreach ($rows as $row) { - if (!empty($row['type'])) { + if (!empty($row['type']) && isset(CertHelper::$cert_config[$row['type']])) { $row['typename'] = CertHelper::$cert_config[$row['type']]['name']; $row['icon'] = CertHelper::$cert_config[$row['type']]['icon']; } else { @@ -599,6 +612,7 @@ class Cert extends BaseController $accounts = []; foreach (Db::name('cert_account')->where('deploy', 0)->select() as $row) { + if (empty($row['type']) || !isset(CertHelper::$cert_config[$row['type']])) continue; $accounts[$row['id']] = ['name' => $row['id'] . '_' . CertHelper::$cert_config[$row['type']]['name'], 'type' => $row['type']]; if (!empty($row['remark'])) { $accounts[$row['id']]['name'] .= '(' . $row['remark'] . ')'; @@ -627,19 +641,23 @@ class Cert extends BaseController if (!checkPermission(2)) return $this->alert('error', '无权限'); $domain = $this->request->post('domain', null, 'trim'); $oid = input('post.oid'); + $aid = input('post.aid', null, 'trim'); $type = input('post.type', null, 'trim'); $status = input('post.status', null, 'trim'); $remark = input('post.remark', null, 'trim'); $offset = input('post.offset/d'); $limit = input('post.limit/d'); - $select = Db::name('cert_deploy')->alias('A')->join('cert_account B', 'A.aid = B.id')->join('cert_order C', 'A.oid = C.id')->join('cert_account D', 'C.aid = D.id'); + $select = Db::name('cert_deploy')->alias('A')->leftJoin('cert_account B', 'A.aid = B.id')->leftJoin('cert_order C', 'A.oid = C.id')->leftJoin('cert_account D', 'C.aid = D.id'); if (!empty($oid)) { $select->where('A.oid', $oid); } elseif (!empty($domain)) { $oids = Db::name('cert_domain')->where('domain', 'like', '%' . $domain . '%')->column('oid'); $select->whereIn('oid', $oids); } + if (!empty($aid)) { + $select->where('A.aid', $aid); + } if (!empty($type)) { $select->where('B.type', $type); } @@ -654,9 +672,15 @@ class Cert extends BaseController $list = []; foreach ($rows as $row) { - $row['typename'] = DeployHelper::$deploy_config[$row['type']]['name']; - $row['icon'] = DeployHelper::$deploy_config[$row['type']]['icon']; - $row['certtypename'] = CertHelper::$cert_config[$row['certtype']]['name']; + if (!empty($row['type']) && isset(DeployHelper::$deploy_config[$row['type']])) { + $row['typename'] = DeployHelper::$deploy_config[$row['type']]['name']; + $row['icon'] = DeployHelper::$deploy_config[$row['type']]['icon']; + } + if (!empty($row['certtype']) && isset(CertHelper::$cert_config[$row['certtype']])) { + $row['certtypename'] = CertHelper::$cert_config[$row['certtype']]['name']; + } else { + $row['certtypename'] = '手动续期'; + } $row['domains'] = Db::name('cert_domain')->where('oid', $row['oid'])->order('sort', 'ASC')->column('domain'); if ($row['error']) $row['error'] = htmlspecialchars(str_replace("'", "\\'", $row['error'])); $list[] = $row; @@ -782,6 +806,7 @@ class Cert extends BaseController $accounts = []; foreach (Db::name('cert_account')->where('deploy', 1)->select() as $row) { + if (empty($row['type']) || !isset(DeployHelper::$deploy_config[$row['type']])) continue; $accounts[$row['id']] = ['name' => $row['id'] . '_' . DeployHelper::$deploy_config[$row['type']]['name'], 'type' => $row['type']]; if (!empty($row['remark'])) { $accounts[$row['id']]['name'] .= '(' . $row['remark'] . ')'; @@ -790,10 +815,15 @@ class Cert extends BaseController View::assign('accounts', $accounts); $orders = []; - foreach (Db::name('cert_order')->alias('A')->join('cert_account B', 'A.aid = B.id')->where('status', '<>', 4)->fieldRaw('A.id,A.aid,B.type,B.remark aremark')->order('id', 'desc')->select() as $row) { + foreach (Db::name('cert_order')->alias('A')->leftJoin('cert_account B', 'A.aid = B.id')->where('status', '<>', 4)->fieldRaw('A.id,A.aid,B.type,B.remark aremark')->order('id', 'desc')->select() as $row) { $domains = Db::name('cert_domain')->where('oid', $row['id'])->order('sort', 'ASC')->column('domain'); $domainstr = count($domains) > 2 ? implode('、', array_slice($domains, 0, 2)) . '等' . count($domains) . '个域名' : implode('、', $domains); - $orders[$row['id']] = ['name' => $row['id'] . '_' . $domainstr . '(' . CertHelper::$cert_config[$row['type']]['name'] . ')']; + if ($row['aid'] == 0) { + $name = $row['id'] . '_' . $domainstr . '(手动续期)'; + } else { + $name = $row['id'] . '_' . $domainstr . '(' . CertHelper::$cert_config[$row['type']]['name'] . ')'; + } + $orders[$row['id']] = ['name' => $name]; } View::assign('orders', $orders); @@ -821,7 +851,7 @@ class Cert extends BaseController $offset = input('post.offset/d'); $limit = input('post.limit/d'); - $select = Db::name('cert_cname')->alias('A')->join('domain B', 'A.did = B.id'); + $select = Db::name('cert_cname')->alias('A')->leftJoin('domain B', 'A.did = B.id'); if (!empty($kw)) { $select->whereLike('A.domain', '%' . $kw . '%'); } diff --git a/app/lib/CertHelper.php b/app/lib/CertHelper.php index d2522ed..fa8f3ca 100644 --- a/app/lib/CertHelper.php +++ b/app/lib/CertHelper.php @@ -177,7 +177,7 @@ location / { 'tencent' => [ 'name' => '腾讯云免费SSL', 'class' => 2, - 'icon' => 'tencent.ico', + 'icon' => 'tencent.png', 'wildcard' => false, 'max_domains' => 1, 'cname' => false, @@ -215,7 +215,7 @@ location / { 'aliyun' => [ 'name' => '阿里云免费SSL', 'class' => 2, - 'icon' => 'aliyun.ico', + 'icon' => 'aliyun.png', 'wildcard' => false, 'max_domains' => 1, 'cname' => false, diff --git a/app/lib/DeployHelper.php b/app/lib/DeployHelper.php index 20698df..363afc9 100644 --- a/app/lib/DeployHelper.php +++ b/app/lib/DeployHelper.php @@ -10,7 +10,8 @@ class DeployHelper 'btpanel' => [ 'name' => '宝塔面板', 'class' => 1, - 'icon' => 'bt.ico', + 'icon' => 'bt.png', + 'desc' => '支持部署到宝塔面板搭建的站点、Docker、邮局与面板本身', 'note' => null, 'inputs' => [ 'url' => [ @@ -63,6 +64,7 @@ class DeployHelper 'name' => 'Kangle用户', 'class' => 1, 'icon' => 'host.png', + 'desc' => '支持虚拟主机与CDN站点', 'note' => '以上登录信息为Easypanel用户面板的,非管理员面板。如选网站密码认证类型,则用户面板登录不能开启验证码。', 'inputs' => [ 'url' => [ @@ -136,6 +138,7 @@ class DeployHelper 'name' => 'Kangle管理员', 'class' => 1, 'icon' => 'host.png', + 'desc' => '支持虚拟主机与CDN站点', 'note' => '以上登录地址需填写Easypanel管理员面板地址,非用户面板。', 'inputs' => [ 'url' => [ @@ -202,6 +205,7 @@ class DeployHelper 'name' => '雷池WAF', 'class' => 1, 'icon' => 'safeline.png', + 'desc' => '', 'note' => null, 'tasknote' => '系统会根据关联SSL证书的域名,自动更新对应证书', 'inputs' => [ @@ -233,7 +237,8 @@ class DeployHelper 'btwaf' => [ 'name' => '堡塔云WAF', 'class' => 1, - 'icon' => 'bt.ico', + 'icon' => 'bt.png', + 'desc' => '', 'note' => null, 'tasknote' => '', 'inputs' => [ @@ -273,6 +278,7 @@ class DeployHelper 'name' => 'Cdnfly', 'class' => 1, 'icon' => 'waf.png', + 'desc' => '', 'note' => '登录Cdnfly控制台->账户中心->API密钥,点击开启后获取', 'inputs' => [ 'url' => [ @@ -318,6 +324,7 @@ class DeployHelper 'name' => 'LeCDN', 'class' => 1, 'icon' => 'waf.png', + 'desc' => '', 'note' => null, 'inputs' => [ 'url' => [ @@ -363,6 +370,7 @@ class DeployHelper 'name' => 'GoEdge', 'class' => 1, 'icon' => 'waf.png', + 'desc' => '', 'note' => '需要先开启HTTP API端口', 'tasknote' => '系统会根据关联SSL证书的域名,自动更新对应证书', 'inputs' => [ @@ -421,6 +429,7 @@ class DeployHelper 'name' => '1Panel', 'class' => 1, 'icon' => 'opanel.png', + 'desc' => '更新面板证书管理内的SSL证书', 'note' => null, 'tasknote' => '系统会根据关联SSL证书的域名,自动更新对应证书', 'inputs' => [ @@ -463,6 +472,7 @@ class DeployHelper 'name' => 'MW面板', 'class' => 1, 'icon' => 'mwpanel.ico', + 'desc' => '', 'note' => null, 'tasknote' => '', 'inputs' => [ @@ -520,6 +530,7 @@ class DeployHelper 'name' => '耗子面板', 'class' => 1, 'icon' => 'ratpanel.ico', + 'desc' => '支持耗子面板 v2.5+ 版本使用', 'note' => '支持耗子面板 v2.5+ 版本使用', 'inputs' => [ 'url' => [ @@ -578,6 +589,7 @@ class DeployHelper 'name' => '群晖面板', 'class' => 1, 'icon' => 'synology.png', + 'desc' => '支持群晖DSM 6.x/7.x版本', 'note' => null, 'tasknote' => '', 'inputs' => [ @@ -633,6 +645,7 @@ class DeployHelper 'name' => 'Proxmox VE', 'class' => 1, 'icon' => 'proxmox.ico', + 'desc' => '部署到PVE节点', 'note' => '在“权限->API令牌”添加令牌,不要选特权分离', 'tasknote' => '', 'inputs' => [ @@ -677,8 +690,9 @@ class DeployHelper 'aliyun' => [ 'name' => '阿里云', 'class' => 2, - 'icon' => 'aliyun.ico', - 'note' => '支持部署到阿里云CDN、ESA、SLB、OSS、WAF等服务', + 'icon' => 'aliyun.png', + 'desc' => '支持部署到阿里云CDN、ESA、SLB、OSS、WAF、FC等服务', + 'note' => '支持部署到阿里云CDN、ESA、SLB、OSS、WAF、FC等服务', 'tasknote' => '', 'inputs' => [ 'AccessKeyId' => [ @@ -824,7 +838,8 @@ class DeployHelper 'tencent' => [ 'name' => '腾讯云', 'class' => 2, - 'icon' => 'tencent.ico', + 'icon' => 'tencent.png', + 'desc' => '支持部署到腾讯云CDN、EO、CLB、COS、TKE、SCF等服务', 'note' => '支持部署到腾讯云CDN、EO、CLB、COS、TKE、SCF等服务', 'tasknote' => '', 'inputs' => [ @@ -959,6 +974,7 @@ class DeployHelper 'name' => '华为云', 'class' => 2, 'icon' => 'huawei.ico', + 'desc' => '支持部署到华为云CDN、ELB、WAF等服务', 'note' => '支持部署到华为云CDN、ELB、WAF等服务', 'inputs' => [ 'AccessKeyId' => [ @@ -1031,6 +1047,7 @@ class DeployHelper 'name' => 'UCloud', 'class' => 2, 'icon' => 'ucloud.ico', + 'desc' => '支持部署到UCDN', 'note' => '支持部署到UCDN', 'inputs' => [ 'PublicKey' => [ @@ -1060,6 +1077,7 @@ class DeployHelper 'name' => '七牛云', 'class' => 2, 'icon' => 'qiniu.ico', + 'desc' => '支持部署到七牛云CDN、OSS', 'note' => '支持部署到七牛云CDN、OSS', 'inputs' => [ 'AccessKey' => [ @@ -1115,6 +1133,7 @@ class DeployHelper 'name' => '多吉云', 'class' => 2, 'icon' => 'cloud.png', + 'desc' => '支持部署到多吉云融合CDN', 'note' => '支持部署到多吉云融合CDN', 'inputs' => [ 'AccessKey' => [ @@ -1152,6 +1171,8 @@ class DeployHelper 'name' => '又拍云', 'class' => 2, 'icon' => 'upyun.ico', + 'desc' => '支持部署到又拍云CDN', + 'note' => '支持部署到又拍云CDN', 'tasknote' => '系统会根据关联SSL证书的域名,进行证书的迁移操作', 'inputs' => [ 'username' => [ @@ -1181,6 +1202,7 @@ class DeployHelper 'name' => '百度云', 'class' => 2, 'icon' => 'baidu.ico', + 'desc' => '支持部署到百度云CDN', 'note' => '支持部署到百度云CDN', 'inputs' => [ 'AccessKeyId' => [ @@ -1218,6 +1240,7 @@ class DeployHelper 'name' => '火山引擎', 'class' => 2, 'icon' => 'huoshan.ico', + 'desc' => '支持部署到火山引擎CDN', 'note' => '支持部署到火山引擎CDN', 'inputs' => [ 'AccessKeyId' => [ @@ -1285,6 +1308,7 @@ class DeployHelper 'name' => '西部数码', 'class' => 2, 'icon' => 'west.ico', + 'desc' => '支持部署到西部数码虚拟主机', 'note' => '支持部署到西部数码虚拟主机', 'inputs' => [ 'username' => [ @@ -1322,6 +1346,7 @@ class DeployHelper 'name' => '网宿科技', 'class' => 2, 'icon' => 'wangsu.ico', + 'desc' => '支持部署到网宿CDN', 'note' => '适用产品:网页加速、下载分发、全站加速、点播分发、直播分发、上传加速、移动加速、上网加速、S-P2P、PCDN、应用性能管理、WEB应用防火墙、BotGuard爬虫管理、WSS、DMS、DDoS云清洗、应用加速、应用安全加速解决方案、IPv6一体化解决方案、电商安全加速解决方案、金融安全加速解决方案、政企安全加速解决方案、DDoS云清洗(非网站业务)、区块链安全加速解决方案、IPv6安全加速解决方案、CDN Pro。暂不支持AKSK鉴权。', 'inputs' => [ 'username' => [ @@ -1390,6 +1415,7 @@ class DeployHelper 'name' => '白山云', 'class' => 2, 'icon' => 'waf.png', + 'desc' => '替换白山云证书管理内的证书', 'note' => null, 'inputs' => [ 'account' => [ @@ -1429,7 +1455,8 @@ class DeployHelper 'name' => '天翼云', 'class' => 2, 'icon' => 'ctyun.ico', - 'note' => '支持部署到天翼云CDN', + 'desc' => '支持部署到天翼云CDN、边缘加速', + 'note' => '支持部署到天翼云CDN、边缘加速', 'inputs' => [ 'AccessKeyId' => [ 'name' => 'AccessKeyId', @@ -1477,6 +1504,7 @@ class DeployHelper 'name' => '括彩云', 'class' => 2, 'icon' => 'kuocai.jpg', + 'desc' => '替换括彩云证书管理内的证书', 'note' => '支持括彩云及其代理商,填写控制台登录账号及密码', 'inputs' => [ 'username' => [ @@ -1512,41 +1540,11 @@ class DeployHelper ], ], ], - 'allwaf' => [ - 'name' => 'AllWAF', - 'class' => 2, - 'icon' => 'waf.png', - 'note' => '在ALLWAF访问控制页面创建AccessKey', - 'tasknote' => '系统会根据关联SSL证书的域名,自动更新对应证书', - 'inputs' => [ - 'accessKeyId' => [ - 'name' => 'AccessKey ID', - 'type' => 'input', - 'placeholder' => '', - 'required' => true, - ], - 'accessKey' => [ - 'name' => 'AccessKey密钥', - 'type' => 'input', - 'placeholder' => '', - 'required' => true, - ], - 'proxy' => [ - 'name' => '使用代理服务器', - 'type' => 'radio', - 'options' => [ - '0' => '否', - '1' => '是', - ], - 'value' => '0' - ], - ], - 'taskinputs' => [], - ], 'aws' => [ 'name' => 'AWS', 'class' => 2, - 'icon' => 'aws.ico', + 'icon' => 'aws.png', + 'desc' => '支持部署到Amazon CloudFront、AWS Certificate Manager', 'note' => '支持部署到Amazon CloudFront、AWS Certificate Manager', 'inputs' => [ 'AccessKeyId' => [ @@ -1603,6 +1601,7 @@ class DeployHelper 'name' => 'Gcore', 'class' => 2, 'icon' => 'gcore.ico', + 'desc' => '替换Gcore CDN证书', 'note' => '在 个人资料->API令牌 页面创建API令牌', 'inputs' => [ 'account' => [ @@ -1647,6 +1646,7 @@ class DeployHelper 'name' => 'Cachefly', 'class' => 2, 'icon' => 'cloud.png', + 'desc' => '替换Cachefly CDN证书', 'note' => '在 API Tokens 页面生成 API Token', 'inputs' => [ 'account' => [ @@ -1679,6 +1679,7 @@ class DeployHelper 'name' => 'SSH服务器', 'class' => 3, 'icon' => 'server.png', + 'desc' => '可通过SSH连接到Linux/Windows服务器并部署证书', 'note' => '可通过SSH连接到Linux/Windows服务器并部署证书,php需要安装ssh2扩展', 'tasknote' => '请确保路径存在且有写入权限,路径一定要以/开头(Windows路径请使用/代替\,且需要在最开头加/)', 'inputs' => [ @@ -1805,6 +1806,7 @@ class DeployHelper 'name' => 'FTP服务器', 'class' => 3, 'icon' => 'server.png', + 'desc' => '可将证书上传到FTP服务器', 'note' => '可将证书上传到FTP服务器,php需要安装ftp扩展', 'tasknote' => '请确保路径存在且有写入权限', 'inputs' => [ @@ -1888,6 +1890,7 @@ class DeployHelper 'name' => '复制到本机', 'class' => 3, 'icon' => 'server2.png', + 'desc' => '将证书复制到本机指定路径', 'note' => '将证书复制到本机指定路径', 'tasknote' => '请确保php进程有对证书保存路径的写入权限,宝塔面板需关闭防跨站攻击,如果当前是Docker运行的,则需要做目录映射到宿主机。', 'inputs' => [], diff --git a/app/lib/deploy/allwaf.php b/app/lib/deploy/allwaf.php deleted file mode 100644 index 8d7c82b..0000000 --- a/app/lib/deploy/allwaf.php +++ /dev/null @@ -1,146 +0,0 @@ -accessKeyId = $config['accessKeyId']; - $this->accessKey = $config['accessKey']; - $this->proxy = $config['proxy'] == 1; - } - - public function check() - { - if (empty($this->url) || empty($this->accessKeyId) || empty($this->accessKey)) throw new Exception('必填参数不能为空'); - $this->getAccessToken(); - } - - public function deploy($fullchain, $privatekey, $config, &$info) - { - $domains = $config['domainList']; - if (empty($domains)) throw new Exception('没有设置要部署的域名'); - - $this->getAccessToken(); - - $params = [ - 'domains' => $domains, - 'offset' => 0, - 'size' => 10, - ]; - try { - $data = $this->request('/SSLCertService/listSSLCerts', $params); - } catch (Exception $e) { - throw new Exception('获取证书列表失败:' . $e->getMessage()); - } - $list = json_decode(base64_decode($data['sslCertsJSON']), true); - if (!$list || empty($list)) { - throw new Exception('证书列表为空'); - } - $this->log('获取证书列表成功(total=' . count($list) . ')'); - - $certInfo = openssl_x509_parse($fullchain, true); - $cert_name = str_replace('*.', '', $certInfo['subject']['CN']) . '-' . $certInfo['validFrom_time_t']; - - if (!empty($list)) { - foreach ($list as $row) { - $params = [ - 'sslCertId' => $row['id'], - 'isOn' => true, - 'name' => $row['name'], - 'description' => $row['description'], - 'serverName' => $row['serverName'], - 'isCA' => false, - 'certData' => base64_encode($fullchain), - 'keyData' => base64_encode($privatekey), - 'timeBeginAt' => $certInfo['validFrom_time_t'], - 'timeEndAt' => $certInfo['validTo_time_t'], - 'dnsNames' => $domains, - 'commonNames' => [$certInfo['issuer']['CN']], - ]; - $this->request('/SSLCertService/updateSSLCert', $params); - $this->log('证书ID:' . $row['id'] . '更新成功!'); - } - } else { - $params = [ - 'isOn' => true, - 'name' => $cert_name, - 'description' => $cert_name, - 'serverName' => $certInfo['subject']['CN'], - 'isCA' => false, - 'certData' => base64_encode($fullchain), - 'keyData' => base64_encode($privatekey), - 'timeBeginAt' => $certInfo['validFrom_time_t'], - 'timeEndAt' => $certInfo['validTo_time_t'], - 'dnsNames' => $domains, - 'commonNames' => [$certInfo['issuer']['CN']], - ]; - $result = $this->request('/SSLCertService/createSSLCert', $params); - $this->log('证书ID:' . $result['sslCertId'] . '添加成功!'); - } - } - - private function getAccessToken() - { - $path = '/APIAccessTokenService/getAPIAccessToken'; - $params = [ - 'type' => $this->usertype, - 'accessKeyId' => $this->accessKeyId, - 'accessKey' => $this->accessKey, - ]; - $result = $this->request($path, $params); - if (isset($result['token'])) { - $this->accessToken = $result['token']; - } else { - throw new Exception('登录成功,获取AccessToken失败'); - } - } - - private function request($path, $params = null) - { - $url = $this->url . $path; - $headers = []; - $body = null; - if ($this->accessToken) { - $headers[] = 'X-Cloud-Access-Token: ' . $this->accessToken; - } - if ($params) { - $headers[] = 'Content-Type: application/json'; - $body = json_encode($params); - } - $response = curl_client($url, $body, null, null, $headers, $this->proxy); - $result = json_decode($response['body'], true); - if (isset($result['code']) && $result['code'] == 200) { - return isset($result['data']) ? $result['data'] : null; - } elseif (isset($result['message'])) { - throw new Exception($result['message']); - } else { - if (!empty($response['body'])) $this->log('Response:' . $response['body']); - throw new Exception('返回数据解析失败'); - } - } - - public function setLogger($func) - { - $this->logger = $func; - } - - private function log($txt) - { - if ($this->logger) { - call_user_func($this->logger, $txt); - } - } -} diff --git a/app/service/CertDeployService.php b/app/service/CertDeployService.php index 47c3a86..2791778 100644 --- a/app/service/CertDeployService.php +++ b/app/service/CertDeployService.php @@ -89,6 +89,9 @@ class CertDeployService private function saveResult($status, $error = null, $retrytime = null) { $this->task['status'] = $status; + if (mb_strlen($error) > 300) { + $error = mb_strcut($error, 0, 300); + } $update = ['status' => $status, 'error' => $error, 'retrytime' => $retrytime]; if ($status == 1){ $update['retry'] = 0; diff --git a/app/service/CertOrderService.php b/app/service/CertOrderService.php index d26a2eb..a136949 100644 --- a/app/service/CertOrderService.php +++ b/app/service/CertOrderService.php @@ -178,6 +178,9 @@ class CertOrderService private function saveResult($status, $error = null, $retrytime = null) { $this->order['status'] = $status; + if (mb_strlen($error) > 300) { + $error = mb_strcut($error, 0, 300); + } $update = ['status' => $status, 'error' => $error, 'updatetime' => date('Y-m-d H:i:s'), 'retrytime' => $retrytime]; $res = Db::name('cert_order')->where('id', $this->order['id'])->data($update); if ($status < 0 || $retrytime) { diff --git a/app/view/cert/account_form.html b/app/view/cert/account_form.html index 752f88b..4a443b2 100644 --- a/app/view/cert/account_form.html +++ b/app/view/cert/account_form.html @@ -9,19 +9,104 @@ color: #f56c6c; margin-right: 4px; } +/* 账户类型卡片样式 */ +.account-type-container { + display: flex; + flex-wrap: wrap; + gap: 15px; + margin-bottom: 20px; +} +.account-type-category { + width: 100%; + margin-bottom: 10px; + font-size: 18px; + font-weight: bold; + color: #333; + border-bottom: 1px solid #eee; + padding-bottom: 5px; +} +.account-type-card { + width: calc(25% - 15px); + min-width: 200px; + padding: 10px; + border: 1px solid #ddd; + border-radius: 5px; + cursor: pointer; + transition: all 0.3s; + background: #fff; + height: 100px; + overflow: hidden; +} +.account-type-card:hover { + border-color: #409EFF; + box-shadow: 0 2px 12px 0 rgba(0,0,0,0.1); +} +.account-type-card .icon { + width: 30px; + margin: 11px 8px; + float: left; +} +.account-type-card .content { + margin-left: 38px; +} +.account-type-card .title { + font-size: 14px; + font-weight: bold; + margin-bottom: 3px; + color: #333; +} +.account-type-card .desc { + font-size: 12px; + color: #999; + line-height: 1.4; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; + text-overflow: ellipsis; +} +@media (max-width: 768px) { + .account-type-card { + width: calc(50% - 15px); + } +} +@media (max-width: 480px) { + .account-type-card { + width: 100%; + } +}

返回{if $action=='edit'}编辑{else}添加{/if}{$title}

-
+ +
+
+ + +
+
+ + +
- +
+ {{ typeList[set.type].name }} + 重新选择 +
+
@@ -104,6 +189,7 @@ new Vue({ el: '#app', data: { action: '{$action}', + selectedType: false, set: { deploy: '{$deploy}', id: '', @@ -140,16 +226,24 @@ new Vue({ } } }, - mounted() { - this.typeOption = Object.keys(classList).map((key) => { - var tempList = []; - Object.keys(typeList).forEach((key2) => { - if(typeList[key2].class == key){ - tempList.push({label: typeList[key2].name, value: key2}) - } + computed: { + groupedTypes() { + return Object.keys(classList).map((key) => { + var tempList = []; + Object.keys(typeList).forEach((key2) => { + if(typeList[key2].class == key){ + tempList.push({label: typeList[key2].name, value: key2}) + } + }) + return {label: classList[key], types: tempList} }) - return {label: classList[key], children: tempList} - }) + } + }, + mounted() { + this.typeOption = this.groupedTypes; + if(this.action == 'edit') { + this.selectedType = true; + } if(this.action == 'edit'){ Object.keys(info).forEach((key) => { this.set[key] = info[key] @@ -181,6 +275,10 @@ new Vue({ }) }, methods: { + selectType(type) { + this.set.type = type; + this.selectedType = true; + }, submit(){ var that=this; Object.keys(this.config).forEach((key) => { @@ -235,4 +333,4 @@ new Vue({ }, }); -{/block} \ No newline at end of file +{/block} diff --git a/app/view/cert/certaccount.html b/app/view/cert/certaccount.html index dcfb725..3759a1e 100644 --- a/app/view/cert/certaccount.html +++ b/app/view/cert/certaccount.html @@ -68,7 +68,7 @@ $(document).ready(function(){ field: '', title: '操作', formatter: function(value, row, index) { - var html = '编辑 删除'; + var html = '编辑 删除 订单'; return html; } }, @@ -79,12 +79,12 @@ function delItem(id){ layer.confirm('确定要删除此账户吗?', { btn: ['确定','取消'] }, function(){ - $.post('/cert/account/del?deploy=0', {id: id}, function(data){ + $.post('/cert/account/del', {id: id, deploy: 0}, function(data){ if(data.code == 0) { layer.msg('删除成功', {icon: 1, time:800}); $('#listTable').bootstrapTable('refresh'); } else { - layer.msg(data.msg, {icon: 2}); + layer.alert(data.msg, {icon: 2}); } }, 'json'); }); diff --git a/app/view/cert/certorder.html b/app/view/cert/certorder.html index 6c11ea8..c6cdd82 100644 --- a/app/view/cert/certorder.html +++ b/app/view/cert/certorder.html @@ -16,6 +16,7 @@ pre.pre-log{height: 330px;overflow-y: auto;width: 100%;background-color: rgba(51 +
diff --git a/app/view/cert/deployaccount.html b/app/view/cert/deployaccount.html index a392d80..c7d1e0c 100644 --- a/app/view/cert/deployaccount.html +++ b/app/view/cert/deployaccount.html @@ -68,7 +68,7 @@ $(document).ready(function(){ field: '', title: '操作', formatter: function(value, row, index) { - var html = '编辑 删除'; + var html = '编辑 删除 任务'; return html; } }, @@ -79,12 +79,12 @@ function delItem(id){ layer.confirm('确定要删除此账户吗?', { btn: ['确定','取消'] }, function(){ - $.post('/cert/account/del?deploy=1', {id: id}, function(data){ + $.post('/cert/account/del', {id: id, deploy: 1}, function(data){ if(data.code == 0) { layer.msg('删除成功', {icon: 1, time:800}); $('#listTable').bootstrapTable('refresh'); } else { - layer.msg(data.msg, {icon: 2}); + layer.alert(data.msg, {icon: 2}); } }, 'json'); }); diff --git a/app/view/cert/deploytask.html b/app/view/cert/deploytask.html index 481e490..709eb48 100644 --- a/app/view/cert/deploytask.html +++ b/app/view/cert/deploytask.html @@ -12,6 +12,7 @@ pre.pre-log{height: 330px;overflow-y: auto;width: 100%;background-color: rgba(51
+
@@ -80,6 +81,7 @@ $(document).ready(function(){ field: 'typename', title: '自动部署账户', formatter: function(value, row, index) { + if(!value) return '已被删除' return ''+(row.aremark?row.aremark:value+'('+row.aid+')')+''; } }, diff --git a/public/static/images/aliyun.png b/public/static/images/aliyun.png new file mode 100644 index 0000000000000000000000000000000000000000..f519fbb0b22c99999bcfe3a55d65e7ad085beaa6 GIT binary patch literal 4622 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 O1JJu|gebe^i2V=l6PX79 literal 0 HcmV?d00001 diff --git a/public/static/images/aws.png b/public/static/images/aws.png new file mode 100644 index 0000000000000000000000000000000000000000..0c132f7b29fd9c244ec1cd27ba56c13a5021b05a GIT binary patch literal 8626 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 diff --git a/public/static/images/maoyun.png b/public/static/images/maoyun.png new file mode 100644 index 0000000000000000000000000000000000000000..2ef8410aa93e297da4a09593a9ed733280cf7420 GIT binary patch literal 2597 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 Xf#UiPf=C5l00000NkvXXu0mjf6{)rg diff --git a/public/static/images/tencent.png b/public/static/images/tencent.png new file mode 100644 index 0000000000000000000000000000000000000000..9d26cf5c3c631e7832f9973f7b4208d9ac304160 GIT binary patch literal 7459 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 qr#g2U8xH9^wESsd<^OOwuM`zXF