mirror of https://github.com/certd/certd
Merge branch 'v2-dev' into v2
commit
ed1a9fc7aa
|
@ -17,6 +17,7 @@ gen
|
|||
/test/*.private.*
|
||||
|
||||
/*.log
|
||||
nohup.out
|
||||
|
||||
/packages/ui/*/.idea
|
||||
/packages/ui/*/node_modules
|
||||
|
|
10
CHANGELOG.md
10
CHANGELOG.md
|
@ -3,6 +3,16 @@
|
|||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.34.3](https://github.com/certd/certd/compare/v1.34.2...v1.34.3) (2025-05-15)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 宝塔插件、1panel 改成完全免费版 ([a53b6cd](https://github.com/certd/certd/commit/a53b6cd28ff2ce5662ada82379ea44a06b179b81))
|
||||
* 添加 FlexCDN 更新证书插件 ([bf040d4](https://github.com/certd/certd/commit/bf040d4c428d29c06fbaca5e29100e0c583b2b0b))
|
||||
* 小助手可以关闭 ([3e2101a](https://github.com/certd/certd/commit/3e2101aa5b56548614102e900d59819ce8c7e97c))
|
||||
* 支持部署到maoyun cdn ([68f333f](https://github.com/certd/certd/commit/68f333fb87ce85eed27436ecb0f76351c0ccb0d1))
|
||||
* 支持AI分析报错 ([aa96859](https://github.com/certd/certd/commit/aa96859798166426e485947a6590464de189de05))
|
||||
|
||||
## [1.34.2](https://github.com/certd/certd/compare/v1.34.1...v1.34.2) (2025-05-11)
|
||||
|
||||
### Bug Fixes
|
||||
|
|
16
README.md
16
README.md
|
@ -149,14 +149,14 @@ https://afdian.com/a/greper
|
|||
|
||||
专业版特权对比
|
||||
|
||||
| 功能 | 免费版 | 专业版 |
|
||||
|---------|--------------------|-----------------------------|
|
||||
| 免费证书申请 | 免费无限制 | 免费无限制 |
|
||||
| 域名数量 | 无限制 | 无限制 |
|
||||
| 证书流水线条数 | 无限制 | 无限制 |
|
||||
| 站点证书监控 | 限制1条 | 无限制 |
|
||||
| 自动部署插件 | 阿里云CDN、腾讯云、七牛CDN、主机部署等 | 支持群晖、宝塔、1Panel等,持续开发中 |
|
||||
| 通知 | 邮件通知、自定义webhook | 邮件免配置、企微、飞书、anpush、server酱等 |
|
||||
| 功能 | 免费版 | 专业版 |
|
||||
|---------|---------------------------------------|--------------------------------|
|
||||
| 免费证书申请 | 免费无限制 | 免费无限制 |
|
||||
| 域名数量 | 无限制 | 无限制 |
|
||||
| 证书流水线条数 | 无限制 | 无限制 |
|
||||
| 站点证书监控 | 限制1条 | 无限制 |
|
||||
| 自动部署插件 | 阿里云CDN、腾讯云、七牛CDN、主机部署、宝塔、1Panel等大部分插件 | 群晖 |
|
||||
| 通知 | 邮件通知、自定义webhook | 邮件免配置、企微、钉钉、飞书、anpush、server酱等 |
|
||||
|
||||
|
||||
************************
|
||||
|
|
|
@ -1 +1 @@
|
|||
20:28
|
||||
00:14
|
||||
|
|
|
@ -106,6 +106,7 @@ export default defineConfig({
|
|||
{
|
||||
text: "常见问题",
|
||||
items: [
|
||||
{text: "QA", link: "/guide/qa/use"},
|
||||
{text: "常见报错处理", link: "/guide/qa/"},
|
||||
{text: "群晖证书部署", link: "/guide/use/synology/"},
|
||||
{text: "腾讯云密钥获取", link: "/guide/use/tencent/"},
|
||||
|
|
|
@ -3,6 +3,16 @@
|
|||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.34.3](https://github.com/certd/certd/compare/v1.34.2...v1.34.3) (2025-05-15)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 宝塔插件、1panel 改成完全免费版 ([a53b6cd](https://github.com/certd/certd/commit/a53b6cd28ff2ce5662ada82379ea44a06b179b81))
|
||||
* 添加 FlexCDN 更新证书插件 ([bf040d4](https://github.com/certd/certd/commit/bf040d4c428d29c06fbaca5e29100e0c583b2b0b))
|
||||
* 小助手可以关闭 ([3e2101a](https://github.com/certd/certd/commit/3e2101aa5b56548614102e900d59819ce8c7e97c))
|
||||
* 支持部署到maoyun cdn ([68f333f](https://github.com/certd/certd/commit/68f333fb87ce85eed27436ecb0f76351c0ccb0d1))
|
||||
* 支持AI分析报错 ([aa96859](https://github.com/certd/certd/commit/aa96859798166426e485947a6590464de189de05))
|
||||
|
||||
## [1.34.2](https://github.com/certd/certd/compare/v1.34.1...v1.34.2) (2025-05-11)
|
||||
|
||||
### Bug Fixes
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
|
||||
# 授权插件Demo
|
||||
|
||||
```ts
|
||||
import { AccessInput, BaseAccess, IsAccess } from '@certd/pipeline';
|
||||
import { isDev } from '../../utils/env.js';
|
||||
|
||||
/**
|
||||
* 这个注解将注册一个授权配置
|
||||
* 在certd的后台管理系统中,用户可以选择添加此类型的授权
|
||||
*/
|
||||
@IsAccess({
|
||||
name: 'demo',
|
||||
title: '授权插件示例',
|
||||
icon: 'clarity:plugin-line',
|
||||
desc: '',
|
||||
})
|
||||
export class DemoAccess extends BaseAccess {
|
||||
/**
|
||||
* 授权属性配置
|
||||
*/
|
||||
@AccessInput({
|
||||
title: '密钥Id',
|
||||
component: {
|
||||
placeholder: 'demoKeyId',
|
||||
},
|
||||
required: true,
|
||||
})
|
||||
demoKeyId = '';
|
||||
|
||||
/**
|
||||
* 授权属性配置
|
||||
*/
|
||||
@AccessInput({
|
||||
//标题
|
||||
title: '密钥串',
|
||||
component: {
|
||||
//input组件的placeholder
|
||||
placeholder: 'demoKeySecret',
|
||||
},
|
||||
//是否必填
|
||||
required: true,
|
||||
//改属性是否需要加密
|
||||
encrypt: true,
|
||||
})
|
||||
//属性名称
|
||||
demoKeySecret = '';
|
||||
}
|
||||
new DemoAccess();
|
||||
```
|
||||
|
||||
|
||||
# 阿里云授权
|
||||
```ts
|
||||
|
||||
import { IsAccess, AccessInput, BaseAccess } from "@certd/pipeline";
|
||||
|
||||
@IsAccess({
|
||||
name: "aliyun",
|
||||
title: "阿里云授权",
|
||||
desc: "",
|
||||
icon: "ant-design:aliyun-outlined",
|
||||
order: 0,
|
||||
})
|
||||
export class AliyunAccess extends BaseAccess {
|
||||
@AccessInput({
|
||||
title: "accessKeyId",
|
||||
component: {
|
||||
placeholder: "accessKeyId",
|
||||
},
|
||||
helper: "登录阿里云控制台->AccessKey管理页面获取。",
|
||||
required: true,
|
||||
})
|
||||
accessKeyId = "";
|
||||
@AccessInput({
|
||||
title: "accessKeySecret",
|
||||
component: {
|
||||
placeholder: "accessKeySecret",
|
||||
},
|
||||
required: true,
|
||||
encrypt: true,
|
||||
helper: "注意:证书申请需要dns解析权限;其他阿里云插件,需要对应的权限,比如证书上传需要证书管理权限;嫌麻烦就用主账号的全量权限的accessKey",
|
||||
})
|
||||
accessKeySecret = "";
|
||||
}
|
||||
|
||||
new AliyunAccess();
|
||||
```
|
|
@ -45,4 +45,5 @@ Certd 存储了证书以及授权等敏感数据,所以需要严格保障安
|
|||
* 请`务必`使用`web应用防火墙`防护本应用,防止XSS、SQL注入等攻击
|
||||
* 请`务必`做好`服务器本身`的安全防护,防止数据库泄露
|
||||
* 请`务必`做好[`数据备份`](../../use/backup/),避免数据丢失
|
||||
* 请`务必`修改管理员账号用户名,且建议将admin注册为普通用户,且设置为禁用。
|
||||
* 建议开启[`站点隐藏`](./hidden/)功能
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
# 源码部署
|
||||
如果没有`git`和`nodejs`基础,则不推荐
|
||||
如果没有开发基础、没有运维基础、没有`git`和`nodejs`基础,强烈不推荐此方式
|
||||
|
||||
## 一、源码安装
|
||||
|
||||
### 环境要求
|
||||
|
@ -42,8 +43,8 @@ git pull
|
|||
kill -9 $(lsof -t -i:7001)
|
||||
# 重新编译启动
|
||||
./start.sh
|
||||
```
|
||||
|
||||
```
|
||||
::: warning
|
||||
升级certd版本前,切记切记先备份一下数据
|
||||
:::
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 82 KiB |
|
@ -17,3 +17,57 @@ services:
|
|||
# - 8.8.8.8 # 谷歌公共dns
|
||||
# - 8.8.4.4
|
||||
```
|
||||
|
||||
如果仍然有问题,按如下步骤检查是否能够ping通域名
|
||||
```shell
|
||||
docker exec -it certd /bin/sh
|
||||
ping www.baidu.com
|
||||
ping gg.px.certd.handfree.work
|
||||
ping app.handfree.work
|
||||
```
|
||||
|
||||
如果您是宝塔部署的
|
||||
可以试试将容器网络加入brige网络,看是否解决问题
|
||||

|
||||
|
||||
如果还是不行,请联系我们
|
||||
|
||||
|
||||
## 2. 连接IPv6超时
|
||||
docker-compose 需要放开IPv6网络的配置
|
||||
```yaml
|
||||
services:
|
||||
certd:
|
||||
networks:
|
||||
- ip6net
|
||||
# ↓↓↓↓ -------------------------------------------------------------- 启用ipv6网络,还需要把上面networks的注释放开
|
||||
networks:
|
||||
ip6net:
|
||||
enable_ipv6: true
|
||||
ipam:
|
||||
config:
|
||||
- subnet: 2001:db8::/64
|
||||
|
||||
```
|
||||
|
||||
## 3. SSL_CERT_NOT_MATCH_DOMAIN_ERROR
|
||||
部署证书任务报类似 `SSL_CERT_NOT_MATCH_DOMAIN_ERROR`错误
|
||||
这是由于当前流水线的证书域名与要部署的目标站点的域名不匹配导致的,在申请证书任务中,增加目标站点域名,重新运行流水线即可
|
||||
|
||||
|
||||
## 4. 没有服务器配置文件,请检查是否开启了外网映射!
|
||||
宝塔网站证书部署报错:`Error: 没有服务器配置文件,请检查是否开启了外网映射!`
|
||||
解决方案:先手动在宝塔网站中设置一次证书
|
||||
|
||||
|
||||
## 5. 如何查看容器日志
|
||||
```shell
|
||||
docker logs -f --tail 200 certd
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
# 使用问题
|
||||
|
||||
|
||||
## 1. 是否支持IP证书
|
||||
|
||||
因为ACME协议不支持IP证书,所以certd目前也不支持IP证书
|
||||
|
||||
|
||||
## 2. 建议设置多长时间运行一次流水线
|
||||
建议每天运行一次,检查证书过期时间
|
||||
当证书没过期时,自动跳过部署
|
||||
当证书到期前35天(创建流水线时可以修改),将会自动重新申请证书,自动部署
|
||||
|
||||
|
|
@ -18,6 +18,8 @@ CERTD_HTTPS_port=7002
|
|||
|
||||
### 2、配置复制到本机任务
|
||||
将证书复制到certd的证书安装位置
|
||||
证书路径:`ssl/cert.crt`
|
||||
私钥路径:`ssl/cert.key`
|
||||
|
||||

|
||||

|
||||
|
|
|
@ -9,5 +9,5 @@
|
|||
}
|
||||
},
|
||||
"npmClient": "pnpm",
|
||||
"version": "1.34.2"
|
||||
"version": "1.34.3"
|
||||
}
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.34.3](https://github.com/publishlab/node-acme-client/compare/v1.34.2...v1.34.3) (2025-05-15)
|
||||
|
||||
**Note:** Version bump only for package @certd/acme-client
|
||||
|
||||
## [1.34.2](https://github.com/publishlab/node-acme-client/compare/v1.34.1...v1.34.2) (2025-05-11)
|
||||
|
||||
### Performance Improvements
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"description": "Simple and unopinionated ACME client",
|
||||
"private": false,
|
||||
"author": "nmorsman",
|
||||
"version": "1.34.2",
|
||||
"version": "1.34.3",
|
||||
"type": "module",
|
||||
"module": "scr/index.js",
|
||||
"main": "src/index.js",
|
||||
|
@ -18,7 +18,7 @@
|
|||
"types"
|
||||
],
|
||||
"dependencies": {
|
||||
"@certd/basic": "^1.34.2",
|
||||
"@certd/basic": "^1.34.3",
|
||||
"@peculiar/x509": "^1.11.0",
|
||||
"asn1js": "^3.0.5",
|
||||
"axios": "^1.7.2",
|
||||
|
@ -69,5 +69,5 @@
|
|||
"bugs": {
|
||||
"url": "https://github.com/publishlab/node-acme-client/issues"
|
||||
},
|
||||
"gitHead": "a1e504c1387e9b0554c8d030cb53c5058e7d683a"
|
||||
"gitHead": "0b152a3cb8ef13113f9612c1bf555755e6f5b209"
|
||||
}
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.34.3](https://github.com/certd/certd/compare/v1.34.2...v1.34.3) (2025-05-15)
|
||||
|
||||
**Note:** Version bump only for package @certd/basic
|
||||
|
||||
## [1.34.2](https://github.com/certd/certd/compare/v1.34.1...v1.34.2) (2025-05-11)
|
||||
|
||||
**Note:** Version bump only for package @certd/basic
|
||||
|
|
|
@ -1 +1 @@
|
|||
20:23
|
||||
00:08
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@certd/basic",
|
||||
"private": false,
|
||||
"version": "1.34.2",
|
||||
"version": "1.34.3",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
|
@ -45,5 +45,5 @@
|
|||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "a1e504c1387e9b0554c8d030cb53c5058e7d683a"
|
||||
"gitHead": "0b152a3cb8ef13113f9612c1bf555755e6f5b209"
|
||||
}
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.34.3](https://github.com/certd/certd/compare/v1.34.2...v1.34.3) (2025-05-15)
|
||||
|
||||
**Note:** Version bump only for package @certd/pipeline
|
||||
|
||||
## [1.34.2](https://github.com/certd/certd/compare/v1.34.1...v1.34.2) (2025-05-11)
|
||||
|
||||
**Note:** Version bump only for package @certd/pipeline
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@certd/pipeline",
|
||||
"private": false,
|
||||
"version": "1.34.2",
|
||||
"version": "1.34.3",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
|
@ -17,8 +17,8 @@
|
|||
"pub": "npm publish"
|
||||
},
|
||||
"dependencies": {
|
||||
"@certd/basic": "^1.34.2",
|
||||
"@certd/plus-core": "^1.34.2",
|
||||
"@certd/basic": "^1.34.3",
|
||||
"@certd/plus-core": "^1.34.3",
|
||||
"dayjs": "^1.11.7",
|
||||
"lodash-es": "^4.17.21",
|
||||
"reflect-metadata": "^0.1.13"
|
||||
|
@ -44,5 +44,5 @@
|
|||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "a1e504c1387e9b0554c8d030cb53c5058e7d683a"
|
||||
"gitHead": "0b152a3cb8ef13113f9612c1bf555755e6f5b209"
|
||||
}
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.34.3](https://github.com/certd/certd/compare/v1.34.2...v1.34.3) (2025-05-15)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
## [1.34.2](https://github.com/certd/certd/compare/v1.34.1...v1.34.2) (2025-05-11)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@certd/lib-huawei",
|
||||
"private": false,
|
||||
"version": "1.34.2",
|
||||
"version": "1.34.3",
|
||||
"main": "./dist/bundle.js",
|
||||
"module": "./dist/bundle.js",
|
||||
"types": "./dist/d/index.d.ts",
|
||||
|
@ -24,5 +24,5 @@
|
|||
"prettier": "^2.8.8",
|
||||
"tslib": "^2.8.1"
|
||||
},
|
||||
"gitHead": "a1e504c1387e9b0554c8d030cb53c5058e7d683a"
|
||||
"gitHead": "0b152a3cb8ef13113f9612c1bf555755e6f5b209"
|
||||
}
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.34.3](https://github.com/certd/certd/compare/v1.34.2...v1.34.3) (2025-05-15)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
## [1.34.2](https://github.com/certd/certd/compare/v1.34.1...v1.34.2) (2025-05-11)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@certd/lib-iframe",
|
||||
"private": false,
|
||||
"version": "1.34.2",
|
||||
"version": "1.34.3",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
|
@ -31,5 +31,5 @@
|
|||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "a1e504c1387e9b0554c8d030cb53c5058e7d683a"
|
||||
"gitHead": "0b152a3cb8ef13113f9612c1bf555755e6f5b209"
|
||||
}
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.34.3](https://github.com/certd/certd/compare/v1.34.2...v1.34.3) (2025-05-15)
|
||||
|
||||
**Note:** Version bump only for package @certd/jdcloud
|
||||
|
||||
## [1.34.2](https://github.com/certd/certd/compare/v1.34.1...v1.34.2) (2025-05-11)
|
||||
|
||||
**Note:** Version bump only for package @certd/jdcloud
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@certd/jdcloud",
|
||||
"version": "1.34.2",
|
||||
"version": "1.34.3",
|
||||
"description": "jdcloud openApi sdk",
|
||||
"main": "./dist/bundle.js",
|
||||
"module": "./dist/bundle.js",
|
||||
|
@ -61,5 +61,5 @@
|
|||
"fetch"
|
||||
]
|
||||
},
|
||||
"gitHead": "a1e504c1387e9b0554c8d030cb53c5058e7d683a"
|
||||
"gitHead": "0b152a3cb8ef13113f9612c1bf555755e6f5b209"
|
||||
}
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.34.3](https://github.com/certd/certd/compare/v1.34.2...v1.34.3) (2025-05-15)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
## [1.34.2](https://github.com/certd/certd/compare/v1.34.1...v1.34.2) (2025-05-11)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@certd/lib-k8s",
|
||||
"private": false,
|
||||
"version": "1.34.2",
|
||||
"version": "1.34.3",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
|
@ -17,7 +17,7 @@
|
|||
"pub": "npm publish"
|
||||
},
|
||||
"dependencies": {
|
||||
"@certd/basic": "^1.34.2",
|
||||
"@certd/basic": "^1.34.3",
|
||||
"@kubernetes/client-node": "0.21.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -32,5 +32,5 @@
|
|||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "a1e504c1387e9b0554c8d030cb53c5058e7d683a"
|
||||
"gitHead": "0b152a3cb8ef13113f9612c1bf555755e6f5b209"
|
||||
}
|
||||
|
|
|
@ -3,6 +3,12 @@
|
|||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.34.3](https://github.com/certd/certd/compare/v1.34.2...v1.34.3) (2025-05-15)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 小助手可以关闭 ([3e2101a](https://github.com/certd/certd/commit/3e2101aa5b56548614102e900d59819ce8c7e97c))
|
||||
|
||||
## [1.34.2](https://github.com/certd/certd/compare/v1.34.1...v1.34.2) (2025-05-11)
|
||||
|
||||
### Performance Improvements
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@certd/lib-server",
|
||||
"version": "1.34.2",
|
||||
"version": "1.34.3",
|
||||
"description": "midway with flyway, sql upgrade way ",
|
||||
"private": false,
|
||||
"type": "module",
|
||||
|
@ -27,10 +27,10 @@
|
|||
],
|
||||
"license": "AGPL",
|
||||
"dependencies": {
|
||||
"@certd/acme-client": "^1.34.2",
|
||||
"@certd/basic": "^1.34.2",
|
||||
"@certd/pipeline": "^1.34.2",
|
||||
"@certd/plus-core": "^1.34.2",
|
||||
"@certd/acme-client": "^1.34.3",
|
||||
"@certd/basic": "^1.34.3",
|
||||
"@certd/pipeline": "^1.34.3",
|
||||
"@certd/plus-core": "^1.34.3",
|
||||
"@midwayjs/cache": "~3.14.0",
|
||||
"@midwayjs/core": "~3.20.3",
|
||||
"@midwayjs/i18n": "~3.20.3",
|
||||
|
@ -61,5 +61,5 @@
|
|||
"typeorm": "^0.3.11",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "a1e504c1387e9b0554c8d030cb53c5058e7d683a"
|
||||
"gitHead": "0b152a3cb8ef13113f9612c1bf555755e6f5b209"
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ export class SysPublicSettings extends BaseSettings {
|
|||
icpNo?: string;
|
||||
mpsNo?: string;
|
||||
robots?: boolean = true;
|
||||
aiChatEnabled = true;
|
||||
}
|
||||
|
||||
export class SysPrivateSettings extends BaseSettings {
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.34.3](https://github.com/certd/certd/compare/v1.34.2...v1.34.3) (2025-05-15)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
## [1.34.2](https://github.com/certd/certd/compare/v1.34.1...v1.34.2) (2025-05-11)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@certd/midway-flyway-js",
|
||||
"version": "1.34.2",
|
||||
"version": "1.34.3",
|
||||
"description": "midway with flyway, sql upgrade way ",
|
||||
"private": false,
|
||||
"type": "module",
|
||||
|
@ -46,5 +46,5 @@
|
|||
"typeorm": "^0.3.11",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "a1e504c1387e9b0554c8d030cb53c5058e7d683a"
|
||||
"gitHead": "0b152a3cb8ef13113f9612c1bf555755e6f5b209"
|
||||
}
|
||||
|
|
|
@ -3,6 +3,10 @@
|
|||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.34.3](https://github.com/certd/certd/compare/v1.34.2...v1.34.3) (2025-05-15)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-cert
|
||||
|
||||
## [1.34.2](https://github.com/certd/certd/compare/v1.34.1...v1.34.2) (2025-05-11)
|
||||
|
||||
**Note:** Version bump only for package @certd/plugin-cert
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@certd/plugin-cert",
|
||||
"private": false,
|
||||
"version": "1.34.2",
|
||||
"version": "1.34.3",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
|
@ -16,10 +16,10 @@
|
|||
"pub": "npm publish"
|
||||
},
|
||||
"dependencies": {
|
||||
"@certd/acme-client": "^1.34.2",
|
||||
"@certd/basic": "^1.34.2",
|
||||
"@certd/pipeline": "^1.34.2",
|
||||
"@certd/plugin-lib": "^1.34.2",
|
||||
"@certd/acme-client": "^1.34.3",
|
||||
"@certd/basic": "^1.34.3",
|
||||
"@certd/pipeline": "^1.34.3",
|
||||
"@certd/plugin-lib": "^1.34.3",
|
||||
"@google-cloud/publicca": "^1.3.0",
|
||||
"dayjs": "^1.11.7",
|
||||
"jszip": "^3.10.1",
|
||||
|
@ -43,5 +43,5 @@
|
|||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "a1e504c1387e9b0554c8d030cb53c5058e7d683a"
|
||||
"gitHead": "0b152a3cb8ef13113f9612c1bf555755e6f5b209"
|
||||
}
|
||||
|
|
|
@ -3,6 +3,12 @@
|
|||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.34.3](https://github.com/certd/certd/compare/v1.34.2...v1.34.3) (2025-05-15)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 支持部署到maoyun cdn ([68f333f](https://github.com/certd/certd/commit/68f333fb87ce85eed27436ecb0f76351c0ccb0d1))
|
||||
|
||||
## [1.34.2](https://github.com/certd/certd/compare/v1.34.1...v1.34.2) (2025-05-11)
|
||||
|
||||
### Performance Improvements
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "@certd/plugin-lib",
|
||||
"private": false,
|
||||
"version": "1.34.2",
|
||||
"version": "1.34.3",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
|
@ -18,8 +18,8 @@
|
|||
"dependencies": {
|
||||
"@alicloud/pop-core": "^1.7.10",
|
||||
"@aws-sdk/client-s3": "^3.787.0",
|
||||
"@certd/basic": "^1.34.2",
|
||||
"@certd/pipeline": "^1.34.2",
|
||||
"@certd/basic": "^1.34.3",
|
||||
"@certd/pipeline": "^1.34.3",
|
||||
"@kubernetes/client-node": "0.21.0",
|
||||
"ali-oss": "^6.22.0",
|
||||
"basic-ftp": "^5.0.5",
|
||||
|
@ -50,5 +50,5 @@
|
|||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "a1e504c1387e9b0554c8d030cb53c5058e7d683a"
|
||||
"gitHead": "0b152a3cb8ef13113f9612c1bf555755e6f5b209"
|
||||
}
|
||||
|
|
|
@ -1,87 +1 @@
|
|||
import { merge } from "lodash-es";
|
||||
|
||||
export function createCertDomainGetterInputDefine(opts?: { certInputKey?: string; props?: any }) {
|
||||
const certInputKey = opts?.certInputKey || "cert";
|
||||
return merge(
|
||||
{
|
||||
title: "当前证书域名",
|
||||
component: {
|
||||
name: "cert-domains-getter",
|
||||
},
|
||||
mergeScript: `
|
||||
return {
|
||||
component:{
|
||||
inputKey: ctx.compute(({form})=>{
|
||||
return form.${certInputKey}
|
||||
}),
|
||||
}
|
||||
}
|
||||
`,
|
||||
required: true,
|
||||
},
|
||||
opts?.props
|
||||
);
|
||||
}
|
||||
|
||||
export function createRemoteSelectInputDefine(opts?: {
|
||||
title: string;
|
||||
certDomainsInputKey?: string;
|
||||
accessIdInputKey?: string;
|
||||
typeName?: string;
|
||||
action: string;
|
||||
type?: string;
|
||||
watches?: string[];
|
||||
helper?: string;
|
||||
formItem?: any;
|
||||
mode?: string;
|
||||
multi?: boolean;
|
||||
required?: boolean;
|
||||
rules?: any;
|
||||
mergeScript?: string;
|
||||
}) {
|
||||
const title = opts?.title || "请选择";
|
||||
const certDomainsInputKey = opts?.certDomainsInputKey || "certDomains";
|
||||
const accessIdInputKey = opts?.accessIdInputKey || "accessId";
|
||||
const typeName = opts?.typeName;
|
||||
const action = opts?.action;
|
||||
const type = opts?.type || "plugin";
|
||||
const watches = opts?.watches || [];
|
||||
const helper = opts?.helper || "请选择";
|
||||
let mode = "tags";
|
||||
if (opts.multi === false) {
|
||||
mode = undefined;
|
||||
} else {
|
||||
mode = opts?.mode ?? "tags";
|
||||
}
|
||||
|
||||
const item = {
|
||||
title,
|
||||
component: {
|
||||
name: "remote-select",
|
||||
vModel: "value",
|
||||
mode,
|
||||
type,
|
||||
typeName,
|
||||
action,
|
||||
watches: [certDomainsInputKey, accessIdInputKey, ...watches],
|
||||
},
|
||||
rules: opts?.rules,
|
||||
required: opts.required ?? true,
|
||||
mergeScript:
|
||||
opts.mergeScript ??
|
||||
`
|
||||
return {
|
||||
component:{
|
||||
form: ctx.compute(({form})=>{
|
||||
return form
|
||||
})
|
||||
},
|
||||
}
|
||||
`,
|
||||
helper,
|
||||
};
|
||||
|
||||
return merge(item, opts?.formItem);
|
||||
}
|
||||
|
||||
|
||||
export * from "./util.js";
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
import { merge } from "lodash-es";
|
||||
|
||||
export function createCertDomainGetterInputDefine(opts?: { certInputKey?: string; props?: any }) {
|
||||
const certInputKey = opts?.certInputKey || "cert";
|
||||
return merge(
|
||||
{
|
||||
title: "当前证书域名",
|
||||
component: {
|
||||
name: "cert-domains-getter",
|
||||
},
|
||||
mergeScript: `
|
||||
return {
|
||||
component:{
|
||||
inputKey: ctx.compute(({form})=>{
|
||||
return form.${certInputKey}
|
||||
}),
|
||||
}
|
||||
}
|
||||
`,
|
||||
required: true,
|
||||
},
|
||||
opts?.props
|
||||
);
|
||||
}
|
||||
|
||||
export function createRemoteSelectInputDefine(opts?: {
|
||||
title: string;
|
||||
certDomainsInputKey?: string;
|
||||
accessIdInputKey?: string;
|
||||
typeName?: string;
|
||||
action: string;
|
||||
type?: string;
|
||||
watches?: string[];
|
||||
helper?: string;
|
||||
formItem?: any;
|
||||
mode?: string;
|
||||
multi?: boolean;
|
||||
required?: boolean;
|
||||
rules?: any;
|
||||
mergeScript?: string;
|
||||
}) {
|
||||
const title = opts?.title || "请选择";
|
||||
const certDomainsInputKey = opts?.certDomainsInputKey || "certDomains";
|
||||
const accessIdInputKey = opts?.accessIdInputKey || "accessId";
|
||||
const typeName = opts?.typeName;
|
||||
const action = opts?.action;
|
||||
const type = opts?.type || "plugin";
|
||||
const watches = opts?.watches || [];
|
||||
const helper = opts?.helper || "请选择";
|
||||
let mode = "tags";
|
||||
if (opts.multi === false) {
|
||||
mode = undefined;
|
||||
} else {
|
||||
mode = opts?.mode ?? "tags";
|
||||
}
|
||||
|
||||
const item = {
|
||||
title,
|
||||
component: {
|
||||
name: "remote-select",
|
||||
vModel: "value",
|
||||
mode,
|
||||
type,
|
||||
typeName,
|
||||
action,
|
||||
watches: [certDomainsInputKey, accessIdInputKey, ...watches],
|
||||
},
|
||||
rules: opts?.rules,
|
||||
required: opts.required ?? true,
|
||||
mergeScript:
|
||||
opts.mergeScript ??
|
||||
`
|
||||
return {
|
||||
component:{
|
||||
form: ctx.compute(({form})=>{
|
||||
return form
|
||||
})
|
||||
},
|
||||
}
|
||||
`,
|
||||
helper,
|
||||
};
|
||||
|
||||
return merge(item, opts?.formItem);
|
||||
}
|
|
@ -24,7 +24,7 @@ export class FtpAccess extends BaseAccess {
|
|||
host!: string;
|
||||
|
||||
@AccessInput({
|
||||
title: "host",
|
||||
title: "端口",
|
||||
value: 21,
|
||||
component: {
|
||||
placeholder: "21",
|
||||
|
|
|
@ -3,6 +3,13 @@
|
|||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.34.3](https://github.com/certd/certd/compare/v1.34.2...v1.34.3) (2025-05-15)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 小助手可以关闭 ([3e2101a](https://github.com/certd/certd/commit/3e2101aa5b56548614102e900d59819ce8c7e97c))
|
||||
* 支持AI分析报错 ([aa96859](https://github.com/certd/certd/commit/aa96859798166426e485947a6590464de189de05))
|
||||
|
||||
## [1.34.2](https://github.com/certd/certd/compare/v1.34.1...v1.34.2) (2025-05-11)
|
||||
|
||||
### Bug Fixes
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@certd/ui-client",
|
||||
"version": "1.34.2",
|
||||
"version": "1.34.3",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite --open",
|
||||
|
@ -102,8 +102,8 @@
|
|||
"zod-defaults": "^0.1.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@certd/lib-iframe": "^1.34.2",
|
||||
"@certd/pipeline": "^1.34.2",
|
||||
"@certd/lib-iframe": "^1.34.3",
|
||||
"@certd/pipeline": "^1.34.3",
|
||||
"@rollup/plugin-commonjs": "^25.0.7",
|
||||
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||
"@types/chai": "^4.3.12",
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<FsFormProvider>
|
||||
<contextHolder />
|
||||
<router-view />
|
||||
<MaxKBChat ref="chatBox" />
|
||||
<MaxKBChat v-if="settingsStore.sysPublic.aiChatEnabled !== false" ref="chatBox" />
|
||||
</FsFormProvider>
|
||||
</AConfigProvider>
|
||||
</template>
|
||||
|
@ -22,7 +22,7 @@ import AConfigProvider from "ant-design-vue/es/config-provider";
|
|||
import { Modal } from "ant-design-vue";
|
||||
import MaxKBChat from "/@/components/ai/index.vue";
|
||||
import { util } from "/@/utils";
|
||||
|
||||
import { useSettingStore } from "/@/store/settings";
|
||||
defineOptions({
|
||||
name: "App",
|
||||
});
|
||||
|
@ -49,6 +49,7 @@ localeChanged("zh-cn");
|
|||
provide("fn:router.reload", reload);
|
||||
provide("fn:locale.changed", localeChanged);
|
||||
|
||||
const settingsStore = useSettingStore();
|
||||
const { isDark } = usePreferences();
|
||||
const { tokens } = useAntdDesignTokens();
|
||||
|
||||
|
@ -74,8 +75,12 @@ const tokenTheme = computed(() => {
|
|||
// settingStore.init();
|
||||
|
||||
const chatBox = ref();
|
||||
onMounted(async () => {
|
||||
// await util.sleep(5000);
|
||||
// await chatBox.value.openChat({ q: "hello" });
|
||||
});
|
||||
// onMounted(async () => {
|
||||
// await util.sleep(2000);
|
||||
// await chatBox.value.openChat({ q: "hello" });
|
||||
// });
|
||||
const openChat = (q: string) => {
|
||||
chatBox.value.openChat({ q });
|
||||
};
|
||||
provide("fn:ai.open", openChat);
|
||||
</script>
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
</div>
|
||||
|
||||
<!-- 聊天按钮 -->
|
||||
<div v-show="!chatVisible" class="maxkb-chat-button" :style="buttonPosition" @click="toggleChat">
|
||||
<div v-show="!chatVisible" class="maxkb-chat-button" @click="toggleChat">
|
||||
<img src="https://maxkb.handfree.work/ui/MaxKB.gif" />
|
||||
</div>
|
||||
|
||||
|
@ -123,7 +123,10 @@ onMounted(() => {
|
|||
});
|
||||
|
||||
async function openChat(req: { q: string }) {
|
||||
showGuide.value = true;
|
||||
if (!req.q) {
|
||||
return;
|
||||
}
|
||||
chatVisible.value = true;
|
||||
|
||||
const iframeId = "maxkb-chat";
|
||||
|
||||
|
@ -132,7 +135,13 @@ async function openChat(req: { q: string }) {
|
|||
throw new Error("iframe not found");
|
||||
return;
|
||||
}
|
||||
iframe.contentWindow?.postMessage(req, "*");
|
||||
iframe.contentWindow?.postMessage(
|
||||
{
|
||||
...req,
|
||||
from: "certd",
|
||||
},
|
||||
"*"
|
||||
);
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
|
@ -227,10 +236,10 @@ defineExpose({
|
|||
#maxkb .maxkb-tips .maxkb-button button::after {
|
||||
border: none;
|
||||
}
|
||||
#maxkb .maxkb-tips . {
|
||||
#maxkb .maxkb-tips {
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
top: 20px;
|
||||
//top: 20px;
|
||||
cursor: pointer;
|
||||
}
|
||||
#maxkb-chat-container {
|
||||
|
@ -248,7 +257,7 @@ defineExpose({
|
|||
|
||||
#maxkb .maxkb-chat-button {
|
||||
position: fixed;
|
||||
right: 0px;
|
||||
right: 10px;
|
||||
bottom: 30px;
|
||||
cursor: pointer;
|
||||
z-index: 10000;
|
||||
|
|
|
@ -18,7 +18,7 @@ const props = defineProps<{
|
|||
modelValue: string;
|
||||
title: string;
|
||||
action: string;
|
||||
form: any;
|
||||
form?: any;
|
||||
button?: any;
|
||||
}>();
|
||||
|
||||
|
|
|
@ -52,6 +52,10 @@ onErrorCaptured(e => {
|
|||
onMounted(async () => {
|
||||
await settingStore.checkUrlBound();
|
||||
});
|
||||
|
||||
function goGithub() {
|
||||
window.open("https://github.com/certd/certd");
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
@ -63,14 +67,14 @@ onMounted(async () => {
|
|||
<LockScreen :avatar @to-login="handleLogout" />
|
||||
</template>
|
||||
<template #header-right-0>
|
||||
<div class="hover:bg-accent ml-1 mr-2 cursor-pointer rounded-full hidden md:block">
|
||||
<tutorial-button v-if="!settingStore.isComm" class="flex-center header-btn" />
|
||||
<div v-if="!settingStore.isComm" class="hover:bg-accent ml-1 mr-2 cursor-pointer rounded-full hidden md:block">
|
||||
<tutorial-button class="flex-center header-btn" />
|
||||
</div>
|
||||
<div class="hover:bg-accent ml-1 mr-2 cursor-pointer rounded-full">
|
||||
<vip-button class="flex-center header-btn" mode="nav" />
|
||||
</div>
|
||||
<div class="hover:bg-accent ml-1 mr-2 cursor-pointer rounded-full">
|
||||
<fs-icon icon="ion:logo-github" />
|
||||
<div v-if="!settingStore.isComm" class="hover:bg-accent ml-1 mr-2 cursor-pointer rounded-full">
|
||||
<fs-button shape="circle" type="text" icon="ion:logo-github" :text="null" @click="goGithub" />
|
||||
</div>
|
||||
</template>
|
||||
<template #footer>
|
||||
|
|
|
@ -41,6 +41,7 @@ export type SysPublicSetting = {
|
|||
icpNo?: string;
|
||||
mpsNo?: string;
|
||||
robots?: boolean;
|
||||
aiChatEnabled?: boolean;
|
||||
};
|
||||
export type SuiteSetting = {
|
||||
enabled?: boolean;
|
||||
|
|
|
@ -18,11 +18,11 @@ interface Props {
|
|||
}
|
||||
|
||||
defineOptions({
|
||||
name: "LayoutHeader"
|
||||
name: "LayoutHeader",
|
||||
});
|
||||
|
||||
withDefaults(defineProps<Props>(), {
|
||||
theme: "light"
|
||||
theme: "light",
|
||||
});
|
||||
|
||||
const emit = defineEmits<{ clearPreferencesAndLogout: [] }>();
|
||||
|
@ -39,42 +39,42 @@ const rightSlots = computed(() => {
|
|||
if (preferences.widget.globalSearch) {
|
||||
list.push({
|
||||
index: REFERENCE_VALUE,
|
||||
name: "global-search"
|
||||
name: "global-search",
|
||||
});
|
||||
}
|
||||
|
||||
if (preferencesButtonPosition.value.header) {
|
||||
list.push({
|
||||
index: REFERENCE_VALUE + 10,
|
||||
name: "preferences"
|
||||
name: "preferences",
|
||||
});
|
||||
}
|
||||
if (preferences.widget.themeToggle) {
|
||||
list.push({
|
||||
index: REFERENCE_VALUE + 20,
|
||||
name: "theme-toggle"
|
||||
name: "theme-toggle",
|
||||
});
|
||||
}
|
||||
if (preferences.widget.languageToggle) {
|
||||
list.push({
|
||||
index: REFERENCE_VALUE + 30,
|
||||
name: "language-toggle"
|
||||
name: "language-toggle",
|
||||
});
|
||||
}
|
||||
if (preferences.widget.fullscreen) {
|
||||
list.push({
|
||||
index: REFERENCE_VALUE + 40,
|
||||
name: "fullscreen"
|
||||
name: "fullscreen",
|
||||
});
|
||||
}
|
||||
if (preferences.widget.notification) {
|
||||
list.push({
|
||||
index: REFERENCE_VALUE + 50,
|
||||
name: "notification"
|
||||
name: "notification",
|
||||
});
|
||||
}
|
||||
|
||||
Object.keys(slots).forEach((key) => {
|
||||
Object.keys(slots).forEach(key => {
|
||||
const name = key.split("-");
|
||||
if (key.startsWith("header-right")) {
|
||||
list.push({ index: Number(name[2]), name: key });
|
||||
|
@ -89,11 +89,11 @@ const leftSlots = computed(() => {
|
|||
if (preferences.widget.refresh) {
|
||||
list.push({
|
||||
index: 0,
|
||||
name: "refresh"
|
||||
name: "refresh",
|
||||
});
|
||||
}
|
||||
|
||||
Object.keys(slots).forEach((key) => {
|
||||
Object.keys(slots).forEach(key => {
|
||||
const name = key.split("-");
|
||||
if (key.startsWith("header-left")) {
|
||||
list.push({ index: Number(name[2]), name: key });
|
||||
|
@ -108,7 +108,7 @@ function clearPreferencesAndLogout() {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<template v-for="slot in leftSlots.filter((item) => item.index < REFERENCE_VALUE)" :key="slot.name">
|
||||
<template v-for="slot in leftSlots.filter(item => item.index < REFERENCE_VALUE)" :key="slot.name">
|
||||
<slot :name="slot.name">
|
||||
<template v-if="slot.name === 'refresh'">
|
||||
<VbenIconButton class="my-0 mr-1 rounded-md" @click="refresh">
|
||||
|
@ -120,7 +120,7 @@ function clearPreferencesAndLogout() {
|
|||
<div class="flex-center hidden lg:block">
|
||||
<slot name="breadcrumb"></slot>
|
||||
</div>
|
||||
<template v-for="slot in leftSlots.filter((item) => item.index > REFERENCE_VALUE)" :key="slot.name">
|
||||
<template v-for="slot in leftSlots.filter(item => item.index > REFERENCE_VALUE)" :key="slot.name">
|
||||
<slot :name="slot.name"></slot>
|
||||
</template>
|
||||
<div :class="`menu-align-${preferences.header.menuAlign}`" class="flex h-full min-w-0 flex-1 items-center">
|
||||
|
|
|
@ -9,15 +9,15 @@ import { preferences, updatePreferences } from "/@/vben/preferences";
|
|||
import { VbenDropdownRadioMenu, VbenIconButton } from "/@/vben//shadcn-ui";
|
||||
|
||||
defineOptions({
|
||||
name: "LanguageToggle"
|
||||
name: "LanguageToggle",
|
||||
});
|
||||
|
||||
async function handleUpdate(value: string) {
|
||||
const locale = value as SupportedLanguagesType;
|
||||
updatePreferences({
|
||||
app: {
|
||||
locale
|
||||
}
|
||||
locale,
|
||||
},
|
||||
});
|
||||
await loadLocaleMessages(locale);
|
||||
}
|
||||
|
|
|
@ -11,11 +11,11 @@ interface Props {
|
|||
}
|
||||
|
||||
defineOptions({
|
||||
name: "ThemeToggleButton"
|
||||
name: "ThemeToggleButton",
|
||||
});
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
type: "normal"
|
||||
type: "normal",
|
||||
});
|
||||
|
||||
const isDark = defineModel<boolean>();
|
||||
|
@ -29,13 +29,13 @@ const bindProps = computed(() => {
|
|||
|
||||
return type === "normal"
|
||||
? {
|
||||
variant: "heavy" as const
|
||||
variant: "heavy" as const,
|
||||
}
|
||||
: {
|
||||
class: "rounded-full",
|
||||
size: "icon" as const,
|
||||
style: { padding: "7px" },
|
||||
variant: "icon" as const
|
||||
variant: "icon" as const,
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -59,12 +59,12 @@ function toggleTheme(event: MouseEvent) {
|
|||
const clipPath = [`circle(0px at ${x}px ${y}px)`, `circle(${endRadius}px at ${x}px ${y}px)`];
|
||||
document.documentElement.animate(
|
||||
{
|
||||
clipPath: isDark.value ? [...clipPath].reverse() : clipPath
|
||||
clipPath: isDark.value ? [...clipPath].reverse() : clipPath,
|
||||
},
|
||||
{
|
||||
duration: 450,
|
||||
easing: "ease-in",
|
||||
pseudoElement: isDark.value ? "::view-transition-old(root)" : "::view-transition-new(root)"
|
||||
pseudoElement: isDark.value ? "::view-transition-old(root)" : "::view-transition-new(root)",
|
||||
}
|
||||
);
|
||||
});
|
||||
|
|
|
@ -10,16 +10,16 @@ import { ToggleGroup, ToggleGroupItem, VbenTooltip } from "/@/vben//shadcn-ui";
|
|||
import ThemeButton from "./theme-button.vue";
|
||||
|
||||
defineOptions({
|
||||
name: "ThemeToggle"
|
||||
name: "ThemeToggle",
|
||||
});
|
||||
|
||||
withDefaults(defineProps<{ shouldOnHover?: boolean }>(), {
|
||||
shouldOnHover: false
|
||||
shouldOnHover: false,
|
||||
});
|
||||
|
||||
function handleChange(isDark: boolean) {
|
||||
updatePreferences({
|
||||
theme: { mode: isDark ? "dark" : "light" }
|
||||
theme: { mode: isDark ? "dark" : "light" },
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -29,18 +29,18 @@ const PRESETS = [
|
|||
{
|
||||
icon: Sun,
|
||||
name: "light",
|
||||
title: $t("preferences.theme.light")
|
||||
title: $t("preferences.theme.light"),
|
||||
},
|
||||
{
|
||||
icon: MoonStar,
|
||||
name: "dark",
|
||||
title: $t("preferences.theme.dark")
|
||||
title: $t("preferences.theme.dark"),
|
||||
},
|
||||
{
|
||||
icon: SunMoon,
|
||||
name: "auto",
|
||||
title: $t("preferences.followSystem")
|
||||
}
|
||||
title: $t("preferences.followSystem"),
|
||||
},
|
||||
];
|
||||
</script>
|
||||
<template>
|
||||
|
@ -49,7 +49,7 @@ const PRESETS = [
|
|||
<template #trigger>
|
||||
<ThemeButton :model-value="isDark" type="icon" @update:model-value="handleChange" />
|
||||
</template>
|
||||
<ToggleGroup :model-value="preferences.theme.mode" class="gap-2" type="single" variant="outline" @update:model-value="(val) => updatePreferences({ theme: { mode: val as ThemeModeType } })">
|
||||
<ToggleGroup :model-value="preferences.theme.mode" class="gap-2" type="single" variant="outline" @update:model-value="val => updatePreferences({ theme: { mode: val as ThemeModeType } })">
|
||||
<ToggleGroupItem v-for="item in PRESETS" :key="item.name" :value="item.name">
|
||||
<component :is="item.icon" class="size-5" />
|
||||
</ToggleGroupItem>
|
||||
|
|
|
@ -18,7 +18,7 @@ const props = withDefaults(defineProps<Props>(), {
|
|||
disabled: false,
|
||||
loading: false,
|
||||
size: "default",
|
||||
variant: "default"
|
||||
variant: "default",
|
||||
});
|
||||
|
||||
const isDisabled = computed(() => {
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
<script setup lang="ts">
|
||||
import type { ButtonVariants } from '../../ui';
|
||||
import type { VbenButtonProps } from './button';
|
||||
import type { ButtonVariants } from "../../ui";
|
||||
import type { VbenButtonProps } from "./button";
|
||||
|
||||
import { computed, useSlots } from 'vue';
|
||||
import { computed, useSlots } from "vue";
|
||||
|
||||
import { cn } from '/@/vben/shared/utils';
|
||||
import { cn } from "/@/vben/shared/utils";
|
||||
|
||||
import { VbenTooltip } from '../tooltip';
|
||||
import VbenButton from './button.vue';
|
||||
import { VbenTooltip } from "../tooltip";
|
||||
import VbenButton from "./button.vue";
|
||||
|
||||
interface Props extends VbenButtonProps {
|
||||
class?: any;
|
||||
|
@ -15,7 +15,7 @@ interface Props extends VbenButtonProps {
|
|||
onClick?: () => void;
|
||||
tooltip?: string;
|
||||
tooltipDelayDuration?: number;
|
||||
tooltipSide?: 'bottom' | 'left' | 'right' | 'top';
|
||||
tooltipSide?: "bottom" | "left" | "right" | "top";
|
||||
variant?: ButtonVariants;
|
||||
}
|
||||
|
||||
|
@ -23,8 +23,8 @@ const props = withDefaults(defineProps<Props>(), {
|
|||
disabled: false,
|
||||
onClick: () => {},
|
||||
tooltipDelayDuration: 200,
|
||||
tooltipSide: 'bottom',
|
||||
variant: 'icon',
|
||||
tooltipSide: "bottom",
|
||||
variant: "icon",
|
||||
});
|
||||
|
||||
const slots = useSlots();
|
||||
|
@ -33,30 +33,13 @@ const showTooltip = computed(() => !!slots.tooltip || !!props.tooltip);
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<VbenButton
|
||||
v-if="!showTooltip"
|
||||
:class="cn('rounded-full', props.class)"
|
||||
:disabled="disabled"
|
||||
:variant="variant"
|
||||
size="icon"
|
||||
@click="onClick"
|
||||
>
|
||||
<VbenButton v-if="!showTooltip" :class="cn('rounded-full', props.class)" :disabled="disabled" :variant="variant" size="icon" @click="onClick">
|
||||
<slot></slot>
|
||||
</VbenButton>
|
||||
|
||||
<VbenTooltip
|
||||
v-else
|
||||
:delay-duration="tooltipDelayDuration"
|
||||
:side="tooltipSide"
|
||||
>
|
||||
<VbenTooltip v-else :delay-duration="tooltipDelayDuration" :side="tooltipSide">
|
||||
<template #trigger>
|
||||
<VbenButton
|
||||
:class="cn('rounded-full', props.class)"
|
||||
:disabled="disabled"
|
||||
:variant="variant"
|
||||
size="icon"
|
||||
@click="onClick"
|
||||
>
|
||||
<VbenButton :class="cn('rounded-full', props.class)" :disabled="disabled" :variant="variant" size="icon" @click="onClick">
|
||||
<slot></slot>
|
||||
</VbenButton>
|
||||
</template>
|
||||
|
|
|
@ -11,13 +11,13 @@ export function getCommonColumnDefine(crudExpose: any, typeRef: any, api: any) {
|
|||
return "access";
|
||||
});
|
||||
const AccessTypeDictRef = dict({
|
||||
url: "/pi/access/accessTypeDict"
|
||||
url: "/pi/access/accessTypeDict",
|
||||
});
|
||||
const defaultPluginConfig = {
|
||||
component: {
|
||||
name: "a-input",
|
||||
vModel: "value"
|
||||
}
|
||||
vModel: "value",
|
||||
},
|
||||
};
|
||||
|
||||
function buildDefineFields(define: any, form: any, mode: string) {
|
||||
|
@ -34,7 +34,7 @@ export function getCommonColumnDefine(crudExpose: any, typeRef: any, api: any) {
|
|||
const key = "access." + mapKey;
|
||||
const field = {
|
||||
...value,
|
||||
key
|
||||
key,
|
||||
};
|
||||
const column = merge({ title: key }, defaultPluginConfig, field);
|
||||
|
||||
|
@ -77,13 +77,13 @@ export function getCommonColumnDefine(crudExpose: any, typeRef: any, api: any) {
|
|||
type: "dict-select",
|
||||
dict: AccessTypeDictRef,
|
||||
search: {
|
||||
show: true
|
||||
show: true,
|
||||
},
|
||||
column: {
|
||||
width: 200,
|
||||
component: {
|
||||
color: "auto"
|
||||
}
|
||||
color: "auto",
|
||||
},
|
||||
},
|
||||
form: {
|
||||
component: {
|
||||
|
@ -100,7 +100,7 @@ export function getCommonColumnDefine(crudExpose: any, typeRef: any, api: any) {
|
|||
{item.label}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
rules: [{ required: true, message: "请选择类型" }],
|
||||
valueChange: {
|
||||
|
@ -116,7 +116,7 @@ export function getCommonColumnDefine(crudExpose: any, typeRef: any, api: any) {
|
|||
form.access = {};
|
||||
}
|
||||
buildDefineFields(define, form, mode);
|
||||
}
|
||||
},
|
||||
},
|
||||
helper: {
|
||||
render: () => {
|
||||
|
@ -125,12 +125,12 @@ export function getCommonColumnDefine(crudExpose: any, typeRef: any, api: any) {
|
|||
return "";
|
||||
}
|
||||
return <div innerHTML={utils.transformLink(define.desc)}></div>;
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
addForm: {
|
||||
value: typeRef
|
||||
}
|
||||
value: typeRef,
|
||||
},
|
||||
} as ColumnCompositionProps,
|
||||
setting: {
|
||||
column: { show: false },
|
||||
|
@ -149,8 +149,8 @@ export function getCommonColumnDefine(crudExpose: any, typeRef: any, api: any) {
|
|||
valueResolve({ form }) {
|
||||
const setting = form.access;
|
||||
form.setting = JSON.stringify(setting);
|
||||
}
|
||||
}
|
||||
} as ColumnCompositionProps
|
||||
},
|
||||
},
|
||||
} as ColumnCompositionProps,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ async function batchUpdateGroupRequest(groupId: number) {
|
|||
const pipelineGroupDictRef = dict({
|
||||
url: "/pi/pipeline/group/all",
|
||||
value: "id",
|
||||
label: "name"
|
||||
label: "name",
|
||||
});
|
||||
const { openCrudFormDialog } = useFormWrapper();
|
||||
|
||||
|
@ -33,9 +33,9 @@ async function openGroupSelectDialog() {
|
|||
type: "dict-select",
|
||||
dict: pipelineGroupDictRef,
|
||||
form: {
|
||||
rules: [{ required: true, message: "请选择分组" }]
|
||||
}
|
||||
}
|
||||
rules: [{ required: true, message: "请选择分组" }],
|
||||
},
|
||||
},
|
||||
},
|
||||
form: {
|
||||
mode: "edit",
|
||||
|
@ -44,18 +44,18 @@ async function openGroupSelectDialog() {
|
|||
await batchUpdateGroupRequest(form.groupId);
|
||||
},
|
||||
col: {
|
||||
span: 22
|
||||
span: 22,
|
||||
},
|
||||
labelCol: {
|
||||
style: {
|
||||
width: "100px"
|
||||
}
|
||||
width: "100px",
|
||||
},
|
||||
},
|
||||
wrapper: {
|
||||
title: "批量修改分组",
|
||||
width: 600
|
||||
}
|
||||
}
|
||||
width: 600,
|
||||
},
|
||||
},
|
||||
} as any;
|
||||
await openCrudFormDialog({ crudOptions });
|
||||
}
|
||||
|
|
|
@ -22,6 +22,11 @@
|
|||
</div>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
<template #footer>
|
||||
<fs-button key="aiChat" type="primary" icon="ion:color-wand-outline" @click="taskModal.onAiChat">AI分析</fs-button>
|
||||
<fs-button key="cancel" icon="ion:close-circle-outline" @click="taskModal.onOk">关闭</fs-button>
|
||||
<fs-button key="submit" icon="ion:checkmark-circle-outline" type="primary" @click="taskModal.onOk">确定</fs-button>
|
||||
</template>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
|
@ -37,11 +42,15 @@ export default {
|
|||
props: {},
|
||||
emits: ["run"],
|
||||
setup(props: any, ctx: any) {
|
||||
const openAiChat: any = inject("fn:ai.open", (q: string) => {});
|
||||
const taskModal = ref({
|
||||
open: false,
|
||||
onOk() {
|
||||
taskViewClose();
|
||||
},
|
||||
onAiChat() {
|
||||
onAiChat();
|
||||
},
|
||||
cancelText: "关闭",
|
||||
});
|
||||
const { isMobile } = usePreferences();
|
||||
|
@ -52,6 +61,24 @@ export default {
|
|||
return "left";
|
||||
});
|
||||
|
||||
function onAiChat() {
|
||||
const logs = currentHistory.value?.logs[activeKey.value];
|
||||
if (!logs || logs.length === 0) {
|
||||
return;
|
||||
}
|
||||
let logText = "";
|
||||
for (let log of logs) {
|
||||
logText += log + "\n";
|
||||
}
|
||||
const maxLength = 5000;
|
||||
if (logText.length > maxLength) {
|
||||
logText = logText.substring(logText.length - maxLength);
|
||||
}
|
||||
if (openAiChat) {
|
||||
openAiChat(logText);
|
||||
}
|
||||
}
|
||||
|
||||
const detail = ref({ nodes: [] });
|
||||
const activeKey = ref();
|
||||
const currentHistory: Ref<RunHistory> | undefined = inject("currentHistory");
|
||||
|
|
|
@ -9,7 +9,10 @@
|
|||
<a-col :span="6">
|
||||
<statistic-card title="用户总数" :count="count.userCount">
|
||||
<template #footer>
|
||||
<router-link to="/sys/authority/user" class="flex"><fs-icon icon="ion:settings-outline" class="mr-5 fs-16" /> 管理用户</router-link>
|
||||
<router-link to="/sys/authority/user" class="flex">
|
||||
<fs-icon icon="ion:settings-outline" class="mr-5 fs-16" />
|
||||
管理用户
|
||||
</router-link>
|
||||
</template>
|
||||
</statistic-card>
|
||||
</a-col>
|
||||
|
@ -21,7 +24,10 @@
|
|||
<a-col :span="6">
|
||||
<statistic-card title="全站流水线总数" :count="count.pipelineCount">
|
||||
<template #footer>
|
||||
<router-link to="/certd/pipeline" class="flex"><fs-icon icon="ion:settings-outline" class="mr-5 fs-16" /> 管理流水线</router-link>
|
||||
<router-link to="/certd/pipeline" class="flex">
|
||||
<fs-icon icon="ion:settings-outline" class="mr-5 fs-16" />
|
||||
管理流水线
|
||||
</router-link>
|
||||
</template>
|
||||
</statistic-card>
|
||||
</a-col>
|
||||
|
@ -42,21 +48,23 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref } from "vue";
|
||||
import { onMounted, ref, Ref } from "vue";
|
||||
import { FsIcon } from "@fast-crud/fast-crud";
|
||||
import StatisticCard from "/@/views/framework/home/dashboard/statistic-card.vue";
|
||||
import DayCount from "/@/views/framework/home/dashboard/charts/day-count.vue";
|
||||
import { GetStatisticCount } from "./api";
|
||||
|
||||
const count = ref({});
|
||||
function transformCountPerDayToChartData(key) {
|
||||
count.value[key] = count.value[key].map((item) => {
|
||||
const count: Ref = ref({});
|
||||
|
||||
function transformCountPerDayToChartData(key: string) {
|
||||
count.value[key] = count.value[key].map((item:any) => {
|
||||
return {
|
||||
name: item.date,
|
||||
value: item.count
|
||||
value: item.count,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
async function loadCount() {
|
||||
count.value = await GetStatisticCount();
|
||||
transformCountPerDayToChartData("userRegisterCountPerDay");
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
<a-input v-model:value="formState.public.mpsNo" placeholder="京公网安备xxxxxxx号" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item label="开启小助手" :name="['public', 'aiChatEnabled']">
|
||||
<a-switch v-model:checked="formState.public.aiChatEnabled" />
|
||||
</a-form-item>
|
||||
<a-form-item label="允许爬虫" :name="['public', 'robots']">
|
||||
<a-switch v-model:checked="formState.public.robots" />
|
||||
</a-form-item>
|
||||
|
|
|
@ -3,6 +3,12 @@
|
|||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.34.3](https://github.com/certd/certd/compare/v1.34.2...v1.34.3) (2025-05-15)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 添加 FlexCDN 更新证书插件 ([bf040d4](https://github.com/certd/certd/commit/bf040d4c428d29c06fbaca5e29100e0c583b2b0b))
|
||||
|
||||
## [1.34.2](https://github.com/certd/certd/compare/v1.34.1...v1.34.2) (2025-05-11)
|
||||
|
||||
### Bug Fixes
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@certd/ui-server",
|
||||
"version": "1.34.2",
|
||||
"version": "1.34.3",
|
||||
"description": "fast-server base midway",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
|
@ -41,19 +41,19 @@
|
|||
"@aws-sdk/client-acm": "^3.699.0",
|
||||
"@aws-sdk/client-cloudfront": "^3.699.0",
|
||||
"@aws-sdk/client-s3": "^3.705.0",
|
||||
"@certd/acme-client": "^1.34.2",
|
||||
"@certd/basic": "^1.34.2",
|
||||
"@certd/commercial-core": "^1.34.2",
|
||||
"@certd/jdcloud": "^1.34.2",
|
||||
"@certd/lib-huawei": "^1.34.2",
|
||||
"@certd/lib-k8s": "^1.34.2",
|
||||
"@certd/lib-server": "^1.34.2",
|
||||
"@certd/midway-flyway-js": "^1.34.2",
|
||||
"@certd/pipeline": "^1.34.2",
|
||||
"@certd/plugin-cert": "^1.34.2",
|
||||
"@certd/plugin-lib": "^1.34.2",
|
||||
"@certd/plugin-plus": "^1.34.2",
|
||||
"@certd/plus-core": "^1.34.2",
|
||||
"@certd/acme-client": "^1.34.3",
|
||||
"@certd/basic": "^1.34.3",
|
||||
"@certd/commercial-core": "^1.34.3",
|
||||
"@certd/jdcloud": "^1.34.3",
|
||||
"@certd/lib-huawei": "^1.34.3",
|
||||
"@certd/lib-k8s": "^1.34.3",
|
||||
"@certd/lib-server": "^1.34.3",
|
||||
"@certd/midway-flyway-js": "^1.34.3",
|
||||
"@certd/pipeline": "^1.34.3",
|
||||
"@certd/plugin-cert": "^1.34.3",
|
||||
"@certd/plugin-lib": "^1.34.3",
|
||||
"@certd/plugin-plus": "^1.34.3",
|
||||
"@certd/plus-core": "^1.34.3",
|
||||
"@corsinvest/cv4pve-api-javascript": "^8.3.0",
|
||||
"@huaweicloud/huaweicloud-sdk-cdn": "^3.1.120",
|
||||
"@huaweicloud/huaweicloud-sdk-core": "^3.1.120",
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
import {Inject, Provide, Scope, ScopeEnum} from "@midwayjs/core";
|
||||
import {BaseService, PageReq} from "@certd/lib-server";
|
||||
import {PluginEntity} from "../entity/plugin.js";
|
||||
import {InjectEntityModel} from "@midwayjs/typeorm";
|
||||
import {Repository} from "typeorm";
|
||||
import {isComm} from "@certd/plus-core";
|
||||
import {BuiltInPluginService} from "../../pipeline/service/builtin-plugin-service.js";
|
||||
import {merge} from "lodash-es";
|
||||
import {accessRegistry, notificationRegistry, pluginRegistry} from "@certd/pipeline";
|
||||
import {dnsProviderRegistry} from "@certd/plugin-cert";
|
||||
import {logger} from "@certd/basic";
|
||||
import { Inject, Provide, Scope, ScopeEnum } from "@midwayjs/core";
|
||||
import { BaseService, PageReq } from "@certd/lib-server";
|
||||
import { PluginEntity } from "../entity/plugin.js";
|
||||
import { InjectEntityModel } from "@midwayjs/typeorm";
|
||||
import { Repository } from "typeorm";
|
||||
import { isComm } from "@certd/plus-core";
|
||||
import { BuiltInPluginService } from "../../pipeline/service/builtin-plugin-service.js";
|
||||
import { merge } from "lodash-es";
|
||||
import { accessRegistry, notificationRegistry, pluginRegistry } from "@certd/pipeline";
|
||||
import { dnsProviderRegistry } from "@certd/plugin-cert";
|
||||
import { logger } from "@certd/basic";
|
||||
import yaml from "js-yaml";
|
||||
import {getDefaultAccessPlugin, getDefaultDeployPlugin, getDefaultDnsPlugin} from "./default-plugin.js";
|
||||
import { getDefaultAccessPlugin, getDefaultDeployPlugin, getDefaultDnsPlugin } from "./default-plugin.js";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
import { IsAccess, AccessInput, BaseAccess } from "@certd/pipeline";
|
||||
import { HttpClient } from "@certd/basic";
|
||||
import { FlexCDNClient } from "./client.js";
|
||||
|
||||
/**
|
||||
*/
|
||||
@IsAccess({
|
||||
name: "flexcdn",
|
||||
title: "FlexCDN授权",
|
||||
desc: "",
|
||||
icon: "svg:icon-lucky"
|
||||
})
|
||||
export class FlexCDNAccess extends BaseAccess {
|
||||
@AccessInput({
|
||||
title: "接口地址",
|
||||
component: {
|
||||
placeholder: "http://xxxxxxx:8080",
|
||||
name: "a-input",
|
||||
vModel: "value"
|
||||
},
|
||||
required: true
|
||||
})
|
||||
endpoint!: string;
|
||||
|
||||
@AccessInput({
|
||||
title: "用户类型",
|
||||
component: {
|
||||
placeholder: "请选择",
|
||||
name: "a-select",
|
||||
vModel: "value",
|
||||
options: [
|
||||
{
|
||||
value: "user",
|
||||
label: "普通用户"
|
||||
},
|
||||
{
|
||||
value: "admin",
|
||||
label: "管理员"
|
||||
}
|
||||
]
|
||||
},
|
||||
required: true
|
||||
})
|
||||
type!: string;
|
||||
|
||||
@AccessInput({
|
||||
title: "accessKeyId",
|
||||
component: {
|
||||
placeholder: "accessKeyId",
|
||||
component: {
|
||||
name: "a-input",
|
||||
vModel: "value"
|
||||
}
|
||||
},
|
||||
encrypt: false,
|
||||
required: true
|
||||
})
|
||||
accessKeyId!: string;
|
||||
|
||||
@AccessInput({
|
||||
title: "accessKey",
|
||||
component: {
|
||||
placeholder: "accessKey",
|
||||
component: {
|
||||
name: "a-input",
|
||||
vModel: "value"
|
||||
}
|
||||
},
|
||||
encrypt: true,
|
||||
required: true
|
||||
})
|
||||
accessKey!: string;
|
||||
|
||||
@AccessInput({
|
||||
title: "忽略证书校验",
|
||||
component: {
|
||||
name: "a-switch",
|
||||
vModel: "checked"
|
||||
},
|
||||
encrypt: false,
|
||||
required: true
|
||||
})
|
||||
skipSslVerify!: boolean;
|
||||
|
||||
@AccessInput({
|
||||
title: "测试",
|
||||
component: {
|
||||
name: "api-test",
|
||||
action: "TestRequest"
|
||||
},
|
||||
helper: "点击测试接口看是否正常"
|
||||
})
|
||||
testRequest = true;
|
||||
|
||||
async onTestRequest() {
|
||||
const http: HttpClient = this.ctx.http;
|
||||
const client = new FlexCDNClient({
|
||||
logger: this.ctx.logger,
|
||||
http,
|
||||
access: this
|
||||
});
|
||||
const token = await client.getToken();
|
||||
if (token) {
|
||||
return "ok";
|
||||
}
|
||||
throw "测试失败,未知错误";
|
||||
}
|
||||
}
|
||||
|
||||
new FlexCDNAccess();
|
|
@ -0,0 +1,81 @@
|
|||
import { HttpClient, HttpRequestConfig, ILogger } from "@certd/basic";
|
||||
import { FlexCDNAccess } from "./access.js";
|
||||
|
||||
export class FlexCDNClient {
|
||||
http: HttpClient;
|
||||
logger: ILogger;
|
||||
access: FlexCDNAccess;
|
||||
token: string;
|
||||
|
||||
constructor(opts: { logger: ILogger; http: HttpClient; access: FlexCDNAccess }) {
|
||||
this.logger = opts.logger;
|
||||
this.http = opts.http;
|
||||
this.access = opts.access;
|
||||
}
|
||||
|
||||
async getToken() {
|
||||
|
||||
/*
|
||||
步骤2:调用API获取AccessToken
|
||||
接口地址
|
||||
/APIAccessTokenService/getAPIAccessToken
|
||||
请求方法
|
||||
POST。
|
||||
|
||||
请求参数
|
||||
{
|
||||
"type": "admin",
|
||||
"accessKeyId": "zr9cmR42AEZxRyIV",
|
||||
"accessKey": "2w5p5NSZZuplUPsfPMzM7dFmTrI7xyja"
|
||||
}
|
||||
其中
|
||||
type - 如果是用户(即平台用户)AccessKey,则值为 user;如果是管理员(即系统用户)AccessKey,则值为 admin;
|
||||
accessKeyId 和 accessKey 换成你在步骤1中创建的AccessKey对应的数据。
|
||||
响应结果
|
||||
{
|
||||
"code": 200,
|
||||
"data": {
|
||||
"token": "IKNSMufZ1vDiXp5rSd9QR01m1174Oum5sah4amWFgbRb7lOKjuk62Spl7hgcazctzGhGG7jPgfmYUPojulC0FK5cLbrj8n7kxW7BtSawH9gWW14IWOzBY6UcpyXQndFu",
|
||||
"expiresAt": 1609686945
|
||||
},
|
||||
"message": "ok"
|
||||
}
|
||||
*/
|
||||
|
||||
const res = await this.doRequest({
|
||||
url: "/APIAccessTokenService/getAPIAccessToken",
|
||||
method: "POST",
|
||||
data: {
|
||||
type: this.access.type,
|
||||
accessKeyId: this.access.accessKeyId,
|
||||
accessKey: this.access.accessKey,
|
||||
},
|
||||
});
|
||||
this.token = res.token
|
||||
return this.token
|
||||
}
|
||||
|
||||
async doRequest(req: HttpRequestConfig) {
|
||||
|
||||
const headers = {
|
||||
...req.headers,
|
||||
}
|
||||
if(this.token){
|
||||
headers[ "X-Cloud-Access-Token"] = this.token
|
||||
}
|
||||
const res = await this.http.request({
|
||||
...req,
|
||||
headers,
|
||||
baseURL: this.access.endpoint,
|
||||
logRes:false,
|
||||
logParams:false,
|
||||
skipSslVerify: true,
|
||||
});
|
||||
if (res.code === 200) {
|
||||
return res.data;
|
||||
} else {
|
||||
throw new Error(res.message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
export * from "./plugins/index.js";
|
||||
export * from "./access.js";
|
||||
export * from "./client.js";
|
|
@ -0,0 +1 @@
|
|||
export * from "./plugin-refresh-cert.js";
|
|
@ -0,0 +1,128 @@
|
|||
import { AbstractTaskPlugin, IsTaskPlugin, pluginGroups, RunStrategy, TaskInput } from "@certd/pipeline";
|
||||
import { CertApplyPluginNames, CertInfo } from "@certd/plugin-cert";
|
||||
import { createCertDomainGetterInputDefine, createRemoteSelectInputDefine } from "@certd/plugin-lib";
|
||||
import { FlexCDNAccess } from "../access.js";
|
||||
import { FlexCDNClient } from "../client.js";
|
||||
|
||||
@IsTaskPlugin({
|
||||
//命名规范,插件类型+功能(就是目录plugin-demo中的demo),大写字母开头,驼峰命名
|
||||
name: "FlexCDNRefreshCert",
|
||||
title: "FlexCDN-更新证书",
|
||||
icon: "svg:icon-lucky",
|
||||
//插件分组
|
||||
group: pluginGroups.cdn.key,
|
||||
needPlus: false,
|
||||
default: {
|
||||
//默认值配置照抄即可
|
||||
strategy: {
|
||||
runStrategy: RunStrategy.SkipWhenSucceed,
|
||||
},
|
||||
},
|
||||
})
|
||||
//类名规范,跟上面插件名称(name)一致
|
||||
export class FlexCDNRefreshCert extends AbstractTaskPlugin {
|
||||
//证书选择,此项必须要有
|
||||
@TaskInput({
|
||||
title: "域名证书",
|
||||
helper: "请选择前置任务输出的域名证书",
|
||||
component: {
|
||||
name: "output-selector",
|
||||
from: [...CertApplyPluginNames],
|
||||
},
|
||||
// required: true, // 必填
|
||||
})
|
||||
cert!: CertInfo;
|
||||
|
||||
@TaskInput(createCertDomainGetterInputDefine({ props: { required: false } }))
|
||||
certDomains!: string[];
|
||||
|
||||
//授权选择框
|
||||
@TaskInput({
|
||||
title: "FlexCDN授权",
|
||||
component: {
|
||||
name: "access-selector",
|
||||
type: "FlexCDN", //固定授权类型
|
||||
},
|
||||
required: true, //必填
|
||||
})
|
||||
accessId!: string;
|
||||
//
|
||||
|
||||
@TaskInput(
|
||||
createRemoteSelectInputDefine({
|
||||
title: "证书Id",
|
||||
helper: "要更新的Flex证书id",
|
||||
action: FlexCDNRefreshCert.prototype.onGetCertList.name,
|
||||
})
|
||||
)
|
||||
certList!: number[];
|
||||
|
||||
//插件实例化时执行的方法
|
||||
async onInstance() {}
|
||||
|
||||
//插件执行方法
|
||||
async execute(): Promise<void> {
|
||||
const access: FlexCDNAccess = await this.getAccess<FlexCDNAccess>(this.accessId);
|
||||
|
||||
const client = new FlexCDNClient({
|
||||
http: this.ctx.http,
|
||||
logger: this.logger,
|
||||
access,
|
||||
});
|
||||
await client.getToken();
|
||||
for (const item of this.certList) {
|
||||
this.logger.info(`开始更新证书:${item}`);
|
||||
|
||||
const res = await client.doRequest({
|
||||
url: `/SSLCertService/findEnabledSSLCertConfig`,
|
||||
data: {
|
||||
sslCertId: item,
|
||||
},
|
||||
});
|
||||
|
||||
await client.doRequest({
|
||||
url: `/SSLCertService/updateSSLCert`,
|
||||
data: {
|
||||
...res,
|
||||
sslCertId: item,
|
||||
certData: this.cert.crt,
|
||||
keyData: this.cert.key,
|
||||
},
|
||||
});
|
||||
|
||||
this.logger.info(`更新证书${item}成功`);
|
||||
}
|
||||
|
||||
this.logger.info("部署完成");
|
||||
}
|
||||
|
||||
async onGetCertList() {
|
||||
const access: FlexCDNAccess = await this.getAccess<FlexCDNAccess>(this.accessId);
|
||||
const client = new FlexCDNClient({
|
||||
http: this.ctx.http,
|
||||
logger: this.logger,
|
||||
access,
|
||||
});
|
||||
await client.getToken();
|
||||
const res = await client.doRequest({
|
||||
url: "/SSLCertService/listSSLCerts",
|
||||
data: { size: 1000},
|
||||
method: "POST",
|
||||
});
|
||||
const list = res.sslCertsJSON;
|
||||
if (!list || list.length === 0) {
|
||||
throw new Error("没有找到证书,请先在控制台上传一次证书且关联网站");
|
||||
}
|
||||
|
||||
const options = list.map((item: any) => {
|
||||
return {
|
||||
label: `${item.name}<${item.id}-${item.firstServerName}>`,
|
||||
value: item.id,
|
||||
domain: JSON.parse(item.serverNamesJSON),
|
||||
};
|
||||
});
|
||||
return this.ctx.utils.options.buildGroupOptions(options, this.certDomains);
|
||||
}
|
||||
}
|
||||
//实例化一下,注册插件
|
||||
new FlexCDNRefreshCert();
|
|
@ -64,7 +64,7 @@ export class UploadCertToHostPlugin extends AbstractTaskPlugin {
|
|||
crtPath!: string;
|
||||
@TaskInput({
|
||||
title: '私钥保存路径',
|
||||
helper: '需要有写入权限,路径要包含私钥文件名,例如:/tmp/cert.key',
|
||||
helper: '原本的私钥保存路径,需要有写入权限,路径要包含私钥文件名,例如:/tmp/cert.key',
|
||||
component: {
|
||||
placeholder: '/root/deploy/nginx/cert.key',
|
||||
},
|
||||
|
@ -212,8 +212,9 @@ export class UploadCertToHostPlugin extends AbstractTaskPlugin {
|
|||
name: 'a-textarea',
|
||||
vModel: 'value',
|
||||
rows: 6,
|
||||
placeholder: 'systemctl restart nginx ',
|
||||
},
|
||||
helper: '上传后执行脚本命令,不填则不执行\n注意:如果目标主机是windows,且终端是cmd,系统会自动将多行命令通过“&&”连接成一行',
|
||||
helper: '上传后执行脚本命令,让证书生效(比如重启nginx),不填则不执行\n注意:如果目标主机是windows,且终端是cmd,系统会自动将多行命令通过“&&”连接成一行',
|
||||
required: false,
|
||||
})
|
||||
script!: string;
|
||||
|
|
7656
pnpm-lock.yaml
7656
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
32
start.sh
32
start.sh
|
@ -1,17 +1,31 @@
|
|||
#
|
||||
set -e
|
||||
|
||||
echo "即将删除packages下除ui之外的其他目录,按y确认(如果您没有修改过源码,按y即可)"
|
||||
read -p "y/n: " confirm
|
||||
if [ $confirm != "y" ]; then
|
||||
echo "取消操作"
|
||||
exit 1
|
||||
fi
|
||||
find ./packages -mindepth 1 -maxdepth 1 -type d ! -name 'ui' -exec rm -rf {} +
|
||||
|
||||
find ./packages -mindepth 1 -maxdepth 1 -type d ! -name 'ui' -exec rm -rf {} +
|
||||
echo "删除成功"
|
||||
|
||||
# 检查输入是否正确 循环输入
|
||||
while true; do
|
||||
echo "是否后台运行(第一次运行建议选择n,调试没有问题之后,重新运行,选择y)"
|
||||
read -p "y/n: " confirmNohup
|
||||
# 校验输入是否正确
|
||||
if [ $confirmNohup != "y" ] && [ $confirmNohup != "n" ]; then
|
||||
echo "输入错误"
|
||||
else
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
|
||||
echo "安装pnpm, 前提是已经安装了nodejs"
|
||||
npm install -g pnpm@ --registry https://registry.npmmirror.com
|
||||
npm install -g pnpm --registry https://registry.npmmirror.com
|
||||
echo "安装依赖"
|
||||
pnpm install --registry https://registry.npmmirror.com
|
||||
|
||||
|
@ -27,8 +41,14 @@ cd ../certd-server
|
|||
npm run build
|
||||
echo "构建完成"
|
||||
echo "启动服务"
|
||||
# 前台运行
|
||||
npm run start
|
||||
|
||||
# 后台运行
|
||||
# nohup npm run start &
|
||||
# 前台运行
|
||||
if [ $confirmNohup != "y" ]; then
|
||||
echo "当前运行模式为前台运行,ctrl+c或者关闭ssh将会停止运行"
|
||||
npm run start
|
||||
else
|
||||
echo "当前运行模式为后台运行,可以通过tail -f ./certd.log 命令查看日志"
|
||||
nohup npm run start > certd.log &
|
||||
fi
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue