Compare commits
63 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0b152a3cb8 | ||
|
|
1a0e096ddb | ||
|
|
bf040d4c42 | ||
|
|
3e2101aa5b | ||
|
|
44f11b38e7 | ||
|
|
06f8514bc1 | ||
|
|
d9a9f1c25c | ||
|
|
e77f7244ba | ||
|
|
09779cd1e1 | ||
|
|
11024168db | ||
|
|
304914513e | ||
|
|
03d0efcfc6 | ||
|
|
0c2bdc9146 | ||
|
|
188450b0c0 | ||
|
|
ddf6bbfa46 | ||
|
|
2c7c98a152 | ||
|
|
d31ac75718 | ||
|
|
4b28c659de | ||
|
|
00b937e52a | ||
|
|
68f333fb87 | ||
|
|
085b4d9319 | ||
|
|
b8edd14f39 | ||
|
|
61a19d694b | ||
|
|
aa96859798 | ||
|
|
abf015f485 | ||
|
|
0b9a02afde | ||
|
|
e332ce28f8 | ||
|
|
08e779f9f1 | ||
|
|
a53b6cd28f | ||
|
|
5a5af60f97 | ||
|
|
50cc17c7cb | ||
|
|
a1e504c138 | ||
|
|
4cc413047c | ||
|
|
2397097e4d | ||
|
|
c88f959ec9 | ||
|
|
0b2e28b62d | ||
|
|
c7f2ead696 | ||
|
|
b454e02d01 | ||
|
|
47df2ffc3e | ||
|
|
d18e431e2f | ||
|
|
0a147d2db7 | ||
|
|
ccdc933064 | ||
|
|
023f2d4569 | ||
|
|
06a7371d2b | ||
|
|
626f5d3487 | ||
|
|
8cd3b9fe2e | ||
|
|
716c35d52a | ||
|
|
8cc0f3918b | ||
|
|
98b51f0799 | ||
|
|
81d6dad548 | ||
|
|
41bc11cf96 | ||
|
|
721dbe415a | ||
|
|
f5c0b51428 | ||
|
|
892c6ad80c | ||
|
|
a47805e494 | ||
|
|
9dd49054d1 | ||
|
|
f5d1d1a0b7 | ||
|
|
d75fcb7fec | ||
|
|
826be45b6a | ||
|
|
d35d9c17c5 | ||
|
|
638c9720cf | ||
|
|
08a190882f | ||
|
|
bfa7530a39 |
1
.gitignore
vendored
@@ -17,6 +17,7 @@ gen
|
||||
/test/*.private.*
|
||||
|
||||
/*.log
|
||||
nohup.out
|
||||
|
||||
/packages/ui/*/.idea
|
||||
/packages/ui/*/node_modules
|
||||
|
||||
23
CHANGELOG.md
@@ -3,6 +3,29 @@
|
||||
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
|
||||
|
||||
* 修复部署到又拍云强制https无效的bug ([2397097](https://github.com/certd/certd/commit/2397097e4ddcb6f593210598e8779ffd44ac3f8f))
|
||||
* 修复刷新流水线页面后,日志不自动更新的bug ([0b2e28b](https://github.com/certd/certd/commit/0b2e28b62dd5eb6804c602083e65c87a9d1d72d2))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 集成智能问答机器人 ([9dd4905](https://github.com/certd/certd/commit/9dd49054d18ec436a5029444ca55a38adc682933))
|
||||
* 支持设置网安备案号 ([d18e431](https://github.com/certd/certd/commit/d18e431e2f08e6b37704032c4ea6fbdd8e971442))
|
||||
* http方式支持校验443端口 ([d75fcb7](https://github.com/certd/certd/commit/d75fcb7fec421a9a638eaa27fe9378c84b5e0f19))
|
||||
|
||||
## [1.34.1](https://github.com/certd/certd/compare/v1.34.0...v1.34.1) (2025-05-05)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
47
README.md
@@ -5,28 +5,35 @@ Certd 是一个免费全自动申请和自动部署更新SSL证书的管理系
|
||||
|
||||
关键字:证书自动申请、证书自动更新、证书自动续期、证书自动续签、证书管理工具
|
||||
|
||||
> 关于证书续期:
|
||||
>* 实际上没有办法不改变证书文件本身情况下直接续期或者续签。
|
||||
>* 我们所说的续期,其实就是按照全套流程重新申请一份新证书,然后重新部署上去。
|
||||
>* 免费证书过期时间90天,以后可能还会缩短,所以自动化部署必不可少
|
||||
|
||||
|
||||
> 流水线数量现已调整为无限制,欢迎大家使用
|
||||
|
||||
## 一、特性
|
||||
本项目不仅支持证书申请过程自动化,还可以自动化部署更新证书,让你的证书永不过期。
|
||||
|
||||
* 全自动申请证书(支持所有注册商注册的域名)
|
||||
* 全自动申请证书(支持所有注册商注册的域名,支持DNS-01、HTTP-01、CNAME代理等多种域名验证方式)
|
||||
* 全自动部署更新证书(目前支持部署到主机、阿里云、腾讯云等70+部署插件)
|
||||
* 支持DNS-01、HTTP-01、CNAME代理等多种域名验证方式
|
||||
* 支持通配符域名/泛域名,支持多个域名打到一个证书上,支持pem、pfx、der、jks等多种证书格式
|
||||
* 邮件通知、webhook通知
|
||||
* 私有化部署,数据保存本地,授权信息加密存储,镜像由Github Actions构建,过程公开透明
|
||||
* 支持SQLite,PostgreSQL、MySQL数据库
|
||||
* 邮件通知、webhook通知、企微、钉钉、飞书、anpush等多种通知方式
|
||||
* 私有化部署,数据保存本地,安装升级非常简单快捷
|
||||
* 镜像由Github Actions构建,过程公开透明
|
||||
* 授权加密,站点隐藏,2FA,密码防爆破等多重安全保障
|
||||
* 支持SQLite,PostgreSQL、MySQL多种数据库
|
||||
* 开放接口支持
|
||||
* 站点证书监控
|
||||
* 多用户管理
|
||||
|
||||
|
||||

|
||||
|
||||
>
|
||||
> 流水线数量现已调整为无限制,欢迎大家使用
|
||||
>
|
||||
|
||||
> 关于证书续期:
|
||||
>* 实际上没有办法不改变证书文件本身情况下直接续期或者续签。
|
||||
>* 我们所说的续期,其实就是按照全套流程重新申请一份新证书,然后重新部署上去。
|
||||
>* 免费证书过期时间90天,以后可能还会缩短,所以自动化部署必不可少
|
||||
|
||||
|
||||
|
||||
## 二、在线体验
|
||||
|
||||
@@ -143,14 +150,14 @@ https://afdian.com/a/greper
|
||||
|
||||
专业版特权对比
|
||||
|
||||
| 功能 | 免费版 | 专业版 |
|
||||
|---------|--------------------|-----------------------------|
|
||||
| 免费证书申请 | 免费无限制 | 免费无限制 |
|
||||
| 域名数量 | 无限制 | 无限制 |
|
||||
| 证书流水线条数 | 无限制 | 无限制 |
|
||||
| 站点证书监控 | 限制1条 | 无限制 |
|
||||
| 自动部署插件 | 阿里云CDN、腾讯云、七牛CDN、主机部署等 | 支持群晖、宝塔、1Panel等,持续开发中 |
|
||||
| 通知 | 邮件通知、自定义webhook | 邮件免配置、企微、飞书、anpush、server酱等 |
|
||||
| 功能 | 免费版 | 专业版 |
|
||||
|---------|---------------------------------------|--------------------------------|
|
||||
| 免费证书申请 | 免费无限制 | 免费无限制 |
|
||||
| 域名数量 | 无限制 | 无限制 |
|
||||
| 证书流水线条数 | 无限制 | 无限制 |
|
||||
| 站点证书监控 | 限制1条 | 无限制 |
|
||||
| 自动部署插件 | 阿里云CDN、腾讯云、七牛CDN、主机部署、宝塔、1Panel等大部分插件 | 群晖 |
|
||||
| 通知 | 邮件通知、自定义webhook | 邮件免配置、企微、钉钉、飞书、anpush、server酱等 |
|
||||
|
||||
|
||||
************************
|
||||
|
||||
@@ -1 +1 @@
|
||||
17:28
|
||||
20:28
|
||||
|
||||
@@ -3,6 +3,8 @@ services:
|
||||
certd:
|
||||
# 镜像 # ↓↓↓↓↓ ---- 镜像版本号,建议改成固定版本号,例如:certd:1.29.0
|
||||
image: registry.cn-shenzhen.aliyuncs.com/handsfree/certd:latest
|
||||
# image: ghcr.io/certd/certd:latest # --------- 如果 报镜像not found,可以尝试其他镜像源
|
||||
# image: greper/certd:latest
|
||||
container_name: certd # 容器名
|
||||
restart: unless-stopped # 自动重启
|
||||
volumes:
|
||||
@@ -35,6 +37,8 @@ services:
|
||||
# networks:
|
||||
# - ip6net
|
||||
environment:
|
||||
# ↓↓↓↓ ----------------------------------------------------- 使用上海东八时区
|
||||
# - TZ=Asia/Shanghai
|
||||
# 设置环境变量即可自定义certd配置
|
||||
# 配置项见: packages/ui/certd-server/src/config/config.default.ts
|
||||
# 配置规则: certd_ + 配置项, 点号用_代替
|
||||
|
||||
@@ -88,22 +88,26 @@ export default defineConfig({
|
||||
text: "特性",
|
||||
items: [
|
||||
{text: "CNAME代理校验", link: "/guide/feature/cname/index.md"},
|
||||
{text: "插件列表", link: "/guide/plugins.md"},
|
||||
{text: "多数据库支持", link: "/guide/install/database.md"},
|
||||
{text: "开放接口", link: "/guide/open/index.md"},
|
||||
{
|
||||
text: "站点安全", items: [
|
||||
{text: "安全特性", link: "/guide/feature/safe"},
|
||||
{text: "站点隐藏", link: "/guide/feature/safe/hidden"},
|
||||
{text: "安全生产建议", link: "/guide/feature/safe/suggest"},
|
||||
text: "站点安全", link: "/guide/feature/safe"
|
||||
},
|
||||
{
|
||||
text: "插件列表", items: [
|
||||
{text: "授权提供商", link: "/guide/plugins/access"},
|
||||
{text: "DNS提供商", link: "/guide/plugins/dns-provider"},
|
||||
{text: "任务插件", link: "/guide/plugins/deploy"},
|
||||
{text: "通知插件", link: "/guide/plugins/notification"},
|
||||
]
|
||||
},
|
||||
|
||||
]
|
||||
},
|
||||
{
|
||||
text: "常见问题",
|
||||
items: [
|
||||
{text: "QA", link: "/guide/qa/use"},
|
||||
{text: "常见报错处理", link: "/guide/qa/"},
|
||||
{text: "群晖证书部署", link: "/guide/use/synology/"},
|
||||
{text: "腾讯云密钥获取", link: "/guide/use/tencent/"},
|
||||
{text: "连接windows主机", link: "/guide/use/host/windows.md"},
|
||||
@@ -115,8 +119,14 @@ export default defineConfig({
|
||||
{text: "js脚本插件使用", link: "/guide/use/custom-script/index.md"},
|
||||
{text: "邮箱配置", link: "/guide/use/email/index.md"},
|
||||
{text: "IPv6支持", link: "/guide/use/setting/ipv6.md"},
|
||||
{text: "其他插件使用", link: "/deploy/"},
|
||||
{text: "商业版说明", link: "/comm/"},
|
||||
{text: "ESXi", link: "/guide/use/ESXi/index.md"},
|
||||
]
|
||||
},
|
||||
{
|
||||
text: "商业版配置", link: "/guide/use/comm/", items: [
|
||||
{text: "支付宝配置", link: "/guide/use/comm/payments/alipay.md"},
|
||||
{text: "微信支付配置", link: "/guide/use/comm/payments/wxpay.md"},
|
||||
{text: "彩虹易支付配置", link: "/guide/use/comm/payments/yizhifu.md"},
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -133,26 +143,6 @@ export default defineConfig({
|
||||
]
|
||||
}
|
||||
],
|
||||
"/deploy/": [
|
||||
{
|
||||
text: "部署证书插件",
|
||||
items: [
|
||||
{text: "插件说明", link: "/deploy/index.md"},
|
||||
{text: "部署到ESXi", link: "/deploy/ESXi/index.md"},
|
||||
]
|
||||
}
|
||||
],
|
||||
"/comm/": [
|
||||
{
|
||||
text: "商业版",
|
||||
items: [
|
||||
{text: "支付宝配置", link: "/comm/payments/alipay.md"},
|
||||
{text: "微信支付配置", link: "/comm/payments/wxpay.md"},
|
||||
{text: "彩虹易支付配置", link: "/comm/payments/yizhifu.md"},
|
||||
]
|
||||
}
|
||||
]
|
||||
,
|
||||
},
|
||||
|
||||
socialLinks: [
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
# 部署插件说明
|
||||
|
||||
## 待完善
|
||||
|
||||
@@ -3,6 +3,31 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.34.2](https://github.com/certd/certd/compare/v1.34.1...v1.34.2) (2025-05-11)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 修复部署到又拍云强制https无效的bug ([2397097](https://github.com/certd/certd/commit/2397097e4ddcb6f593210598e8779ffd44ac3f8f))
|
||||
* 修复刷新流水线页面后,日志不自动更新的bug ([0b2e28b](https://github.com/certd/certd/commit/0b2e28b62dd5eb6804c602083e65c87a9d1d72d2))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 集成智能问答机器人 ([9dd4905](https://github.com/certd/certd/commit/9dd49054d18ec436a5029444ca55a38adc682933))
|
||||
* 支持设置网安备案号 ([d18e431](https://github.com/certd/certd/commit/d18e431e2f08e6b37704032c4ea6fbdd8e971442))
|
||||
* http方式支持校验443端口 ([d75fcb7](https://github.com/certd/certd/commit/d75fcb7fec421a9a638eaa27fe9378c84b5e0f19))
|
||||
|
||||
## [1.34.1](https://github.com/certd/certd/compare/v1.34.0...v1.34.1) (2025-05-05)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* 根据SOA记录判断子域名托管有缺陷,改回手动配置子域名托管记录的方式 ([1b280a2](https://github.com/certd/certd/commit/1b280a2940f9e2d919b0bf23b89cc185be1fa498))
|
||||
* 修复宝塔授权测试按钮显示错误的bug ([048696e](https://github.com/certd/certd/commit/048696ee9386491bb68592fb3a47d1c900bb68bf))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 支持部署证书到火山dcdn ([5f85219](https://github.com/certd/certd/commit/5f852194953dc1b4e6336770f417507b8f5a33ad))
|
||||
* 支持部署证书到unicloud ([a63d687](https://github.com/certd/certd/commit/a63d687f1c573159f0857693f37602b0e1e44072))
|
||||
|
||||
# [1.34.0](https://github.com/certd/certd/compare/v1.33.8...v1.34.0) (2025-04-28)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
88
docs/guide/development/demo/access.md
Normal file
@@ -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();
|
||||
```
|
||||
@@ -22,4 +22,6 @@
|
||||

|
||||
|
||||
## 3、忘记解除地址和解除密码怎么办
|
||||
登录服务器,在数据库平级的目录下创建`.unhidden`文件即可`临时解除`站点隐藏
|
||||
登录服务器,在数据库平级的目录下创建`.unhidden`命名的空白文件,即可临时解除站点隐藏
|
||||
临时解除后会自动删除`.unhidden`文件,请尽快设置好新的`解除地址`和`解除密码`,并记住
|
||||
|
||||
|
||||
@@ -1,36 +1,49 @@
|
||||
# 站点安全特性
|
||||
# 安全特性
|
||||
|
||||
Certd 存储了证书以及授权等敏感数据,所以需要严格保障安全。
|
||||
我们非常重视您的数据安全,提供了以下安全特性
|
||||
Certd 存储了证书以及授权等敏感数据,所以需要严格保障安全。
|
||||
我们提供了以下安全特性,以及安全生产建议(请遵照建议进行生产部署以保障数据安全)
|
||||
|
||||
## 1、 授权数据加密存储【默认开启】
|
||||
## 一、站点安全特性
|
||||
|
||||
### 1、 授权数据加密存储【默认开启】
|
||||
* 所有的授权敏感字段会加密后存储
|
||||
* 每个用户独立维护授权数据,连管理员都无权查看
|
||||
|
||||

|
||||
星号部分为加密数据
|
||||
|
||||
## 2、 密码防爆破【默认开启】
|
||||
### 2、 密码防爆破【默认开启】
|
||||
* 登录失败次数过多,账号将被锁定,最高24小时(重启服务可解除锁定)
|
||||
* 用户登录密码加密hash后存储,无法计算出密码明文
|
||||

|
||||
|
||||
## 3、站点隐藏【建议开启】
|
||||
### 3、站点隐藏【建议开启】
|
||||
* 一般来说Certd设置好之后,后续很少需要访问修改。
|
||||
* 所以我们平时可以把站点访问关闭,需要的时候再打开,减少站点被攻击的风险
|
||||
* 请前往 `系统管理->系统设置->安全设置->开启站点隐藏`
|
||||
* [站点隐藏设置说明](./hidden/)
|
||||

|
||||
|
||||
## 4、登录双重验证
|
||||
点击查看 [站点隐藏功能详细使用说明](./hidden/)
|
||||
|
||||
|
||||
### 4、登录双重验证
|
||||
|
||||
支持2FA双重认证
|
||||
|
||||

|
||||
|
||||
## 5、数据库自动备份【建议开启】
|
||||
### 5、数据库自动备份【建议开启】
|
||||
* [自动备份设置说明](../../use/backup/)
|
||||
|
||||
|
||||
## 更多安全生产建议
|
||||
[安全生产建议](./suggest.md)
|
||||
## 二、安全生产建议
|
||||
|
||||
尽管`Cert`本身实现了很多安全特性,但`外部环境的安全`仍需要您来确保。
|
||||
请`务必`遵循如下建议做好安全防护
|
||||
|
||||
* 请`务必`使用`HTTPS协议`访问本应用,避免被中间人攻击
|
||||
* 请`务必`使用`web应用防火墙`防护本应用,防止XSS、SQL注入等攻击
|
||||
* 请`务必`做好`服务器本身`的安全防护,防止数据库泄露
|
||||
* 请`务必`做好[`数据备份`](../../use/backup/),避免数据丢失
|
||||
* 请`务必`修改管理员账号用户名,且建议将admin注册为普通用户,且设置为禁用。
|
||||
* 建议开启[`站点隐藏`](./hidden/)功能
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
# 安全生产建议
|
||||
|
||||
尽管`Cert`本身实现了很多安全特性,但`外部环境的安全`仍需要您来确保。
|
||||
请`务必`遵循如下建议做好安全防护
|
||||
|
||||
* 请`务必`使用`HTTPS协议`访问本应用,避免被中间人攻击
|
||||
* 请`务必`使用`web应用防火墙`防护本应用,防止XSS、SQL注入等攻击
|
||||
* 请`务必`做好`服务器本身`的安全防护,防止数据库泄露
|
||||
* 请`务必`做好[`数据备份`](../../use/backup/),避免数据丢失
|
||||
* 建议开启[`站点隐藏`](./hidden/)功能
|
||||
@@ -5,32 +5,28 @@ Certd 是一款开源、免费、全自动申请和部署更新SSL证书的工
|
||||
|
||||
关键字:证书自动申请、证书自动更新、证书自动续期、证书自动续签、证书管理工具
|
||||
|
||||
## 1、关于证书续期
|
||||
>* 实际上没有办法不改变证书文件本身情况下直接续期或者续签。
|
||||
>* 我们所说的续期,其实就是按照全套流程重新申请一份新证书,然后重新部署上去。
|
||||
>* 免费证书过期时间90天,以后可能还会缩短,所以自动化部署必不可少
|
||||
|
||||
## 一、特性
|
||||
|
||||
## 2、项目特性
|
||||
本项目不仅支持证书申请过程自动化,还可以自动化部署更新证书,让你的证书永不过期。
|
||||
|
||||
* 全自动申请证书(支持所有注册商注册的域名)
|
||||
* 全自动部署更新证书(目前支持部署到主机、部署到阿里云、腾讯云等,目前已支持60+部署插件)
|
||||
* 支持通配符域名/泛域名,支持多个域名打到一个证书上
|
||||
* 邮件通知
|
||||
* 私有化部署,保障数据安全
|
||||
* 支持SQLite、Postgresql、MySQL数据库
|
||||
* 全自动申请证书(支持所有注册商注册的域名,支持DNS-01、HTTP-01、CNAME代理等多种域名验证方式)
|
||||
* 全自动部署更新证书(目前支持部署到主机、阿里云、腾讯云等70+部署插件)
|
||||
* 支持通配符域名/泛域名,支持多个域名打到一个证书上,支持pem、pfx、der、jks等多种证书格式
|
||||
* 邮件通知、webhook通知、企微、钉钉、飞书、anpush等多种通知方式
|
||||
* 私有化部署,数据保存本地,安装升级非常简单快捷
|
||||
* 镜像由Github Actions构建,过程公开透明
|
||||
* 授权加密,站点隐藏,2FA,密码防爆破等多重安全保障
|
||||
* 支持SQLite,PostgreSQL、MySQL多种数据库
|
||||
* 开放接口支持
|
||||
* 站点证书监控
|
||||
* 多用户管理
|
||||
|
||||
|
||||

|
||||
|
||||
## 二、一些说明
|
||||
* 本项目申请证书过程遵循acme协议
|
||||
* 需要验证域名所有权,一般有两种方式
|
||||
* http-01: 在网站根目录下放置一份txt文件
|
||||
* dns-01: 需要给域名添加txt解析记录,通配符域名只能用这种方式(本项目仅支持dns-01)
|
||||
* 证书续期:
|
||||
* 实际上没有办法不改变证书文件本身情况下直接续期或者续签。
|
||||
* 我们所说的续期,其实就是按照全套流程重新申请一份新证书,然后重新部署上去。
|
||||
* 免费证书过期时间90天,以后可能还会缩短,所以自动化部署必不可少
|
||||
* 设置每天自动运行,当证书过期前35天,会自动重新申请证书并部署
|
||||
|
||||
## 三、证书颁发机构对比
|
||||
* Let's Encrypt:申请最简单。
|
||||
* Google: 大厂光环,兼容性好,首次需要翻墙获取EAB。
|
||||
* ZeroSSL: 需要EAB,获取EAB无需翻墙。
|
||||
@@ -1,5 +1,6 @@
|
||||
# 源码部署
|
||||
如果没有`git`和`nodejs`基础,则不推荐
|
||||
如果没有开发基础、没有运维基础、没有`git`和`nodejs`基础,强烈不推荐此方式
|
||||
|
||||
## 一、源码安装
|
||||
|
||||
### 环境要求
|
||||
@@ -42,8 +43,8 @@ git pull
|
||||
kill -9 $(lsof -t -i:7001)
|
||||
# 重新编译启动
|
||||
./start.sh
|
||||
```
|
||||
|
||||
```
|
||||
::: warning
|
||||
升级certd版本前,切记切记先备份一下数据
|
||||
:::
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
# 插件列表
|
||||
|
||||

|
||||
|
||||
|
||||
58
docs/guide/plugins/access.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# 授权列表
|
||||
|
||||
| 序号 | 名称 | 说明 |
|
||||
|-----|-----|-----|
|
||||
| 1.| **阿里云授权** | |
|
||||
| 2.| **EAB授权** | ZeroSSL证书申请需要EAB授权 |
|
||||
| 3.| **google cloud** | 谷歌云授权 |
|
||||
| 4.| **主机登录授权** | |
|
||||
| 5.| **SFTP授权** | |
|
||||
| 6.| **阿里云OSS授权** | 包含地域和Bucket |
|
||||
| 7.| **FTP授权** | |
|
||||
| 8.| **腾讯云** | |
|
||||
| 9.| **腾讯云COS授权** | 腾讯云对象存储授权,包含地域和存储桶 |
|
||||
| 10.| **七牛云授权** | |
|
||||
| 11.| **七牛OSS授权** | |
|
||||
| 12.| **天翼云授权** | |
|
||||
| 13.| **s3/minio授权** | S3/minio oss授权 |
|
||||
| 14.| **baota授权** | |
|
||||
| 15.| **易盾DCDN授权** | https://user.yiduncdn.com |
|
||||
| 16.| **易盾rcdn授权** | 易盾CDN,每月免费30G,[注册即领](https://rhcdn.yiduncdn.com/register?code=8mn536rrzfbf8) |
|
||||
| 17.| **易发云短信** | sms.yfyidc.cn/ |
|
||||
| 18.| **cdnfly授权** | |
|
||||
| 19.| **群晖登录授权** | |
|
||||
| 20.| **k8s授权** | |
|
||||
| 21.| **1panel授权** | 账号和密码 |
|
||||
| 22.| **百度云授权** | |
|
||||
| 23.| **LeCDN授权** | |
|
||||
| 24.| **白山云授权** | |
|
||||
| 25.| **plesk授权** | |
|
||||
| 26.| **易支付** | |
|
||||
| 27.| **支付宝** | |
|
||||
| 28.| **微信支付** | |
|
||||
| 29.| **长亭雷池授权** | |
|
||||
| 30.| **lucky** | |
|
||||
| 31.| **括彩云cdn授权** | 括彩云CDN,每月免费30G,[注册即领](https://kuocaicdn.com/register?code=8mn536rrzfbf8) |
|
||||
| 32.| **uniCloud** | unicloud授权 |
|
||||
| 33.| **华为云授权** | |
|
||||
| 34.| **西部数码授权** | |
|
||||
| 35.| **多吉云** | |
|
||||
| 36.| **我爱云授权** | 我爱云CDN |
|
||||
| 37.| **CacheFly** | CacheFly |
|
||||
| 38.| **Gcore** | Gcore |
|
||||
| 39.| **亚马逊云aws授权** | |
|
||||
| 40.| **dns.la授权** | |
|
||||
| 41.| **又拍云** | |
|
||||
| 42.| **火山引擎** | |
|
||||
| 43.| **京东云** | |
|
||||
| 44.| **51dns授权** | |
|
||||
|
||||
<style module>
|
||||
table th:first-of-type {
|
||||
width: 65px;
|
||||
}
|
||||
table th:nth-of-type(2) {
|
||||
width: 240px;
|
||||
}
|
||||
</style>
|
||||
|
||||
130
docs/guide/plugins/deploy.md
Normal file
@@ -0,0 +1,130 @@
|
||||
# 任务插件
|
||||
共 `70` 款任务插件
|
||||
## 1. 证书申请
|
||||
|
||||
| 序号 | 名称 | 说明 |
|
||||
|-----|-----|-----|
|
||||
| 1.| **证书申请(JS版)** | 免费通配符域名证书申请,支持多个域名打到同一个证书上 |
|
||||
| 2.| **证书申请(Lego)** | 支持海量DNS解析提供商,推荐使用,一样的免费通配符域名证书申请,支持多个域名打到同一个证书上 |
|
||||
| 3.| **商用证书托管** | 手动上传自定义证书后,自动部署(每次证书有更新,都需要手动上传一次) |
|
||||
## 2. 主机
|
||||
|
||||
| 序号 | 名称 | 说明 |
|
||||
|-----|-----|-----|
|
||||
| 1.| **FTP-上传证书到FTP** | 将证书上传到FTP服务器 |
|
||||
| 2.| **IIS-部署到IIS站点** | |
|
||||
| 3.| **主机-执行远程主机脚本命令** | 可以执行重启nginx等操作让证书生效 |
|
||||
| 4.| **主机-部署证书到SSH主机** | SFTP上传证书到主机,然后SSH执行部署脚本命令 |
|
||||
## 3. CDN
|
||||
|
||||
| 序号 | 名称 | 说明 |
|
||||
|-----|-----|-----|
|
||||
| 1.| **易盾-部署到易盾DCDN** | 主要是防御,http://user.yiduncdn.com/ |
|
||||
| 2.| **易盾-部署到易盾RCDN** | 易盾CDN,每月免费30G,[注册即领](https://rhcdn.yiduncdn.com/register?code=8mn536rrzfbf8) |
|
||||
| 3.| **cdnfly-部署证书到cdnfly** | cdnfly |
|
||||
| 4.| **百度云-部署证书到CDN** | 部署到百度云CDN |
|
||||
| 5.| **LeCDN-更新证书** | |
|
||||
| 6.| **LeCDN-更新证书V2** | 支持新版本LeCDN |
|
||||
| 7.| **白山云-更新证书** | |
|
||||
| 8.| **天翼云-部署证书到CDN** | 部署证书到天翼云CDN和全站加速 |
|
||||
| 9.| **括彩云-部署到括彩云CDN** | 括彩云CDN,每月免费30G,[注册即领](https://kuocaicdn.com/register?code=8mn536rrzfbf8) |
|
||||
| 10.| **多吉云-部署到多吉云CDN** | |
|
||||
| 11.| **我爱云-部署证书到我爱云CDN** | 部署证书到我爱云CDN |
|
||||
| 12.| **CacheFly-部署证书到CacheFly** | 部署证书到 CacheFly |
|
||||
| 13.| **Gcore-部署证书到Gcore** | 仅上传 并不会部署到cdn |
|
||||
| 14.| **Gcore-刷新Gcore证书** | 刷新现有的证书 |
|
||||
| 15.| **又拍云-部署证书到CDN/USS** | 支持又拍云CDN,又拍云云存储USS |
|
||||
## 4. 面板
|
||||
|
||||
| 序号 | 名称 | 说明 |
|
||||
|-----|-----|-----|
|
||||
| 1.| **宝塔-面板证书部署** | 部署宝塔面板本身的ssl证书 |
|
||||
| 2.| **宝塔-网站证书部署** | 部署宝塔管理的站点的ssl证书,目前支持网站站点、docker站点等 |
|
||||
| 3.| **群晖-部署证书到群晖面板** | Synology,支持6.x以上版本 |
|
||||
| 4.| **K8S-部署证书到Secret** | 部署证书到k8s的secret |
|
||||
| 5.| **K8S-Ingress 证书部署** | 部署证书到k8s的Ingress |
|
||||
| 6.| **1Panel-部署证书到1Panel** | 更新1Panel的证书 |
|
||||
| 7.| **Plesk-部署Plesk网站证书** | |
|
||||
| 8.| **雷池-更新证书** | 更新长亭雷池WAF的证书 |
|
||||
| 9.| **lucky-更新Lucky证书** | |
|
||||
| 10.| **uniCloud-部署到服务空间** | 部署到服务空间 |
|
||||
| 11.| **威联通-部署证书到威联通** | 部署证书到qnap |
|
||||
## 5. 阿里云
|
||||
|
||||
| 序号 | 名称 | 说明 |
|
||||
|-----|-----|-----|
|
||||
| 1.| **阿里云-部署到Ack** | 部署到阿里云Ack集群Ingress等通过Secret管理证书的应用 |
|
||||
| 2.| **阿里云-部署至任意云资源** | 【不建议使用】需要消耗阿里云自动部署次数,支持SLB、LIVE、webHosting、VOD、CR、DCDN、DDoS、CDN、ALB、APIGateway、FC、GA、MSE、NLB、OSS、SAE、WAF等云产品 |
|
||||
| 3.| **阿里云-部署证书至CDN** | 自动部署域名证书至阿里云CDN |
|
||||
| 4.| **阿里云-部署证书至DCDN** | 依赖证书申请前置任务,自动部署域名证书至阿里云DCDN |
|
||||
| 5.| **阿里云-部署证书至OSS** | 自动部署域名证书至阿里云OSS |
|
||||
| 6.| **阿里云-上传证书到阿里云** | 如果不想在阿里云上同一份证书上传多次,可以把此任务作为前置任务,其他阿里云任务证书那一项选择此任务的输出 |
|
||||
| 7.| **阿里云-部署至阿里云WAF** | 部署证书到阿里云WAF |
|
||||
| 8.| **阿里云-部署至ALB(应用负载均衡)** | ALB,更新监听器的默认证书 |
|
||||
| 9.| **阿里云-部署至NLB(网络负载均衡)** | NLB,网络负载均衡,更新监听器的默认证书 |
|
||||
| 10.| **阿里云-部署至SLB(传统负载均衡)** | 部署证书到阿里云SLB(传统负载均衡) |
|
||||
| 11.| **阿里云-部署至阿里云FC(3.0)** | 部署证书到阿里云函数计算(FC3.0),【注意】证书的加密算法必须选择【pkcs1旧版】 |
|
||||
## 6. 华为云
|
||||
|
||||
| 序号 | 名称 | 说明 |
|
||||
|-----|-----|-----|
|
||||
| 1.| **华为云-部署证书至CDN** | |
|
||||
## 7. 腾讯云
|
||||
|
||||
| 序号 | 名称 | 说明 |
|
||||
|-----|-----|-----|
|
||||
| 1.| **腾讯云-部署证书到任意云资源** | 支持负载均衡、CDN、DDoS、直播、点播、Web应用防火墙、API网关、TEO、容器服务、对象存储、轻应用服务器、云原生微服务、云开发 |
|
||||
| 2.| **腾讯云-部署到CLB** | 暂时只支持单向认证证书,暂时只支持通用负载均衡 |
|
||||
| 3.| **腾讯云-部署到CDN(废弃)** | 已废弃,请使用v2版 |
|
||||
| 4.| **腾讯云-部署到CDN-v2** | 推荐使用 |
|
||||
| 5.| **腾讯云-上传证书到腾讯云** | 上传成功后输出:tencentCertId |
|
||||
| 6.| **腾讯云-部署证书到COS** | 部署到腾讯云COS源站域名证书【注意:很不稳定,需要重试很多次偶尔才能成功一次】 |
|
||||
| 7.| **腾讯云-部署到腾讯云EO** | 腾讯云边缘安全加速平台EO,必须配置上传证书到腾讯云任务 |
|
||||
| 8.| **腾讯云-删除即将过期证书** | 仅删除未使用的证书 |
|
||||
| 9.| **腾讯云-部署到TKE-ingress** | serverless集群请使用K8S部署插件;Qcloud类型需要【上传到腾讯云】作为前置任务;ApiServer未开启外网访问则需要做域名的内网IP映射 |
|
||||
## 8. 火山引擎
|
||||
|
||||
| 序号 | 名称 | 说明 |
|
||||
|-----|-----|-----|
|
||||
| 1.| **火山引擎-部署证书至CDN** | 支持网页,文件下载,音视频点播 |
|
||||
| 2.| **火山引擎-部署证书至CLB** | 部署至火山引擎负载均衡 |
|
||||
| 3.| **火山引擎-上传证书至证书中心** | 上传证书至火山引擎证书中心 |
|
||||
| 4.| **火山引擎-部署证书至ALB** | 部署至火山引擎应用负载均衡 |
|
||||
| 5.| **火山引擎-部署证书至Live** | 部署至火山引擎视频直播 |
|
||||
## 9. 京东云
|
||||
|
||||
| 序号 | 名称 | 说明 |
|
||||
|-----|-----|-----|
|
||||
| 1.| **京东云-部署证书至CDN** | 京东云内容分发网络 |
|
||||
| 2.| **京东云-更新已有证书** | 更新SSL数字证书中的证书 |
|
||||
| 3.| **京东云-上传新证书** | 上传证书到SSL数字证书中心 |
|
||||
## 10. 七牛云
|
||||
|
||||
| 序号 | 名称 | 说明 |
|
||||
|-----|-----|-----|
|
||||
| 1.| **七牛云-部署证书至OSS** | 自动部署域名证书至七牛云KODO,注意是自定义源站域名,不是CDN域名 |
|
||||
| 2.| **七牛云-部署证书至CDN** | 自动部署域名证书至七牛云CDN |
|
||||
## 11. 亚马逊云
|
||||
|
||||
| 序号 | 名称 | 说明 |
|
||||
|-----|-----|-----|
|
||||
| 1.| **AWS-部署证书到CloudFront** | 部署证书到 AWS CloudFront |
|
||||
## 12. 其他
|
||||
|
||||
| 序号 | 名称 | 说明 |
|
||||
|-----|-----|-----|
|
||||
| 1.| **Demo-测试插件** | |
|
||||
| 2.| **重启 Certd** | 【仅管理员可用】 重启 certd的https服务,用于更新 Certd 的 ssl 证书 |
|
||||
| 3.| **自定义js脚本** | 【仅管理员】运行自定义js脚本执行 |
|
||||
| 4.| **等待** | 等待一段时间 |
|
||||
| 5.| **数据库备份** | 仅支持备份SQLite数据库 |
|
||||
|
||||
<style module>
|
||||
table th:first-of-type {
|
||||
width: 65px;
|
||||
}
|
||||
table th:nth-of-type(2) {
|
||||
width: 240px;
|
||||
}
|
||||
</style>
|
||||
|
||||
22
docs/guide/plugins/dns-provider.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# DNS提供商
|
||||
|
||||
| 序号 | 名称 | 说明 |
|
||||
|-----|-----|-----|
|
||||
| 1.| **阿里云** | 阿里云DNS解析提供商 |
|
||||
| 2.| **腾讯云** | 腾讯云域名DNS解析提供者 |
|
||||
| 3.| **华为云** | 华为云DNS解析提供商 |
|
||||
| 4.| **西部数码** | west dns provider |
|
||||
| 5.| **dns.la** | dns.la |
|
||||
| 6.| **火山引擎** | 火山引擎DNS解析提供商 |
|
||||
| 7.| **京东云** | 京东云DNS解析提供商 |
|
||||
| 8.| **51dns** | 51DNS |
|
||||
|
||||
<style module>
|
||||
table th:first-of-type {
|
||||
width: 65px;
|
||||
}
|
||||
table th:nth-of-type(2) {
|
||||
width: 240px;
|
||||
}
|
||||
</style>
|
||||
|
||||
26
docs/guide/plugins/notification.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# 通知插件
|
||||
|
||||
| 序号 | 名称 | 说明 |
|
||||
|-----|-----|-----|
|
||||
| 1.| **企业微信通知** | 企业微信群聊机器人通知 |
|
||||
| 2.| **电子邮件** | 电子邮件通知 |
|
||||
| 3.| **爱语飞飞微信通知(iyuu)** | https://iyuu.cn/ |
|
||||
| 4.| **自定义webhook** | 根据模版自定义http请求 |
|
||||
| 5.| **Server酱ᵀ** | https://sct.ftqq.com/ |
|
||||
| 6.| **Server酱³** | https://doc.sc3.ft07.com/serverchan3 |
|
||||
| 7.| **AnPush** | https://anpush.com |
|
||||
| 8.| **Telegram通知** | Telegram Bot推送通知 |
|
||||
| 9.| **Discord 通知** | Discord 机器人通知 |
|
||||
| 10.| **Slack通知** | Slack消息推送通知 |
|
||||
| 11.| **Bark 通知** | Bark 推送通知插件 |
|
||||
| 12.| **飞书通知** | 飞书群聊webhook通知 |
|
||||
|
||||
<style module>
|
||||
table th:first-of-type {
|
||||
width: 65px;
|
||||
}
|
||||
table th:nth-of-type(2) {
|
||||
width: 240px;
|
||||
}
|
||||
</style>
|
||||
|
||||
BIN
docs/guide/qa/images/baota-net.png
Normal file
|
After Width: | Height: | Size: 82 KiB |
73
docs/guide/qa/index.md
Normal file
@@ -0,0 +1,73 @@
|
||||
# 常见报错解决
|
||||
|
||||
## 1. getaddrinfo ENOTFOUND错误
|
||||
如果出现`getaddrinfo ENOTFOUND`错误,可以尝试在`docker-compose.yaml`中设置dns
|
||||
```yaml
|
||||
version: '3.3' # 兼容旧版docker-compose
|
||||
services:
|
||||
certd:
|
||||
#↓↓↓↓ ------------ # 如果出现getaddrinfo ENOTFOUND错误,可以尝试设置dns
|
||||
dns:
|
||||
- 223.5.5.5 # 阿里云公共dns
|
||||
- 223.6.6.6
|
||||
# # ↓↓↓↓ ------- # 如果你服务器在腾讯云,可以用这个替换上面阿里云的公共dns
|
||||
# - 119.29.29.29 # 腾讯云公共dns
|
||||
# - 182.254.116.116
|
||||
# # ↓↓↓↓ ------- # 如果你服务器部署在国外,可以用这个替换上面阿里云的公共dns
|
||||
# - 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
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
14
docs/guide/qa/use.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# 使用问题
|
||||
|
||||
|
||||
## 1. 是否支持IP证书
|
||||
|
||||
因为ACME协议不支持IP证书,所以certd目前也不支持IP证书
|
||||
|
||||
|
||||
## 2. 建议设置多长时间运行一次流水线
|
||||
建议每天运行一次,检查证书过期时间
|
||||
当证书没过期时,自动跳过部署
|
||||
当证书到期前35天(创建流水线时可以修改),将会自动重新申请证书,自动部署
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 165 KiB After Width: | Height: | Size: 165 KiB |
@@ -17,7 +17,9 @@ CERTD_HTTPS_port=7002
|
||||
参考Certd顶部的创建证书流水线教程
|
||||
|
||||
### 2、配置复制到本机任务
|
||||
将证书复制到certd的证书安装位置
|
||||
将证书复制到certd的证书安装位置
|
||||
证书路径:`ssl/cert.crt`
|
||||
私钥路径:`ssl/cert.key`
|
||||
|
||||

|
||||

|
||||
|
||||
BIN
docs/guide/use/pretask/images/pretask1.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
docs/guide/use/pretask/images/pretask2.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
13
docs/guide/use/pretask/index.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# 带输出的前置任务
|
||||
|
||||
前置任务输出可以在后续任务中使用
|
||||
|
||||
比如上传证书到阿里云,会返回阿里云的CertId,之后其他阿里云的部署任务可以选择复用这个证书
|
||||
|
||||
## 复用证书
|
||||
|
||||

|
||||
|
||||
在后续任务中可以选择前置任务的输出
|
||||
|
||||

|
||||
@@ -9,5 +9,5 @@
|
||||
}
|
||||
},
|
||||
"npmClient": "pnpm",
|
||||
"version": "1.34.1"
|
||||
"version": "1.34.3"
|
||||
}
|
||||
|
||||
@@ -30,7 +30,8 @@
|
||||
"init": "lerna run build",
|
||||
"docs:dev": "vitepress dev docs",
|
||||
"docs:build": "vitepress build docs",
|
||||
"docs:preview": "vitepress preview docs"
|
||||
"docs:preview": "vitepress preview docs",
|
||||
"pub": "echo 1"
|
||||
},
|
||||
"license": "AGPL-3.0",
|
||||
"dependencies": {
|
||||
|
||||
@@ -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/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
|
||||
|
||||
* http方式支持校验443端口 ([d75fcb7](https://github.com/publishlab/node-acme-client/commit/d75fcb7fec421a9a638eaa27fe9378c84b5e0f19))
|
||||
|
||||
## [1.34.1](https://github.com/publishlab/node-acme-client/compare/v1.34.0...v1.34.1) (2025-05-05)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"description": "Simple and unopinionated ACME client",
|
||||
"private": false,
|
||||
"author": "nmorsman",
|
||||
"version": "1.34.1",
|
||||
"version": "1.34.3",
|
||||
"type": "module",
|
||||
"module": "scr/index.js",
|
||||
"main": "src/index.js",
|
||||
@@ -18,7 +18,7 @@
|
||||
"types"
|
||||
],
|
||||
"dependencies": {
|
||||
"@certd/basic": "^1.34.1",
|
||||
"@certd/basic": "^1.34.3",
|
||||
"@peculiar/x509": "^1.11.0",
|
||||
"asn1js": "^3.0.5",
|
||||
"axios": "^1.7.2",
|
||||
@@ -51,7 +51,8 @@
|
||||
"lint": "eslint .",
|
||||
"lint-types": "tsd",
|
||||
"prepublishOnly": "npm run build-docs",
|
||||
"test": "mocha -t 60000 \"test/setup.js\" \"test/**/*.spec.js\""
|
||||
"test": "mocha -t 60000 \"test/setup.js\" \"test/**/*.spec.js\"",
|
||||
"pub": "npm publish"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -68,5 +69,5 @@
|
||||
"bugs": {
|
||||
"url": "https://github.com/publishlab/node-acme-client/issues"
|
||||
},
|
||||
"gitHead": "9749fc817d3cfd435e8cb3f2f86edc81d69e2310"
|
||||
"gitHead": "a1e504c1387e9b0554c8d030cb53c5058e7d683a"
|
||||
}
|
||||
|
||||
@@ -234,6 +234,7 @@ export default async (client, userOpts) => {
|
||||
throw new CancelError("用户取消");
|
||||
}
|
||||
|
||||
const waitDnsDiffuseTime = opts.waitDnsDiffuseTime || 30;
|
||||
try {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await runPromisePa(challengePromises);
|
||||
@@ -242,8 +243,8 @@ export default async (client, userOpts) => {
|
||||
await wait(60 * 1000);
|
||||
} else {
|
||||
await runPromisePa(localVerifyTasks, 1000);
|
||||
log("本地校验完成,等待30s")
|
||||
await wait(30 * 1000)
|
||||
log(`本地校验完成,等待${waitDnsDiffuseTime}s`)
|
||||
await wait(waitDnsDiffuseTime * 1000)
|
||||
}
|
||||
|
||||
log("开始向提供商请求挑战验证");
|
||||
|
||||
@@ -24,22 +24,46 @@ const dns = dnsSdk.promises
|
||||
*/
|
||||
|
||||
async function verifyHttpChallenge(authz, challenge, keyAuthorization, suffix = `/.well-known/acme-challenge/${challenge.token}`) {
|
||||
|
||||
async function doQuery(challengeUrl){
|
||||
log(`正在测试请求 ${challengeUrl} `)
|
||||
// const httpsPort = axios.defaults.acmeSettings.httpsChallengePort || 443;
|
||||
// const challengeUrl = `https://${authz.identifier.value}:${httpsPort}${suffix}`;
|
||||
|
||||
/* May redirect to HTTPS with invalid/self-signed cert - https://letsencrypt.org/docs/challenge-types/#http-01-challenge */
|
||||
const httpsAgent = new https.Agent({ rejectUnauthorized: false });
|
||||
|
||||
log(`Sending HTTP query to ${authz.identifier.value}, suffix: ${suffix}, port: ${httpPort}`);
|
||||
let data = ""
|
||||
try{
|
||||
const resp = await axios.get(challengeUrl, { httpsAgent });
|
||||
data = (resp.data || '').replace(/\s+$/, '');
|
||||
}catch (e) {
|
||||
log(`[error] HTTP request error from ${authz.identifier.value}`,e.message);
|
||||
return false
|
||||
}
|
||||
|
||||
if (!data || (data !== keyAuthorization)) {
|
||||
log(`[error] Authorization not found in HTTP response from ${authz.identifier.value}`);
|
||||
return false
|
||||
}
|
||||
return true
|
||||
|
||||
}
|
||||
|
||||
const httpPort = axios.defaults.acmeSettings.httpChallengePort || 80;
|
||||
const challengeUrl = `http://${authz.identifier.value}:${httpPort}${suffix}`;
|
||||
|
||||
/* May redirect to HTTPS with invalid/self-signed cert - https://letsencrypt.org/docs/challenge-types/#http-01-challenge */
|
||||
const httpsAgent = new https.Agent({ rejectUnauthorized: false });
|
||||
|
||||
log(`Sending HTTP query to ${authz.identifier.value}, suffix: ${suffix}, port: ${httpPort}`);
|
||||
const resp = await axios.get(challengeUrl, { httpsAgent });
|
||||
const data = (resp.data || '').replace(/\s+$/, '');
|
||||
|
||||
log(`Query successful, HTTP status code: ${resp.status}`);
|
||||
|
||||
if (!data || (data !== keyAuthorization)) {
|
||||
throw new Error(`Authorization not found in HTTP response from ${authz.identifier.value}`);
|
||||
if (!await doQuery(challengeUrl)) {
|
||||
const httpsPort = axios.defaults.acmeSettings.httpsChallengePort || 443;
|
||||
const httpsChallengeUrl = `https://${authz.identifier.value}:${httpsPort}${suffix}`;
|
||||
const res = await doQuery(httpsChallengeUrl)
|
||||
if (!res) {
|
||||
throw new Error(`[error] 验证失败,请检查以上测试url是否可以正常访问`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
log(`Key authorization match for ${challenge.type}/${authz.identifier.value}, ACME challenge verified`);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
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.34.1](https://github.com/certd/certd/compare/v1.34.0...v1.34.1) (2025-05-05)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
@@ -1 +1 @@
|
||||
00:16
|
||||
00:08
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/basic",
|
||||
"private": false,
|
||||
"version": "1.34.1",
|
||||
"version": "1.34.3",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
@@ -12,7 +12,8 @@
|
||||
"build": "npm run before-build && tsc --skipLibCheck",
|
||||
"dev-build": "npm run build",
|
||||
"preview": "vite preview",
|
||||
"test": "mocha --loader=ts-node/esm"
|
||||
"test": "mocha --loader=ts-node/esm",
|
||||
"pub": "npm publish"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.7.2",
|
||||
@@ -44,5 +45,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "9749fc817d3cfd435e8cb3f2f86edc81d69e2310"
|
||||
"gitHead": "a1e504c1387e9b0554c8d030cb53c5058e7d683a"
|
||||
}
|
||||
|
||||
@@ -145,7 +145,8 @@ export function createAxiosService({ logger }: { logger: Logger }) {
|
||||
} else {
|
||||
logger.info("http response status:", response?.status);
|
||||
}
|
||||
if (response?.config?.returnResponse) {
|
||||
|
||||
if (response?.config?.returnOriginRes) {
|
||||
return response;
|
||||
}
|
||||
return response.data;
|
||||
@@ -215,7 +216,7 @@ export type HttpRequestConfig<D = any> = {
|
||||
logParams?: boolean;
|
||||
logRes?: boolean;
|
||||
httpProxy?: string;
|
||||
returnResponse?: boolean;
|
||||
returnOriginRes?: boolean;
|
||||
} & AxiosRequestConfig<D>;
|
||||
export type HttpClient = {
|
||||
request<D = any, R = any>(config: HttpRequestConfig<D>): Promise<HttpClientResponse<R>>;
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
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.34.1](https://github.com/certd/certd/compare/v1.34.0...v1.34.1) (2025-05-05)
|
||||
|
||||
**Note:** Version bump only for package @certd/pipeline
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/pipeline",
|
||||
"private": false,
|
||||
"version": "1.34.1",
|
||||
"version": "1.34.3",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
@@ -13,11 +13,12 @@
|
||||
"dev-build": "npm run build",
|
||||
"build3": "rollup -c",
|
||||
"preview": "vite preview",
|
||||
"test": "mocha --loader=ts-node/esm"
|
||||
"test": "mocha --loader=ts-node/esm",
|
||||
"pub": "npm publish"
|
||||
},
|
||||
"dependencies": {
|
||||
"@certd/basic": "^1.34.1",
|
||||
"@certd/plus-core": "^1.34.1",
|
||||
"@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"
|
||||
@@ -43,5 +44,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "9749fc817d3cfd435e8cb3f2f86edc81d69e2310"
|
||||
"gitHead": "a1e504c1387e9b0554c8d030cb53c5058e7d683a"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
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.34.1](https://github.com/certd/certd/compare/v1.34.0...v1.34.1) (2025-05-05)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-huawei
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/lib-huawei",
|
||||
"private": false,
|
||||
"version": "1.34.1",
|
||||
"version": "1.34.3",
|
||||
"main": "./dist/bundle.js",
|
||||
"module": "./dist/bundle.js",
|
||||
"types": "./dist/d/index.d.ts",
|
||||
@@ -10,7 +10,8 @@
|
||||
"before-build": "rimraf dist && rimraf tsconfig.tsbuildinfo && rimraf .rollup.cache",
|
||||
"build": "npm run before-build && rollup -c ",
|
||||
"dev-build": "npm run build",
|
||||
"preview": "vite preview"
|
||||
"preview": "vite preview",
|
||||
"pub": "npm publish"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.7.2",
|
||||
@@ -23,5 +24,5 @@
|
||||
"prettier": "^2.8.8",
|
||||
"tslib": "^2.8.1"
|
||||
},
|
||||
"gitHead": "9749fc817d3cfd435e8cb3f2f86edc81d69e2310"
|
||||
"gitHead": "a1e504c1387e9b0554c8d030cb53c5058e7d683a"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
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.34.1](https://github.com/certd/certd/compare/v1.34.0...v1.34.1) (2025-05-05)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-iframe
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/lib-iframe",
|
||||
"private": false,
|
||||
"version": "1.34.1",
|
||||
"version": "1.34.3",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
@@ -13,7 +13,8 @@
|
||||
"dev-build": "npm run build",
|
||||
"build3": "rollup -c",
|
||||
"build2": "vue-tsc --noEmit && vite build",
|
||||
"preview": "vite preview"
|
||||
"preview": "vite preview",
|
||||
"pub": "npm publish"
|
||||
},
|
||||
"dependencies": {
|
||||
"nanoid": "^4.0.0"
|
||||
@@ -30,5 +31,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "9749fc817d3cfd435e8cb3f2f86edc81d69e2310"
|
||||
"gitHead": "a1e504c1387e9b0554c8d030cb53c5058e7d683a"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
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.34.1](https://github.com/certd/certd/compare/v1.34.0...v1.34.1) (2025-05-05)
|
||||
|
||||
**Note:** Version bump only for package @certd/jdcloud
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/jdcloud",
|
||||
"version": "1.34.1",
|
||||
"version": "1.34.3",
|
||||
"description": "jdcloud openApi sdk",
|
||||
"main": "./dist/bundle.js",
|
||||
"module": "./dist/bundle.js",
|
||||
@@ -9,7 +9,8 @@
|
||||
"test": "cross-env NODE_CONFIG_DIR=./test/config mocha --recursive --require babel-register",
|
||||
"dev": "babel src --out-dir babel -w",
|
||||
"build": "rollup -c ",
|
||||
"dev-build": "npm run build"
|
||||
"dev-build": "npm run build",
|
||||
"pub": "npm publish"
|
||||
},
|
||||
"author": "",
|
||||
"license": "Apache",
|
||||
@@ -60,5 +61,5 @@
|
||||
"fetch"
|
||||
]
|
||||
},
|
||||
"gitHead": "9749fc817d3cfd435e8cb3f2f86edc81d69e2310"
|
||||
"gitHead": "a1e504c1387e9b0554c8d030cb53c5058e7d683a"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
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.34.1](https://github.com/certd/certd/compare/v1.34.0...v1.34.1) (2025-05-05)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-k8s
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/lib-k8s",
|
||||
"private": false,
|
||||
"version": "1.34.1",
|
||||
"version": "1.34.3",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"module": "./dist/index.js",
|
||||
@@ -13,10 +13,11 @@
|
||||
"dev-build": "npm run build",
|
||||
"build3": "rollup -c",
|
||||
"build2": "vue-tsc --noEmit && vite build",
|
||||
"preview": "vite preview"
|
||||
"preview": "vite preview",
|
||||
"pub": "npm publish"
|
||||
},
|
||||
"dependencies": {
|
||||
"@certd/basic": "^1.34.1",
|
||||
"@certd/basic": "^1.34.3",
|
||||
"@kubernetes/client-node": "0.21.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -31,5 +32,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "9749fc817d3cfd435e8cb3f2f86edc81d69e2310"
|
||||
"gitHead": "a1e504c1387e9b0554c8d030cb53c5058e7d683a"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,18 @@
|
||||
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
|
||||
|
||||
* 支持设置网安备案号 ([d18e431](https://github.com/certd/certd/commit/d18e431e2f08e6b37704032c4ea6fbdd8e971442))
|
||||
|
||||
## [1.34.1](https://github.com/certd/certd/compare/v1.34.0...v1.34.1) (2025-05-05)
|
||||
|
||||
**Note:** Version bump only for package @certd/lib-server
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/lib-server",
|
||||
"version": "1.34.1",
|
||||
"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.1",
|
||||
"@certd/basic": "^1.34.1",
|
||||
"@certd/pipeline": "^1.34.1",
|
||||
"@certd/plus-core": "^1.34.1",
|
||||
"@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": "9749fc817d3cfd435e8cb3f2f86edc81d69e2310"
|
||||
"gitHead": "a1e504c1387e9b0554c8d030cb53c5058e7d683a"
|
||||
}
|
||||
|
||||
@@ -25,7 +25,9 @@ export class SysPublicSettings extends BaseSettings {
|
||||
limitUserPipelineCount = 0;
|
||||
managerOtherUserPipeline = false;
|
||||
icpNo?: string;
|
||||
mpsNo?: string;
|
||||
robots?: boolean = true;
|
||||
aiChatEnabled = true;
|
||||
}
|
||||
|
||||
export class SysPrivateSettings extends BaseSettings {
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
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.34.1](https://github.com/certd/certd/compare/v1.34.0...v1.34.1) (2025-05-05)
|
||||
|
||||
**Note:** Version bump only for package @certd/midway-flyway-js
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/midway-flyway-js",
|
||||
"version": "1.34.1",
|
||||
"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": "9749fc817d3cfd435e8cb3f2f86edc81d69e2310"
|
||||
"gitHead": "a1e504c1387e9b0554c8d030cb53c5058e7d683a"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
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.34.1](https://github.com/certd/certd/compare/v1.34.0...v1.34.1) (2025-05-05)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/plugin-cert",
|
||||
"private": false,
|
||||
"version": "1.34.1",
|
||||
"version": "1.34.3",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
@@ -12,13 +12,14 @@
|
||||
"dev-build": "npm run build",
|
||||
"build3": "rollup -c",
|
||||
"build2": "vue-tsc --noEmit && vite build",
|
||||
"preview": "vite preview"
|
||||
"preview": "vite preview",
|
||||
"pub": "npm publish"
|
||||
},
|
||||
"dependencies": {
|
||||
"@certd/acme-client": "^1.34.1",
|
||||
"@certd/basic": "^1.34.1",
|
||||
"@certd/pipeline": "^1.34.1",
|
||||
"@certd/plugin-lib": "^1.34.1",
|
||||
"@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",
|
||||
@@ -42,5 +43,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "9749fc817d3cfd435e8cb3f2f86edc81d69e2310"
|
||||
"gitHead": "a1e504c1387e9b0554c8d030cb53c5058e7d683a"
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ export abstract class AbstractDnsProvider<T = any> implements IDnsProvider<T> {
|
||||
logger!: ILogger;
|
||||
|
||||
usePunyCode(): boolean {
|
||||
//是否使用punycode来添加解析记录
|
||||
//默认都使用原始中文域名来添加
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -63,6 +63,7 @@ type AcmeServiceOptions = {
|
||||
maxCheckRetryCount?: number;
|
||||
userId: number;
|
||||
domainParser: IDomainParser;
|
||||
waitDnsDiffuseTime?: number;
|
||||
};
|
||||
|
||||
export class AcmeService {
|
||||
|
||||
@@ -68,9 +68,9 @@ export class CertApplyPlugin extends CertApplyBasePlugin {
|
||||
],
|
||||
},
|
||||
required: true,
|
||||
helper: `DNS直接验证:域名是在阿里云/腾讯云/华为云/Cloudflare/NameSilo/西数/火山/dns.la/京东云注册的,选它;
|
||||
CNAME代理验证:支持任何注册商注册的域名,但第一次需要手动添加CNAME记录;
|
||||
HTTP文件验证:不支持泛域名,需要配置网站文件上传`,
|
||||
helper: `1. <b>DNS直接验证</b>:域名dns解析是在阿里云/腾讯云/华为云/CF/NameSilo/西数/火山/dns.la/京东云/51dns的,选它
|
||||
2. <b>CNAME代理验证</b>:支持任何注册商的域名,第一次需要手动添加CNAME记录(建议将DNS服务器修改为阿里云/腾讯云的,然后使用DNS直接验证)
|
||||
3. <b>HTTP文件验证</b>:不支持泛域名,需要配置网站文件上传`,
|
||||
})
|
||||
challengeType!: string;
|
||||
|
||||
@@ -290,6 +290,17 @@ HTTP文件验证:不支持泛域名,需要配置网站文件上传`,
|
||||
})
|
||||
maxCheckRetryCount = 20;
|
||||
|
||||
@TaskInput({
|
||||
title: "等待解析生效时长",
|
||||
value: 30,
|
||||
component: {
|
||||
name: "a-input-number",
|
||||
vModel: "value",
|
||||
},
|
||||
helper: "等待解析生效时长(秒)",
|
||||
})
|
||||
waitDnsDiffuseTime = 30;
|
||||
|
||||
acme!: AcmeService;
|
||||
|
||||
eab!: EabAccess;
|
||||
@@ -341,6 +352,7 @@ HTTP文件验证:不支持泛域名,需要配置网站文件上传`,
|
||||
signal: this.ctx.signal,
|
||||
maxCheckRetryCount: this.maxCheckRetryCount,
|
||||
domainParser,
|
||||
waitDnsDiffuseTime: this.waitDnsDiffuseTime,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,18 @@
|
||||
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
|
||||
|
||||
* http方式支持校验443端口 ([d75fcb7](https://github.com/certd/certd/commit/d75fcb7fec421a9a638eaa27fe9378c84b5e0f19))
|
||||
|
||||
## [1.34.1](https://github.com/certd/certd/compare/v1.34.0...v1.34.1) (2025-05-05)
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@certd/plugin-lib",
|
||||
"private": false,
|
||||
"version": "1.34.1",
|
||||
"version": "1.34.3",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
@@ -12,13 +12,14 @@
|
||||
"dev-build": "npm run build",
|
||||
"build3": "rollup -c",
|
||||
"build2": "vue-tsc --noEmit && vite build",
|
||||
"preview": "vite preview"
|
||||
"preview": "vite preview",
|
||||
"pub": "npm publish"
|
||||
},
|
||||
"dependencies": {
|
||||
"@alicloud/pop-core": "^1.7.10",
|
||||
"@aws-sdk/client-s3": "^3.787.0",
|
||||
"@certd/basic": "^1.34.1",
|
||||
"@certd/pipeline": "^1.34.1",
|
||||
"@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",
|
||||
@@ -49,5 +50,5 @@
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.4.2"
|
||||
},
|
||||
"gitHead": "9749fc817d3cfd435e8cb3f2f86edc81d69e2310"
|
||||
"gitHead": "a1e504c1387e9b0554c8d030cb53c5058e7d683a"
|
||||
}
|
||||
|
||||
@@ -52,9 +52,11 @@ export class AliossClient {
|
||||
}
|
||||
}
|
||||
|
||||
async uploadFile(filePath: string, content: Buffer | string) {
|
||||
async uploadFile(filePath: string, content: Buffer | string, timeout = 1000 * 60 * 60) {
|
||||
await this.init();
|
||||
return await this.client.put(filePath, content);
|
||||
return await this.client.put(filePath, content, {
|
||||
timeout,
|
||||
});
|
||||
}
|
||||
|
||||
async removeFile(filePath: string) {
|
||||
@@ -62,9 +64,11 @@ export class AliossClient {
|
||||
return await this.client.delete(filePath);
|
||||
}
|
||||
|
||||
async downloadFile(key: string, savePath: string) {
|
||||
async downloadFile(key: string, savePath: string, timeout = 1000 * 60 * 60) {
|
||||
await this.init();
|
||||
return await this.client.get(key, savePath);
|
||||
return await this.client.get(key, savePath, {
|
||||
timeout,
|
||||
});
|
||||
}
|
||||
|
||||
async listDir(dirKey: string) {
|
||||
|
||||
@@ -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";
|
||||
|
||||
85
packages/plugins/plugin-lib/src/common/util.ts
Normal file
@@ -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,24 @@
|
||||
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
|
||||
|
||||
* 修复刷新流水线页面后,日志不自动更新的bug ([0b2e28b](https://github.com/certd/certd/commit/0b2e28b62dd5eb6804c602083e65c87a9d1d72d2))
|
||||
|
||||
### Performance Improvements
|
||||
|
||||
* 集成智能问答机器人 ([9dd4905](https://github.com/certd/certd/commit/9dd49054d18ec436a5029444ca55a38adc682933))
|
||||
* 支持设置网安备案号 ([d18e431](https://github.com/certd/certd/commit/d18e431e2f08e6b37704032c4ea6fbdd8e971442))
|
||||
|
||||
## [1.34.1](https://github.com/certd/certd/compare/v1.34.0...v1.34.1) (2025-05-05)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/ui-client",
|
||||
"version": "1.34.1",
|
||||
"version": "1.34.3",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "vite --open",
|
||||
@@ -19,7 +19,8 @@
|
||||
"upgrade": "yarn upgrade-interactive --latest",
|
||||
"tsc": "vue-tsc --noEmit --skipLibCheck",
|
||||
"circle:check": "pnpm dependency-cruise --validate --output-type err-html -f dependency-report.html src",
|
||||
"afterPubPush": "git add . && git commit -m \"build: publish success\" && git push"
|
||||
"afterPubPush": "git add . && git commit -m \"build: publish success\" && git push",
|
||||
"pub": "echo 1"
|
||||
},
|
||||
"author": "greper",
|
||||
"license": "AGPL-3.0",
|
||||
@@ -101,8 +102,8 @@
|
||||
"zod-defaults": "^0.1.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@certd/lib-iframe": "^1.34.1",
|
||||
"@certd/pipeline": "^1.34.1",
|
||||
"@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,6 +3,7 @@
|
||||
<FsFormProvider>
|
||||
<contextHolder />
|
||||
<router-view />
|
||||
<MaxKBChat v-if="settingsStore.sysPublic.aiChatEnabled !== false" ref="chatBox" />
|
||||
</FsFormProvider>
|
||||
</AConfigProvider>
|
||||
</template>
|
||||
@@ -10,7 +11,7 @@
|
||||
<script lang="ts" setup>
|
||||
import zhCN from "ant-design-vue/es/locale/zh_CN";
|
||||
import enUS from "ant-design-vue/es/locale/en_US";
|
||||
import { computed, provide, ref } from "vue";
|
||||
import { computed, onMounted, provide, ref } from "vue";
|
||||
import "dayjs/locale/zh-cn";
|
||||
import "dayjs/locale/en";
|
||||
import dayjs from "dayjs";
|
||||
@@ -19,7 +20,9 @@ import { useAntdDesignTokens } from "/@/vben/hooks";
|
||||
import { theme } from "ant-design-vue";
|
||||
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",
|
||||
});
|
||||
@@ -46,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();
|
||||
|
||||
@@ -69,4 +73,14 @@ const tokenTheme = computed(() => {
|
||||
// pageStore.init();
|
||||
// const settingStore = useSettingStore();
|
||||
// settingStore.init();
|
||||
|
||||
const chatBox = ref();
|
||||
// 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>
|
||||
|
||||
@@ -36,7 +36,7 @@ function createService() {
|
||||
return response;
|
||||
}
|
||||
//@ts-ignore
|
||||
if (response.config.returnResponse) {
|
||||
if (response.config.returnOriginRes) {
|
||||
return response;
|
||||
}
|
||||
// dataAxios 是 axios 返回数据中的 data
|
||||
|
||||
316
packages/ui/certd-client/src/components/ai/index.vue
Normal file
@@ -0,0 +1,316 @@
|
||||
<template>
|
||||
<div id="maxkb">
|
||||
<!-- 引导层 -->
|
||||
<div v-if="showGuide" class="maxkb-mask">
|
||||
<div class="maxkb-content" :style="contentStyle"></div>
|
||||
</div>
|
||||
|
||||
<div v-if="showGuide" class="maxkb-tips" :style="tipsStyle">
|
||||
<div class="" @click="closeGuide">
|
||||
<!-- 关闭图标 -->
|
||||
<svg style="vertical-align: middle; overflow: hidden" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none">
|
||||
<path
|
||||
d="M9.95317 8.73169L15.5511 3.13376C15.7138 2.97104 15.9776 2.97104 16.1403 3.13376L16.7296 3.72301C16.8923 3.88573 16.8923 4.14955 16.7296 4.31227L11.1317 9.9102L16.7296 15.5081C16.8923 15.6708 16.8923 15.9347 16.7296 16.0974L16.1403 16.6866C15.9776 16.8494 15.7138 16.8494 15.5511 16.6866L9.95317 11.0887L4.35524 16.6866C4.19252 16.8494 3.9287 16.8494 3.76598 16.6866L3.17673 16.0974C3.01401 15.9347 3.01401 15.6708 3.17673 15.5081L8.77465 9.9102L3.17673 4.31227C3.01401 4.14955 3.01401 3.88573 3.17673 3.72301L3.76598 3.13376C3.9287 2.97104 4.19252 2.97104 4.35524 3.13376L9.95317 8.73169Z"
|
||||
fill="#ffffff"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="maxkb-title">🌟 遇见问题,不再有障碍!</div>
|
||||
<p>你好,我是你的智能小助手。<br />点我,开启高效解答模式,让问题变成过去式。</p>
|
||||
<div class="maxkb-button">
|
||||
<button @click="closeGuide">我知道了</button>
|
||||
</div>
|
||||
<span class="maxkb-arrow"></span>
|
||||
</div>
|
||||
|
||||
<!-- 聊天按钮 -->
|
||||
<div v-show="!chatVisible" class="maxkb-chat-button" @click="toggleChat">
|
||||
<img src="https://maxkb.handfree.work/ui/MaxKB.gif" />
|
||||
</div>
|
||||
|
||||
<!-- 聊天窗口 -->
|
||||
<div id="maxkb-chat-container" :class="{ 'maxkb-enlarge': isFullscreen }" :style="containerStyle">
|
||||
<iframe id="maxkb-chat" allow="microphone" :src="chatUrl"></iframe>
|
||||
<div class="maxkb-operate">
|
||||
<div class="viewport" :class="{ 'maxkb-viewportnone': !isFullscreen }" @click="toggleFullscreen">
|
||||
<!-- 缩小图标 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none">
|
||||
<path
|
||||
d="M7.507 11.6645C7.73712 11.6645 7.94545 11.7578 8.09625 11.9086C8.24706 12.0594 8.34033 12.2677 8.34033 12.4978V16.7976C8.34033 17.0277 8.15378 17.2143 7.92366 17.2143H7.09033C6.86021 17.2143 6.67366 17.0277 6.67366 16.7976V14.5812L3.41075 17.843C3.24803 18.0057 2.98421 18.0057 2.82149 17.843L2.23224 17.2537C2.06952 17.091 2.06952 16.8272 2.23224 16.6645L5.56668 13.3311H3.19634C2.96622 13.3311 2.77967 13.1446 2.77967 12.9145V12.0811C2.77967 11.851 2.96622 11.6645 3.19634 11.6645H7.507ZM16.5991 2.1572C16.7619 1.99448 17.0257 1.99448 17.1884 2.1572L17.7777 2.74645C17.9404 2.90917 17.9404 3.17299 17.7777 3.33571L14.4432 6.66904H16.8136C17.0437 6.66904 17.2302 6.85559 17.2302 7.08571V7.91904C17.2302 8.14916 17.0437 8.33571 16.8136 8.33571H12.5029C12.2728 8.33571 12.0644 8.24243 11.9136 8.09163C11.7628 7.94082 11.6696 7.73249 11.6696 7.50237V3.20257C11.6696 2.97245 11.8561 2.7859 12.0862 2.7859H12.9196C13.1497 2.7859 13.3362 2.97245 13.3362 3.20257V5.419L16.5991 2.1572Z"
|
||||
fill="rgb(100, 106, 115)"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="maxkb-openviewport" :class="{ 'maxkb-viewportnone': isFullscreen }" @click="toggleFullscreen">
|
||||
<!-- 放大图标 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none">
|
||||
<path
|
||||
d="M7.15209 11.5968C7.31481 11.4341 7.57862 11.4341 7.74134 11.5968L8.3306 12.186C8.49332 12.3487 8.49332 12.6126 8.3306 12.7753L4.99615 16.1086H7.3665C7.59662 16.1086 7.78316 16.2952 7.78316 16.5253V17.3586C7.78316 17.5887 7.59662 17.7753 7.3665 17.7753H3.05584C2.82572 17.7753 2.61738 17.682 2.46658 17.5312C2.31578 17.3804 2.2225 17.1721 2.2225 16.9419V12.6421C2.2225 12.412 2.40905 12.2255 2.63917 12.2255H3.4725C3.70262 12.2255 3.88917 12.412 3.88917 12.6421V14.8586L7.15209 11.5968ZM16.937 2.22217C17.1671 2.22217 17.3754 2.31544 17.5262 2.46625C17.677 2.61705 17.7703 2.82538 17.7703 3.0555V7.35531C17.7703 7.58543 17.5837 7.77198 17.3536 7.77198H16.5203C16.2902 7.77198 16.1036 7.58543 16.1036 7.35531V5.13888L12.8407 8.40068C12.678 8.5634 12.4142 8.5634 12.2515 8.40068L11.6622 7.81142C11.4995 7.64871 11.4995 7.38489 11.6622 7.22217L14.9966 3.88883H12.6263C12.3962 3.88883 12.2096 3.70229 12.2096 3.47217V2.63883C12.2096 2.40872 12.3962 2.22217 12.6263 2.22217H16.937Z"
|
||||
fill="rgb(100, 106, 115)"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="maxkb-chat-close" @click="toggleChat">
|
||||
<!-- 关闭图标 -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20" fill="none">
|
||||
<path
|
||||
d="M9.95317 8.73169L15.5511 3.13376C15.7138 2.97104 15.9776 2.97104 16.1403 3.13376L16.7296 3.72301C16.8923 3.88573 16.8923 4.14955 16.7296 4.31227L11.1317 9.9102L16.7296 15.5081C16.8923 15.6708 16.8923 15.9347 16.7296 16.0974L16.1403 16.6866C15.9776 16.8494 15.7138 16.8494 15.5511 16.6866L9.95317 11.0887L4.35524 16.6866C4.19252 16.8494 3.9287 16.8494 3.76598 16.6866L3.17673 16.0974C3.01401 15.9347 3.01401 15.6708 3.17673 15.5081L8.77465 9.9102L3.17673 4.31227C3.01401 4.14955 3.01401 3.88573 3.17673 3.72301L3.76598 3.13376C3.9287 2.97104 4.19252 2.97104 4.35524 3.13376L9.95317 8.73169Z"
|
||||
fill="rgb(100, 106, 115)"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, ref } from "vue";
|
||||
defineOptions({
|
||||
name: "MaxKBChat",
|
||||
});
|
||||
const props = defineProps<{
|
||||
url?: string;
|
||||
showGuideOnInit?: boolean;
|
||||
}>();
|
||||
|
||||
// 响应式状态
|
||||
const showGuide = ref(false);
|
||||
const chatVisible = ref(false);
|
||||
const isFullscreen = ref(false);
|
||||
const buttonPos = ref({ x: 16, y: 30 });
|
||||
const buttonSize = ref({ width: 64, height: 64 });
|
||||
|
||||
// 计算属性
|
||||
const chatUrl = computed(() => {
|
||||
return props.url || "https://maxkb.handfree.work/ui/chat/326a8651825e8a02?mode=embed";
|
||||
});
|
||||
|
||||
const contentStyle = computed(() => ({
|
||||
width: `${buttonSize.value.width}px`,
|
||||
height: `${buttonSize.value.height}px`,
|
||||
}));
|
||||
|
||||
const tipsStyle = computed(() => ({
|
||||
marginRight: `${Math.min(buttonSize.value.width, 500) - 64}px`,
|
||||
}));
|
||||
|
||||
const containerStyle = computed(() => ({
|
||||
display: chatVisible.value ? "block" : "none",
|
||||
right: `${buttonPos.value.x}px`,
|
||||
bottom: `${buttonPos.value.y}px`,
|
||||
}));
|
||||
|
||||
// 方法
|
||||
const closeGuide = () => {
|
||||
showGuide.value = false;
|
||||
localStorage.setItem("maxkbMaskTip", "true");
|
||||
};
|
||||
|
||||
const toggleChat = () => {
|
||||
chatVisible.value = !chatVisible.value;
|
||||
};
|
||||
|
||||
const toggleFullscreen = () => {
|
||||
isFullscreen.value = !isFullscreen.value;
|
||||
};
|
||||
|
||||
// 初始化
|
||||
onMounted(() => {
|
||||
if (props.showGuideOnInit && !localStorage.getItem("maxkbMaskTip")) {
|
||||
showGuide.value = true;
|
||||
}
|
||||
});
|
||||
|
||||
async function openChat(req: { q: string }) {
|
||||
if (!req.q) {
|
||||
return;
|
||||
}
|
||||
chatVisible.value = true;
|
||||
|
||||
const iframeId = "maxkb-chat";
|
||||
|
||||
const iframe = document.getElementById(iframeId) as HTMLIFrameElement | null;
|
||||
if (!iframe) {
|
||||
throw new Error("iframe not found");
|
||||
return;
|
||||
}
|
||||
iframe.contentWindow?.postMessage(
|
||||
{
|
||||
...req,
|
||||
from: "certd",
|
||||
},
|
||||
"*"
|
||||
);
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
openChat,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 这里放置所有样式(保持原有样式不变) */
|
||||
/* 注意将原样式中的 #maxkb 选择器改为 #maxkb-container */
|
||||
/* 示例: */
|
||||
/* 其他样式保持原样... */
|
||||
/* 放大 */
|
||||
#maxkb .maxkb-enlarge {
|
||||
width: 50% !important;
|
||||
height: 100% !important;
|
||||
bottom: 0 !important;
|
||||
right: 0 !important;
|
||||
}
|
||||
@media only screen and (max-width: 768px) {
|
||||
#maxkb .maxkb-enlarge {
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
right: 0 !important;
|
||||
bottom: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* 引导 */
|
||||
|
||||
#maxkb .maxkb-mask {
|
||||
position: fixed;
|
||||
z-index: 10001;
|
||||
background-color: transparent;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
#maxkb .maxkb-mask .maxkb-content {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
box-shadow: 1px 1px 1px 9999px rgba(0, 0, 0, 0.6);
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
bottom: 30px;
|
||||
z-index: 10001;
|
||||
}
|
||||
#maxkb .maxkb-tips {
|
||||
position: fixed;
|
||||
right: calc(0px + 75px);
|
||||
bottom: calc(30px + 0px);
|
||||
padding: 22px 24px 24px;
|
||||
border-radius: 6px;
|
||||
color: #ffffff;
|
||||
font-size: 14px;
|
||||
background: #3370ff;
|
||||
z-index: 10001;
|
||||
}
|
||||
#maxkb .maxkb-tips .maxkb-arrow {
|
||||
position: absolute;
|
||||
background: #3370ff;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
pointer-events: none;
|
||||
transform: rotate(45deg);
|
||||
box-sizing: border-box;
|
||||
/* left */
|
||||
right: -5px;
|
||||
bottom: 33px;
|
||||
border-left-color: transparent;
|
||||
border-bottom-color: transparent;
|
||||
}
|
||||
#maxkb .maxkb-tips .maxkb-title {
|
||||
font-size: 20px;
|
||||
font-weight: 500;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
#maxkb .maxkb-tips .maxkb-button {
|
||||
text-align: right;
|
||||
margin-top: 24px;
|
||||
}
|
||||
#maxkb .maxkb-tips .maxkb-button button {
|
||||
border-radius: 4px;
|
||||
background: #fff;
|
||||
padding: 3px 12px;
|
||||
color: #3370ff;
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
border: none;
|
||||
}
|
||||
#maxkb .maxkb-tips .maxkb-button button::after {
|
||||
border: none;
|
||||
}
|
||||
#maxkb .maxkb-tips {
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
//top: 20px;
|
||||
cursor: pointer;
|
||||
}
|
||||
#maxkb-chat-container {
|
||||
width: 450px;
|
||||
height: 600px;
|
||||
display: none;
|
||||
}
|
||||
@media only screen and (max-width: 768px) {
|
||||
#maxkb-chat-container {
|
||||
width: 100%;
|
||||
height: 70%;
|
||||
right: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
#maxkb .maxkb-chat-button {
|
||||
position: fixed;
|
||||
right: 10px;
|
||||
bottom: 30px;
|
||||
cursor: pointer;
|
||||
z-index: 10000;
|
||||
}
|
||||
#maxkb #maxkb-chat-container {
|
||||
z-index: 10000;
|
||||
position: relative;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #ffffff;
|
||||
background: linear-gradient(188deg, rgba(235, 241, 255, 0.2) 39.6%, rgba(231, 249, 255, 0.2) 94.3%), #eff0f1;
|
||||
box-shadow: 0px 4px 8px 0px rgba(31, 35, 41, 0.1);
|
||||
position: fixed;
|
||||
bottom: 16px;
|
||||
right: 16px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#maxkb #maxkb-chat-container .maxkb-operate {
|
||||
top: 18px;
|
||||
right: 15px;
|
||||
position: absolute;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 18px;
|
||||
}
|
||||
#maxkb #maxkb-chat-container .maxkb-operate .maxkb-chat-close {
|
||||
margin-left: 15px;
|
||||
cursor: pointer;
|
||||
}
|
||||
#maxkb #maxkb-chat-container .maxkb-operate .maxkb-openviewport {
|
||||
cursor: pointer;
|
||||
}
|
||||
#maxkb #maxkb-chat-container .maxkb-operate .maxkb-closeviewport {
|
||||
cursor: pointer;
|
||||
}
|
||||
#maxkb #maxkb-chat-container .maxkb-viewportnone {
|
||||
display: none;
|
||||
}
|
||||
#maxkb #maxkb-chat-container #maxkb-chat {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
border: none;
|
||||
}
|
||||
#maxkb #maxkb-chat-container {
|
||||
animation: appear 0.4s ease-in-out;
|
||||
}
|
||||
@keyframes appear {
|
||||
from {
|
||||
height: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
height: 600px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -19,6 +19,7 @@ export default {
|
||||
"CodeEditor",
|
||||
defineAsyncComponent(() => import("./code-editor/index.vue"))
|
||||
);
|
||||
|
||||
app.component("PiContainer", PiContainer);
|
||||
app.component("TextEditable", TextEditable);
|
||||
app.component("FileInput", FileInput);
|
||||
|
||||
@@ -18,7 +18,7 @@ const props = defineProps<{
|
||||
modelValue: string;
|
||||
title: string;
|
||||
action: string;
|
||||
form: any;
|
||||
form?: any;
|
||||
button?: any;
|
||||
}>();
|
||||
|
||||
|
||||
@@ -15,8 +15,13 @@
|
||||
<template v-if="sysPublic.icpNo">
|
||||
<span>
|
||||
<a href="https://beian.miit.gov.cn/" target="_blank">{{ sysPublic.icpNo }}</a>
|
||||
<a-divider type="vertical" />
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<span v-if="sysPublic.mpsNo">
|
||||
<a href="http://www.beian.gov.cn/portal/registerSystemInfo" target="_blank">{{ sysPublic.mpsNo }}</a>
|
||||
</span>
|
||||
</div>
|
||||
<div class="ml-5">v{{ version }}</div>
|
||||
</div>
|
||||
@@ -26,7 +31,7 @@ import { computed, onMounted, ref } from "vue";
|
||||
import { useSettingStore } from "/@/store/settings";
|
||||
|
||||
defineOptions({
|
||||
name: "PageFooter"
|
||||
name: "PageFooter",
|
||||
});
|
||||
const version = ref(import.meta.env.VITE_APP_VERSION);
|
||||
|
||||
|
||||
@@ -20,8 +20,8 @@ const menus = computed(() => [
|
||||
router.push("/certd/mine/user-profile");
|
||||
},
|
||||
icon: "fa-solid:book",
|
||||
text: "账号信息"
|
||||
}
|
||||
text: "账号信息",
|
||||
},
|
||||
]);
|
||||
|
||||
const avatar = computed(() => {
|
||||
@@ -42,7 +42,7 @@ const siteInfo = computed(() => {
|
||||
return settingStore.siteInfo;
|
||||
});
|
||||
|
||||
onErrorCaptured((e) => {
|
||||
onErrorCaptured(e => {
|
||||
console.error("ErrorCaptured:", e);
|
||||
// notification.error({ message: e.message });
|
||||
//阻止错误向上传递
|
||||
@@ -52,6 +52,10 @@ onErrorCaptured((e) => {
|
||||
onMounted(async () => {
|
||||
await settingStore.checkUrlBound();
|
||||
});
|
||||
|
||||
function goGithub() {
|
||||
window.open("https://github.com/certd/certd");
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -63,12 +67,15 @@ 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 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>
|
||||
<PageFooter></PageFooter>
|
||||
|
||||
@@ -133,7 +133,7 @@ const asideCollapsed = ref(false);
|
||||
function asideCollapsedToggle() {
|
||||
asideCollapsed.value = !asideCollapsed.value;
|
||||
}
|
||||
onErrorCaptured((e) => {
|
||||
onErrorCaptured(e => {
|
||||
console.error("ErrorCaptured:", e);
|
||||
// notification.error({ message: e.message });
|
||||
//阻止错误向上传递
|
||||
|
||||
@@ -31,6 +31,10 @@
|
||||
<a-divider type="vertical" />
|
||||
<a href="https://beian.miit.gov.cn/" target="_blank">{{ sysPublic.icpNo }}</a>
|
||||
</span>
|
||||
<span v-if="sysPublic.mpsNo">
|
||||
<a-divider type="vertical" />
|
||||
<a href="http://www.beian.gov.cn/portal/registerSystemInfo" target="_blank">{{ sysPublic.mpsNo }}</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -39,7 +39,9 @@ export type SysPublicSetting = {
|
||||
limitUserPipelineCount?: number;
|
||||
managerOtherUserPipeline?: boolean;
|
||||
icpNo?: string;
|
||||
mpsNo?: string;
|
||||
robots?: boolean;
|
||||
aiChatEnabled?: boolean;
|
||||
};
|
||||
export type SuiteSetting = {
|
||||
enabled?: boolean;
|
||||
|
||||
@@ -18,7 +18,7 @@ import { useLayout } from "./hooks/use-layout";
|
||||
interface Props extends VbenLayoutProps {}
|
||||
|
||||
defineOptions({
|
||||
name: "VbenLayout"
|
||||
name: "VbenLayout",
|
||||
});
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
@@ -48,7 +48,7 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
sideCollapseWidth: 60,
|
||||
tabbarEnable: true,
|
||||
tabbarHeight: 40,
|
||||
zIndex: 200
|
||||
zIndex: 200,
|
||||
});
|
||||
|
||||
const emit = defineEmits<{ sideMouseLeave: []; toggleSidebar: [] }>();
|
||||
@@ -193,7 +193,7 @@ const mainStyle = computed(() => {
|
||||
}
|
||||
return {
|
||||
sidebarAndExtraWidth,
|
||||
width
|
||||
width,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -221,7 +221,7 @@ const tabbarStyle = computed((): CSSProperties => {
|
||||
|
||||
return {
|
||||
marginLeft: `${marginLeft}px`,
|
||||
width
|
||||
width,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -231,7 +231,7 @@ const contentStyle = computed((): CSSProperties => {
|
||||
const { footerEnable, footerFixed, footerHeight } = props;
|
||||
return {
|
||||
marginTop: fixed && !isFullContent.value && !headerIsHidden.value && (!isHeaderAutoMode.value || scrollY.value < headerWrapperHeight.value) ? `${headerWrapperHeight.value}px` : 0,
|
||||
paddingBottom: `${footerEnable && footerFixed ? footerHeight : 0}px`
|
||||
paddingBottom: `${footerEnable && footerFixed ? footerHeight : 0}px`,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -249,7 +249,7 @@ const headerWrapperStyle = computed((): CSSProperties => {
|
||||
position: fixed ? "fixed" : "static",
|
||||
top: headerIsHidden.value || isFullContent.value ? `-${headerWrapperHeight.value}px` : 0,
|
||||
width: mainStyle.value.width,
|
||||
"z-index": headerZIndex.value
|
||||
"z-index": headerZIndex.value,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -289,13 +289,13 @@ const showHeaderLogo = computed(() => {
|
||||
|
||||
watch(
|
||||
() => props.isMobile,
|
||||
(val) => {
|
||||
val => {
|
||||
if (val) {
|
||||
sidebarCollapse.value = true;
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
|
||||
@@ -305,7 +305,7 @@ watch(
|
||||
setLayoutHeaderHeight(isFullContent.value ? 0 : height);
|
||||
},
|
||||
{
|
||||
immediate: true
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
|
||||
@@ -315,7 +315,7 @@ watch(
|
||||
setLayoutFooterHeight(height);
|
||||
},
|
||||
{
|
||||
immediate: true
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
|
||||
@@ -336,7 +336,7 @@ watch(
|
||||
mouseMove();
|
||||
},
|
||||
{
|
||||
immediate: true
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -433,9 +433,9 @@ const idMainContent = ELEMENT_ID_MAIN_CONTENT;
|
||||
<div
|
||||
:class="[
|
||||
{
|
||||
'shadow-[0_16px_24px_hsl(var(--background))]': scrollY > 20
|
||||
'shadow-[0_16px_24px_hsl(var(--background))]': scrollY > 20,
|
||||
},
|
||||
SCROLL_FIXED_CLASS
|
||||
SCROLL_FIXED_CLASS,
|
||||
]"
|
||||
:style="headerWrapperStyle"
|
||||
class="overflow-hidden transition-all duration-200"
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -35,7 +35,7 @@ interface Props {
|
||||
/**
|
||||
* 菜单数组
|
||||
*/
|
||||
menus?: Array<{ handler: AnyFunction; icon?: Component; text: string }>;
|
||||
menus?: Array<{ handler: AnyFunction; icon?: Component | string; text: string }>;
|
||||
|
||||
/**
|
||||
* 标签文本
|
||||
@@ -52,7 +52,7 @@ interface Props {
|
||||
}
|
||||
|
||||
defineOptions({
|
||||
name: "UserDropdown"
|
||||
name: "UserDropdown",
|
||||
});
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
@@ -64,7 +64,7 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
tagText: "",
|
||||
text: "",
|
||||
trigger: "click",
|
||||
hoverDelay: 500
|
||||
hoverDelay: 500,
|
||||
});
|
||||
|
||||
const emit = defineEmits<{ logout: [] }>();
|
||||
@@ -72,12 +72,12 @@ const emit = defineEmits<{ logout: [] }>();
|
||||
const { globalLockScreenShortcutKey, globalLogoutShortcutKey } = usePreferences();
|
||||
const lockStore = useLockStore();
|
||||
const [LockModal, lockModalApi] = useVbenModal({
|
||||
connectedComponent: LockScreenModal
|
||||
connectedComponent: LockScreenModal,
|
||||
});
|
||||
const [LogoutModal, logoutModalApi] = useVbenModal({
|
||||
onConfirm() {
|
||||
handleSubmitLogout();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const refTrigger = useTemplateRef("refTrigger");
|
||||
@@ -86,7 +86,7 @@ const [openPopover, hoverWatcher] = useHoverToggle([refTrigger, refContent], ()
|
||||
|
||||
watch(
|
||||
() => props.trigger === "hover" || props.trigger === "both",
|
||||
(val) => {
|
||||
val => {
|
||||
if (val) {
|
||||
hoverWatcher.enable();
|
||||
} else {
|
||||
@@ -94,7 +94,7 @@ watch(
|
||||
}
|
||||
},
|
||||
{
|
||||
immediate: true
|
||||
immediate: true,
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -255,7 +255,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, onMounted, provide, Ref, ref, watch } from "vue";
|
||||
import { defineComponent, onMounted, onUnmounted, provide, Ref, ref, watch } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import PiTaskForm from "./component/task-form/index.vue";
|
||||
import PiTriggerForm from "./component/trigger-form/index.vue";
|
||||
@@ -274,6 +274,7 @@ import { useSettingStore } from "/@/store/settings";
|
||||
import { useUserStore } from "/@/store/user";
|
||||
import TaskShortcuts from "./component/shortcut/task-shortcuts.vue";
|
||||
import { eachSteps, findStep } from "../utils";
|
||||
import { PluginGroups } from "/@/store/plugin";
|
||||
|
||||
export default defineComponent({
|
||||
name: "PipelineEdit",
|
||||
@@ -365,9 +366,14 @@ export default defineComponent({
|
||||
return true;
|
||||
}
|
||||
const intervalLoadHistoryRef = ref();
|
||||
const isLoadingHistory = ref(false);
|
||||
function watchNewHistoryList() {
|
||||
intervalLoadHistoryRef.value = setTimeout(async () => {
|
||||
intervalLoadHistoryRef.value = setInterval(async () => {
|
||||
if (isLoadingHistory.value) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
isLoadingHistory.value = true;
|
||||
if (currentHistory.value == null) {
|
||||
await loadHistoryList();
|
||||
}
|
||||
@@ -375,16 +381,21 @@ export default defineComponent({
|
||||
if (currentHistory.value != null) {
|
||||
if (currentHistory.value.pipeline?.status?.status === "start") {
|
||||
await loadCurrentHistoryDetail();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
} finally {
|
||||
isLoadingHistory.value = false;
|
||||
}
|
||||
watchNewHistoryList();
|
||||
}, 3000);
|
||||
}
|
||||
onMounted(() => {
|
||||
watchNewHistoryList();
|
||||
});
|
||||
onUnmounted(() => {
|
||||
clearInterval(intervalLoadHistoryRef.value);
|
||||
});
|
||||
|
||||
watch(
|
||||
() => {
|
||||
@@ -632,7 +643,6 @@ export default defineComponent({
|
||||
async onOk() {
|
||||
//@ts-ignore
|
||||
await changeCurrentHistory(null);
|
||||
watchNewHistoryList();
|
||||
await props.options.doTrigger({ pipelineId: pipeline.value.id, stepId: stepId });
|
||||
notification.success({ message: "管道已经开始运行" });
|
||||
},
|
||||
@@ -1081,7 +1091,7 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
.layout-right {
|
||||
position: "relative";
|
||||
position: relative;
|
||||
&.collapsed {
|
||||
margin-right: -350px;
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -4,7 +4,13 @@
|
||||
<a-form-item label="ICP备案号" :name="['public', 'icpNo']">
|
||||
<a-input v-model:value="formState.public.icpNo" placeholder="粤ICP备xxxxxxx号" />
|
||||
</a-form-item>
|
||||
<a-form-item label="网安备案号" :name="['public', 'mpsNo']">
|
||||
<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>
|
||||
@@ -53,19 +59,20 @@ import { notification } from "ant-design-vue";
|
||||
import { util } from "/@/utils";
|
||||
|
||||
defineOptions({
|
||||
name: "SettingBase"
|
||||
name: "SettingBase",
|
||||
});
|
||||
|
||||
const formState = reactive<Partial<SysSettings>>({
|
||||
public: {
|
||||
icpNo: ""
|
||||
icpNo: "",
|
||||
mpsNo: "",
|
||||
},
|
||||
private: {}
|
||||
private: {},
|
||||
});
|
||||
|
||||
const urlRules = ref({
|
||||
type: "url",
|
||||
message: "请输入正确的URL"
|
||||
message: "请输入正确的URL",
|
||||
});
|
||||
|
||||
async function loadSysSettings() {
|
||||
@@ -82,7 +89,7 @@ const onFinish = async (form: any) => {
|
||||
await api.SysSettingsSave(form);
|
||||
await settingsStore.loadSysSettings();
|
||||
notification.success({
|
||||
message: "保存成功"
|
||||
message: "保存成功",
|
||||
});
|
||||
} finally {
|
||||
saveLoading.value = false;
|
||||
@@ -96,7 +103,7 @@ const onFinishFailed = (errorInfo: any) => {
|
||||
async function stopOtherUserTimer() {
|
||||
await api.stopOtherUserTimer();
|
||||
notification.success({
|
||||
message: "停止成功"
|
||||
message: "停止成功",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -120,13 +127,13 @@ async function testProxy() {
|
||||
if (!success) {
|
||||
notification.error({
|
||||
message: "测试失败",
|
||||
description: content
|
||||
description: content,
|
||||
});
|
||||
return;
|
||||
}
|
||||
notification.success({
|
||||
message: "测试完成",
|
||||
description: content
|
||||
description: content,
|
||||
});
|
||||
} finally {
|
||||
testProxyLoading.value = false;
|
||||
|
||||
@@ -3,6 +3,18 @@
|
||||
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
|
||||
|
||||
* 修复部署到又拍云强制https无效的bug ([2397097](https://github.com/certd/certd/commit/2397097e4ddcb6f593210598e8779ffd44ac3f8f))
|
||||
|
||||
## [1.34.1](https://github.com/certd/certd/compare/v1.34.0...v1.34.1) (2025-05-05)
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
107
packages/ui/certd-server/export-plugin-md.js
Normal file
@@ -0,0 +1,107 @@
|
||||
import "./dist/plugins/index.js";
|
||||
import { accessRegistry, notificationRegistry, pluginGroups, pluginRegistry } from "@certd/pipeline";
|
||||
import { dnsProviderRegistry } from "@certd/plugin-cert";
|
||||
import fs from "fs";
|
||||
|
||||
function genPluginMd() {
|
||||
const plugins = {
|
||||
access: [],
|
||||
deploy: [],
|
||||
dnsProvider: [],
|
||||
notification: []
|
||||
};
|
||||
|
||||
plugins.access = accessRegistry.getDefineList();
|
||||
plugins.deploy = pluginRegistry.getDefineList();
|
||||
plugins.dnsProvider = dnsProviderRegistry.getDefineList();
|
||||
plugins.notification = notificationRegistry.getDefineList();
|
||||
|
||||
|
||||
// function genMd(list) {
|
||||
// let mdContent = `<table style='width:100%'>
|
||||
// <thead style='width:100%'>
|
||||
// <tr >
|
||||
// <th width='70'>序号</th><th width='265'>名称</th><th>说明</th>
|
||||
// </tr>
|
||||
// </thead>
|
||||
// <tbody>
|
||||
// `;
|
||||
// let i = 0;
|
||||
// for (const x of list) {
|
||||
// i++
|
||||
// mdContent += `<tr> <td>${i}.</td> <td style='font-weight: bold'>${x.title}</td> <td>${x.desc||''}</td> </tr>`;
|
||||
// }
|
||||
// mdContent += `</tbody></table>`;
|
||||
// return mdContent;
|
||||
// }
|
||||
|
||||
// function genMd(list) {
|
||||
// let mdContent = ``;
|
||||
// let i = 0;
|
||||
// for (const x of list) {
|
||||
// i++
|
||||
// mdContent += `${i}. **${x.title}** \n${x.desc||''} \n\n\n`;
|
||||
// }
|
||||
// return mdContent;
|
||||
// }
|
||||
|
||||
function genMd(list) {
|
||||
let mdContent = `
|
||||
| 序号 | 名称 | 说明 |
|
||||
|-----|-----|-----|
|
||||
`;
|
||||
let i = 0;
|
||||
for (const x of list) {
|
||||
i++
|
||||
mdContent += `| ${i}.| **${x.title}** | ${x.desc||''} | \n`;
|
||||
}
|
||||
return mdContent;
|
||||
}
|
||||
|
||||
function addTableStyle(){
|
||||
return `
|
||||
<style module>
|
||||
table th:first-of-type {
|
||||
width: 65px;
|
||||
}
|
||||
table th:nth-of-type(2) {
|
||||
width: 240px;
|
||||
}
|
||||
</style>
|
||||
`
|
||||
}
|
||||
|
||||
let mdContent = "";
|
||||
mdContent = "# 授权列表\n";
|
||||
mdContent += genMd(plugins.access);
|
||||
mdContent += addTableStyle()
|
||||
fs.writeFileSync("../../../docs/guide/plugins/access.md", mdContent);
|
||||
|
||||
mdContent = "# DNS提供商\n";
|
||||
mdContent += genMd(plugins.dnsProvider);
|
||||
mdContent += addTableStyle()
|
||||
fs.writeFileSync("../../../docs/guide/plugins/dns-provider.md", mdContent);
|
||||
|
||||
|
||||
mdContent = "# 通知插件\n";
|
||||
mdContent += genMd(plugins.notification);
|
||||
mdContent += addTableStyle()
|
||||
fs.writeFileSync("../../../docs/guide/plugins/notification.md", mdContent);
|
||||
|
||||
|
||||
mdContent = "# 任务插件\n";
|
||||
mdContent += `共 \`${plugins.deploy.length}\` 款任务插件 \n`
|
||||
let index =0
|
||||
for (const key in pluginGroups) {
|
||||
index++
|
||||
const group = pluginGroups[key];
|
||||
mdContent += `## ${index}. ${group.title}\n`;
|
||||
mdContent += genMd(group.plugins);
|
||||
}
|
||||
mdContent += addTableStyle()
|
||||
fs.writeFileSync("../../../docs/guide/plugins/deploy.md", mdContent);
|
||||
|
||||
process.exit()
|
||||
}
|
||||
|
||||
genPluginMd()
|
||||
@@ -50,49 +50,52 @@ export default async function loadModules(dir) {
|
||||
function isPrototypeOf(value,cls){
|
||||
return cls.prototype.isPrototypeOf(value.prototype)
|
||||
}
|
||||
async function genMetadata(){
|
||||
const modules = await loadModules('./dist/plugins');
|
||||
|
||||
const modules = await loadModules('./dist/plugins');
|
||||
fs.rmSync("./metadata", { recursive: true });
|
||||
fs.mkdirSync("./metadata", { recursive: true });
|
||||
for (const key in modules) {
|
||||
console.log(key)
|
||||
const module = modules[key]
|
||||
const entry = Object.entries(module)
|
||||
for (const [name, value] of entry) {
|
||||
//如果有define属性
|
||||
if(value.define){
|
||||
//那么就是插件
|
||||
let location = key.substring(4)
|
||||
location = location.substring(0, location.length - 3)
|
||||
location = location.replaceAll("\\","/")
|
||||
location += ".js"
|
||||
location = `../../..${location}` // 从modules/plugin/plugin-service 加载 ../../plugins目录下的文件
|
||||
|
||||
fs.rmSync("./metadata", { recursive: true });
|
||||
fs.mkdirSync("./metadata", { recursive: true });
|
||||
for (const key in modules) {
|
||||
console.log(key)
|
||||
const module = modules[key]
|
||||
const entry = Object.entries(module)
|
||||
for (const [name, value] of entry) {
|
||||
//如果有define属性
|
||||
if(value.define){
|
||||
//那么就是插件
|
||||
let location = key.substring(4)
|
||||
location = location.substring(0, location.length - 3)
|
||||
location = location.replaceAll("\\","/")
|
||||
location += ".js"
|
||||
location = `../../..${location}` // 从modules/plugin/plugin-service 加载 ../../plugins目录下的文件
|
||||
const pluginDefine = {
|
||||
...value.define
|
||||
}
|
||||
pluginDefine.type = "builtIn"
|
||||
if(pluginDefine.accessType){
|
||||
pluginDefine.pluginType = "dnsProvider"
|
||||
}else if(isPrototypeOf(value,AbstractTaskPlugin)){
|
||||
pluginDefine.pluginType = "deploy"
|
||||
}else if(isPrototypeOf(value,BaseNotification)){
|
||||
pluginDefine.pluginType = "notification"
|
||||
}else if(isPrototypeOf(value,BaseAccess)){
|
||||
pluginDefine.pluginType = "access"
|
||||
}else{
|
||||
console.log(`[warning] 未知的插件类型:${pluginDefine.name}`)
|
||||
}
|
||||
|
||||
const pluginDefine = {
|
||||
...value.define
|
||||
const filePath = path.join(`./metadata/${pluginDefine.pluginType}_${pluginDefine.name}.yaml`)
|
||||
|
||||
pluginDefine.scriptFilePath = location
|
||||
const data = yaml.dump(pluginDefine)
|
||||
fs.writeFileSync(filePath,data ,'utf8')
|
||||
}
|
||||
pluginDefine.type = "builtIn"
|
||||
if(pluginDefine.accessType){
|
||||
pluginDefine.pluginType = "dnsProvider"
|
||||
}else if(isPrototypeOf(value,AbstractTaskPlugin)){
|
||||
pluginDefine.pluginType = "deploy"
|
||||
}else if(isPrototypeOf(value,BaseNotification)){
|
||||
pluginDefine.pluginType = "notification"
|
||||
}else if(isPrototypeOf(value,BaseAccess)){
|
||||
pluginDefine.pluginType = "access"
|
||||
}else{
|
||||
console.log(`[warning] 未知的插件类型:${pluginDefine.name}`)
|
||||
}
|
||||
const filePath = path.join(`./metadata/${pluginDefine.pluginType}_${pluginDefine.name}.yaml`)
|
||||
|
||||
pluginDefine.scriptFilePath = location
|
||||
const data = yaml.dump(pluginDefine)
|
||||
fs.writeFileSync(filePath,data ,'utf8')
|
||||
}
|
||||
}
|
||||
process.exit()
|
||||
}
|
||||
// import why from 'why-is-node-running'
|
||||
// setTimeout(() => why(), 100); // 延迟打印原因
|
||||
genMetadata()
|
||||
|
||||
process.exit()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@certd/ui-server",
|
||||
"version": "1.34.1",
|
||||
"version": "1.34.3",
|
||||
"description": "fast-server base midway",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
@@ -22,13 +22,15 @@
|
||||
"ci": "npm run cov",
|
||||
"build": "mwtsc --cleanOutDir --skipLibCheck",
|
||||
"export-metadata": "node export-plugin-yaml.js",
|
||||
"export-md": "node export-plugin-md.js",
|
||||
"dev-build": "echo 1",
|
||||
"build-on-docker": "node ./before-build.js && npm run build",
|
||||
"up-mw-deps": "npx midway-version -u -w",
|
||||
"heap": "cross-env NODE_ENV=local clinic heapprofiler -- node ./bootstrap.js",
|
||||
"flame": "clinic flame -- node ./bootstrap.js",
|
||||
"tsc": "tsc --skipLibCheck",
|
||||
"slimming": "node ./slimming.js"
|
||||
"slimming": "node ./slimming.js",
|
||||
"pub": "echo 1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@alicloud/fc20230330": "^4.1.7",
|
||||
@@ -39,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.1",
|
||||
"@certd/basic": "^1.34.1",
|
||||
"@certd/commercial-core": "^1.34.1",
|
||||
"@certd/jdcloud": "^1.34.1",
|
||||
"@certd/lib-huawei": "^1.34.1",
|
||||
"@certd/lib-k8s": "^1.34.1",
|
||||
"@certd/lib-server": "^1.34.1",
|
||||
"@certd/midway-flyway-js": "^1.34.1",
|
||||
"@certd/pipeline": "^1.34.1",
|
||||
"@certd/plugin-cert": "^1.34.1",
|
||||
"@certd/plugin-lib": "^1.34.1",
|
||||
"@certd/plugin-plus": "^1.34.1",
|
||||
"@certd/plus-core": "^1.34.1",
|
||||
"@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";
|
||||
|
||||
|
||||