From 5f95ee987fc36a09391a020a4e9cdd4b6f00a1dc Mon Sep 17 00:00:00 2001 From: ahe Date: Fri, 17 Apr 2026 16:46:44 +0800 Subject: [PATCH 1/4] =?UTF-8?q?fix=20=E7=AB=99=E7=82=B9IP=E7=9B=91?= =?UTF-8?q?=E6=8E=A7=E6=8F=90=E7=A4=BA=E6=9D=83=E9=99=90=E4=B8=8D=E8=B6=B3?= =?UTF-8?q?=20(#714)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../certd-client/src/views/certd/monitor/site/ip/index.vue | 6 ------ 1 file changed, 6 deletions(-) diff --git a/packages/ui/certd-client/src/views/certd/monitor/site/ip/index.vue b/packages/ui/certd-client/src/views/certd/monitor/site/ip/index.vue index 3f07bf92d..c3434a669 100644 --- a/packages/ui/certd-client/src/views/certd/monitor/site/ip/index.vue +++ b/packages/ui/certd-client/src/views/certd/monitor/site/ip/index.vue @@ -8,7 +8,6 @@ import { onActivated, onMounted, ref, Ref } from "vue"; import { useFs } from "@fast-crud/fast-crud"; import createCrudOptions from "./crud"; -import { siteIpApi } from "./api"; defineOptions({ name: "SiteIpCertMonitor", @@ -23,11 +22,6 @@ const { crudBinding, crudRef, crudExpose } = useFs({ }, }); -const siteInfoRef: Ref = ref({}); -onMounted(async () => { - siteInfoRef.value = await siteIpApi.GetObj(props.siteId); -}); - // 页面打开后获取列表数据 onMounted(() => { crudExpose.doRefresh(); From 23b465867244b199bab9b61863a5ca43644834a9 Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Fri, 17 Apr 2026 17:04:29 +0800 Subject: [PATCH 2/4] =?UTF-8?q?perf:=20apisix=E6=94=AF=E6=8C=81v2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/plugins/plugin-apisix/access.ts | 35 +++++++++++++++++-- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/packages/ui/certd-server/src/plugins/plugin-apisix/access.ts b/packages/ui/certd-server/src/plugins/plugin-apisix/access.ts index e2e15737d..df21b626f 100644 --- a/packages/ui/certd-server/src/plugins/plugin-apisix/access.ts +++ b/packages/ui/certd-server/src/plugins/plugin-apisix/access.ts @@ -32,6 +32,27 @@ export class ApisixAccess extends BaseAccess { }) apiKey = ''; + @AccessInput({ + title: '版本', + component: { + name:"a-select", + options: [ + { + label: "v3.x", + value: "3", + }, + { + label: "v2.x", + value: "2", + }, + ] + }, + helper: "apisix系统的版本", + value:"3", + required: true, + }) + version = '3'; + @AccessInput({ title: "测试", @@ -49,17 +70,24 @@ export class ApisixAccess extends BaseAccess { } async getCertList(){ + const sslPath = this.getSslPath(); const req = { - url :"/apisix/admin/ssls", + url :`/apisix/admin/${sslPath}`, method: "get", } return await this.doRequest(req); } + getSslPath(){ + const sslPath = this.version === '3' ? 'ssls' : 'ssl'; + return sslPath; + } + async createCert(opts:{cert:CertInfo}){ const certReader = new CertReader(opts.cert) + const sslPath = this.getSslPath(); const req = { - url :"/apisix/admin/ssls", + url :`/apisix/admin/${sslPath}`, method: "post", data:{ cert: opts.cert.crt, @@ -72,8 +100,9 @@ export class ApisixAccess extends BaseAccess { async updateCert (opts:{cert:CertInfo,id:string}){ const certReader = new CertReader(opts.cert) + const sslPath = this.getSslPath(); const req = { - url :`/apisix/admin/ssls/${opts.id}`, + url :`/apisix/admin/${sslPath}/${opts.id}`, method: "put", data:{ cert: opts.cert.crt, From edeb817c39597e4fa73a17ff4ca3f712f0320fec Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Fri, 17 Apr 2026 19:22:10 +0800 Subject: [PATCH 3/4] =?UTF-8?q?perf(technitium):=20=E6=B7=BB=E5=8A=A0Techn?= =?UTF-8?q?itium=20DNS=20Server=E6=8F=92=E4=BB=B6=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增Technitium DNS Server插件,包含DNS提供商和授权配置 - 实现DNS记录创建、删除和域名列表获取功能 - 添加默认DNS传播等待时间配置 - 优化用户取消操作时的错误处理 - 为图标选择组件添加过滤功能 - 更新DNS提供商开发文档 --- .trae/skills/access-plugin-dev/SKILL.md | 14 + .trae/skills/dns-provider-dev/SKILL.md | 47 +- packages/core/acme-client/src/auto.js | 3 +- packages/core/acme-client/src/client.js | 2 +- packages/core/acme-client/src/util.js | 7 +- packages/core/acme-client/types/index.d.ts | 1 + .../src/components/icon-select.vue | 2 +- .../cert/dns-provider-selector/index.vue | 2 +- .../plugin-cert/plugin/cert-plugin/acme.ts | 1 + .../src/plugins/plugin-demo/dns-provider.ts | 29 +- .../src/plugins/plugin-technitium/APIDOCS.md | 7493 +++++++++++++++++ .../src/plugins/plugin-technitium/access.ts | 179 + .../plugins/plugin-technitium/dns-provider.ts | 94 + .../src/plugins/plugin-technitium/index.ts | 2 + 14 files changed, 7863 insertions(+), 13 deletions(-) create mode 100644 packages/ui/certd-server/src/plugins/plugin-technitium/APIDOCS.md create mode 100644 packages/ui/certd-server/src/plugins/plugin-technitium/access.ts create mode 100644 packages/ui/certd-server/src/plugins/plugin-technitium/dns-provider.ts create mode 100644 packages/ui/certd-server/src/plugins/plugin-technitium/index.ts diff --git a/.trae/skills/access-plugin-dev/SKILL.md b/.trae/skills/access-plugin-dev/SKILL.md index 20e28a074..71eae368b 100644 --- a/.trae/skills/access-plugin-dev/SKILL.md +++ b/.trae/skills/access-plugin-dev/SKILL.md @@ -145,6 +145,20 @@ async doRequest(req: { action: string, data?: any }) { utils: typeof utils; accessService: IAccessService; } + + // this.ctx.http 只有request方法 + // 方法参数 + export type HttpRequestConfig = { + skipSslVerify?: boolean; + skipCheckRes?: boolean; + logParams?: boolean; + logRes?: boolean; + logData?: boolean; + httpProxy?: string; + returnOriginRes?: boolean; + } & AxiosRequestConfig; + + */ const res = await this.ctx.http.request({ url: "https://api.demo.cn/api/", diff --git a/.trae/skills/dns-provider-dev/SKILL.md b/.trae/skills/dns-provider-dev/SKILL.md index aab1540c7..4f8edb88a 100644 --- a/.trae/skills/dns-provider-dev/SKILL.md +++ b/.trae/skills/dns-provider-dev/SKILL.md @@ -105,6 +105,28 @@ async removeRecord(options: RemoveRecordOptions): Promise { } ``` +### 6. 实现 getDomainListPage 方法 +```typescript + /** + * 实现获取域名列表 + */ + async getDomainListPage(req: PageSearch): Promise> { + const pager = new Pager(req); + const res = await this.http.request({ + // 请求接口获取域名列表 + }) + const list = res.Domains?.map(item => ({ + id: item.Id, + domain: item.DomainName, + })) || [] + + return { + list, + total: res.Total, + } + } +``` + ### 6. 实例化插件 ```typescript @@ -204,11 +226,28 @@ export class DemoDnsProvider extends AbstractDnsProvider { this.logger.info('删除域名解析成功:', fullRecord, value); } + + /** + * 实现获取域名列表 + */ + async getDomainListPage(req: PageSearch): Promise> { + const pager = new Pager(req); + const res = await this.http.request({ + // 请求接口获取域名列表 + }) + const list = res.Domains?.map(item => ({ + id: item.Id, + domain: item.DomainName, + })) || [] + + return { + list, + total: res.Total, + } + } } // 实例化这个 provider,将其自动注册到系统中 -if (isDev()) { - // 你的实现 要去掉这个 if,不然生产环境将不会显示 - new DemoDnsProvider(); -} +new DemoDnsProvider(); + ``` \ No newline at end of file diff --git a/packages/core/acme-client/src/auto.js b/packages/core/acme-client/src/auto.js index 57b0e963b..03030c703 100644 --- a/packages/core/acme-client/src/auto.js +++ b/packages/core/acme-client/src/auto.js @@ -21,7 +21,8 @@ const defaultOpts = { }, challengeRemoveFn: async () => { throw new Error("Missing challengeRemoveFn()"); - } + }, + waitDnsDiffuseTime: 30, }; /** diff --git a/packages/core/acme-client/src/client.js b/packages/core/acme-client/src/client.js index 3f4bbcb01..0811648b7 100644 --- a/packages/core/acme-client/src/client.js +++ b/packages/core/acme-client/src/client.js @@ -577,7 +577,7 @@ class AcmeClient { const verifyFn = async (abort) => { if (this.opts.signal && this.opts.signal.aborted) { - abort(); + abort(true); throw new CancelError('用户取消'); } diff --git a/packages/core/acme-client/src/util.js b/packages/core/acme-client/src/util.js index a869619da..82a44069c 100644 --- a/packages/core/acme-client/src/util.js +++ b/packages/core/acme-client/src/util.js @@ -50,15 +50,18 @@ class Backoff { async function retryPromise(fn, attempts, backoff, logger = log) { let aborted = false; + let abortedFromUser = false; try { - const setAbort = () => { aborted = true; } + const setAbort = (fromUser = false) => { aborted = true; abortedFromUser = fromUser; } const data = await fn(setAbort); return data; } catch (e) { if (aborted){ - logger(`用户取消重试`); + if (abortedFromUser){ + logger(`用户取消重试`); + } throw e; } if ( ((backoff.attempts + 1) >= attempts)) { diff --git a/packages/core/acme-client/types/index.d.ts b/packages/core/acme-client/types/index.d.ts index a1d9dd899..805451f60 100644 --- a/packages/core/acme-client/types/index.d.ts +++ b/packages/core/acme-client/types/index.d.ts @@ -68,6 +68,7 @@ export interface ClientAutoOptions { preferredChain?: string; signal?: AbortSignal; profile?:string; + waitDnsDiffuseTime?: number; } export class Client { diff --git a/packages/ui/certd-client/src/components/icon-select.vue b/packages/ui/certd-client/src/components/icon-select.vue index 833de00ff..d7772cc28 100644 --- a/packages/ui/certd-client/src/components/icon-select.vue +++ b/packages/ui/certd-client/src/components/icon-select.vue @@ -1,5 +1,5 @@